diff --git a/.gitignore b/.gitignore index e58135604..75a4e462b 100644 --- a/.gitignore +++ b/.gitignore @@ -86,15 +86,13 @@ src/test/buildenv.py # Resources cpp qrc_*.cpp -# Qt creator -*.pro.user - # Mac specific .DS_Store build #lcov *.gcno +*.gcda /*.info test_bitcoin.coverage/ total.coverage/ @@ -108,6 +106,9 @@ qa/pull-tester/run-bitcoind-for-test.sh qa/pull-tester/tests_config.py qa/pull-tester/cache/* qa/pull-tester/test.*/* +qa/tmp +cache/ +share/BitcoindComparisonTool.jar !src/leveldb*/Makefile diff --git a/.travis.yml b/.travis.yml index 8e9684826..95ef36bf0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,13 @@ # - A travis bug causes caches to trample eachother when using the same # compiler key (which we don't use anyway). This is worked around for now by # replacing the "compilers" with a build name prefixed by the no-op ":" -# command. See: https://github.com/travis-ci/casher/issues/6 +# command. See: https://github.com/travis-ci/travis-ci/issues/4393 +# - sudo/dist/group are set so as to get Blue Box VMs, necessary for [loopback] +# IPv6 support + +sudo: required +dist: precise +group: legacy os: linux language: cpp @@ -11,6 +17,7 @@ env: global: - MAKEJOBS=-j3 - RUN_TESTS=false + - CHECK_DOC=0 - BOOST_TEST_RANDOM=1$TRAVIS_BUILD_ID - CCACHE_SIZE=100M - CCACHE_TEMPDIR=/tmp/.ccache-temp @@ -29,7 +36,7 @@ matrix: fast_finish: true include: - compiler: ": ARM" - env: HOST=arm-linux-gnueabihf PACKAGES="g++-arm-linux-gnueabihf" DEP_OPTS="NO_QT=1" GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" + env: HOST=arm-linux-gnueabihf PACKAGES="g++-arm-linux-gnueabihf" DEP_OPTS="NO_QT=1" CHECK_DOC=1 GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" - compiler: ": Win32" env: HOST=i686-w64-mingw32 PPA="ppa:ubuntu-wine/ppa" PACKAGES="nsis gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev wine1.7 bc" RUN_TESTS=true GOAL="deploy" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" MAKEJOBS="-j2" - compiler: ": 32-bit + dash" @@ -41,7 +48,7 @@ matrix: - compiler: ": No wallet" env: HOST=x86_64-unknown-linux-gnu DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" - compiler: ": Cross-Mac" - env: HOST=x86_64-apple-darwin11 PACKAGES="cmake libcap-dev libz-dev libbz2-dev" BITCOIN_CONFIG="--enable-reduce-exports" OSX_SDK=10.9 GOAL="deploy" + env: HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev" BITCOIN_CONFIG="--enable-reduce-exports" OSX_SDK=10.9 GOAL="deploy" exclude: - compiler: gcc install: @@ -51,11 +58,13 @@ install: - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES; fi before_script: - unset CC; unset CXX + - if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/check-doc.py; fi - mkdir -p depends/SDKs depends/sdk-sources - - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then wget $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -O depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi + - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS script: + - export TRAVIS_COMMIT_LOG=`git log --format=fuller -1` - if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST - BITCOIN_CONFIG_ALL="--disable-dependency-tracking --prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" @@ -69,6 +78,8 @@ script: - make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false ) - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib - if [ "$RUN_TESTS" = "true" ]; then make check; fi - - if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.py; fi + - if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.py --coverage; fi after_script: + - echo $TRAVIS_COMMIT_RANGE + - echo $TRAVIS_COMMIT_LOG - if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then (echo "Upload goes here. Something like: scp -r $BASE_OUTDIR server" || echo "upload failed"); fi diff --git a/.tx/config b/.tx/config index 6c534f06e..d6cc3aab8 100644 --- a/.tx/config +++ b/.tx/config @@ -1,7 +1,7 @@ [main] host = https://www.transifex.com -[bitcoin.qt-translation-011x] +[bitcoin.qt-translation-012x] file_filter = src/qt/locale/bitcoin_.ts source_file = src/qt/locale/bitcoin_en.ts source_lang = en diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1d42dea84..53d6527d4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -95,6 +95,8 @@ Anyone may participate in peer review which is expressed by comments in the pull - Concept ACK means "I agree in the general principle of this pull request"; - Nit refers to trivial, often non-blocking issues. +Reviewers should include the commit hash which they reviewed in their comments. + Project maintainers reserve the right to weigh the opinions of peer reviewers using common sense judgement and also may weight based on meritocracy: Those that have demonstrated a deeper commitment and understanding towards the project (over time) or have clear domain expertise may naturally have more weight, as one would expect in all walks of life. Where a patch set affects consensus critical code, the bar will be set much higher in terms of discussion and peer review requirements, keeping in mind that mistakes could be very costly to the wider community. This includes refactoring of consensus critical code. diff --git a/COPYING b/COPYING index 314d2e2ff..c6be8e547 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2009-2015 The Bitcoin Core developers +Copyright (c) 2009-2016 The Bitcoin Core developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile.am b/Makefile.am index de2d3f583..5783c1fdd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,43 +3,53 @@ SUBDIRS = src .PHONY: deploy FORCE GZIP_ENV="-9n" +export PYTHONPATH if BUILD_BITCOIN_LIBS pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libbitcoinconsensus.pc endif -BITCOIND_BIN=$(top_builddir)/src/lbrycrdd$(EXEEXT) -BITCOIN_QT_BIN=$(top_builddir)/src/qt/lbrycrd-qt$(EXEEXT) -BITCOIN_CLI_BIN=$(top_builddir)/src/lbrycrd-cli$(EXEEXT) +BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT) +BITCOIN_QT_BIN=$(top_builddir)/src/qt/$(BITCOIN_GUI_NAME)$(EXEEXT) +BITCOIN_CLI_BIN=$(top_builddir)/src/$(BITCOIN_CLI_NAME)$(EXEEXT) BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT) +empty := +space := $(empty) $(empty) + OSX_APP=Bitcoin-Qt.app -OSX_DMG=Bitcoin-Core.dmg +OSX_VOLNAME = $(subst $(space),-,$(PACKAGE_NAME)) +OSX_DMG = $(OSX_VOLNAME).dmg +OSX_BACKGROUND_SVG=background.svg OSX_BACKGROUND_IMAGE=background.tiff +OSX_BACKGROUND_IMAGE_DPIS=36 72 +OSX_DSSTORE_GEN=$(top_srcdir)/contrib/macdeploy/custom_dsstore.py OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist -OSX_BASE_LPROJ_DIR=$(top_srcdir)/contrib/macdeploy/Base.lproj/InfoPlist.strings OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns OSX_PLIST=$(top_srcdir)/share/qt/Info.plist #not installed OSX_QT_TRANSLATIONS = da,de,es,hu,ru,uk,zh_CN,zh_TW DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md) +BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \ + $(top_srcdir)/contrib/devtools/security-check.py + WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \ $(top_srcdir)/share/pixmaps/nsis-header.bmp \ $(top_srcdir)/share/pixmaps/nsis-wizard.bmp \ $(top_srcdir)/doc/README_windows.txt -OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) $(OSX_BASE_LPROJ_DIR) \ - $(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) \ - $(top_srcdir)/contrib/macdeploy/DS_Store \ +OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \ + $(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_SVG) \ + $(OSX_DSSTORE_GEN) \ $(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \ $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \ leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \ - baseline_filtered.info block_test_filtered.info \ + baseline_filtered.info block_test_filtered.info rpc_test.info rpc_test_filtered.info \ leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info dist-hook: @@ -87,17 +97,20 @@ $(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(BITCOIN_QT_BIN) $(MKDIR_P) $(@D) STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $< $@ -$(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings: $(OSX_BASE_LPROJ_DIR) +$(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings: $(MKDIR_P) $(@D) - $(INSTALL_DATA) $< $@ + echo '{ CFBundleDisplayName = "$(PACKAGE_NAME)"; CFBundleName = "$(PACKAGE_NAME)"; }' > $@ OSX_APP_BUILT=$(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lproj \ $(OSX_APP)/Contents/Resources/bitcoin.icns $(OSX_APP)/Contents/Info.plist \ $(OSX_APP)/Contents/MacOS/Bitcoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings +osx_volname: + echo $(OSX_VOLNAME) >$@ + if BUILD_DARWIN $(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) - $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -add-qt-tr $(OSX_QT_TRANSLATIONS) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 + $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -add-qt-tr $(OSX_QT_TRANSLATIONS) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 -volname $(OSX_VOLNAME) deploydir: $(OSX_DMG) else @@ -111,16 +124,20 @@ $(APP_DIST_DIR)/Applications: $(APP_DIST_EXTRAS): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt $(OSX_DMG): $(APP_DIST_EXTRAS) - $(GENISOIMAGE) -no-cache-inodes -D -l -probe -V "Bitcoin-Core" -no-pad -r -apple -o $@ dist + $(GENISOIMAGE) -no-cache-inodes -D -l -probe -V "$(OSX_VOLNAME)" -no-pad -r -dir-mode 0755 -apple -o $@ dist -$(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE): contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) +dpi%.$(OSX_BACKGROUND_IMAGE): contrib/macdeploy/$(OSX_BACKGROUND_SVG) + sed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < "$<" | $(RSVG_CONVERT) -f png -d $* -p $* | $(IMAGEMAGICK_CONVERT) - $@ +OSX_BACKGROUND_IMAGE_DPIFILES := $(foreach dpi,$(OSX_BACKGROUND_IMAGE_DPIS),dpi$(dpi).$(OSX_BACKGROUND_IMAGE)) +$(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE): $(OSX_BACKGROUND_IMAGE_DPIFILES) $(MKDIR_P) $(@D) - $(INSTALL) $< $@ -$(APP_DIST_DIR)/.DS_Store: contrib/macdeploy/DS_Store - $(INSTALL) $< $@ + $(TIFFCP) -c none $(OSX_BACKGROUND_IMAGE_DPIFILES) $@ + +$(APP_DIST_DIR)/.DS_Store: $(OSX_DSSTORE_GEN) + $(PYTHON) $< "$@" "$(OSX_VOLNAME)" $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING) - INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2 + INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2 deploydir: $(APP_DIST_EXTRAS) endif @@ -170,7 +187,7 @@ test_bitcoin_filtered.info: test_bitcoin.info block_test.info: test_bitcoin_filtered.info $(MKDIR_P) qa/tmp - -@TIMEOUT=15 qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool 0 + -@TIMEOUT=15 qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool $(COMPARISON_TOOL_REORG_TESTS) $(LCOV) -c -d $(abs_builddir)/src --t BitcoinJBlockTest -o $@ $(LCOV) -z -d $(abs_builddir)/src $(LCOV) -z -d $(abs_builddir)/src/leveldb @@ -178,11 +195,20 @@ block_test.info: test_bitcoin_filtered.info block_test_filtered.info: block_test.info $(LCOV) -r $< "/usr/include/*" -o $@ +rpc_test.info: test_bitcoin_filtered.info + -@TIMEOUT=15 python qa/pull-tester/rpc-tests.py $(EXTENDED_RPC_TESTS) + $(LCOV) -c -d $(abs_builddir)/src --t rpc-tests -o $@ + $(LCOV) -z -d $(abs_builddir)/src + $(LCOV) -z -d $(abs_builddir)/src/leveldb + +rpc_test_filtered.info: rpc_test.info + $(LCOV) -r $< "/usr/include/*" -o $@ + test_bitcoin_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -o $@ -total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info block_test_filtered.info - $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a block_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt +total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info block_test_filtered.info rpc_test_filtered.info + $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a block_test_filtered.info -a rpc_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info $(GENHTML) -s $< -o $(@D) @@ -204,11 +230,11 @@ endif dist_noinst_SCRIPTS = autogen.sh -EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.py qa/pull-tester/tests_config.py qa/rpc-tests $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) +EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.py qa/rpc-tests $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS) CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER) .INTERMEDIATE: $(COVERAGE_INFO) clean-local: - rm -rf test_bitcoin.coverage/ total.coverage/ $(OSX_APP) + rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ qa/tmp/ cache/ $(OSX_APP) diff --git a/README.md b/README.md index 401becc98..8a3352319 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,14 @@ out collectively by the network. Bitcoin Core is the name of open source software which enables the use of this currency. For more information, as well as an immediately useable, binary version of -the Bitcoin Core software, see https://www.bitcoin.org/en/download. +the Bitcoin Core software, see https://bitcoin.org/en/download, or read the +[original whitepaper](https://bitcoincore.org/bitcoin.pdf). License ------- Bitcoin Core is released under the terms of the MIT license. See [COPYING](COPYING) for more -information or see http://opensource.org/licenses/MIT. +information or see https://opensource.org/licenses/MIT. Development Process ------------------- @@ -53,24 +54,23 @@ lots of money. ### Automated Testing -Developers are strongly encouraged to write unit tests for new code, and to -submit new unit tests for old code. Unit tests can be compiled and run (assuming they weren't disabled in configure) with: `make check` +Developers are strongly encouraged to write [unit tests](/doc/unit-tests.md) for new code, and to +submit new unit tests for old code. Unit tests can be compiled and run +(assuming they weren't disabled in configure) with: `make check` -There are also regression and integration tests of the RPC interface, written +There are also [regression and integration tests](/qa) of the RPC interface, written in Python, that are run automatically on the build server. -These tests can be run with: `qa/pull-tester/rpc-tests.py` +These tests can be run (if the [test dependencies](/qa) are installed) with: `qa/pull-tester/rpc-tests.py` -Every pull request is built for both Windows and Linux on a dedicated server, -and unit and sanity tests are automatically run. The binaries produced may be -used for manual QA testing — a link to them will appear in a comment on the -pull request posted by [BitcoinPullTester](https://github.com/BitcoinPullTester). See https://github.com/TheBlueMatt/test-scripts -for the build/test scripts. +The Travis CI system makes sure that every pull request is built for Windows +and Linux, OS X, and that unit and sanity tests are automatically run. ### Manual Quality Assurance (QA) Testing -Large changes should have a test plan, and should be tested by somebody other -than the developer who wrote the code. -See https://github.com/bitcoin/QA/ for how to create a test plan. +Changes should be tested by somebody other than the developer who wrote the +code. This is especially important for large or high-risk changes. It is useful +to add a test plan to the pull request description if testing the changes is +not straightforward. Translations ------------ diff --git a/autogen.sh b/autogen.sh index 3e26a1830..46e36ff5b 100755 --- a/autogen.sh +++ b/autogen.sh @@ -6,4 +6,6 @@ if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then LIBTOOLIZE="${GLIBTOOLIZE}" export LIBTOOLIZE fi +which autoreconf >/dev/null || \ + (echo "configuration failed, please install autoconf first" && exit 1) autoreconf --install --force --warnings=all diff --git a/build-aux/m4/ax_boost_base.m4 b/build-aux/m4/ax_boost_base.m4 index 3f24d5ddc..45d948933 100644 --- a/build-aux/m4/ax_boost_base.m4 +++ b/build-aux/m4/ax_boost_base.m4 @@ -33,7 +33,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 23 +#serial 26 AC_DEFUN([AX_BOOST_BASE], [ @@ -95,8 +95,8 @@ if test "x$want_boost" = "xyes"; then x86_64) libsubdirs="lib64 libx32 lib lib64" ;; - ppc64|s390x|sparc64|aarch64) - libsubdirs="lib64 lib lib64" + ppc64|s390x|sparc64|aarch64|ppc64le) + libsubdirs="lib64 lib lib64 ppc64le" ;; esac @@ -170,7 +170,7 @@ if test "x$want_boost" = "xyes"; then AC_MSG_RESULT(yes) succeeded=yes found_system=yes - ],[: + ],[ ]) AC_LANG_POP([C++]) @@ -179,6 +179,10 @@ if test "x$want_boost" = "xyes"; then dnl if we found no boost with system layout we search for boost libraries dnl built and installed without the --layout=system option or for a staged(not installed) version if test "x$succeeded" != "xyes"; then + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + BOOST_CPPFLAGS= + BOOST_LDFLAGS= _version=0 if test "$ac_boost_path" != ""; then if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then @@ -191,6 +195,12 @@ if test "x$want_boost" = "xyes"; then VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE" done + dnl if nothing found search for layout used in Windows distributions + if test -z "$BOOST_CPPFLAGS"; then + if test -d "$ac_boost_path/boost" && test -r "$ac_boost_path/boost"; then + BOOST_CPPFLAGS="-I$ac_boost_path" + fi + fi fi else if test "$cross_compiling" != yes; then @@ -253,7 +263,7 @@ if test "x$want_boost" = "xyes"; then AC_MSG_RESULT(yes) succeeded=yes found_system=yes - ],[: + ],[ ]) AC_LANG_POP([C++]) fi diff --git a/build-aux/m4/ax_boost_program_options.m4 b/build-aux/m4/ax_boost_program_options.m4 index f59144185..2bdb59371 100644 --- a/build-aux/m4/ax_boost_program_options.m4 +++ b/build-aux/m4/ax_boost_program_options.m4 @@ -29,7 +29,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 22 +#serial 24 AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], [ @@ -63,9 +63,9 @@ AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], AC_CACHE_CHECK([whether the Boost::Program_Options library is available], ax_cv_boost_program_options, [AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::program_options::options_description generic("Generic options"); + [[boost::program_options::error err("Error message"); return 0;]])], ax_cv_boost_program_options=yes, ax_cv_boost_program_options=no) AC_LANG_POP([C++]) @@ -74,7 +74,6 @@ AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], AC_DEFINE(HAVE_BOOST_PROGRAM_OPTIONS,,[define if the Boost::PROGRAM_OPTIONS library is available]) BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` if test "x$ax_boost_user_program_options_lib" = "x"; then - ax_lib= for libextension in `ls $BOOSTLIBDIR/libboost_program_options*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.dylib* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.dylib.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.a.*$;\1;'` ; do ax_lib=${libextension} AC_CHECK_LIB($ax_lib, exit, diff --git a/build-aux/m4/ax_boost_system.m4 b/build-aux/m4/ax_boost_system.m4 index 9c78280fc..1c05450cb 100644 --- a/build-aux/m4/ax_boost_system.m4 +++ b/build-aux/m4/ax_boost_system.m4 @@ -31,7 +31,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 17 +#serial 18 AC_DEFUN([AX_BOOST_SYSTEM], [ @@ -68,9 +68,10 @@ AC_DEFUN([AX_BOOST_SYSTEM], ax_cv_boost_system, [AC_LANG_PUSH([C++]) CXXFLAGS_SAVE=$CXXFLAGS + CXXFLAGS= AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::system::system_category]])], + [[boost::system::error_category *a = 0;]])], ax_cv_boost_system=yes, ax_cv_boost_system=no) CXXFLAGS=$CXXFLAGS_SAVE AC_LANG_POP([C++]) diff --git a/build-aux/m4/ax_check_compile_flag.m4 b/build-aux/m4/ax_check_compile_flag.m4 index c3a8d695a..ca3639715 100644 --- a/build-aux/m4/ax_check_compile_flag.m4 +++ b/build-aux/m4/ax_check_compile_flag.m4 @@ -4,7 +4,7 @@ # # SYNOPSIS # -# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # @@ -19,6 +19,8 @@ # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # @@ -53,19 +55,19 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 4 AC_DEFUN([AX_CHECK_COMPILE_FLAG], -[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) -AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], +AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl diff --git a/build-aux/m4/ax_check_link_flag.m4 b/build-aux/m4/ax_check_link_flag.m4 index e2d0d363e..eb01a6ce1 100644 --- a/build-aux/m4/ax_check_link_flag.m4 +++ b/build-aux/m4/ax_check_link_flag.m4 @@ -4,7 +4,7 @@ # # SYNOPSIS # -# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # @@ -19,6 +19,8 @@ # EXTRA-FLAGS FLAG". This can for example be used to force the linker to # issue an error when a bad flag is given. # +# INPUT gives an alternative input source to AC_LINK_IFELSE. +# # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. # @@ -53,18 +55,19 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 4 AC_DEFUN([AX_CHECK_LINK_FLAG], -[AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ ax_check_save_flags=$LDFLAGS LDFLAGS="$LDFLAGS $4 $1" - AC_LINK_IFELSE([AC_LANG_PROGRAM()], + AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) LDFLAGS=$ax_check_save_flags]) -AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], +AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl diff --git a/build-aux/m4/ax_check_preproc_flag.m4 b/build-aux/m4/ax_check_preproc_flag.m4 index b1cfef6b8..ca1d5ee2b 100644 --- a/build-aux/m4/ax_check_preproc_flag.m4 +++ b/build-aux/m4/ax_check_preproc_flag.m4 @@ -4,7 +4,7 @@ # # SYNOPSIS # -# AX_CHECK_PREPROC_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# AX_CHECK_PREPROC_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # @@ -19,6 +19,8 @@ # "CPPFLAGS EXTRA-FLAGS FLAG". This can for example be used to force the # preprocessor to issue an error when a bad flag is given. # +# INPUT gives an alternative input source to AC_PREPROC_IFELSE. +# # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{COMPILE,LINK}_FLAG. # @@ -53,19 +55,19 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 4 AC_DEFUN([AX_CHECK_PREPROC_FLAG], -[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]cppflags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG preprocessor accepts $1], CACHEVAR, [ ax_check_save_flags=$CPPFLAGS CPPFLAGS="$CPPFLAGS $4 $1" - AC_PREPROC_IFELSE([AC_LANG_PROGRAM()], + AC_PREPROC_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) CPPFLAGS=$ax_check_save_flags]) -AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], +AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl diff --git a/build-aux/m4/ax_gcc_func_attribute.m4 b/build-aux/m4/ax_gcc_func_attribute.m4 index 275ca63a2..c788ca9bd 100644 --- a/build-aux/m4/ax_gcc_func_attribute.m4 +++ b/build-aux/m4/ax_gcc_func_attribute.m4 @@ -31,6 +31,7 @@ # cold # const # constructor +# constructor_priority for constructor attribute with priority # deprecated # destructor # dllexport @@ -73,7 +74,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 2 +#serial 3 AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1]) @@ -103,6 +104,9 @@ AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ [const], [ int foo( void ) __attribute__(($1)); ], + [constructor_priority], [ + int foo( void ) __attribute__((__constructor__(65535/2))); + ], [constructor], [ int foo( void ) __attribute__(($1)); ], @@ -180,6 +184,8 @@ AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ [visibility], [ int foo_def( void ) __attribute__(($1("default"))); int foo_hid( void ) __attribute__(($1("hidden"))); + int foo_int( void ) __attribute__(($1("internal"))); + int foo_pro( void ) __attribute__(($1("protected"))); ], [warning], [ int foo( void ) __attribute__(($1(""))); diff --git a/build-aux/m4/ax_pthread.m4 b/build-aux/m4/ax_pthread.m4 index d383ad5c6..d218d1af7 100644 --- a/build-aux/m4/ax_pthread.m4 +++ b/build-aux/m4/ax_pthread.m4 @@ -19,10 +19,10 @@ # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, -# but also link it with them as well. e.g. you should link with +# but also to link with them as well. For example, you might link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # -# If you are only building threads programs, you may wish to use these +# If you are only building threaded programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" @@ -30,8 +30,8 @@ # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant -# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name -# (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to +# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with @@ -82,35 +82,40 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 21 +#serial 22 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_PROG_SED]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). +# requires special compiler flags (e.g. on Tru64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) - AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) - AC_MSG_RESULT([$ax_pthread_ok]) - if test x"$ax_pthread_ok" = xno; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) + AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) + AC_MSG_RESULT([$ax_pthread_ok]) + if test "x$ax_pthread_ok" = "xno"; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" fi # We must check for the threads library under a number of different @@ -123,7 +128,7 @@ fi # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. -ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: @@ -132,186 +137,334 @@ ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mt # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# ... -mt is also the pthreads flag for HP/aCC +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) -case ${host_os} in - solaris*) +case $host_os in - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthreads/-mt/ - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: + freebsd*) - ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" - ;; + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) - darwin*) - ax_pthread_flags="-pthread $ax_pthread_flags" - ;; + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], + [ +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + ], + [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) + ;; + + solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" + ;; esac -# Clang doesn't consider unrecognized options an error unless we specify -# -Werror. We throw in some extra Clang-specific options to ensure that -# this doesn't happen for GCC, which also accepts -Werror. +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) -AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags]) -save_CFLAGS="$CFLAGS" -ax_pthread_extra_flags="-Werror" -CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])], - [AC_MSG_RESULT([yes])], - [ax_pthread_extra_flags= - AC_MSG_RESULT([no])]) -CFLAGS="$save_CFLAGS" +AS_IF([test "x$GCC" = "xyes"], + [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"]) -if test x"$ax_pthread_ok" = xno; then -for flag in $ax_pthread_flags; do +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled - case $flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; - -*) - AC_MSG_CHECKING([whether pthreads work with $flag]) - PTHREAD_CFLAGS="$flag" - ;; + aix* | freebsd*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; - pthread-config) - AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) - if test x"$ax_pthread_config" = xno; then continue; fi - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; + *) + ax_pthread_check_macro="--" + ;; +esac +AS_IF([test "x$ax_pthread_check_macro" = "x--"], + [ax_pthread_check_cond=0], + [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) - *) - AC_MSG_CHECKING([for the pthreads library -l$flag]) - PTHREAD_LIBS="-l$flag" - ;; - esac +# Are we compiling with Clang? - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" +AC_CACHE_CHECK([whether $CC is Clang], + [ax_cv_PTHREAD_CLANG], + [ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], + [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + ], + [ax_cv_PTHREAD_CLANG=yes]) + fi + ]) +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include - static void routine(void *a) { a = 0; } - static void *start_routine(void *a) { return a; }], - [pthread_t th; pthread_attr_t attr; - pthread_create(&th, 0, start_routine, 0); - pthread_join(th, 0); - pthread_attr_init(&attr); - pthread_cleanup_push(routine, 0); - pthread_cleanup_pop(0) /* ; */])], - [ax_pthread_ok=yes], - []) +ax_pthread_clang_warning=no - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way - AC_MSG_RESULT([$ax_pthread_ok]) - if test "x$ax_pthread_ok" = xyes; then - break; - fi +if test "x$ax_pthread_clang" = "xyes"; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + PTHREAD_CFLAGS="-pthread" + PTHREAD_LIBS= + + ax_pthread_ok=yes + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [ac_link="$ax_pthread_2step_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [break]) + ]) + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + ]) + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -mt,pthread) + AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) + PTHREAD_CFLAGS="-mt" + PTHREAD_LIBS="-lpthread" + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) + PTHREAD_CFLAGS="$ax_pthread_try_flag" + ;; + + pthread-config) + AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) + AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) + PTHREAD_LIBS="-l$ax_pthread_try_flag" + ;; + esac + + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; }], + [pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */])], + [ax_pthread_ok=yes], + []) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + AC_MSG_RESULT([$ax_pthread_ok]) + AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" done fi # Various other checks: -if test "x$ax_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" - # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_MSG_CHECKING([for joinable pthread attribute]) - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], - [int attr = $attr; return attr /* ; */])], - [attr_name=$attr; break], - []) - done - AC_MSG_RESULT([$attr_name]) - if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then - AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], - [Define to necessary symbol if this constant - uses a non-standard name on your system.]) - fi + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_CACHE_CHECK([for joinable pthread attribute], + [ax_cv_PTHREAD_JOINABLE_ATTR], + [ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [int attr = $ax_pthread_attr; return attr /* ; */])], + [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], + []) + done + ]) + AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"], + [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], + [$ax_cv_PTHREAD_JOINABLE_ATTR], + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + ax_pthread_joinable_attr_defined=yes + ]) - AC_MSG_CHECKING([if more special flags are required for pthreads]) - flag=no - case ${host_os} in - aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; - osf* | hpux*) flag="-D_REENTRANT";; - solaris*) - if test "$GCC" = "yes"; then - flag="-D_REENTRANT" - else - # TODO: What about Clang on Solaris? - flag="-mt -D_REENTRANT" - fi - ;; - esac - AC_MSG_RESULT([$flag]) - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi + AC_CACHE_CHECK([whether more special flags are required for pthreads], + [ax_cv_PTHREAD_SPECIAL_FLAGS], + [ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + ]) + AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"], + [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes]) - AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], - [ax_cv_PTHREAD_PRIO_INHERIT], [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[int i = PTHREAD_PRIO_INHERIT;]])], - [ax_cv_PTHREAD_PRIO_INHERIT=yes], - [ax_cv_PTHREAD_PRIO_INHERIT=no]) - ]) - AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], - [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) + AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], + [ax_cv_PTHREAD_PRIO_INHERIT], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int i = PTHREAD_PRIO_INHERIT;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) + ]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"], + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) + ax_pthread_prio_inherit_defined=yes + ]) - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" - # More AIX lossage: compile with *_r variant - if test "x$GCC" != xyes; then - case $host_os in - aix*) - AS_CASE(["x/$CC"], - [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], - [#handle absolute path differently from PATH based program lookup - AS_CASE(["x$CC"], - [x/*], - [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], - [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) - ;; - esac - fi + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + AS_CASE(["x/$CC"], + [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], + [#handle absolute path differently from PATH based program lookup + AS_CASE(["x$CC"], + [x/*], + [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], + [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) + ;; + esac + fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" @@ -321,12 +474,12 @@ AC_SUBST([PTHREAD_CFLAGS]) AC_SUBST([PTHREAD_CC]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$ax_pthread_ok" = xyes; then - ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) - : +if test "x$ax_pthread_ok" = "xyes"; then + ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) + : else - ax_pthread_ok=no - $2 + ax_pthread_ok=no + $2 fi AC_LANG_POP ])dnl AX_PTHREAD diff --git a/build-aux/m4/bitcoin_find_bdb48.m4 b/build-aux/m4/bitcoin_find_bdb48.m4 index 0bf558d25..2aa493a6a 100644 --- a/build-aux/m4/bitcoin_find_bdb48.m4 +++ b/build-aux/m4/bitcoin_find_bdb48.m4 @@ -38,7 +38,7 @@ AC_DEFUN([BITCOIN_FIND_BDB48],[ done if test "x$bdbpath" = "xX"; then AC_MSG_RESULT([no]) - AC_MSG_ERROR([libdb_cxx headers missing, Bitcoin Core requires this library for wallet functionality (--disable-wallet to disable wallet functionality)]) + AC_MSG_ERROR([libdb_cxx headers missing, ]AC_PACKAGE_NAME[ requires this library for wallet functionality (--disable-wallet to disable wallet functionality)]) elif test "x$bdb48path" = "xX"; then BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdbpath}],db_cxx) AC_ARG_WITH([incompatible-bdb],[AS_HELP_STRING([--with-incompatible-bdb], [allow using a bdb version other than 4.8])],[ @@ -60,7 +60,7 @@ AC_DEFUN([BITCOIN_FIND_BDB48],[ ]) done if test "x$BDB_LIBS" = "x"; then - AC_MSG_ERROR([libdb_cxx missing, Bitcoin Core requires this library for wallet functionality (--disable-wallet to disable wallet functionality)]) + AC_MSG_ERROR([libdb_cxx missing, ]AC_PACKAGE_NAME[ requires this library for wallet functionality (--disable-wallet to disable wallet functionality)]) fi AC_SUBST(BDB_LIBS) ]) diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index 121e10bd3..efffa4887 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -50,7 +50,7 @@ AC_DEFUN([BITCOIN_QT_INIT],[ dnl enable qt support AC_ARG_WITH([gui], [AS_HELP_STRING([--with-gui@<:@=no|qt4|qt5|auto@:>@], - [build bitcoin-qt GUI (default=auto, qt4 tried first)])], + [build bitcoin-qt GUI (default=auto, qt5 tried first)])], [ bitcoin_qt_want_version=$withval if test x$bitcoin_qt_want_version = xyes; then @@ -106,7 +106,9 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ dnl results to QT_LIBS. BITCOIN_QT_CHECK([ TEMP_CPPFLAGS=$CPPFLAGS + TEMP_CXXFLAGS=$CXXFLAGS CPPFLAGS="$QT_INCLUDES $CPPFLAGS" + CXXFLAGS="$PIC_FLAGS $CXXFLAGS" if test x$bitcoin_qt_got_major_vers = x5; then _BITCOIN_QT_IS_STATIC if test x$bitcoin_cv_static_qt = xyes; then @@ -149,6 +151,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ fi fi CPPFLAGS=$TEMP_CPPFLAGS + CXXFLAGS=$TEMP_CXXFLAGS ]) if test x$use_pkgconfig$qt_bin_path = xyes; then @@ -157,6 +160,43 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ fi fi + if test x$use_hardening != xno; then + BITCOIN_QT_CHECK([ + AC_MSG_CHECKING(whether -fPIE can be used with this Qt config) + TEMP_CPPFLAGS=$CPPFLAGS + TEMP_CXXFLAGS=$CXXFLAGS + CPPFLAGS="$QT_INCLUDES $CPPFLAGS" + CXXFLAGS="$PIE_FLAGS $CXXFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ + #if defined(QT_REDUCE_RELOCATIONS) + choke; + #endif + ]])], + [ AC_MSG_RESULT(yes); QT_PIE_FLAGS=$PIE_FLAGS ], + [ AC_MSG_RESULT(no); QT_PIE_FLAGS=$PIC_FLAGS] + ) + CPPFLAGS=$TEMP_CPPFLAGS + CXXFLAGS=$TEMP_CXXFLAGS + ]) + else + BITCOIN_QT_CHECK([ + AC_MSG_CHECKING(whether -fPIC is needed with this Qt config) + TEMP_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$QT_INCLUDES $CPPFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ + #if defined(QT_REDUCE_RELOCATIONS) + choke; + #endif + ]])], + [ AC_MSG_RESULT(no)], + [ AC_MSG_RESULT(yes); QT_PIE_FLAGS=$PIC_FLAGS] + ) + CPPFLAGS=$TEMP_CPPFLAGS + ]) + fi + BITCOIN_QT_PATH_PROGS([MOC], [moc-qt${bitcoin_qt_got_major_vers} moc${bitcoin_qt_got_major_vers} moc], $qt_bin_path) BITCOIN_QT_PATH_PROGS([UIC], [uic-qt${bitcoin_qt_got_major_vers} uic${bitcoin_qt_got_major_vers} uic], $qt_bin_path) BITCOIN_QT_PATH_PROGS([RCC], [rcc-qt${bitcoin_qt_got_major_vers} rcc${bitcoin_qt_got_major_vers} rcc], $qt_bin_path) @@ -180,7 +220,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ dnl enable qt support - AC_MSG_CHECKING(whether to build Bitcoin Core GUI) + AC_MSG_CHECKING(whether to build ]AC_PACKAGE_NAME[ GUI) BITCOIN_QT_CHECK([ bitcoin_enable_qt=yes bitcoin_enable_qt_test=yes @@ -202,6 +242,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ ]) AC_MSG_RESULT([$bitcoin_enable_qt (Qt${bitcoin_qt_got_major_vers})]) + AC_SUBST(QT_PIE_FLAGS) AC_SUBST(QT_INCLUDES) AC_SUBST(QT_LIBS) AC_SUBST(QT_LDFLAGS) @@ -343,7 +384,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG],[ dnl qt version is set to 'auto' and the preferred version wasn't found. Now try the other. if test x$have_qt = xno && test x$bitcoin_qt_want_version = xauto; then - if test x$auto_priority_version = x$qt5; then + if test x$auto_priority_version = xqt5; then PKG_CHECK_MODULES([QT], [$qt4_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes; QT_LIB_PREFIX=Qt; bitcoin_qt_got_major_vers=4], [have_qt=no]) else PKG_CHECK_MODULES([QT], [$qt5_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes; QT_LIB_PREFIX=Qt5; bitcoin_qt_got_major_vers=5], [have_qt=no]) @@ -373,6 +414,8 @@ dnl Outputs: bitcoin_qt_got_major_vers is set to "4" or "5". dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no. AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ TEMP_CPPFLAGS="$CPPFLAGS" + TEMP_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$PIC_FLAGS $CXXFLAGS" TEMP_LIBS="$LIBS" BITCOIN_QT_CHECK([ if test x$qt_include_path != x; then @@ -442,6 +485,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ fi ]) CPPFLAGS="$TEMP_CPPFLAGS" + CXXFLAGS="$TEMP_CXXFLAGS" LIBS="$TEMP_LIBS" ]) diff --git a/configure.ac b/configure.ac index a807044f9..81a63e7ef 100644 --- a/configure.ac +++ b/configure.ac @@ -1,17 +1,24 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 0) -define(_CLIENT_VERSION_MINOR, 11) +define(_CLIENT_VERSION_MINOR, 12) define(_CLIENT_VERSION_REVISION, 99) define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, false) -define(_COPYRIGHT_YEAR, 2015) -AC_INIT([LBRYcrd Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/lbryio/lbrycrd/issues],[lbrycrd]) +define(_COPYRIGHT_YEAR, 2016) +define(_COPYRIGHT_HOLDERS,[The %s developers]) +define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[LBRY]]) +AC_INIT([LBRYcrd Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/lbryio/lbrycrd/issues],[lbrycrd],[https://lbry.io/]) AC_CONFIG_SRCDIR([src/main.cpp]) AC_CONFIG_HEADERS([src/config/bitcoin-config.h]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux/m4]) +BITCOIN_DAEMON_NAME=lbrycrdd +BITCOIN_GUI_NAME=lbrycrd-qt +BITCOIN_CLI_NAME=lbrycrd-cli +BITCOIN_TX_NAME=lbrycrd-tx + AC_CANONICAL_HOST AH_TOP([#ifndef BITCOIN_CONFIG_H]) @@ -58,11 +65,16 @@ AC_PATH_TOOL(STRIP, strip) AC_PATH_TOOL(GCOV, gcov) AC_PATH_PROG(LCOV, lcov) AC_PATH_PROG(JAVA, java) +AC_PATH_PROGS([PYTHON], [python3 python2.7 python2 python]) AC_PATH_PROG(GENHTML, genhtml) AC_PATH_PROG([GIT], [git]) AC_PATH_PROG(CCACHE,ccache) AC_PATH_PROG(XGETTEXT,xgettext) AC_PATH_PROG(HEXDUMP,hexdump) +AC_PATH_TOOL(READELF, readelf) +AC_PATH_TOOL(CPPFILT, c++filt) + +AC_ARG_VAR(PYTHONPATH, Augments the default search path for python module files) dnl pkg-config check. PKG_PROG_PKG_CONFIG @@ -91,8 +103,13 @@ AC_ARG_ENABLE(tests, [use_tests=$enableval], [use_tests=yes]) +AC_ARG_ENABLE(gui-tests, + AS_HELP_STRING([--disable-gui-tests],[do not compile GUI tests (default is to compile if GUI and tests enabled)]), + [use_gui_tests=$enableval], + [use_gui_tests=$use_tests]) + AC_ARG_ENABLE(bench, - AS_HELP_STRING([--enable-bench],[compile benchmarks (default is yes)]), + AS_HELP_STRING([--disable-bench],[do not compile benchmarks (default is to compile)]), [use_bench=$enableval], [use_bench=yes]) @@ -106,6 +123,11 @@ AC_ARG_ENABLE([comparison-tool-reorg-tests], [use_comparison_tool_reorg_tests=$enableval], [use_comparison_tool_reorg_tests=no]) +AC_ARG_ENABLE([extended-rpc-tests], + AS_HELP_STRING([--enable-extended-rpc-tests],[enable expensive RPC tests when using lcov (default no)]), + [use_extended_rpc_tests=$enableval], + [use_extended_rpc_tests=no]) + AC_ARG_WITH([qrencode], [AS_HELP_STRING([--with-qrencode], [enable QR code support (default is yes if qt is enabled and libqrencode is found)])], @@ -142,6 +164,12 @@ AC_ARG_ENABLE([glibc-back-compat], [use_glibc_compat=$enableval], [use_glibc_compat=no]) +AC_ARG_WITH([system-univalue], + [AS_HELP_STRING([--with-system-univalue], + [Build with system UniValue (default is no)])], + [system_univalue=$withval], + [system_univalue=no] +) AC_ARG_ENABLE([zmq], [AS_HELP_STRING([--disable-zmq], [disable ZMQ notifications])], @@ -308,6 +336,9 @@ case $host in AC_PATH_TOOL([INSTALLNAMETOOL], [install_name_tool], install_name_tool) AC_PATH_TOOL([OTOOL], [otool], otool) AC_PATH_PROGS([GENISOIMAGE], [genisoimage mkisofs],genisoimage) + AC_PATH_PROGS([RSVG_CONVERT], [rsvg-convert rsvg],rsvg-convert) + AC_PATH_PROGS([IMAGEMAGICK_CONVERT], [convert],convert) + AC_PATH_PROGS([TIFFCP], [tiffcp],tiffcp) dnl libtool will try to strip the static lib, which is a problem for dnl cross-builds because strip attempts to call a hard-coded ld, @@ -320,6 +351,7 @@ case $host in AX_CHECK_LINK_FLAG([[-Wl,-headerpad_max_install_names]], [LDFLAGS="$LDFLAGS -Wl,-headerpad_max_install_names"]) CPPFLAGS="$CPPFLAGS -DMAC_OSX" + OBJCXXFLAGS="$CXXFLAGS" ;; *linux*) TARGET_OS=linux @@ -341,6 +373,10 @@ else AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 0) fi +if test x$use_extended_rpc_tests != xno; then + AC_SUBST(EXTENDED_RPC_TESTS, -extended) +fi + if test x$use_lcov = xyes; then if test x$LCOV = x; then AC_MSG_ERROR("lcov testing requested but lcov not found") @@ -351,6 +387,9 @@ if test x$use_lcov = xyes; then if test x$JAVA = x; then AC_MSG_ERROR("lcov testing requested but java not found") fi + if test x$PYTHON = x; then + AC_MSG_ERROR("lcov testing requested but python not found") + fi if test x$GENHTML = x; then AC_MSG_ERROR("lcov testing requested but genhtml not found") fi @@ -395,6 +434,10 @@ AX_GCC_FUNC_ATTRIBUTE([dllimport]) if test x$use_glibc_compat != xno; then + #glibc absorbed clock_gettime in 2.17. librt (its previous location) is safe to link + #in anyway for back-compat. + AC_CHECK_LIB([rt],[clock_gettime],, AC_MSG_ERROR(lib missing)) + #__fdelt_chk's params and return type have changed from long unsigned int to long int. # See which one is present here. AC_MSG_CHECKING(__fdelt_chk type) @@ -408,7 +451,13 @@ if test x$use_glibc_compat != xno; then [ fdelt_type="long int"]) AC_MSG_RESULT($fdelt_type) AC_DEFINE_UNQUOTED(FDELT_TYPE, $fdelt_type,[parameter and return value type for __fdelt_chk]) +else + AC_SEARCH_LIBS([clock_gettime],[rt]) +fi +if test x$TARGET_OS != xwindows; then + # All windows code is PIC, forcing it on just adds useless compile warnings + AX_CHECK_COMPILE_FLAG([-fPIC],[PIC_FLAGS="-fPIC"]) fi if test x$use_hardening != xno; then @@ -428,8 +477,7 @@ if test x$use_hardening != xno; then AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"]) if test x$TARGET_OS != xwindows; then - # All windows code is PIC, forcing it on just adds useless compile warnings - AX_CHECK_COMPILE_FLAG([-fPIE],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fPIE"]) + AX_CHECK_COMPILE_FLAG([-fPIE],[PIE_FLAGS="-fPIE"]) AX_CHECK_LINK_FLAG([[-pie]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"]) fi @@ -438,11 +486,6 @@ if test x$use_hardening != xno; then AC_CHECK_LIB([ssp], [main],, AC_MSG_ERROR(lib missing)) ;; esac - - CXXFLAGS="$CXXFLAGS $HARDENED_CXXFLAGS" - CPPFLAGS="$CPPFLAGS $HARDENED_CPPFLAGS" - LDFLAGS="$LDFLAGS $HARDENED_LDFLAGS" - OBJCXXFLAGS="$CXXFLAGS" fi dnl this flag screws up non-darwin gcc even when the check fails. special-case it. @@ -476,8 +519,6 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [ AC_MSG_RESULT(no)] ) -AC_SEARCH_LIBS([clock_gettime],[rt]) - AC_MSG_CHECKING([for visibility attribute]) AC_LINK_IFELSE([AC_LANG_SOURCE([ int foo_def( void ) __attribute__((visibility("default"))); @@ -525,7 +566,7 @@ fi BITCOIN_QT_INIT dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus -BITCOIN_QT_CONFIGURE([$use_pkgconfig], [qt4]) +BITCOIN_QT_CONFIGURE([$use_pkgconfig], [qt5]) if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests = xnononono; then use_boost=no @@ -606,6 +647,42 @@ if test x$use_boost = xyes; then BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB $BOOST_CHRONO_LIB" + +dnl If boost (prior to 1.57) was built without c++11, it emulated scoped enums +dnl using c++98 constructs. Unfortunately, this implementation detail leaked into +dnl the abi. This was fixed in 1.57. + +dnl When building against that installed version using c++11, the headers pick up +dnl on the native c++11 scoped enum support and enable it, however it will fail to +dnl link. This can be worked around by disabling c++11 scoped enums if linking will +dnl fail. +dnl BOOST_NO_SCOPED_ENUMS was changed to BOOST_NO_CXX11_SCOPED_ENUMS in 1.51. + +TEMP_LIBS="$LIBS" +LIBS="$BOOST_LIBS $LIBS" +TEMP_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +AC_MSG_CHECKING([for mismatched boost c++11 scoped enums]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include "boost/config.hpp" + #include "boost/version.hpp" + #if !defined(BOOST_NO_SCOPED_ENUMS) && !defined(BOOST_NO_CXX11_SCOPED_ENUMS) && BOOST_VERSION < 105700 + #define BOOST_NO_SCOPED_ENUMS + #define BOOST_NO_CXX11_SCOPED_ENUMS + #define CHECK + #endif + #include "boost/filesystem.hpp" + ]],[[ + #if defined(CHECK) + boost::filesystem::copy_file("foo", "bar"); + #else + choke; + #endif + ]])], + [AC_MSG_RESULT(mismatched); BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_NO_SCOPED_ENUMS -DBOOST_NO_CXX11_SCOPED_ENUMS"], [AC_MSG_RESULT(ok)]) +LIBS="$TEMP_LIBS" +CPPFLAGS="$TEMP_CPPFLAGS" + dnl Boost >= 1.50 uses sleep_for rather than the now-deprecated sleep, however dnl it was broken from 1.50 to 1.52 when backed by nanosleep. Use sleep_for if dnl a working version is available, else fall back to sleep. sleep was removed @@ -729,6 +806,44 @@ else fi fi +dnl univalue check + +if test x$system_univalue != xno ; then + found_univalue=no + if test x$use_pkgconfig = xyes; then + : #NOP + m4_ifdef( + [PKG_CHECK_MODULES], + [ + PKG_CHECK_MODULES([UNIVALUE],[libunivalue],[found_univalue=yes],[true]) + ] + ) + else + AC_CHECK_HEADER([univalue.h],[ + AC_CHECK_LIB([univalue], [main],[ + UNIVALUE_LIBS=-lunivalue + found_univalue=yes + ],[true]) + ],[true]) + fi + + if test x$found_univalue = xyes ; then + system_univalue=yes + elif test x$system_univalue = xyes ; then + AC_MSG_ERROR([univalue not found]) + else + system_univalue=no + fi +fi + +if test x$system_univalue = xno ; then + UNIVALUE_CFLAGS='-I$(srcdir)/univalue/include' + UNIVALUE_LIBS='univalue/libunivalue.la' +fi +AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$system_univalue = xno]) +AC_SUBST(UNIVALUE_CFLAGS) +AC_SUBST(UNIVALUE_LIBS) + CXXFLAGS_TEMP="$CXXFLAGS" LIBS_TEMP="$LIBS" CXXFLAGS="$CXXFLAGS $SSL_CFLAGS $CRYPTO_CFLAGS" @@ -814,8 +929,8 @@ else fi dnl these are only used when qt is enabled +BUILD_TEST_QT="" if test x$bitcoin_enable_qt != xno; then - BUILD_QT=qt dnl enable dbus support AC_MSG_CHECKING([whether to build GUI with support for D-Bus]) if test x$bitcoin_enable_qt_dbus != xno; then @@ -845,9 +960,9 @@ if test x$bitcoin_enable_qt != xno; then fi AC_MSG_CHECKING([whether to build test_bitcoin-qt]) - if test x$use_tests$bitcoin_enable_qt_test = xyesyes; then + if test x$use_gui_tests$bitcoin_enable_qt_test = xyesyes; then AC_MSG_RESULT([yes]) - BUILD_TEST_QT="test" + BUILD_TEST_QT="yes" else AC_MSG_RESULT([no]) fi @@ -858,9 +973,10 @@ AM_CONDITIONAL([ENABLE_ZMQ], [test "x$use_zmq" = "xyes"]) AC_MSG_CHECKING([whether to build test_bitcoin]) if test x$use_tests = xyes; then AC_MSG_RESULT([yes]) - BUILD_TEST="test" + BUILD_TEST="yes" else AC_MSG_RESULT([no]) + BUILD_TEST="" fi AC_MSG_CHECKING([whether to reduce exports]) @@ -878,39 +994,53 @@ AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) -AM_CONDITIONAL([ENABLE_TESTS],[test x$use_tests = xyes]) +AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes]) -AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$use_tests$bitcoin_enable_qt_test = xyesyes]) +AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$BUILD_TEST_QT = xyes]) AM_CONDITIONAL([ENABLE_BENCH],[test x$use_bench = xyes]) AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes]) AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes]) AM_CONDITIONAL([USE_COMPARISON_TOOL],[test x$use_comparison_tool != xno]) AM_CONDITIONAL([USE_COMPARISON_TOOL_REORG_TESTS],[test x$use_comparison_tool_reorg_test != xno]) AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) +AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes]) AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version]) AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version]) AC_DEFINE(CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION, [Build revision]) AC_DEFINE(CLIENT_VERSION_BUILD, _CLIENT_VERSION_BUILD, [Version Build]) AC_DEFINE(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE, [Version is release]) -AC_DEFINE(COPYRIGHT_YEAR, _COPYRIGHT_YEAR, [Version is release]) +AC_DEFINE(COPYRIGHT_YEAR, _COPYRIGHT_YEAR, [Copyright year]) +AC_DEFINE(COPYRIGHT_HOLDERS, "_COPYRIGHT_HOLDERS", [Copyright holder(s) before %s replacement]) +AC_DEFINE(COPYRIGHT_HOLDERS_SUBSTITUTION, "_COPYRIGHT_HOLDERS_SUBSTITUTION", [Replacement for %s in copyright holders string]) +define(_COPYRIGHT_HOLDERS_FINAL, [patsubst(_COPYRIGHT_HOLDERS, [%s], [_COPYRIGHT_HOLDERS_SUBSTITUTION])]) +AC_DEFINE(COPYRIGHT_HOLDERS_FINAL, "_COPYRIGHT_HOLDERS_FINAL", [Copyright holder(s)]) AC_SUBST(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR) AC_SUBST(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR) AC_SUBST(CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION) AC_SUBST(CLIENT_VERSION_BUILD, _CLIENT_VERSION_BUILD) AC_SUBST(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE) AC_SUBST(COPYRIGHT_YEAR, _COPYRIGHT_YEAR) +AC_SUBST(COPYRIGHT_HOLDERS, "_COPYRIGHT_HOLDERS") +AC_SUBST(COPYRIGHT_HOLDERS_SUBSTITUTION, "_COPYRIGHT_HOLDERS_SUBSTITUTION") +AC_SUBST(COPYRIGHT_HOLDERS_FINAL, "_COPYRIGHT_HOLDERS_FINAL") +AC_SUBST(BITCOIN_DAEMON_NAME) +AC_SUBST(BITCOIN_GUI_NAME) +AC_SUBST(BITCOIN_CLI_NAME) +AC_SUBST(BITCOIN_TX_NAME) AC_SUBST(RELDFLAGS) +AC_SUBST(HARDENED_CXXFLAGS) +AC_SUBST(HARDENED_CPPFLAGS) +AC_SUBST(HARDENED_LDFLAGS) +AC_SUBST(PIC_FLAGS) +AC_SUBST(PIE_FLAGS) AC_SUBST(LIBTOOL_APP_LDFLAGS) AC_SUBST(USE_UPNP) AC_SUBST(USE_QRCODE) AC_SUBST(BOOST_LIBS) AC_SUBST(TESTDEFS) AC_SUBST(LEVELDB_TARGET_FLAGS) -AC_SUBST(BUILD_TEST) -AC_SUBST(BUILD_QT) -AC_SUBST(BUILD_TEST_QT) AC_SUBST(MINIUPNPC_CPPFLAGS) AC_SUBST(MINIUPNPC_LIBS) AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py]) @@ -940,8 +1070,12 @@ PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR" unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" -ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no" -AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue]) +if test x$system_univalue = xno; then + AC_CONFIG_SUBDIRS([src/univalue]) +fi + +ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery" +AC_CONFIG_SUBDIRS([src/secp256k1]) AC_OUTPUT diff --git a/contrib/README.md b/contrib/README.md index 125594312..32b3a170a 100644 --- a/contrib/README.md +++ b/contrib/README.md @@ -11,10 +11,10 @@ Repository Tools ### [Developer tools](/contrib/devtools) ### Specific tools for developers working on this repository. -Contains the script `github-merge.sh` for merging github pull requests securely and signing them using GPG. +Contains the script `github-merge.py` for merging github pull requests securely and signing them using GPG. ### [Verify-Commits](/contrib/verify-commits) ### -Tool to verify that every merge commit was signed by a developer using the above `github-merge.sh` script. +Tool to verify that every merge commit was signed by a developer using the above `github-merge.py` script. ### [Linearize](/contrib/linearize) ### Construct a linear, no-fork, best version of the blockchain. @@ -34,23 +34,22 @@ Contains files used to package bitcoind/bitcoin-qt for Debian-based Linux systems. If you compile bitcoind/bitcoin-qt yourself, there are some useful files here. ### [Gitian-descriptors](/contrib/gitian-descriptors) ### -Gavin's notes on getting gitian builds up and running using KVM. +Notes on getting Gitian builds up and running using KVM. -### [Gitian-downloader](/contrib/gitian-downloader) -Various PGP files of core developers. +### [Gitian-keys](/contrib/gitian-keys) +PGP keys used for signing Bitcoin Core [Gitian release](/doc/release-process.md) results. ### [MacDeploy](/contrib/macdeploy) ### Scripts and notes for Mac builds. +### [RPM](/contrib/rpm) ### +RPM spec file for building bitcoin-core on RPM based distributions + Test and Verify Tools --------------------- ### [TestGen](/contrib/testgen) ### Utilities to generate test vectors for the data-driven Bitcoin tests. -### [Test Patches](/contrib/test-patches) ### -These patches are applied when the automated pull-tester -tests each pull and when master is tested using jenkins. - ### [Verify SF Binaries](/contrib/verifysfbinaries) ### This script attempts to download and verify the signature file SHA256SUMS.asc from SourceForge. diff --git a/contrib/debian/control b/contrib/debian/control index 2fd68583c..fce6bc011 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -23,7 +23,7 @@ Build-Depends: debhelper, libprotobuf-dev, protobuf-compiler, python Standards-Version: 3.9.2 -Homepage: https://www.bitcoin.org/ +Homepage: https://bitcoincore.org/ Vcs-Git: git://github.com/bitcoin/bitcoin.git Vcs-Browser: https://github.com/bitcoin/bitcoin @@ -31,14 +31,11 @@ Package: bitcoind Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer network based digital currency - daemon - Bitcoin is a free open source peer-to-peer electronic cash system that - is completely decentralized, without the need for a central server or - trusted parties. Users hold the crypto keys to their own money and - transact directly with each other, with the help of a P2P network to - check for double-spending. - . - Full transaction history is stored locally at each client. This - requires 20+ GB of space, slowly growing. + Bitcoin is an experimental new digital currency that enables instant + payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer + technology to operate with no central authority: managing transactions + and issuing money are carried out collectively by the network. Bitcoin Core + is the name of the open source software which enables the use of this currency. . This package provides the daemon, bitcoind, and the CLI tool bitcoin-cli to interact with the daemon. @@ -47,14 +44,11 @@ Package: bitcoin-qt Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer network based digital currency - Qt GUI - Bitcoin is a free open source peer-to-peer electronic cash system that - is completely decentralized, without the need for a central server or - trusted parties. Users hold the crypto keys to their own money and - transact directly with each other, with the help of a P2P network to - check for double-spending. - . - Full transaction history is stored locally at each client. This - requires 20+ GB of space, slowly growing. + Bitcoin is an experimental new digital currency that enables instant + payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer + technology to operate with no central authority: managing transactions + and issuing money are carried out collectively by the network. Bitcoin Core + is the name of the open source software which enables the use of this currency. . This package provides Bitcoin-Qt, a GUI for Bitcoin based on Qt. @@ -62,11 +56,11 @@ Package: bitcoin-tx Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer digital currency - standalone transaction tool - Bitcoin is a free open source peer-to-peer electronic cash system that - is completely decentralized, without the need for a central server or - trusted parties. Users hold the crypto keys to their own money and - transact directly with each other, with the help of a P2P network to - check for double-spending. + Bitcoin is an experimental new digital currency that enables instant + payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer + technology to operate with no central authority: managing transactions + and issuing money are carried out collectively by the network. Bitcoin Core + is the name of the open source software which enables the use of this currency. . This package provides bitcoin-tx, a command-line transaction creation tool which can be used without a bitcoin daemon. Some means of diff --git a/contrib/debian/copyright b/contrib/debian/copyright index 83ce560a7..c039a7bae 100644 --- a/contrib/debian/copyright +++ b/contrib/debian/copyright @@ -5,7 +5,7 @@ Upstream-Contact: Satoshi Nakamoto Source: https://github.com/bitcoin/bitcoin Files: * -Copyright: 2009-2015, Bitcoin Core Developers +Copyright: 2009-2016, Bitcoin Core Developers License: Expat Comment: The Bitcoin Core Developers encompasses the current developers listed on bitcoin.org, as well as the numerous contributors to the project. @@ -21,6 +21,7 @@ License: GPL-3+ Files: src/qt/res/icons/add.png src/qt/res/icons/address-book.png + src/qt/res/icons/chevron.png src/qt/res/icons/configure.png src/qt/res/icons/debugwindow.png src/qt/res/icons/edit.png @@ -56,6 +57,8 @@ Comment: Inspired by Stephan Hutchings Typicons Files: src/qt/res/icons/tx_mined.png src/qt/res/src/mine.svg + src/qt/res/icons/fontbigger.png + src/qt/res/icons/fontsmaller.png Copyright: Jonas Schnelli License: Expat Comment: diff --git a/contrib/debian/manpages/bitcoin-cli.1 b/contrib/debian/manpages/bitcoin-cli.1 index 154b45873..16c338dd3 100644 --- a/contrib/debian/manpages/bitcoin-cli.1 +++ b/contrib/debian/manpages/bitcoin-cli.1 @@ -1,4 +1,4 @@ -.TH BITCOIN-CLI "1" "February 2015" "bitcoin-cli 0.10" +.TH BITCOIN-CLI "1" "February 2016" "bitcoin-cli 0.12" .SH NAME bitcoin-cli \- a remote procedure call client for Bitcoin Core. .SH SYNOPSIS @@ -11,31 +11,7 @@ This manual page documents the bitcoin-cli program. bitcoin-cli is an RPC client .SH OPTIONS .TP \fB\-?\fR -Show the help message. -.TP -\fB\-conf=\fR -Specify configuration file (default: bitcoin.conf). -.TP -\fB\-datadir=\fR -Specify data directory. -.TP -\fB\-testnet\fR -Connect to a Bitcoin Core instance running in testnet mode. -.TP -\fB\-regtest\fR -Connect to a Bitcoin Core instance running in regtest mode (see documentation for -regtest on bitcoind). -.TP -\fB\-rpcuser=\fR -Username for JSON\-RPC connections. -.TP -\fB\-rpcpassword=\fR -Password for JSON\-RPC connections. -.TP -\fB\-rpcport=\fR -Listen for JSON\-RPC connections on (default: 8332 or testnet: 18332). -.TP -\fB\-rpcconnect=\fR -Send commands to node running on (default: 127.0.0.1). +Show possible options. .SH "SEE ALSO" \fBbitcoind\fP, \fBbitcoin.conf\fP diff --git a/contrib/debian/manpages/bitcoin-qt.1 b/contrib/debian/manpages/bitcoin-qt.1 index 05eadc94c..685a28208 100644 --- a/contrib/debian/manpages/bitcoin-qt.1 +++ b/contrib/debian/manpages/bitcoin-qt.1 @@ -1,4 +1,4 @@ -.TH BITCOIN-QT "1" "April 2013" "bitcoin-qt 1" +.TH BITCOIN-QT "1" "February 2016" "bitcoin-qt 0.12" .SH NAME bitcoin-qt \- peer-to-peer network based digital currency .SH DESCRIPTION @@ -8,184 +8,6 @@ bitcoin\-qt [command\-line options] .SH OPTIONS .TP \-? -This help message -.TP -\fB\-conf=\fR -Specify configuration file (default: bitcoin.conf) -.TP -\fB\-pid=\fR -Specify pid file (default: bitcoind.pid) -.TP -\fB\-gen\fR -Generate coins -.TP -\fB\-gen\fR=\fI0\fR -Don't generate coins -.TP -\fB\-datadir=\fR -Specify data directory -.TP -\fB\-dbcache=\fR -Set database cache size in megabytes (default: 25) -.TP -\fB\-timeout=\fR -Specify connection timeout in milliseconds (default: 5000) -.TP -\fB\-proxy=\fR -Connect through SOCKS5 proxy -.TP -\fB\-tor=\fR -Use proxy to reach tor hidden services (default: same as \fB\-proxy\fR) -.TP -\fB\-dns\fR -Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR -.TP -\fB\-port=\fR -Listen for connections on (default: 8333 or testnet: 18333) -.TP -\fB\-maxconnections=\fR -Maintain at most connections to peers (default: 125) -.TP -\fB\-addnode=\fR -Add a node to connect to and attempt to keep the connection open -.TP -\fB\-connect=\fR -Connect only to the specified node(s) -.TP -\fB\-seednode=\fR -Connect to a node to retrieve peer addresses, and disconnect -.TP -\fB\-externalip=\fR -Specify your own public address -.TP -\fB\-onlynet=\fR -Only connect to nodes in network (IPv4, IPv6 or Tor) -.TP -\fB\-discover\fR -Discover own IP address (default: 1 when listening and no \fB\-externalip\fR) -.TP -\fB\-checkpoints\fR -Only accept block chain matching built\-in checkpoints (default: 1) -.TP -\fB\-listen\fR -Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR) -.TP -\fB\-bind=\fR -Bind to given address and always listen on it. Use [host]:port notation for IPv6 -.TP -\fB\-dnsseed\fR -Find peers using DNS lookup (default: 1 unless \fB\-connect\fR) -.TP -\fB\-banscore=\fR -Threshold for disconnecting misbehaving peers (default: 100) -.TP -\fB\-bantime=\fR -Number of seconds to keep misbehaving peers from reconnecting (default: 86400) -.TP -\fB\-maxreceivebuffer=\fR -Maximum per\-connection receive buffer, *1000 bytes (default: 5000) -.TP -\fB\-maxsendbuffer=\fR -Maximum per\-connection send buffer, *1000 bytes (default: 1000) -.TP -\fB\-upnp\fR -Use UPnP to map the listening port (default: 1 when listening) -.TP -\fB\-paytxfee=\fR -Fee per KB to add to transactions you send -.TP -\fB\-server\fR -Accept command line and JSON\-RPC commands -.TP -\fB\-testnet\fR -Use the test network -.TP -\fB\-debug\fR -Output extra debugging information. Implies all other \fB\-debug\fR* options -.TP -\fB\-debugnet\fR -Output extra network debugging information -.TP -\fB\-logtimestamps\fR -Prepend debug output with timestamp -.TP -\fB\-shrinkdebugfile\fR -Shrink debug.log file on client startup (default: 1 when no \fB\-debug\fR) -.TP -\fB\-printtoconsole\fR -Send trace/debug info to console instead of debug.log file -.TP -\fB\-rpcuser=\fR -Username for JSON\-RPC connections -.TP -\fB\-rpcpassword=\fR -Password for JSON\-RPC connections -.TP -\fB\-rpcport=\fR -Listen for JSON\-RPC connections on (default: 8332 or testnet: 18332) -.TP -\fB\-rpcallowip=\fR -Allow JSON\-RPC connections from specified IP address -.TP -\fB\-rpcthreads=\fR -Set the number of threads to service RPC calls (default: 4) -.TP -\fB\-blocknotify=\fR -Execute command when the best block changes (%s in cmd is replaced by block hash) -.TP -\fB\-walletnotify=\fR -Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) -.TP -\fB\-alertnotify=\fR -Execute command when a relevant alert is received (%s in cmd is replaced by message) -.TP -\fB\-upgradewallet\fR -Upgrade wallet to latest format -.TP -\fB\-keypool=\fR -Set key pool size to (default: 100) -.TP -\fB\-rescan\fR -Rescan the block chain for missing wallet transactions -.TP -\fB\-salvagewallet\fR -Attempt to recover private keys from a corrupt wallet.dat -.TP -\fB\-checkblocks=\fR -How many blocks to check at startup (default: 288, 0 = all) -.TP -\fB\-checklevel=\fR -How thorough the block verification is (0\-4, default: 3) -.TP -\fB\-txindex\fR -Maintain a full transaction index (default: 0) -.TP -\fB\-loadblock=\fR -Imports blocks from external blk000??.dat file -.TP -\fB\-reindex\fR -Rebuild block chain index from current blk000??.dat files -.TP -\fB\-par=\fR -Set the number of script verification threads (1\-16, 0=auto, default: 0) -.SS "Block creation options:" -.TP -\fB\-blockminsize=\fR -Set minimum block size in bytes (default: 0) -.TP -\fB\-blockmaxsize=\fR -Set maximum block size in bytes (default: 250000) -.HP -\fB\-blockprioritysize=\fR Set maximum size of high\-priority/low\-fee transactions in bytes (default: 27000) -.PP -Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) -.SS "UI options:" -.TP -\fB\-lang=\fR -Set language, for example "de_DE" (default: system locale) -.TP -\fB\-min\fR -Start minimized -.TP -\fB\-splash\fR -Show splash screen on startup (default: 1) +List options. +.SH "SEE ALSO" +bitcoind(1) diff --git a/contrib/debian/manpages/bitcoin.conf.5 b/contrib/debian/manpages/bitcoin.conf.5 index 0cf4d991e..839dc26c1 100644 --- a/contrib/debian/manpages/bitcoin.conf.5 +++ b/contrib/debian/manpages/bitcoin.conf.5 @@ -1,75 +1,15 @@ -.TH BITCOIN.CONF "5" "January 2011" "bitcoin.conf 3.19" +.TH BITCOIN.CONF "5" "February 2016" "bitcoin.conf 0.12" .SH NAME bitcoin.conf \- bitcoin configuration file .SH SYNOPSIS All command-line options (except for '\-conf') may be specified in a configuration file, and all configuration file options may also be specified on the command line. Command-line options override values set in the configuration file. .TP -The configuration file is a list of 'setting=value' pairs, one per line, with optional comments starting with the '#' character. +The configuration file is a list of 'setting=value' pairs, one per line, with optional comments starting with the '#' character. Please refer to bitcoind(1) for a up to date list of valid options. .TP The configuration file is not automatically created; you can create it using your favorite plain-text editor. By default, bitcoind(1) will look for a file named bitcoin.conf(5) in the bitcoin data directory, but both the data directory and the configuration file path may be changed using the '\-datadir' and '\-conf' command-line arguments. .SH LOCATION bitcoin.conf should be located in $HOME/.bitcoin -.SH NETWORK-RELATED SETTINGS -.TP -.TP -\fBtestnet=\fR[\fI'1'\fR|\fI'0'\fR] -Enable or disable run on the test network instead of the real *bitcoin* network. -.TP -\fBproxy=\fR\fI'127.0.0.1:9050'\fR -Connect via a socks4 proxy. -.TP -\fBaddnode=\fR\fI'10.0.0.2:8333'\fR -Use as many *addnode=* settings as you like to connect to specific peers. -.TP -\fBconnect=\fR\fI'10.0.0.1:8333'\fR -Use as many *connect=* settings as you like to connect ONLY to specific peers. -.TP -\fRmaxconnections=\fR\fI'value'\fR -Maximum number of inbound+outbound connections. -.SH JSON-RPC OPTIONS -.TP -\fBserver=\fR[\fI'1'\fR|\fI'0'\fR] -Tells *bitcoin* to accept or not accept JSON-RPC commands. -.TP -\fBrpcuser=\fR\fI'username'\fR -You must set *rpcuser* to secure the JSON-RPC api. -.TP -\fBrpcpassword=\fR\fI'password'\fR -You must set *rpcpassword* to secure the JSON-RPC api. -.TP -\fBrpcallowip=\fR\fI'192.168.1.*'\fR -By default, only RPC connections from localhost are allowed. Specify as many *rpcallowip=* settings as you like to allow connections from other hosts (and you may use * as a wildcard character). -.TP -\fBrpcport=\fR\fI'8332'\fR -Listen for RPC connections on this TCP port. -.TP -\fBrpcconnect=\fR\fI'127.0.0.1'\fR -You can use *bitcoin* or *bitcoind(1)* to send commands to *bitcoin*/*bitcoind(1)* running on another host using this option. -.TP -.SH MISCELLANEOUS OPTIONS -.TP -\fBgen=\fR[\fI'0'\fR|\fI'1'\fR] -Enable or disable attempt to generate bitcoins. -.TP -\fB4way=\fR[\fI'0'\fR|\fI'1'\fR] -Enable or disable use SSE instructions to try to generate bitcoins faster. -.TP -\fBkeypool=\fR\fI'100'\fR -Pre-generate this many public/private key pairs, so wallet backups will be valid for both prior transactions and several dozen future transactions. -.TP -\fBpaytxfee=\fR\fI'0.00'\fR -Pay an optional transaction fee every time you send bitcoins. Transactions with fees are more likely than free transactions to be included in generated blocks, so may be validated sooner. -.TP -\fBallowreceivebyip=\fR\fI'1'\fR -Allow direct connections for the 'pay via IP address' feature. -.TP -.SH USER INTERFACE OPTIONS -.TP -\fBmin=\fR[\fI'0'\fR|\fI'1'\fR] -Enable or disable start bitcoind minimized. -.TP -\fBminimizetotray=\fR[\fI'0'\fR|\fI'1'\fR] -Enable or disable minimize to the system tray. + .SH "SEE ALSO" bitcoind(1) .SH AUTHOR diff --git a/contrib/debian/manpages/bitcoind.1 b/contrib/debian/manpages/bitcoind.1 index 5b0f2921a..5c3e52f44 100644 --- a/contrib/debian/manpages/bitcoind.1 +++ b/contrib/debian/manpages/bitcoind.1 @@ -1,4 +1,4 @@ -.TH BITCOIND "1" "January 2011" "bitcoind 3.19" +.TH BITCOIND "1" "February 2016" "bitcoind 0.12" .SH NAME bitcoind \- peer-to-peer network based digital currency .SH SYNOPSIS @@ -6,185 +6,20 @@ bitcoin [options] [params] .TP bitcoin [options] help \- Get help for a command .SH DESCRIPTION -This manual page documents the bitcoind program. Bitcoin is a peer-to-peer digital currency. Peer-to-peer (P2P) means that there is no central authority to issue new money or keep track of transactions. Instead, these tasks are managed collectively by the nodes of the network. Advantages: - -Bitcoins can be sent easily through the Internet, without having to trust middlemen. Transactions are designed to be irreversible. Be safe from instability caused by fractional reserve banking and central banks. The limited inflation of the Bitcoin system’s money supply is distributed evenly (by CPU power) throughout the network, not monopolized by banks. +This manual page documents the bitcoind program. Bitcoin is an experimental new digital currency that enables instant payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate with no central authority: managing transactions and issuing money are carried out collectively by the network. Bitcoin Core is the name of open source software which enables the use of this currency. .SH OPTIONS .TP -\fB\-conf=\fR -Specify configuration file (default: bitcoin.conf) -.TP -\fB\-gen\fR -Generate coins -.TP -\fB\-gen\fR=\fI0\fR -Don't generate coins -.TP -\fB\-min\fR -Start minimized -.TP -\fB\-datadir=\fR -Specify data directory -.TP -\fB\-proxy=\fR -Connect through SOCKS5 proxy -.TP -\fB\-addnode=\fR -Add a node to connect to -.TP -\fB\-connect=\fR -Connect only to the specified node -.TP -\fB\-paytxfee=\fR -Fee per KB to add to transactions you send -.TP -\fB\-server\fR -Accept command line and JSON\-RPC commands -.TP -\fB\-daemon\fR -Run in the background as a daemon and accept commands -.TP -\fB\-testnet\fR -Use the test network -.TP -\fB\-rpcuser=\fR -Username for JSON\-RPC connections -.TP -\fB\-rpcpassword=\fR -Password for JSON\-RPC connections -.TP -\fB\-rpcport=\fR -Listen for JSON\-RPC connections on -.TP -\fB\-rpcallowip=\fR -Allow JSON\-RPC connections from specified IP address -.TP -\fB\-rpcconnect=\fR -Send commands to node running on -.TP \-? -This help message +List of possible options. .SH COMMANDS .TP -\fBbackupwallet 'destination'\fR -Safely copies *wallet.dat* to 'destination', which can be a directory or a path with filename. -.TP -\fBgetaccount 'bitcoinaddress'\fR -DEPRECATED. Returns the account associated with the given address. -.TP -\fBsetaccount 'bitcoinaddress' ['account']\fR -DEPRECATED. Sets the ['account'] associated with the given address. ['account'] may be omitted to remove an address from ['account']. -.TP -\fBgetaccountaddress 'account'\fR -DEPRECATED. Returns a new bitcoin address for 'account'. -.TP -\fBgetaddressesbyaccount 'account'\fR -DEPRECATED. Returns the list of addresses associated with the given 'account'. -.TP -\fBgetbalance 'account'\fR -Returns the server's available balance, or the balance for 'account' (accounts are deprecated). -.TP -\fBgetblockcount\fR -Returns the number of blocks in the longest block chain. -.TP -\fBgetblocknumber\fR -Returns the block number of the latest block in the longest block chain. -.TP -\fBgetconnectioncount\fR -Returns the number of connections to other nodes. -.TP -\fBgetdifficulty\fR -Returns the proof-of-work difficulty as a multiple of the minimum difficulty. -.TP -\fBgetgenerate\fR -Returns boolean true if server is trying to generate bitcoins, false otherwise. -.TP -\fBsetgenerate 'generate' ['genproclimit']\fR -Generation is limited to ['genproclimit'] processors, \-1 is unlimited. -.TP -\fBgethashespersec\fR -Returns a recent hashes per second performance measurement while generating. -.TP -\fBgetinfo\fR -Returns an object containing server information. -.TP -\fBgetnewaddress 'account'\fR -Returns a new bitcoin address for receiving payments. If 'account' is specified (deprecated), it is added to the address book so payments received with the address will be credited to 'account'. -.TP -\fBgetreceivedbyaccount 'account' ['minconf=1']\fR -DEPRECATED. Returns the total amount received by addresses associated with 'account' in transactions with at least ['minconf'] confirmations. -.TP -\fBgetreceivedbyaddress 'bitcoinaddress' ['minconf=1']\fR -Returns the total amount received by 'bitcoinaddress' in transactions with at least ['minconf'] confirmations. -.TP -\fBgettransaction 'txid'\fR -Returns information about a specific transaction, given hexadecimal transaction ID. -.TP -\fBgetwork 'data'\fR -If 'data' is specified, tries to solve the block and returns true if it was successful. If 'data' is not specified, returns formatted hash 'data' to work on: +\fBhelp\fR +List commands. - "midstate" : precomputed hash state after hashing the first half of the data. - "data" : block data. - "hash1" : formatted hash buffer for second hash. - "target" : little endian hash target. .TP \fBhelp 'command'\fR -List commands, or get help for a command. -.TP -\fBlistaccounts ['minconf=1']\fR -DEPRECATED. List accounts and their current balances. - *note: requires bitcoin 0.3.20 or later. -.TP -\fBlistreceivedbyaccount ['minconf=1'] ['includeempty=false']\fR -['minconf'] is the minimum number of confirmations before payments are included. ['includeempty'] whether to include addresses that haven't received any payments. Returns an array of objects containing: - - "account" : DEPRECATED. the account of the receiving address. - "amount" : total amount received by the address. - "confirmations" : number of confirmations of the most recent transaction included. -.TP -\fBlistreceivedbyaddress ['minconf=1'] ['includeempty=false']\fR -['minconf'] is the minimum number of confirmations before payments are included. ['includeempty'] whether to include addresses that haven't received any payments. Returns an array of objects containing: - - "address" : receiving address. - "account" : DEPRECATED. the account of the receiving address. - "amount" : total amount received by the address. - "confirmations" : number of confirmations of the most recent transaction included. -.TP -\fBlisttransactions 'account' ['count=10']\fR -Returns a list of the last ['count'] transactions for 'account' \- for all accounts if 'account' is not specified or is "*". Each entry in the list may contain: - - "category" : will be generate, send, receive, or move. - "amount" : amount of transaction. - "fee" : Fee (if any) paid (only for send transactions). - "confirmations" : number of confirmations (only for generate/send/receive). - "txid" : transaction ID (only for generate/send/receive). - "otheraccount" : account funds were moved to or from (only for move). - "message" : message associated with transaction (only for send). - "to" : message-to associated with transaction (only for send). - - *note: requires bitcoin 0.3.20 or later. -.TP -\fBmove <'fromaccount'> <'toaccount'> <'amount'> ['minconf=1'] ['comment']\fR -DEPRECATED. Moves funds between accounts. -.TP -\fBsendfrom* <'account'> <'bitcoinaddress'> <'amount'> ['minconf=1'] ['comment'] ['comment-to']\fR -DEPRECATED. Sends amount from account's balance to 'bitcoinaddress'. This method will fail if there is less than amount bitcoins with ['minconf'] confirmations in the account's balance (unless account is the empty-string-named default account; it behaves like the *sendtoaddress* method). Returns transaction ID on success. -.TP -\fBsendtoaddress 'bitcoinaddress' 'amount' ['comment'] ['comment-to']\fR -Sends amount from the server's available balance to 'bitcoinaddress'. amount is a real and is rounded to the nearest 0.01. Returns transaction id on success. -.TP -\fBstop\fR -Stops the bitcoin server. -.TP -\fBvalidateaddress 'bitcoinaddress'\fR -Checks that 'bitcoinaddress' looks like a proper bitcoin address. Returns an object containing: - - "isvalid" : true or false. - "ismine" : true if the address is in the server's wallet. - "address" : bitcoinaddress. - - *note: ismine and address are only returned if the address is valid. +Get help for a command. .SH "SEE ALSO" bitcoin.conf(5) diff --git a/contrib/debian/watch b/contrib/debian/watch index c96d2f8e7..4d9e0cfa5 100644 --- a/contrib/debian/watch +++ b/contrib/debian/watch @@ -1,7 +1,5 @@ # Run the "uscan" command to check for upstream updates and more. version=3 # use qa.debian.org redirector; see man uscan -opts=uversionmangle=s/(\d)(alpha|beta|rc)/$1~$2/;s/\-src//,dversionmangle=s/~dfsg\d*// \ - http://sf.net/bitcoin/bitcoin-(\d.*)-linux\.tar\.gz debian opts=uversionmangle=s/(\d)(alpha|beta|rc)/$1~$2/,dversionmangle=s/~dfsg\d*// \ http://githubredir.debian.net/github/bitcoin/bitcoin v(.*).tar.gz diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md index f90afa7f2..1103ca86c 100644 --- a/contrib/devtools/README.md +++ b/contrib/devtools/README.md @@ -1,15 +1,69 @@ Contents -=========== +======== This directory contains tools for developers working on this repository. -github-merge.sh -================== +check-doc.py +============ + +Check if all command line args are documented. The return value indicates the +number of undocumented args. + +clang-format.py +=============== + +A script to format cpp source code according to [.clang-format](../../src/.clang-format). This should only be applied to new files or files which are currently not actively developed on. Also, git subtrees are not subject to formatting. + +clang-format-diff.py +=================== + +A script to format unified git diffs according to [.clang-format](../../src/.clang-format). + +For instance, to format the last commit with 0 lines of context, +the script should be called from the git root folder as follows. + +``` +git diff -U0 HEAD~1.. | ./contrib/devtools/clang-format-diff.py -p1 -i -v +``` + +fix-copyright-headers.py +======================== + +Every year newly updated files need to have its copyright headers updated to reflect the current year. +If you run this script from the root folder it will automatically update the year on the copyright header for all +source files if these have a git commit from the current year. + +For example a file changed in 2015 (with 2015 being the current year): + +```// Copyright (c) 2009-2013 The Bitcoin Core developers``` + +would be changed to: + +```// Copyright (c) 2009-2015 The Bitcoin Core developers``` + +git-subtree-check.sh +==================== + +Run this script from the root of the repository to verify that a subtree matches the contents of +the commit it claims to have been updated to. + +To use, make sure that you have fetched the upstream repository branch in which the subtree is +maintained: +* for `src/secp256k1`: https://github.com/bitcoin/secp256k1.git (branch master) +* for `src/leveldb`: https://github.com/bitcoin/leveldb.git (branch bitcoin-fork) +* for `src/univalue`: https://github.com/bitcoin/univalue.git (branch master) + +Usage: `git-subtree-check.sh DIR COMMIT` + +`COMMIT` may be omitted, in which case `HEAD` is used. + +github-merge.py +=============== A small script to automate merging pull-requests securely and sign them with GPG. For example: - ./github-merge.sh bitcoin/bitcoin 3077 + ./github-merge.py 3077 (in any git repository) will help you merge pull request #3077 for the bitcoin/bitcoin repository. @@ -36,24 +90,22 @@ Configuring the github-merge tool for the bitcoin repository is done in the foll git config githubmerge.testcmd "make -j4 check" (adapt to whatever you want to use for testing) git config --global user.signingkey mykeyid (if you want to GPG sign) -fix-copyright-headers.py -=========================== +optimize-pngs.py +================ -Every year newly updated files need to have its copyright headers updated to reflect the current year. -If you run this script from src/ it will automatically update the year on the copyright header for all -.cpp and .h files if these have a git commit from the current year. +A script to optimize png files in the bitcoin +repository (requires pngcrush). -For example a file changed in 2014 (with 2014 being the current year): -```// Copyright (c) 2009-2013 The Bitcoin Core developers``` +security-check.py and test-security-check.py +============================================ -would be changed to: -```// Copyright (c) 2009-2014 The Bitcoin Core developers``` +Perform basic ELF security checks on a series of executables. symbol-check.py -================== +=============== A script to check that the (Linux) executables produced by gitian only contain -allowed gcc, glibc and libstdc++ version symbols. This makes sure they are +allowed gcc, glibc and libstdc++ version symbols. This makes sure they are still compatible with the minimum supported Linux distribution versions. Example usage after a gitian build: @@ -70,7 +122,7 @@ If there are 'unsupported' symbols, the return value will be 1 a list like this .../64/test_bitcoin: symbol _ZNSt8__detail15_List_nod from unsupported version GLIBCXX_3.4.15 update-translations.py -======================= +====================== Run this script from the root of the repository to update all translations from transifex. It will do the following automatically: @@ -80,17 +132,3 @@ It will do the following automatically: - add missing translations to the build system (TODO) See doc/translation-process.md for more information. - -git-subtree-check.sh -==================== - -Run this script from the root of the repository to verify that a subtree matches the contents of -the commit it claims to have been updated to. - -To use, make sure that you have fetched the upstream repository branch in which the subtree is -maintained: -* for src/secp256k1: https://github.com/bitcoin/secp256k1.git (branch master) -* for sec/leveldb: https://github.com/bitcoin/leveldb.git (branch bitcoin-fork) - -Usage: git-subtree-check.sh DIR COMMIT -COMMIT may be omitted, in which case HEAD is used. diff --git a/contrib/devtools/check-doc.py b/contrib/devtools/check-doc.py new file mode 100755 index 000000000..8c73cf1e8 --- /dev/null +++ b/contrib/devtools/check-doc.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +''' +This checks if all command line args are documented. +Return value is 0 to indicate no error. + +Author: @MarcoFalke +''' + +from subprocess import check_output +import re + +FOLDER_GREP = 'src' +FOLDER_TEST = 'src/test/' +CMD_ROOT_DIR = '`git rev-parse --show-toplevel`/%s' % FOLDER_GREP +CMD_GREP_ARGS = r"egrep -r -I '(map(Multi)?Args(\.count\(|\[)|Get(Bool)?Arg\()\"\-[^\"]+?\"' %s | grep -v '%s'" % (CMD_ROOT_DIR, FOLDER_TEST) +CMD_GREP_DOCS = r"egrep -r -I 'HelpMessageOpt\(\"\-[^\"=]+?(=|\")' %s" % (CMD_ROOT_DIR) +REGEX_ARG = re.compile(r'(?:map(?:Multi)?Args(?:\.count\(|\[)|Get(?:Bool)?Arg\()\"(\-[^\"]+?)\"') +REGEX_DOC = re.compile(r'HelpMessageOpt\(\"(\-[^\"=]+?)(?:=|\")') +# list unsupported, deprecated and duplicate args as they need no documentation +SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay']) + +def main(): + used = check_output(CMD_GREP_ARGS, shell=True) + docd = check_output(CMD_GREP_DOCS, shell=True) + + args_used = set(re.findall(REGEX_ARG,used)) + args_docd = set(re.findall(REGEX_DOC,docd)).union(SET_DOC_OPTIONAL) + args_need_doc = args_used.difference(args_docd) + args_unknown = args_docd.difference(args_used) + + print "Args used : %s" % len(args_used) + print "Args documented : %s" % len(args_docd) + print "Args undocumented: %s" % len(args_need_doc) + print args_need_doc + print "Args unknown : %s" % len(args_unknown) + print args_unknown + + exit(len(args_need_doc)) + +if __name__ == "__main__": + main() diff --git a/contrib/devtools/clang-format-diff.py b/contrib/devtools/clang-format-diff.py new file mode 100755 index 000000000..13d2573b9 --- /dev/null +++ b/contrib/devtools/clang-format-diff.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python +# +#===- clang-format-diff.py - ClangFormat Diff Reformatter ----*- python -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. +# +# ============================================================ +# +# University of Illinois/NCSA +# Open Source License +# +# Copyright (c) 2007-2015 University of Illinois at Urbana-Champaign. +# All rights reserved. +# +# Developed by: +# +# LLVM Team +# +# University of Illinois at Urbana-Champaign +# +# http://llvm.org +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal with +# 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 whom the Software is furnished to do +# so, subject to the following conditions: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimers. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimers in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of the LLVM Team, University of Illinois at +# Urbana-Champaign, nor the names of its contributors may be used to +# endorse or promote products derived from this Software without specific +# prior written permission. +# +# THE 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 +# CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +# SOFTWARE. +# +# ============================================================ +# +#===------------------------------------------------------------------------===# + +r""" +ClangFormat Diff Reformatter +============================ + +This script reads input from a unified diff and reformats all the changed +lines. This is useful to reformat all the lines touched by a specific patch. +Example usage for git/svn users: + + git diff -U0 HEAD^ | clang-format-diff.py -p1 -i + svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i + +""" + +import argparse +import difflib +import re +import string +import subprocess +import StringIO +import sys + + +# Change this to the full path if clang-format is not on the path. +binary = 'clang-format' + + +def main(): + parser = argparse.ArgumentParser(description= + 'Reformat changed lines in diff. Without -i ' + 'option just output the diff that would be ' + 'introduced.') + parser.add_argument('-i', action='store_true', default=False, + help='apply edits to files instead of displaying a diff') + parser.add_argument('-p', metavar='NUM', default=0, + help='strip the smallest prefix containing P slashes') + parser.add_argument('-regex', metavar='PATTERN', default=None, + help='custom pattern selecting file paths to reformat ' + '(case sensitive, overrides -iregex)') + parser.add_argument('-iregex', metavar='PATTERN', default= + r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc|js|ts|proto' + r'|protodevel|java)', + help='custom pattern selecting file paths to reformat ' + '(case insensitive, overridden by -regex)') + parser.add_argument('-sort-includes', action='store_true', default=False, + help='let clang-format sort include blocks') + parser.add_argument('-v', '--verbose', action='store_true', + help='be more verbose, ineffective without -i') + args = parser.parse_args() + + # Extract changed lines for each file. + filename = None + lines_by_file = {} + for line in sys.stdin: + match = re.search('^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line) + if match: + filename = match.group(2) + if filename == None: + continue + + if args.regex is not None: + if not re.match('^%s$' % args.regex, filename): + continue + else: + if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE): + continue + + match = re.search('^@@.*\+(\d+)(,(\d+))?', line) + if match: + start_line = int(match.group(1)) + line_count = 1 + if match.group(3): + line_count = int(match.group(3)) + if line_count == 0: + continue + end_line = start_line + line_count - 1; + lines_by_file.setdefault(filename, []).extend( + ['-lines', str(start_line) + ':' + str(end_line)]) + + # Reformat files containing changes in place. + for filename, lines in lines_by_file.iteritems(): + if args.i and args.verbose: + print 'Formatting', filename + command = [binary, filename] + if args.i: + command.append('-i') + if args.sort_includes: + command.append('-sort-includes') + command.extend(lines) + command.extend(['-style=file', '-fallback-style=none']) + p = subprocess.Popen(command, stdout=subprocess.PIPE, + stderr=None, stdin=subprocess.PIPE) + stdout, stderr = p.communicate() + if p.returncode != 0: + sys.exit(p.returncode); + + if not args.i: + with open(filename) as f: + code = f.readlines() + formatted_code = StringIO.StringIO(stdout).readlines() + diff = difflib.unified_diff(code, formatted_code, + filename, filename, + '(before formatting)', '(after formatting)') + diff_string = string.join(diff, '') + if len(diff_string) > 0: + sys.stdout.write(diff_string) + +if __name__ == '__main__': + main() diff --git a/contrib/devtools/clang-format.py b/contrib/devtools/clang-format.py new file mode 100755 index 000000000..cee99047a --- /dev/null +++ b/contrib/devtools/clang-format.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +''' +Wrapper script for clang-format + +Copyright (c) 2015 MarcoFalke +Copyright (c) 2015 The Bitcoin Core developers +Distributed under the MIT software license, see the accompanying +file COPYING or http://www.opensource.org/licenses/mit-license.php. +''' + +import os +import sys +import subprocess + +tested_versions = ['3.6.0', '3.6.1', '3.6.2'] # A set of versions known to produce the same output +accepted_file_extensions = ('.h', '.cpp') # Files to format + +def check_clang_format_version(clang_format_exe): + try: + output = subprocess.check_output([clang_format_exe, '-version']) + for ver in tested_versions: + if ver in output: + print "Detected clang-format version " + ver + return + raise RuntimeError("Untested version: " + output) + except Exception as e: + print 'Could not verify version of ' + clang_format_exe + '.' + raise e + +def check_command_line_args(argv): + required_args = ['{clang-format-exe}', '{files}'] + example_args = ['clang-format-3.x', 'src/main.cpp', 'src/wallet/*'] + + if(len(argv) < len(required_args) + 1): + for word in (['Usage:', argv[0]] + required_args): + print word, + print '' + for word in (['E.g:', argv[0]] + example_args): + print word, + print '' + sys.exit(1) + +def run_clang_format(clang_format_exe, files): + for target in files: + if os.path.isdir(target): + for path, dirs, files in os.walk(target): + run_clang_format(clang_format_exe, (os.path.join(path, f) for f in files)) + elif target.endswith(accepted_file_extensions): + print "Format " + target + subprocess.check_call([clang_format_exe, '-i', '-style=file', target], stdout=open(os.devnull, 'wb'), stderr=subprocess.STDOUT) + else: + print "Skip " + target + +def main(argv): + check_command_line_args(argv) + clang_format_exe = argv[1] + files = argv[2:] + check_clang_format_version(clang_format_exe) + run_clang_format(clang_format_exe, files) + +if __name__ == "__main__": + main(sys.argv) diff --git a/contrib/devtools/fix-copyright-headers.py b/contrib/devtools/fix-copyright-headers.py index 5e8495254..b6414a551 100755 --- a/contrib/devtools/fix-copyright-headers.py +++ b/contrib/devtools/fix-copyright-headers.py @@ -1,53 +1,46 @@ #!/usr/bin/env python ''' -Run this script inside of src/ and it will look for all the files -that were changed this year that still have the last year in the -copyright headers, and it will fix the headers on that file using -a perl regex one liner. +Run this script to update all the copyright headers of files +that were changed this year. -For example: if it finds something like this and we're in 2014 +For example: -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2012 The Bitcoin Core developers it will change it to -// Copyright (c) 2009-2014 The Bitcoin Core developers - -It will do this for all the files in the folder and its children. - -Author: @gubatron +// Copyright (c) 2009-2015 The Bitcoin Core developers ''' import os import time +import re year = time.gmtime()[0] -last_year = year - 1 -command = "perl -pi -e 's/%s The Bitcoin/%s The Bitcoin/' %s" -listFilesCommand = "find . | grep %s" +CMD_GIT_DATE = 'git log --format=@%%at -1 %s | date +"%%Y" -u -f -' +CMD_REGEX= "perl -pi -e 's/(20\d\d)(?:-20\d\d)? The Bitcoin/$1-%s The Bitcoin/' %s" +REGEX_CURRENT= re.compile("%s The Bitcoin" % year) +CMD_LIST_FILES= "find %s | grep %s" -extensions = [".cpp",".h"] +FOLDERS = ["./qa", "./src"] +EXTENSIONS = [".cpp",".h", ".py"] -def getLastGitModifiedDate(filePath): - gitGetLastCommitDateCommand = "git log " + filePath +" | grep Date | head -n 1" - p = os.popen(gitGetLastCommitDateCommand) - result = "" - for l in p: - result = l - break - result = result.replace("\n","") - return result +def get_git_date(file_path): + r = os.popen(CMD_GIT_DATE % file_path) + for l in r: + # Result is one line, so just return + return l.replace("\n","") + return "" n=1 -for extension in extensions: - foundFiles = os.popen(listFilesCommand % extension) - for filePath in foundFiles: - filePath = filePath[1:-1] - if filePath.endswith(extension): - filePath = os.getcwd() + filePath - modifiedTime = getLastGitModifiedDate(filePath) - if len(modifiedTime) > 0 and str(year) in modifiedTime: - print n,"Last Git Modified: ", modifiedTime, " - ", filePath - os.popen(command % (last_year,year,filePath)) - n = n + 1 - - +for folder in FOLDERS: + for extension in EXTENSIONS: + for file_path in os.popen(CMD_LIST_FILES % (folder, extension)): + file_path = os.getcwd() + file_path[1:-1] + if file_path.endswith(extension): + git_date = get_git_date(file_path) + if str(year) == git_date: + # Only update if current year is not found + if REGEX_CURRENT.search(open(file_path, "r").read()) is None: + print n,"Last git edit", git_date, "-", file_path + os.popen(CMD_REGEX % (year,file_path)) + n = n + 1 diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py new file mode 100755 index 000000000..f82362fe4 --- /dev/null +++ b/contrib/devtools/github-merge.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python3 +# Copyright (c) 2016 Bitcoin Core Developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# This script will locally construct a merge commit for a pull request on a +# github repository, inspect it, sign it and optionally push it. + +# The following temporary branches are created/overwritten and deleted: +# * pull/$PULL/base (the current master we're merging onto) +# * pull/$PULL/head (the current state of the remote pull request) +# * pull/$PULL/merge (github's merge) +# * pull/$PULL/local-merge (our merge) + +# In case of a clean merge that is accepted by the user, the local branch with +# name $BRANCH is overwritten with the merged result, and optionally pushed. +from __future__ import division,print_function,unicode_literals +import os,sys +from sys import stdin,stdout,stderr +import argparse +import subprocess +import json,codecs +try: + from urllib.request import Request,urlopen +except: + from urllib2 import Request,urlopen + +# External tools (can be overridden using environment) +GIT = os.getenv('GIT','git') +BASH = os.getenv('BASH','bash') + +# OS specific configuration for terminal attributes +ATTR_RESET = '' +ATTR_PR = '' +COMMIT_FORMAT = '%h %s (%an)%d' +if os.name == 'posix': # if posix, assume we can use basic terminal escapes + ATTR_RESET = '\033[0m' + ATTR_PR = '\033[1;36m' + COMMIT_FORMAT = '%C(bold blue)%h%Creset %s %C(cyan)(%an)%Creset%C(green)%d%Creset' + +def git_config_get(option, default=None): + ''' + Get named configuration option from git repository. + ''' + try: + return subprocess.check_output([GIT,'config','--get',option]).rstrip().decode('utf-8') + except subprocess.CalledProcessError as e: + return default + +def retrieve_pr_info(repo,pull): + ''' + Retrieve pull request information from github. + Return None if no title can be found, or an error happens. + ''' + try: + req = Request("https://api.github.com/repos/"+repo+"/pulls/"+pull) + result = urlopen(req) + reader = codecs.getreader('utf-8') + obj = json.load(reader(result)) + return obj + except Exception as e: + print('Warning: unable to retrieve pull information from github: %s' % e) + return None + +def ask_prompt(text): + print(text,end=" ",file=stderr) + stderr.flush() + reply = stdin.readline().rstrip() + print("",file=stderr) + return reply + +def parse_arguments(): + epilog = ''' + In addition, you can set the following git configuration variables: + githubmerge.repository (mandatory), + user.signingkey (mandatory), + githubmerge.host (default: git@github.com), + githubmerge.branch (no default), + githubmerge.testcmd (default: none). + ''' + parser = argparse.ArgumentParser(description='Utility to merge, sign and push github pull requests', + epilog=epilog) + parser.add_argument('pull', metavar='PULL', type=int, nargs=1, + help='Pull request ID to merge') + parser.add_argument('branch', metavar='BRANCH', type=str, nargs='?', + default=None, help='Branch to merge against (default: githubmerge.branch setting, or base branch for pull, or \'master\')') + return parser.parse_args() + +def main(): + # Extract settings from git repo + repo = git_config_get('githubmerge.repository') + host = git_config_get('githubmerge.host','git@github.com') + opt_branch = git_config_get('githubmerge.branch',None) + testcmd = git_config_get('githubmerge.testcmd') + signingkey = git_config_get('user.signingkey') + if repo is None: + print("ERROR: No repository configured. Use this command to set:", file=stderr) + print("git config githubmerge.repository /", file=stderr) + exit(1) + if signingkey is None: + print("ERROR: No GPG signing key set. Set one using:",file=stderr) + print("git config --global user.signingkey ",file=stderr) + exit(1) + + host_repo = host+":"+repo # shortcut for push/pull target + + # Extract settings from command line + args = parse_arguments() + pull = str(args.pull[0]) + + # Receive pull information from github + info = retrieve_pr_info(repo,pull) + if info is None: + exit(1) + title = info['title'] + # precedence order for destination branch argument: + # - command line argument + # - githubmerge.branch setting + # - base branch for pull (as retrieved from github) + # - 'master' + branch = args.branch or opt_branch or info['base']['ref'] or 'master' + + # Initialize source branches + head_branch = 'pull/'+pull+'/head' + base_branch = 'pull/'+pull+'/base' + merge_branch = 'pull/'+pull+'/merge' + local_merge_branch = 'pull/'+pull+'/local-merge' + + devnull = open(os.devnull,'w') + try: + subprocess.check_call([GIT,'checkout','-q',branch]) + except subprocess.CalledProcessError as e: + print("ERROR: Cannot check out branch %s." % (branch), file=stderr) + exit(3) + try: + subprocess.check_call([GIT,'fetch','-q',host_repo,'+refs/pull/'+pull+'/*:refs/heads/pull/'+pull+'/*']) + except subprocess.CalledProcessError as e: + print("ERROR: Cannot find pull request #%s on %s." % (pull,host_repo), file=stderr) + exit(3) + try: + subprocess.check_call([GIT,'log','-q','-1','refs/heads/'+head_branch], stdout=devnull, stderr=stdout) + except subprocess.CalledProcessError as e: + print("ERROR: Cannot find head of pull request #%s on %s." % (pull,host_repo), file=stderr) + exit(3) + try: + subprocess.check_call([GIT,'log','-q','-1','refs/heads/'+merge_branch], stdout=devnull, stderr=stdout) + except subprocess.CalledProcessError as e: + print("ERROR: Cannot find merge of pull request #%s on %s." % (pull,host_repo), file=stderr) + exit(3) + try: + subprocess.check_call([GIT,'fetch','-q',host_repo,'+refs/heads/'+branch+':refs/heads/'+base_branch]) + except subprocess.CalledProcessError as e: + print("ERROR: Cannot find branch %s on %s." % (branch,host_repo), file=stderr) + exit(3) + subprocess.check_call([GIT,'checkout','-q',base_branch]) + subprocess.call([GIT,'branch','-q','-D',local_merge_branch], stderr=devnull) + subprocess.check_call([GIT,'checkout','-q','-b',local_merge_branch]) + + try: + # Create unsigned merge commit. + if title: + firstline = 'Merge #%s: %s' % (pull,title) + else: + firstline = 'Merge #%s' % (pull,) + message = firstline + '\n\n' + message += subprocess.check_output([GIT,'log','--no-merges','--topo-order','--pretty=format:%h %s (%an)',base_branch+'..'+head_branch]).decode('utf-8') + try: + subprocess.check_call([GIT,'merge','-q','--commit','--no-edit','--no-ff','-m',message.encode('utf-8'),head_branch]) + except subprocess.CalledProcessError as e: + print("ERROR: Cannot be merged cleanly.",file=stderr) + subprocess.check_call([GIT,'merge','--abort']) + exit(4) + logmsg = subprocess.check_output([GIT,'log','--pretty=format:%s','-n','1']).decode('utf-8') + if logmsg.rstrip() != firstline.rstrip(): + print("ERROR: Creating merge failed (already merged?).",file=stderr) + exit(4) + + print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET)) + subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch]) + print() + # Run test command if configured. + if testcmd: + # Go up to the repository's root. + toplevel = subprocess.check_output([GIT,'rev-parse','--show-toplevel']).strip() + os.chdir(toplevel) + if subprocess.call(testcmd,shell=True): + print("ERROR: Running %s failed." % testcmd,file=stderr) + exit(5) + + # Show the created merge. + diff = subprocess.check_output([GIT,'diff',merge_branch+'..'+local_merge_branch]) + subprocess.check_call([GIT,'diff',base_branch+'..'+local_merge_branch]) + if diff: + print("WARNING: merge differs from github!",file=stderr) + reply = ask_prompt("Type 'ignore' to continue.") + if reply.lower() == 'ignore': + print("Difference with github ignored.",file=stderr) + else: + exit(6) + reply = ask_prompt("Press 'd' to accept the diff.") + if reply.lower() == 'd': + print("Diff accepted.",file=stderr) + else: + print("ERROR: Diff rejected.",file=stderr) + exit(6) + else: + # Verify the result manually. + print("Dropping you on a shell so you can try building/testing the merged source.",file=stderr) + print("Run 'git diff HEAD~' to show the changes being merged.",file=stderr) + print("Type 'exit' when done.",file=stderr) + if os.path.isfile('/etc/debian_version'): # Show pull number on Debian default prompt + os.putenv('debian_chroot',pull) + subprocess.call([BASH,'-i']) + reply = ask_prompt("Type 'm' to accept the merge.") + if reply.lower() == 'm': + print("Merge accepted.",file=stderr) + else: + print("ERROR: Merge rejected.",file=stderr) + exit(7) + + # Sign the merge commit. + reply = ask_prompt("Type 's' to sign off on the merge.") + if reply == 's': + try: + subprocess.check_call([GIT,'commit','-q','--gpg-sign','--amend','--no-edit']) + except subprocess.CalledProcessError as e: + print("Error signing, exiting.",file=stderr) + exit(1) + else: + print("Not signing off on merge, exiting.",file=stderr) + exit(1) + + # Put the result in branch. + subprocess.check_call([GIT,'checkout','-q',branch]) + subprocess.check_call([GIT,'reset','-q','--hard',local_merge_branch]) + finally: + # Clean up temporary branches. + subprocess.call([GIT,'checkout','-q',branch]) + subprocess.call([GIT,'branch','-q','-D',head_branch],stderr=devnull) + subprocess.call([GIT,'branch','-q','-D',base_branch],stderr=devnull) + subprocess.call([GIT,'branch','-q','-D',merge_branch],stderr=devnull) + subprocess.call([GIT,'branch','-q','-D',local_merge_branch],stderr=devnull) + + # Push the result. + reply = ask_prompt("Type 'push' to push the result to %s, branch %s." % (host_repo,branch)) + if reply.lower() == 'push': + subprocess.check_call([GIT,'push',host_repo,'refs/heads/'+branch]) + +if __name__ == '__main__': + main() + diff --git a/contrib/devtools/github-merge.sh b/contrib/devtools/github-merge.sh deleted file mode 100755 index afb53f039..000000000 --- a/contrib/devtools/github-merge.sh +++ /dev/null @@ -1,185 +0,0 @@ -#!/bin/bash - -# This script will locally construct a merge commit for a pull request on a -# github repository, inspect it, sign it and optionally push it. - -# The following temporary branches are created/overwritten and deleted: -# * pull/$PULL/base (the current master we're merging onto) -# * pull/$PULL/head (the current state of the remote pull request) -# * pull/$PULL/merge (github's merge) -# * pull/$PULL/local-merge (our merge) - -# In case of a clean merge that is accepted by the user, the local branch with -# name $BRANCH is overwritten with the merged result, and optionally pushed. - -REPO="$(git config --get githubmerge.repository)" -if [[ "d$REPO" == "d" ]]; then - echo "ERROR: No repository configured. Use this command to set:" >&2 - echo "git config githubmerge.repository /" >&2 - echo "In addition, you can set the following variables:" >&2 - echo "- githubmerge.host (default git@github.com)" >&2 - echo "- githubmerge.branch (default master)" >&2 - echo "- githubmerge.testcmd (default none)" >&2 - exit 1 -fi - -HOST="$(git config --get githubmerge.host)" -if [[ "d$HOST" == "d" ]]; then - HOST="git@github.com" -fi - -BRANCH="$(git config --get githubmerge.branch)" -if [[ "d$BRANCH" == "d" ]]; then - BRANCH="master" -fi - -TESTCMD="$(git config --get githubmerge.testcmd)" - -PULL="$1" - -if [[ "d$PULL" == "d" ]]; then - echo "Usage: $0 pullnumber [branch]" >&2 - exit 2 -fi - -if [[ "d$2" != "d" ]]; then - BRANCH="$2" -fi - -# Initialize source branches. -git checkout -q "$BRANCH" -if git fetch -q "$HOST":"$REPO" "+refs/pull/$PULL/*:refs/heads/pull/$PULL/*"; then - if ! git log -q -1 "refs/heads/pull/$PULL/head" >/dev/null 2>&1; then - echo "ERROR: Cannot find head of pull request #$PULL on $HOST:$REPO." >&2 - exit 3 - fi - if ! git log -q -1 "refs/heads/pull/$PULL/merge" >/dev/null 2>&1; then - echo "ERROR: Cannot find merge of pull request #$PULL on $HOST:$REPO." >&2 - exit 3 - fi -else - echo "ERROR: Cannot find pull request #$PULL on $HOST:$REPO." >&2 - exit 3 -fi -if git fetch -q "$HOST":"$REPO" +refs/heads/"$BRANCH":refs/heads/pull/"$PULL"/base; then - true -else - echo "ERROR: Cannot find branch $BRANCH on $HOST:$REPO." >&2 - exit 3 -fi -git checkout -q pull/"$PULL"/base -git branch -q -D pull/"$PULL"/local-merge 2>/dev/null -git checkout -q -b pull/"$PULL"/local-merge -TMPDIR="$(mktemp -d -t ghmXXXXX)" - -function cleanup() { - git checkout -q "$BRANCH" - git branch -q -D pull/"$PULL"/head 2>/dev/null - git branch -q -D pull/"$PULL"/base 2>/dev/null - git branch -q -D pull/"$PULL"/merge 2>/dev/null - git branch -q -D pull/"$PULL"/local-merge 2>/dev/null - rm -rf "$TMPDIR" -} - -# Create unsigned merge commit. -( - echo "Merge pull request #$PULL" - echo "" - git log --no-merges --topo-order --pretty='format:%h %s (%an)' pull/"$PULL"/base..pull/"$PULL"/head -)>"$TMPDIR/message" -if git merge -q --commit --no-edit --no-ff -m "$(<"$TMPDIR/message")" pull/"$PULL"/head; then - if [ "d$(git log --pretty='format:%s' -n 1)" != "dMerge pull request #$PULL" ]; then - echo "ERROR: Creating merge failed (already merged?)." >&2 - cleanup - exit 4 - fi -else - echo "ERROR: Cannot be merged cleanly." >&2 - git merge --abort - cleanup - exit 4 -fi - -# Run test command if configured. -if [[ "d$TESTCMD" != "d" ]]; then - # Go up to the repository's root. - while [ ! -d .git ]; do cd ..; done - if ! $TESTCMD; then - echo "ERROR: Running $TESTCMD failed." >&2 - cleanup - exit 5 - fi - # Show the created merge. - git diff pull/"$PULL"/merge..pull/"$PULL"/local-merge >"$TMPDIR"/diff - git diff pull/"$PULL"/base..pull/"$PULL"/local-merge - if [[ "$(<"$TMPDIR"/diff)" != "" ]]; then - echo "WARNING: merge differs from github!" >&2 - read -p "Type 'ignore' to continue. " -r >&2 - if [[ "d$REPLY" =~ ^d[iI][gG][nN][oO][rR][eE]$ ]]; then - echo "Difference with github ignored." >&2 - else - cleanup - exit 6 - fi - fi - read -p "Press 'd' to accept the diff. " -n 1 -r >&2 - echo - if [[ "d$REPLY" =~ ^d[dD]$ ]]; then - echo "Diff accepted." >&2 - else - echo "ERROR: Diff rejected." >&2 - cleanup - exit 6 - fi -else - # Verify the result. - echo "Dropping you on a shell so you can try building/testing the merged source." >&2 - echo "Run 'git diff HEAD~' to show the changes being merged." >&2 - echo "Type 'exit' when done." >&2 - if [[ -f /etc/debian_version ]]; then # Show pull number in prompt on Debian default prompt - export debian_chroot="$PULL" - fi - bash -i - read -p "Press 'm' to accept the merge. " -n 1 -r >&2 - echo - if [[ "d$REPLY" =~ ^d[Mm]$ ]]; then - echo "Merge accepted." >&2 - else - echo "ERROR: Merge rejected." >&2 - cleanup - exit 7 - fi -fi - -# Sign the merge commit. -read -p "Press 's' to sign off on the merge. " -n 1 -r >&2 -echo -if [[ "d$REPLY" =~ ^d[Ss]$ ]]; then - if [[ "$(git config --get user.signingkey)" == "" ]]; then - echo "ERROR: No GPG signing key set, not signing. Set one using:" >&2 - echo "git config --global user.signingkey " >&2 - cleanup - exit 1 - else - if ! git commit -q --gpg-sign --amend --no-edit; then - echo "Error signing, exiting." - cleanup - exit 1 - fi - fi -else - echo "Not signing off on merge, exiting." - cleanup - exit 1 -fi - -# Clean up temporary branches, and put the result in $BRANCH. -git checkout -q "$BRANCH" -git reset -q --hard pull/"$PULL"/local-merge -cleanup - -# Push the result. -read -p "Type 'push' to push the result to $HOST:$REPO, branch $BRANCH. " -r >&2 -if [[ "d$REPLY" =~ ^d[Pp][Uu][Ss][Hh]$ ]]; then - git push "$HOST":"$REPO" refs/heads/"$BRANCH" -fi diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py new file mode 100755 index 000000000..301fea85c --- /dev/null +++ b/contrib/devtools/security-check.py @@ -0,0 +1,181 @@ +#!/usr/bin/python2 +''' +Perform basic ELF security checks on a series of executables. +Exit status will be 0 if successful, and the program will be silent. +Otherwise the exit status will be 1 and it will log which executables failed which checks. +Needs `readelf` (for ELF) and `objdump` (for PE). +''' +from __future__ import division,print_function,unicode_literals +import subprocess +import sys +import os + +READELF_CMD = os.getenv('READELF', '/usr/bin/readelf') +OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump') + +def check_ELF_PIE(executable): + ''' + Check for position independent executable (PIE), allowing for address space randomization. + ''' + p = subprocess.Popen([READELF_CMD, '-h', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + + ok = False + for line in stdout.split(b'\n'): + line = line.split() + if len(line)>=2 and line[0] == b'Type:' and line[1] == b'DYN': + ok = True + return ok + +def get_ELF_program_headers(executable): + '''Return type and flags for ELF program headers''' + p = subprocess.Popen([READELF_CMD, '-l', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + in_headers = False + count = 0 + headers = [] + for line in stdout.split(b'\n'): + if line.startswith(b'Program Headers:'): + in_headers = True + if line == b'': + in_headers = False + if in_headers: + if count == 1: # header line + ofs_typ = line.find(b'Type') + ofs_offset = line.find(b'Offset') + ofs_flags = line.find(b'Flg') + ofs_align = line.find(b'Align') + if ofs_typ == -1 or ofs_offset == -1 or ofs_flags == -1 or ofs_align == -1: + raise ValueError('Cannot parse elfread -lW output') + elif count > 1: + typ = line[ofs_typ:ofs_offset].rstrip() + flags = line[ofs_flags:ofs_align].rstrip() + headers.append((typ, flags)) + count += 1 + return headers + +def check_ELF_NX(executable): + ''' + Check that no sections are writable and executable (including the stack) + ''' + have_wx = False + have_gnu_stack = False + for (typ, flags) in get_ELF_program_headers(executable): + if typ == b'GNU_STACK': + have_gnu_stack = True + if b'W' in flags and b'E' in flags: # section is both writable and executable + have_wx = True + return have_gnu_stack and not have_wx + +def check_ELF_RELRO(executable): + ''' + Check for read-only relocations. + GNU_RELRO program header must exist + Dynamic section must have BIND_NOW flag + ''' + have_gnu_relro = False + for (typ, flags) in get_ELF_program_headers(executable): + # Note: not checking flags == 'R': here as linkers set the permission differently + # This does not affect security: the permission flags of the GNU_RELRO program header are ignored, the PT_LOAD header determines the effective permissions. + # However, the dynamic linker need to write to this area so these are RW. + # Glibc itself takes care of mprotecting this area R after relocations are finished. + # See also http://permalink.gmane.org/gmane.comp.gnu.binutils/71347 + if typ == b'GNU_RELRO': + have_gnu_relro = True + + have_bindnow = False + p = subprocess.Popen([READELF_CMD, '-d', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + for line in stdout.split(b'\n'): + tokens = line.split() + 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]): + have_bindnow = True + return have_gnu_relro and have_bindnow + +def check_ELF_Canary(executable): + ''' + Check for use of stack canary + ''' + p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + ok = False + for line in stdout.split(b'\n'): + if b'__stack_chk_fail' in line: + ok = True + return ok + +def get_PE_dll_characteristics(executable): + ''' + Get PE DllCharacteristics bits + ''' + p = subprocess.Popen([OBJDUMP_CMD, '-x', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + for line in stdout.split('\n'): + tokens = line.split() + if len(tokens)>=2 and tokens[0] == 'DllCharacteristics': + return int(tokens[1],16) + return 0 + + +def check_PE_PIE(executable): + '''PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR)''' + return bool(get_PE_dll_characteristics(executable) & 0x40) + +def check_PE_NX(executable): + '''NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP)''' + return bool(get_PE_dll_characteristics(executable) & 0x100) + +CHECKS = { +'ELF': [ + ('PIE', check_ELF_PIE), + ('NX', check_ELF_NX), + ('RELRO', check_ELF_RELRO), + ('Canary', check_ELF_Canary) +], +'PE': [ + ('PIE', check_PE_PIE), + ('NX', check_PE_NX) +] +} + +def identify_executable(executable): + with open(filename, 'rb') as f: + magic = f.read(4) + if magic.startswith(b'MZ'): + return 'PE' + elif magic.startswith(b'\x7fELF'): + return 'ELF' + return None + +if __name__ == '__main__': + retval = 0 + for filename in sys.argv[1:]: + try: + etype = identify_executable(filename) + if etype is None: + print('%s: unknown format' % filename) + retval = 1 + continue + + failed = [] + for (name, func) in CHECKS[etype]: + if not func(filename): + failed.append(name) + if failed: + print('%s: failed %s' % (filename, ' '.join(failed))) + retval = 1 + except IOError: + print('%s: cannot open' % filename) + retval = 1 + exit(retval) + diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index fad891f80..e26c0fbb9 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python2 # Copyright (c) 2014 Wladimir J. van der Laan # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,10 +11,11 @@ Example usage: find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py ''' -from __future__ import division, print_function +from __future__ import division, print_function, unicode_literals import subprocess import re import sys +import os # Debian 6.0.9 (Squeeze) has: # @@ -41,12 +42,34 @@ MAX_VERSIONS = { 'GLIBCXX': (3,4,13), 'GLIBC': (2,11) } +# See here for a description of _IO_stdin_used: +# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=634261#109 + # Ignore symbols that are exported as part of every executable IGNORE_EXPORTS = { -'_edata', '_end', '_init', '__bss_start', '_fini' +b'_edata', b'_end', b'_init', b'__bss_start', b'_fini', b'_IO_stdin_used' +} +READELF_CMD = os.getenv('READELF', '/usr/bin/readelf') +CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt') +# Allowed NEEDED libraries +ALLOWED_LIBRARIES = { +# bitcoind and bitcoin-qt +b'libgcc_s.so.1', # GCC base support +b'libc.so.6', # C library +b'libpthread.so.0', # threading +b'libanl.so.1', # DNS resolve +b'libm.so.6', # math library +b'librt.so.1', # real-time (clock) +b'ld-linux-x86-64.so.2', # 64-bit dynamic linker +b'ld-linux.so.2', # 32-bit dynamic linker +# bitcoin-qt only +b'libX11-xcb.so.1', # part of X11 +b'libX11.so.6', # part of X11 +b'libxcb.so.1', # part of X11 +b'libfontconfig.so.1', # font support +b'libfreetype.so.6', # font parsing +b'libdl.so.2' # programming interface to dynamic linker } -READELF_CMD = '/usr/bin/readelf' -CPPFILT_CMD = '/usr/bin/c++filt' class CPPFilt(object): ''' @@ -58,7 +81,8 @@ class CPPFilt(object): self.proc = subprocess.Popen(CPPFILT_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE) def __call__(self, mangled): - self.proc.stdin.write(mangled + '\n') + self.proc.stdin.write(mangled + b'\n') + self.proc.stdin.flush() return self.proc.stdout.readline().rstrip() def close(self): @@ -76,28 +100,44 @@ def read_symbols(executable, imports=True): if p.returncode: raise IOError('Could not read symbols for %s: %s' % (executable, stderr.strip())) syms = [] - for line in stdout.split('\n'): + for line in stdout.split(b'\n'): line = line.split() - if len(line)>7 and re.match('[0-9]+:$', line[0]): - (sym, _, version) = line[7].partition('@') - is_import = line[6] == 'UND' - if version.startswith('@'): + if len(line)>7 and re.match(b'[0-9]+:$', line[0]): + (sym, _, version) = line[7].partition(b'@') + is_import = line[6] == b'UND' + if version.startswith(b'@'): version = version[1:] if is_import == imports: syms.append((sym, version)) return syms def check_version(max_versions, version): - if '_' in version: - (lib, _, ver) = version.rpartition('_') + if b'_' in version: + (lib, _, ver) = version.rpartition(b'_') else: lib = version ver = '0' - ver = tuple([int(x) for x in ver.split('.')]) + ver = tuple([int(x) for x in ver.split(b'.')]) if not lib in max_versions: return False return ver <= max_versions[lib] +def read_libraries(filename): + p = subprocess.Popen([READELF_CMD, '-d', '-W', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + libraries = [] + for line in stdout.split(b'\n'): + tokens = line.split() + if len(tokens)>2 and tokens[1] == b'(NEEDED)': + match = re.match(b'^Shared library: \[(.*)\]$', b' '.join(tokens[2:])) + if match: + libraries.append(match.group(1)) + else: + raise ValueError('Unparseable (NEEDED) specification') + return libraries + if __name__ == '__main__': cppfilt = CPPFilt() retval = 0 @@ -105,14 +145,19 @@ if __name__ == '__main__': # Check imported symbols for sym,version in read_symbols(filename, True): if version and not check_version(MAX_VERSIONS, version): - print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym), version)) + print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym).decode('utf-8'), version.decode('utf-8'))) retval = 1 # Check exported symbols for sym,version in read_symbols(filename, False): if sym in IGNORE_EXPORTS: continue - print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym))) + print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym).decode('utf-8'))) retval = 1 + # Check dependency libraries + for library_name in read_libraries(filename): + if library_name not in ALLOWED_LIBRARIES: + print('%s: NEEDED library %s is not allowed' % (filename, library_name.decode('utf-8'))) + retval = 1 exit(retval) diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py new file mode 100755 index 000000000..fed7626aa --- /dev/null +++ b/contrib/devtools/test-security-check.py @@ -0,0 +1,60 @@ +#!/usr/bin/python2 +''' +Test script for security-check.py +''' +from __future__ import division,print_function +import subprocess +import sys +import unittest + +def write_testcode(filename): + with open(filename, 'w') as f: + f.write(''' + #include + int main() + { + printf("the quick brown fox jumps over the lazy god\\n"); + return 0; + } + ''') + +def call_security_check(cc, source, executable, options): + subprocess.check_call([cc,source,'-o',executable] + options) + p = subprocess.Popen(['./security-check.py',executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + (stdout, stderr) = p.communicate() + return (p.returncode, stdout.rstrip()) + +class TestSecurityChecks(unittest.TestCase): + def test_ELF(self): + source = 'test1.c' + executable = 'test1' + cc = 'gcc' + write_testcode(source) + + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-fno-stack-protector','-Wl,-znorelro']), + (1, executable+': failed PIE NX RELRO Canary')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fno-stack-protector','-Wl,-znorelro']), + (1, executable+': failed PIE RELRO Canary')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro']), + (1, executable+': failed PIE RELRO')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro','-pie','-fPIE']), + (1, executable+': failed RELRO')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE']), + (0, '')) + + def test_PE(self): + source = 'test1.c' + executable = 'test1.exe' + cc = 'i686-w64-mingw32-gcc' + write_testcode(source) + + self.assertEqual(call_security_check(cc, source, executable, []), + (1, executable+': failed PIE NX')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat']), + (1, executable+': failed PIE')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase']), + (0, '')) + +if __name__ == '__main__': + unittest.main() + diff --git a/contrib/devtools/update-translations.py b/contrib/devtools/update-translations.py index f955e4a1f..2b6e807b4 100755 --- a/contrib/devtools/update-translations.py +++ b/contrib/devtools/update-translations.py @@ -29,6 +29,8 @@ TX = 'tx' SOURCE_LANG = 'bitcoin_en.ts' # Directory with locale files LOCALE_DIR = 'src/qt/locale' +# Minimum number of messages for translation to be considered at all +MIN_NUM_MESSAGES = 10 def check_at_repository_root(): if not os.path.exists('.git'): @@ -37,7 +39,7 @@ def check_at_repository_root(): exit(1) def fetch_all_translations(): - if subprocess.call([TX, 'pull', '-f']): + if subprocess.call([TX, 'pull', '-f', '-a']): print('Error while fetching translations', file=sys.stderr) exit(1) @@ -70,7 +72,7 @@ def sanitize_string(s): '''Sanitize string for printing''' return s.replace('\n',' ') -def check_format_specifiers(source, translation, errors): +def check_format_specifiers(source, translation, errors, numerus): source_f = split_format_specifiers(find_format_specifiers(source)) # assert that no source messages contain both Qt and strprintf format specifiers # if this fails, go change the source as this is hacky and confusing! @@ -78,10 +80,13 @@ def check_format_specifiers(source, translation, errors): try: translation_f = split_format_specifiers(find_format_specifiers(translation)) except IndexError: - errors.append("Parse error in translation '%s'" % sanitize_string(translation)) + errors.append("Parse error in translation for '%s': '%s'" % (sanitize_string(source), sanitize_string(translation))) return False else: if source_f != translation_f: + if numerus and source_f == (set(), ['n']) and translation_f == (set(), []) and translation.find('%') == -1: + # Allow numerus translations to omit %n specifier (usually when it only has one possible value) + return True errors.append("Mismatch between '%s' and '%s'" % (sanitize_string(source), sanitize_string(translation))) return False return True @@ -148,7 +153,7 @@ def postprocess_translations(reduce_diff_hacks=False): if translation is None: continue errors = [] - valid = check_format_specifiers(source, translation, errors) + valid = check_format_specifiers(source, translation, errors, numerus) for error in errors: print('%s: %s' % (filename, error)) @@ -166,6 +171,15 @@ def postprocess_translations(reduce_diff_hacks=False): if translation_node.get('type') == 'unfinished': context.remove(message) + # check if document is (virtually) empty, and remove it if so + num_messages = 0 + for context in root.findall('context'): + for message in context.findall('message'): + num_messages += 1 + if num_messages < MIN_NUM_MESSAGES: + print('Removing %s, as it contains only %i messages' % (filepath, num_messages)) + continue + # write fixed-up tree # if diff reduction requested, replace some XML to 'sanitize' to qt formatting if reduce_diff_hacks: diff --git a/contrib/gitian-descriptors/README.md b/contrib/gitian-descriptors/README.md index 061b897d2..614970659 100644 --- a/contrib/gitian-descriptors/README.md +++ b/contrib/gitian-descriptors/README.md @@ -1,8 +1,7 @@ -### Gavin's notes on getting gitian builds up and running using KVM:### +### Gavin's notes on getting gitian builds up and running using KVM -These instructions distilled from: -[ https://help.ubuntu.com/community/KVM/Installation]( https://help.ubuntu.com/community/KVM/Installation) -... see there for complete details. +These instructions distilled from +[https://help.ubuntu.com/community/KVM/Installation](https://help.ubuntu.com/community/KVM/Installation). You need the right hardware: you need a 64-bit-capable CPU with hardware virtualization support (Intel VT-x or AMD-V). Not all modern CPUs support hardware virtualization. @@ -27,20 +26,20 @@ Once you've got the right hardware and software: # Create base images cd gitian-builder - bin/make-base-vm --suite precise --arch amd64 + bin/make-base-vm --suite trusty --arch amd64 cd .. # Get inputs (see doc/release-process.md for exact inputs needed and where to get them) ... - # For further build instructions see doc/release-notes.md + # For further build instructions see doc/release-process.md ... --------------------- `gitian-builder` now also supports building using LXC. See -[ https://help.ubuntu.com/12.04/serverguide/lxc.html]( https://help.ubuntu.com/12.04/serverguide/lxc.html) -... for how to get LXC up and running under Ubuntu. +[help.ubuntu.com](https://help.ubuntu.com/14.04/serverguide/lxc.html) +for how to get LXC up and running under Ubuntu. If your main machine is a 64-bit Mac or PC with a few gigabytes of memory and at least 10 gigabytes of free disk space, you can `gitian-build` using diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index a98a71e2f..13941f5d5 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,22 +1,24 @@ --- -name: "bitcoin-linux-0.12" +name: "bitcoin-linux-0.13" enable_cache: true suites: -- "precise" +- "trusty" architectures: - "amd64" packages: +- "curl" - "g++-multilib" - "git-core" - "pkg-config" -- "autoconf2.13" +- "autoconf" - "libtool" - "automake" - "faketime" - "bsdmainutils" - "binutils-gold" -- "libstdc++6-4.6-pic" -reference_datetime: "2015-06-01 00:00:00" +- "ca-certificates" +- "python" +reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin.git" "dir": "bitcoin" @@ -24,7 +26,7 @@ files: [] script: | WRAP_DIR=$HOME/wrapped HOSTS="i686-pc-linux-gnu x86_64-unknown-linux-gnu" - CONFIGFLAGS="--enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" + CONFIGFLAGS="--enable-glibc-back-compat --enable-reduce-exports --disable-bench --disable-gui-tests LDFLAGS=-static-libstdc++" FAKETIME_HOST_PROGS="" FAKETIME_PROGS="date ar ranlib nm strip" @@ -44,7 +46,7 @@ script: | for prog in ${FAKETIME_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} - echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} + echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} @@ -55,7 +57,7 @@ script: | for prog in ${FAKETIME_HOST_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} - echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} + echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} @@ -70,14 +72,6 @@ script: | make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" done - # Ubuntu precise hack: Not an issue in later versions. - # Precise's libstdc++.a is non-pic. There's an optional libstdc++6-4.6-pic - # package which provides libstdc++_pic.a, but the linker can't find it. - # Symlink it to a path that will be included in our link-line so that the - # linker picks it up before the default libstdc++.a. - # This is only necessary for 64bit. - ln -s /usr/lib/gcc/x86_64-linux-gnu/4.6/libstdc++_pic.a ${BASEPREFIX}/x86_64-unknown-linux-gnu/lib/libstdc++.a - # Create the release tarball using (arbitrarily) the first host ./autogen.sh ./configure --prefix=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'` @@ -103,6 +97,8 @@ script: | ./configure --prefix=${BASEPREFIX}/${i} --bindir=${INSTALLPATH}/bin --includedir=${INSTALLPATH}/include --libdir=${INSTALLPATH}/lib --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} make ${MAKEOPTS} + make ${MAKEOPTS} -C src check-security + make ${MAKEOPTS} -C src check-symbols make install-strip cd installed find . -name "lib*.la" -delete diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml index 36d7b0126..c4165470a 100644 --- a/contrib/gitian-descriptors/gitian-osx-signer.yml +++ b/contrib/gitian-descriptors/gitian-osx-signer.yml @@ -1,13 +1,12 @@ --- name: "bitcoin-dmg-signer" suites: -- "precise" +- "trusty" architectures: - "amd64" packages: -- "libc6:i386" - "faketime" -reference_datetime: "2015-06-01 00:00:00" +reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin-detached-sigs.git" "dir": "signature" @@ -23,7 +22,7 @@ script: | for prog in ${FAKETIME_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} - echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} + echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} @@ -33,6 +32,7 @@ script: | SIGNED=bitcoin-osx-signed.dmg tar -xf ${UNSIGNED} + OSX_VOLNAME="$(cat osx_volname)" ./detached-sig-apply.sh ${UNSIGNED} signature/osx - ${WRAP_DIR}/genisoimage -no-cache-inodes -D -l -probe -V "Bitcoin-Core" -no-pad -r -apple -o uncompressed.dmg signed-app + ${WRAP_DIR}/genisoimage -no-cache-inodes -D -l -probe -V "${OSX_VOLNAME}" -no-pad -r -apple -o uncompressed.dmg signed-app ${WRAP_DIR}/dmg dmg uncompressed.dmg ${OUTDIR}/${SIGNED} diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index eeeb408de..c430932f9 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -1,24 +1,33 @@ --- -name: "bitcoin-osx-0.12" +name: "bitcoin-osx-0.13" enable_cache: true suites: -- "precise" +- "trusty" architectures: - "amd64" packages: +- "ca-certificates" +- "curl" - "g++" - "git-core" - "pkg-config" -- "autoconf2.13" +- "autoconf" +- "librsvg2-bin" +- "libtiff-tools" - "libtool" - "automake" - "faketime" - "bsdmainutils" - "cmake" +- "imagemagick" - "libcap-dev" - "libz-dev" - "libbz2-dev" -reference_datetime: "2015-06-01 00:00:00" +- "python" +- "python-dev" +- "python-setuptools" +- "fonts-tuffy" +reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin.git" "dir": "bitcoin" @@ -27,7 +36,7 @@ files: script: | WRAP_DIR=$HOME/wrapped HOSTS="x86_64-apple-darwin11" - CONFIGFLAGS="--enable-reduce-exports GENISOIMAGE=$WRAP_DIR/genisoimage" + CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests GENISOIMAGE=$WRAP_DIR/genisoimage" FAKETIME_HOST_PROGS="" FAKETIME_PROGS="ar ranlib date dmg genisoimage" @@ -49,7 +58,7 @@ script: | for prog in ${FAKETIME_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} - echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} + echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} @@ -60,7 +69,7 @@ script: | for prog in ${FAKETIME_HOST_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} - echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} + echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} @@ -107,8 +116,11 @@ script: | make ${MAKEOPTS} make install-strip + make osx_volname make deploydir + OSX_VOLNAME="$(cat osx_volname)" mkdir -p unsigned-app-${i} + cp osx_volname unsigned-app-${i}/ cp contrib/macdeploy/detached-sig-apply.sh unsigned-app-${i} cp contrib/macdeploy/detached-sig-create.sh unsigned-app-${i} cp ${BASEPREFIX}/${i}/native/bin/dmg ${BASEPREFIX}/${i}/native/bin/genisoimage unsigned-app-${i} @@ -120,7 +132,7 @@ script: | popd make deploy - ${WRAP_DIR}/dmg dmg Bitcoin-Core.dmg ${OUTDIR}/${DISTNAME}-osx-unsigned.dmg + ${WRAP_DIR}/dmg dmg "${OSX_VOLNAME}.dmg" ${OUTDIR}/${DISTNAME}-osx-unsigned.dmg cd installed find . -name "lib*.la" -delete diff --git a/contrib/gitian-descriptors/gitian-win-signer.yml b/contrib/gitian-descriptors/gitian-win-signer.yml index 2a73050e0..27c4f01eb 100644 --- a/contrib/gitian-descriptors/gitian-win-signer.yml +++ b/contrib/gitian-descriptors/gitian-win-signer.yml @@ -1,13 +1,13 @@ --- name: "bitcoin-win-signer" suites: -- "precise" +- "trusty" architectures: - "amd64" packages: - "libssl-dev" - "autoconf" -reference_datetime: "2015-06-01 00:00:00" +reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin-detached-sigs.git" "dir": "signature" diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 5fa0db678..9f7322f0b 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -1,15 +1,16 @@ --- -name: "bitcoin-win-0.12" +name: "bitcoin-win-0.13" enable_cache: true suites: -- "precise" +- "trusty" architectures: - "amd64" packages: +- "curl" - "g++" - "git-core" - "pkg-config" -- "autoconf2.13" +- "autoconf" - "libtool" - "automake" - "faketime" @@ -18,7 +19,9 @@ packages: - "g++-mingw-w64" - "nsis" - "zip" -reference_datetime: "2015-06-01 00:00:00" +- "ca-certificates" +- "python" +reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin.git" "dir": "bitcoin" @@ -26,7 +29,7 @@ files: [] script: | WRAP_DIR=$HOME/wrapped HOSTS="x86_64-w64-mingw32 i686-w64-mingw32" - CONFIGFLAGS="--enable-reduce-exports" + CONFIGFLAGS="--enable-reduce-exports --disable-gui-tests" FAKETIME_HOST_PROGS="g++ ar ranlib nm windres strip" FAKETIME_PROGS="date makensis zip" @@ -46,7 +49,7 @@ script: | for prog in ${FAKETIME_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} - echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} + echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} @@ -57,12 +60,36 @@ script: | for prog in ${FAKETIME_HOST_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} - echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} + echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done + + # Create per-host linker wrapper + # This is only needed for trusty, as the mingw linker leaks a few bytes of + # heap, causing non-determinism. See discussion in https://github.com/bitcoin/bitcoin/pull/6900 + for i in $HOSTS; do + mkdir -p ${WRAP_DIR}/${i} + for prog in collect2; do + echo '#!/bin/bash' > ${WRAP_DIR}/${i}/${prog} + REAL=$(${i}-gcc -print-prog-name=${prog}) + echo "export MALLOC_PERTURB_=255" >> ${WRAP_DIR}/${i}/${prog} + echo "${REAL} \$@" >> $WRAP_DIR/${i}/${prog} + chmod +x ${WRAP_DIR}/${i}/${prog} + done + for prog in gcc g++; do + echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} + echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} + echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} + echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} + echo "export COMPILER_PATH=${WRAP_DIR}/${i}" >> ${WRAP_DIR}/${i}-${prog} + echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} + chmod +x ${WRAP_DIR}/${i}-${prog} + done + done + export PATH=${WRAP_DIR}:${PATH} cd bitcoin @@ -100,6 +127,7 @@ script: | ./configure --prefix=${BASEPREFIX}/${i} --bindir=${INSTALLPATH}/bin --includedir=${INSTALLPATH}/include --libdir=${INSTALLPATH}/lib --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} make ${MAKEOPTS} + make ${MAKEOPTS} -C src check-security make deploy make install-strip cp -f bitcoin-*setup*.exe $OUTDIR/ diff --git a/contrib/gitian-downloader/jonasschnelli-key.pgp b/contrib/gitian-downloader/jonasschnelli-key.pgp deleted file mode 100644 index fe44c0fbd..000000000 Binary files a/contrib/gitian-downloader/jonasschnelli-key.pgp and /dev/null differ diff --git a/contrib/gitian-downloader/linux-download-config b/contrib/gitian-downloader/linux-download-config deleted file mode 100644 index c0048d336..000000000 --- a/contrib/gitian-downloader/linux-download-config +++ /dev/null @@ -1,45 +0,0 @@ ---- -name: bitcoin -urls: -- http://bitcoin.org/bitcoin-latest-linux-gitian.zip -rss: -- url: - xpath: //item/link/text() - pattern: bitcoin-\d+.\d+.\d+-linux-gitian.zip -signers: - 0A82509767C7D4A5D14DA2301AE1D35043E08E54: - name: BlueMatt - key: bluematt - BF6273FAEF7CC0BA1F562E50989F6B3048A116B5: - name: Devrandom - key: devrandom - E463A93F5F3117EEDE6C7316BD02942421F4889F: - name: Luke-Jr - key: luke-jr - D762373D24904A3E42F33B08B9A408E71DAAC974: - name: "Pieter Wuille" - key: sipa - 77E72E69DA7EE0A148C06B21B34821D4944DE5F7: - name: tcatm - key: tcatm - 01CDF4627A3B88AAE4A571C87588242FBE38D3A8: - name: "Gavin Andresen" - key: gavinandresen - 71A3B16735405025D447E8F274810B012346C9A6: - name: "Wladimir J. van der Laan" - key: laanwj - AEC1884398647C47413C1C3FB1179EB7347DC10D: - name: "Warren Togami" - key: wtogami - 9692B91BBF0E8D34DFD33B1882C5C009628ECF0C: - name: michagogo - key: michagogo - E944AE667CF960B1004BC32FCA662BE18B877A60: - name: "Andreas Schildbach" - key: aschildbach - C060A6635913D98A3587D7DB1C2491FFEB0EF770: - name: "Cory Fields" - key: "cfields" - 37EC7D7B0A217CDB4B4E007E7FAB114267E4FA04: - name: "Peter Todd" - key: "petertodd" diff --git a/contrib/gitian-downloader/win32-download-config b/contrib/gitian-downloader/win32-download-config deleted file mode 100644 index 0ad3bdd4f..000000000 --- a/contrib/gitian-downloader/win32-download-config +++ /dev/null @@ -1,45 +0,0 @@ ---- -name: bitcoin -urls: -- http://bitcoin.org/bitcoin-latest-win32-gitian.zip -rss: -- url: - xpath: //item/link/text() - pattern: bitcoin-\d+.\d+.\d+-win32-gitian.zip -signers: - 0A82509767C7D4A5D14DA2301AE1D35043E08E54: - name: BlueMatt - key: bluematt - BF6273FAEF7CC0BA1F562E50989F6B3048A116B5: - name: Devrandom - key: devrandom - E463A93F5F3117EEDE6C7316BD02942421F4889F: - name: Luke-Jr - key: luke-jr - D762373D24904A3E42F33B08B9A408E71DAAC974: - name: "Pieter Wuille" - key: sipa - 77E72E69DA7EE0A148C06B21B34821D4944DE5F7: - name: tcatm - key: tcatm - 01CDF4627A3B88AAE4A571C87588242FBE38D3A8: - name: "Gavin Andresen" - key: gavinandresen - 71A3B16735405025D447E8F274810B012346C9A6: - name: "Wladimir J. van der Laan" - key: laanwj - AEC1884398647C47413C1C3FB1179EB7347DC10D: - name: "Warren Togami" - key: wtogami - 9692B91BBF0E8D34DFD33B1882C5C009628ECF0C: - name: michagogo - key: michagogo - E944AE667CF960B1004BC32FCA662BE18B877A60: - name: "Andreas Schildbach" - key: aschildbach - C060A6635913D98A3587D7DB1C2491FFEB0EF770: - name: "Cory Fields" - key: "cfields" - 37EC7D7B0A217CDB4B4E007E7FAB114267E4FA04: - name: "Peter Todd" - key: "petertodd" diff --git a/contrib/gitian-keys/achow101-key.pgp b/contrib/gitian-keys/achow101-key.pgp new file mode 100644 index 000000000..030fd5cf3 --- /dev/null +++ b/contrib/gitian-keys/achow101-key.pgp @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQINBFT4snkBEACx90Wf5XLo1Xv09p81eaOXc+8bbkSYzqx3ThDNUPRzjYpex9A9 +8FxfBenAykD3EgYuBTco4cbn7Dw11ppyXUw0VjWaagnnAVGxt3SDeY3ADwPss6xg +78FZXxT06xSHZXq1X6pOqhwTAnx3VGx+tR/A2DCsX0vHE6IVThZqyUq2Ei2C0Chc +od8y6JZ1CGNzlRkEgL9A0Zp0If6Uq4tXFxnLL6PtiS1b9V5rNfCSC7l99kIkG5oy ++SPsGRwVqTE2kqtuzkt9qVn6v8KKoZr0BY4IO3KMfJJ4eidOkB+OZK9REEQguDvv +tJfkF2HcMYa1efvQObyvVIfS5gxs7+kcSJxgDVZI5YxRV1OOfI7+w3EW3G+bPBQF +gSBwEaLbD+udr9lDZ4NZc7vTeoZtYVNZ+EQtG+6I9GzxJwEgO5LIwZ3//vh/R4iy +z9W91r7TrlkHUuOGg1hXMCI9sRa65NJtP4BWD0xO07zDKj0JHzeyKwgxB/ixZF2V +kc8EzJSKzRfr+638BMXONcf6NW8n6qIlJT2U2qIwiixjM8AUujGKb8DEgU1vIAn9 +7esOhceOtU/6iLuJrlK+TzMe97NoZCtt6ktmiAp8fu6l9uk3mr8JYLzIMtK+Asf4 +np5YLizABwbt9gEretnGpHrdKMN88mPYwsLjjCh9wiM0bHZNL52JQRkt3QARAQAB +tDNBbmRyZXcgQ2hvdyAoT2ZmaWNpYWwgTmV3IEtleSkgPGFjaG93MTAxQGdtYWls +LmNvbT6JAjYEEwEKACAFAlT4snkCGwMFCwkIBwMFFQoJCAsEFgIBAAIeAQIXgAAK +CRAXVlcy4I5eQfyGD/9idtVjybuXl+LXS4ph4M738PrZfQeLDmnwhVjfZiEOLLs2 +sAwGtL/CC0t9f7K7y+n5HtQoMX52jfVehnTDzeKCjRMs+5ssou+L9zadIAz68beU +7BZ0J1rR3n1kzwsFE3vx3IRno0VCTOgfL48AuuzMPxvEaLMxWQX8mL0PCV5/8Yxx +ftqg4kQ1JKMt5UTxE9/w0cBMphLTwV1Rx6lZILPJgOxYSQ0oOzQYSmucwzH1uOqH +wpgZ7SZIHfRWyi4TjQpU/5T2kMOlN/XdyWsj5+Eq+Y6zI6hq2se1vU3TOc8xN2S3 +7YOza1onUj4if0rWtkJZ2yDnR4lIASUD+/VP2NoWtoy7rB0vIfzbojfwxAp8WuHT +sUTxXd52c3OB+673OlOA+GAg2FfFjR8REojsTbeip35/KmFMpafazVRn+E0c3MfP +/iS43UTlcxewRcDrx/gRplmgO0+CLgLstZOon7Dz0msypeSArhX2xEj4tJb/ccKd +CR/IQl8q/ULQsHX1LwRj0u9doAlkqgIQdKXou4+EmD1jKF92oJMZ+20AJCqfwYQY +9HlCB9SQeCRUtU/fHkAZLPApze6C7a1r0LVIuM6iolWyha5KJ++mj84fAagwy/ag +8TU8kHTLSGPYeg5G/TAbr1XU5kbbqfWfQFMK1xtdZd1BaGP2cDC2QGkr2ot1SLkC +DQRU+LJ5ARAArDftuFPE+ZhgJRuJK163fsD15aHPfv5s+h8kPFv0AuwVs+D75w3y +YGfaRtlwSvK+8EucKOoHI1AQYjTG0dtKJuwEGhQ2qsTWUKe05tEAWu0eN62MOZ/r +Awjxqotj4TeFksfyKedVAYSizD0Xj16fizeWFrfUBNND4OgUgD8KM79oRchtzKBE +HRBP27JksU8tQWc4YcEJUHV66Pji5OCiXxHXJ+JpqKSKeCrVvrvro+pwsY1I3ARA +F4UmLxCcb4GnNq+s76cb2K7XJtWJu5FHeHOsef5ped43pYs35UXI+EvOYNs39XI4 +emMsI0KmuLME2LHO3CJNBirwRFxui27axZk/CSVE1lglnbb25n3QHvbs/31ASCCT +QKZ7+Gce89iow6yG4MkN5W4hLdkGAyNI74b6yAUfugSqPLNSj3YHvVFY3y1acge+ +H7xDO/owRN1kbz+9VMJZxsxB/oZEyEVAE0szHxXbMBhqOME0Y3O6UBrXr7z6R8NG +S20RPet4kxCCTLZOvM/X5FtvimgR2u5qRPHs+zf2VPXIRsJsM3zq9EvmePryGM3r +1rEAvYagukuyt68lOWgKP/2wB0/NIFAs69b1QSJS3U4CQVIs2h84Ucvbh9gX9Y0B +LbV5mxvDDfC/4Nhf4yMfH/CwZDLOUsaRAjCv/lQuN9mnMz9aYnsPha0AEQEAAYkC +HwQYAQoACQUCVPiyeQIbDAAKCRAXVlcy4I5eQec+EACi14L8Vp7tw3tDm/Lrb9fM +LHfoOnZiDCGaXhiXqckbTSogp7hU82m1fIy4VwY7DWbs1iIq7QdDJMBuNn174Qd3 +ZPxHeGwBbR04gEsHkbjXBAA5hMacLvmxYFiPlibz+AO4orUiYu/vlEXhXoFCjSlB +pw0kUG8W8yQ/RyE7ryLv5/bT4LkwUWF7/+gdDzLUy1VeaPDKmBupKVSbEACe4QRH +dUUqE3suKoJ/GylO2sGtFW8BM7+CffX+nvc8hJWzXdYW5InSh0omYJIypIgnQ1gM +MhUdu4gbtYwo44Tlax2mTSg8vSVboYO6pBZVX3IEUnjRHLOCZVZIBFXIFdRrHXO8 +TTkzx9ZoDmZ/DH+Md1NDnS4QsvFbRO/EeDRQAI4cgGhCc4CTrrJSQv8jtl7x8OTx +fnDUbE/n8pLV93j9t1Gd07h0VJSmYj3AR7PiefHS7s2yxS9oOqRayGBqrJFzd2gS ++oXvUBC6pUvM68NgNVCKH7HmIM9tFbqgy8kofTsVDkq9TEJRO+X4hn7UDNJhTjVE +AVRUdku6CJR6wj3RPCbERSNB8uabuv1lgo41baeepLn+tJNO/4hilJ0zvEoryVnJ +ldZ73mHRRRtXoPRXq7OKuDn10AvtYX8y3/q5z6XhLUePFKM91PO8GF0J6bNWrQSq +Khvd4+XHE/ecjLOPvLweAg== +=+hz7 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contrib/gitian-downloader/aschildbach-key.pgp b/contrib/gitian-keys/aschildbach-key.pgp similarity index 100% rename from contrib/gitian-downloader/aschildbach-key.pgp rename to contrib/gitian-keys/aschildbach-key.pgp diff --git a/contrib/gitian-downloader/bluematt-key.pgp b/contrib/gitian-keys/bluematt-key.pgp similarity index 100% rename from contrib/gitian-downloader/bluematt-key.pgp rename to contrib/gitian-keys/bluematt-key.pgp diff --git a/contrib/gitian-downloader/btcdrak-key.pgp b/contrib/gitian-keys/btcdrak-key.pgp similarity index 100% rename from contrib/gitian-downloader/btcdrak-key.pgp rename to contrib/gitian-keys/btcdrak-key.pgp diff --git a/contrib/gitian-downloader/cdecker-key.pgp b/contrib/gitian-keys/cdecker-key.pgp similarity index 100% rename from contrib/gitian-downloader/cdecker-key.pgp rename to contrib/gitian-keys/cdecker-key.pgp diff --git a/contrib/gitian-downloader/centaur1-key.pgp b/contrib/gitian-keys/centaur1-key.pgp similarity index 100% rename from contrib/gitian-downloader/centaur1-key.pgp rename to contrib/gitian-keys/centaur1-key.pgp diff --git a/contrib/gitian-downloader/cfields-key.pgp b/contrib/gitian-keys/cfields-key.pgp similarity index 100% rename from contrib/gitian-downloader/cfields-key.pgp rename to contrib/gitian-keys/cfields-key.pgp diff --git a/contrib/gitian-downloader/devrandom-key.pgp b/contrib/gitian-keys/devrandom-key.pgp similarity index 100% rename from contrib/gitian-downloader/devrandom-key.pgp rename to contrib/gitian-keys/devrandom-key.pgp diff --git a/contrib/gitian-downloader/erkmos.pgp b/contrib/gitian-keys/erkmos.pgp similarity index 100% rename from contrib/gitian-downloader/erkmos.pgp rename to contrib/gitian-keys/erkmos.pgp diff --git a/contrib/gitian-downloader/fanquake-key.pgp b/contrib/gitian-keys/fanquake-key.pgp similarity index 100% rename from contrib/gitian-downloader/fanquake-key.pgp rename to contrib/gitian-keys/fanquake-key.pgp diff --git a/contrib/gitian-downloader/gavinandresen-key.pgp b/contrib/gitian-keys/gavinandresen-key.pgp similarity index 100% rename from contrib/gitian-downloader/gavinandresen-key.pgp rename to contrib/gitian-keys/gavinandresen-key.pgp diff --git a/contrib/gitian-keys/jl2012-key.pgp b/contrib/gitian-keys/jl2012-key.pgp new file mode 100644 index 000000000..b8aad7fd8 --- /dev/null +++ b/contrib/gitian-keys/jl2012-key.pgp @@ -0,0 +1,105 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: GPGTools - https://gpgtools.org + +mQINBFYhRd0BEAC+2VU+8+f9RTPLtl0C815oxaOCA9Tle13xNER8NjFrVwIuFQ64 +nO8Fbhd5KEEARuMS/lc5G6IV0QxBpDGE1sEjPQXrA6UnX8SDkNGhmoAsV07MP2Xl +glN9qqYUEoVD7ueh7Cp3A9rFjg7wcMJCPQDP6lZY4cPgYlE1C31TCrEdAsVVTQg+ +xIYWnhB92VxOJhk0N0h6xtCQ2MOtYDjYcBndQ5iK7L5jy5LI89YVRfbKtWqWZdwR +lgj2JCLeXKauXBI1qbedCJrz5e8nXcdqZt9TXSHo/XhNlqvsLiqBq4aXNU3xRkrv +fcweZ9jR9DjyQzefYFGaiCk37R4qLbaqQRm0luUizkCegIuTv44e/zig0im8yPAI +WtGnmBPSy4MpvvWiVVb+jHikdQG1T7g9kF6gEmj4kj9UseWnasiq+kkSNE67vLxb +uZDfA3QhavRMJbCNEY49/IX6urIsiCLFbe6C7JVWvJ7d5l3MAHE8Sut+ytjX7z7O +LFt7YD6loxGAdopEUZm50xs8PswKDajlzWGFXjDZdzQA1tb2CpHUtDkAInYDutR4 +qA29qtxaBswozzUYiDptGSkBqD1Nus7UAJYkwe2EjeszNPhmIAQXGWx2yWplPOJk +ZWDuhQtrDXZikl70q0ekIJ7bxkpMO8xUuhsBCS3Wn6GAtySy0XTttmItfQARAQAB +tBZqbDIwMTIgPGpsMjAxMkB4YnQuaGs+iQI3BBMBCgAhBQJWIUXdAhsBBQsJCAcD +BRUKCQgLBRYCAwEAAh4BAheAAAoJEMUkKhqzk2UXsbIQAJnXDjhEoKSILJRrKbg+ +MXP3Rhxc/ThXu5C8yhfYqKblqCaNNfEmrlercJKJVMvjY0tVTXYo8BEJmNN7nSNI +su8NheJ9vXacN3XrgkMPuFiUyKj9PGpSsM6Q8MjT0Bzd0pxodk+g0UEjyMktfu/3 +TqLsnoFPOtIjMOkr/uBzZn5d0AXIZQbAz4Xa2zBW+uR3OSXRRXCRJjCSWGIfDX0Y +i/Ea+3Be+y9bMqDa3nPULEkW7+RNuyjLr6QwPZ0/BpTTDcM6Vic2daFPO5B0+o3z +PMFmPcEd4nRHTPM9A5SaJtC8MjF/89mjhpxG3v8RqkqCdqdM2cezi/T4YD4jcynE +F36Ya3GuuewxEZci/N5ySG5gG8Y+80Wgc1e+sNtvIffHk3Wju2kOvNcBA2TBw36V +XCJXHROTA5+Cx4lUxOkQTJoYSVzx852WS6WHeLg1+XnDZvT7ciVIV0ExJQ9C1XOM +wjFMRsTWl+vflxmgCeHCIari57Jw3ij7ghRCgeqLp7FIXK5qSI4Tw2eajJpoTKPs +wlaO6kvOXtaCDH30FuVhKbPxII01Xi/A2ALtTkpA6mfnf19orQjv+HxX/iwUlpHM +UwsuhpZSQYIxIv/BOQnXDfw4TcjnHsqXZbqNzzFEjGurMTlOUX4KeTPscdOLUpnO +1FM4JIVybHHfhCH9Mpq+MIwCiQGBBBMBCABrBQJWpym9BYMJZgGAXhSAAAAAABUA +QGJsb2NraGFzaEBiaXRjb2luLm9yZzAwMDAwMDAwMDAwMDAwMDAwNWJiZWZkNGM3 +Mzk5OTE0OGRmZDQ1MjA5ZjA2MTUwMTljMTNjMGVjOWUwYmQ4MzUACgkQf6sRQmfk ++gQcZAgApPqnaIIE8Q5sruzua50RFRmmBtQys8sM95ciWYE4QaTXUnlhHl4QR4z/ +TQTRSBqXpdHQ9HBWrhFb6E0ykDEVx9zdEt0fvtlhHx1ItrZetfiA4PwidnyoDKs/ +/nt01RGreKSMDGInaQVEQxvEW+A0fwvcCdE8Mh3LcIydohfqUViB0c5zb7rUmize ++2Kt4Uth9T+ooo+UE87pHSJcxlcPOv6Dc7KeoUicD8DwWdsT7oxAMk9jj/ut4UNx +xOEp9Sa3sFN20tHMqyOZwnl22Py0y4ayJnceawpuka/bx7samg/2uUrO+dNKXObN +trebP83+8UFHOo7VGhesuawgwNjWW7kBjQRWIUbHAQwAy6re/3ur/fgNfE9yKivp +Bqmjq0eU5l3iT59hvKr7S+6GHUa+YvE9BBsawDSI4UILNQX0YGT1LRa20mC1okBX +5SIEpWzoZhybTMVMwS2ZHkUyO6VBAieUVojP3XQHFcDAiBvW7RRhJ2BU+v9DGo88 +HAYqKEB85P/i/E/a1xUfTWiiIhA8Dd/Hv6pzIG5QvN8XfrMIayLwpOV1G6KvBIJb +zyUVUvLyQySiZOyDczrAxzYq7b1qv8xwHDUzyUl6skPqbex1cFWIeiML9EY4DnZ9 +l3qb31Bhp+EHydv0esclM5XKQriSg/hsnJOLlCS45z/YhqGOCoD8QxXUJ71NhD/H +QR/AvGyTDcPr1/U1DJ0lG778wCOEe1Nad0G/8rcpHSY66RZR/Wf318S7uJt0mUw2 +JMt1BRxfbdgJaleUAqYjNQAMDb8LfPO6jhQnmf0nN99dpdzkwV/drVRcLDEnupDr +keBsokcuohzE0gbjUT4cNc0DuUsIELMTApG8KQCgzJy/ABEBAAGJA8QEGAEKAA8C +GwIFAlbi67wFCQGu8u4BqcDdIAQZAQoABgUCViFGxwAKCRDunlUgNL4k0qceC/91 +2ocEDwiu9kpBGCW0HD+VSyMVjLWMiClk+jPngvNEt63ZkYqRiy7fwnPuJrLFlaL0 +E0JLIweihC5AyPSJT1Q0LnOwbqCHn1s+9RfIodG/v6M48Ez4GffOtmYwW9KqogK7 +4FwdIx/wOIYDeh4rT7LRaWBNcIXO8J1+v/83u+Vx6TWKZTiZKQMEV8VOJWfSmTCE +6HVgUYvLCPB6DI+X4aVead1kayKOSuXlG/l94B5RHlJB/xQXZd1INyrZetTZxYzZ +CBhIWaZ/ji5vqFot0xVNYplRkbg1Mc96X+hwee8eiB/ySSWxUV/DDkA5ZzuE8n8R +EEjzqazjMNe50P7XKVg/eBE+TpgCDlqv69dqnOF326m6T3+FH/LDOHguQfB7pQKx +siviqjO3molBSyMHL39XFWyteVbgbbSaTRkpX//b7dQoFMiVhigcM78qoymBi6yX +qwpN13JoNuNJhEOwex5eEEUCVibFReUkBrYoGnWbwuOxiLORx/IbuNYOvsTGYEAJ +EMUkKhqzk2UXWScQAIvAgEpQpzuE1CWMBWcM/n4ruUrOVTeo6dYpUGN1LI0758xm +4VI47I8wPEy4pAbdPcqoaNnMcA/NpSYa3hV0svQDLqT96qKTrN71N1gNJa+5w+KN +rwev8MRpjuze9b4dn3avs4L9f0fkpzjSzezKwVb7loFSZqgKAaI0aSoOUTec9+OU +5ymgkYPEEF12ydkyMzLwyKrtEnIqgwQpjYTN/3P1x7Gkhv+E8Lz06TSga84yVy5I +5gO1Hklc3MW0J9jPJe3uALUtEh49KxCE2rdbIX7YbkxWaHHfK98Mu998IXr/4eUe +Zhf2CLC2cuuYbk1/rOcxPmeIJKa6S5PlWOf3Y2yLRO0VKcjD5pcGxiImoDVXC4VM +hztCVLddjU70c1ktSIBQBu9gkpPcECrzjYtpeAavOUgmpP/zQ8X2NGp6+5n9Wwii +tAgByNCg0s+PqcAZxup34b3ZY/t475tDlAmIOovH14Aa8g+0Ketj++9rPpmg9kGs +sGmn4mVItClaA7L9vZQQFnSxjyfICKsSxBhqded0lsinlzBfXDEh3N6fEXh81/Gg +zLUmTlkhcGaFXplYqrUIlkdO9PD4R2h5P6laLhK2dAf7oKavWHZQp02Yb5nVBiDc +KiVWKBP4nuTkWZCG5R966wpR1IOQQ3LykSd5SstcZX6iTpv4NZpCxI4CXpaCuQGN +BFYhSHABDADHaEJVygBdwU81c4YynyTOnWTZX+BR3EvRW51GcnfvjqkqgmlWNLET +JkswQ8+s0mjKGVnz4dkdr4cUbVegj/St7wzoO+m5mYIDMJf1j83Vo6lTo9FJFzbc +HrYC9RS7NkQmD7qzJz4KY/h0n5szFIC/JpYECBNzYrJQc8m2kZiSlyUQJve5/I5J +iI6QnM0x4kixNe32GITmKw9s3E2iRf6yXVlsrPouNS33lPXKtvmO1ae7R+G8Ve+D +JDv+TLxccy2iU9wuz4I3k20+rlmEwk17feDhfleh5Q+qjI4vkaNcXFa5coZE0HyW +SwAtLPSOv2vWkuFeYncXRyzg/CvKR57i9wnqMzNTMt3bHY2HezE13bHln5B/Jqr4 +ihhFQBqPG+UZlGYRfAI60PLh2yftX5xkm/POiLgEKF76/yIZI8wcPzzurAhFaZBp +8/MUv2ZJ/OUT4rdEVV+6XnrijNqVBU8mf8BML5CvjyhsU69yf1mvpiLQr34FNEcn +JekDGPIk97cAEQEAAYkCJQQYAQoADwIbDAUCVuLr0AUJAa7xWwAKCRDFJCoas5Nl +F8NMD/4hRoOKENEq940Z0iJg0TDvRvRnaIYsbneRQ3yg1DGVIQ+4RHmzQdpN9MW0 +5RTRLqJsW25ydWwh7y0O/oBRjaoDRAkMSIyOo/Fy+E9WWBmAwzeYCi91MyfetKIO +ocrXxpXXKnotAFDOgWGF8K+LlTDH/biOrd8ftgOVJWhz3X04ma7xvT2tQTqfFdbt +EivA+jFExq3No0Iq+Ctt/e0H2d9np62SeKBVdpbx9xAc2tPKKDSl+FyB7lj5CK5/ +FKhotl2bJhVXET48P6e+bFVwfRO7o48zuK5CJVbbdjhavQGhQoxfedW2dn9y7QoM +qayUuVIhULE/k+y3jsJBUT7p567nSdUGbc3uKt1sfPKYTdsFbHiTRltXmsIiv4bG +PslbXSvOQblFOXWrAE22CdKmGzhlEiFnbviZCCl0BFf4CwEVBJ3p9Lcoir1l9Aty +HIIFI3z1mmTz4F9BMbe6saNwBzO+Kh4+US5NV/hqvyz0aOLltb6KfI8WF8kOa1Cx +Djz/DTHnvMWO/dIOJuKsThfuxZZq3R1w3O36RB8XzDT/8NV86gfQwN07NWz1rdy4 +60fK36EjOJDqm/434/BDzWh8TqmnSamENxBTbICmWOj/25M26tA2S9zcPLJHTGMA +3yL3QlBtjWY2uNqr51cnZHgPKxBWzaRvcrZ+lUq5EG+F4J7q5rkBjQRWIUitAQwA +5A2AhW9DFxVsM105WEErD2NuM2rvtq7dTwArBEi2KdWkSGQvCE9xgyH8u5AEWxj8 +XXHE/rfunW0d9oF7Z9FbOuV+1HQOAj5hQQWLWHERwZ4gOAqG8ZKAbuwTlqitdiXE +PZiJYZSq0NXtngyeTx7XqzQSatfFOIQLzIiwPQXX0Tt+JB3B2SN/D2NP7rubzfS2 +Bg0ErhV20fPDl8YloEJFfj9lpF0ZJnJ5hXYP9Fl4MoPkyBkGPrJPooZ4FqUFHDiw +mttzP1BzFlwpAPGpI0NrkBdBlfFAtvhjreeB5Z4VYwt1xqoXgI+jYXAxoMl+rtkK +FdWaoT7wHwqDBeBWYXoyXA2dYIY8Ux1jeDBnREck7vaXhln6zXqMAQowE+F9OQnr +Wgf/LoOn5MYxsBDY9mPAO8urxUDE+Dq43JBXlS+jybMNZWdtkaBrIde7dw9IT8Fn +p8pG78DmgPxmRFH9QoypTqMfB+x7ZuB0fk1ud4ut33qLo78BWZoW0H++13CbSmrZ +ABEBAAGJAiUEGAEKAA8CGyAFAlbi690FCQGu8SoACgkQxSQqGrOTZRcNQBAAmeL1 +8Wr7vuvL5dySoYmWqHFvM8gRUwIGza5c3D29NYZJcPJRRkdGCV2IXEuUSOLtnjAN +kTM1TVMMnetqNR8Uryr7z3XjqYLnVwGqOPnFnlkE2zS3pG8AGG6OxxBhuEMvkwcd +1s3tWUlJYRWi1XhEjVZ5Km2pHsVxvoXeJCUVsa8nSXzqF8gOLm409NFMiKkp8QOG +heEV4yWrHkySi1fVfOdrHfBzu2lUmHGgSbmJIpLcK+cL3TjpJ+DkSNbniI13I/Eb +PO4Uai4a3QYz6sspZ7UzF/pjY5v6WpWXiVB5PP2Y5BrMUgWRlFxPYTc3KiIHUYVi +IjVtSOsVaRCHL/SYRq/qHs63XxlxKIhhilbR4OO+CvJ6N/vEpSbx69SqlxgDArZy +g3QQqerlLGpSFim9iWk3QBGWtQ96Ek6rjLLOn7b34I6bxXtfcOEo7gl0Y1TFkfOp +nsXAcRLrrXCpAhgC/vIQRTMKEcC18kj/vY144DwefzYCBhbI/rCSohAq8a/zhq2T +E+xlCYy931HWlUAGx/hms/0q+KQ712Zgk4XxXEx4RZiv3zl9Uph6c7SXxAMb8o2v +PzAxd3ShNOnng9hAl8zk5O1RZPa5u51ppkO1FsJ9zjb2Kvdg4ZEBtK8jETv9ckuq +yj9YmZZSRRQ2dujg81sLQ9CrO7WB3IGpwh+4lHQ= +=1irw +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contrib/gitian-keys/jonasschnelli-key.pgp b/contrib/gitian-keys/jonasschnelli-key.pgp new file mode 100644 index 000000000..3831eaea1 --- /dev/null +++ b/contrib/gitian-keys/jonasschnelli-key.pgp @@ -0,0 +1,110 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQINBFSBrDIBEACrZEqObmtlTf7fOKttE39qqisFfMg0VeEPS37uETMGYsgTEvzv +kfMsXCGsGFLQ78XsHqUeW4uQrtpJH3nUP/Sua1Q12K3lNKTSvVQyEpKoPJwXZahp +jm6GA1ApDxZ/KlmxyobR3X0urnMYNZobl5IKJXlxoKGl4OkGNeFlh42pCXZDnR9n +1Y17ZcDdybkWcqPbDAz8ilOQcFMhDBFg3Di3IVMAaDZP1uwWFb5vx60YB5NhkOpF +nZUH09NJx/7u7QdGPSHOdzW4Xo1HUYtYNDkdOvgZtxpbYEFIaBtVBURMUGwAFagA +3a6qaGnCBWEQftyISLiqcKqKqXudOg/cLa1CAiQFkz+IBhY9BCGDRnB8Dcae6EGI +Djt2lqZTuMSiheTWeNFMGBioHfPLedcwae8KflrIBC+hNS4ay6HJdIc03WMQ4JKK +At8Y8CRLym30/RlqZ2v8CHYqg9Ddlz3+g5JkRKaJTQwFRcX46/tAX+I2NZ8Ra1ea +rF5cRHuCk/oaw5ZXYhj4zJO74rjAoSewAARlrTMSM541atJU1u6aWT7rNiF9QKIj +i8vEufUxN0YfdmvDD3OXwbO7GnfWXS4sPklFIRACp+Y4ib+QnRY0/qGE0yh3RAG4 +r/dyIQ1m3z7Pc9eyPKAhE4S7SxAwoR4yOqQ5NAfZXgFuqWzkW51gkQgGzQARAQAB +tCtKb25hcyBTY2huZWxsaSA8am9uYXMuc2NobmVsbGlAaW5jbHVkZTcuY2g+iQI+ +BBMBAgAoBQJUgawyAhsDBQkDwmcABgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK +CRAicOMMUic59iKUD/93DF04C3lptLjtrhyd4wgpBMJV8yzagGyG+Wk0UR7elQw4 +F1MIvEtIFpuGrcnNfKcqeGGmnnKFTeBjkmgcYvej2fW9XlRA1HgIS0t0ttDv8uVX +vy1xVj1qISB+17EiftxJjCOl2pZFEVpLQ7sSgqnVRMsCS45ag6rioGxtq1j3ifQN +TENnJWhzOXvwzZhLgsyWLjeYvTDbzfAQLpZFowAMibOwu6ObCkn4dhaW+lI3AnPu +76pLsrOljqGvXes6o2d28vjqMrlmsz2xVEJ4bnRPUbLv3bUl6t+19XpiMj94ZCZX +/kvepzSNAs+aYvoldFn0/8haU5wIDXO/zgXSlm4KnhaDf1zutVq/Ng6TGb66mZKc +RoiGHnnuQ45e7VIXRfOmgbbUTUIg+h4YvgCTR8dMoOWpd5AL8lZ3bjYVi1yFd+p1 +dPfrrnN9Yd5ojoZBSrV2j1wLgv7jRIeXL5dWzeAs/JBzltAHWO+9O6NsYXtRTUky +eQa+oBKG1OsEXf63k8PgQf6Nw+di3gy23tKEiCz8lbA2MtekxaZ9Xu9CSEEPIH7t +Aoki6Ey6rD1NUZQPuxQ3aCUTRE2JK4b6nPuAsOEv+cZL0VxNENpbedtGPh4aAA8U +9yvBykWIjRS95k4NDVKIdzhd1geJsUJZq4BKh9Atf/kI+Gb0sqq2Lrf8a1pNX7kC +DQRUgawyARAAwLiAxqv7PsdtJg8tBO+dAnTYtAtBHn8g5GlXtorymB9Aqy0Nzpd1 +de27dYlBdlWdHZavMh27JieZ4rk++74SMAo0PACp6FDnfuu2PmJZTr/Bzvld+B9+ +lOZrMWwDIVSW1npJGUjF1rjgPjvmcGo/IreVFpJ0A33J1p/qsYZsLTXTDDoz0fq8 +3XvwTlkTOkuk6Z6LPo2feDHYydUmdG+9MrgIMpidvywRHRC8nnkix/aX0S72kZuR +qvWwSVs229gtfuWHfvmaQgbugZMqANla3ZYdzExhIIizu7qQPXSYfhsCoywWE2So +9QXZIiVJge2P/hUr2gTiRNTfmhupDeqb1E+i7x9txTrNc40gbTu3qs3/fjKIWrXw +Dy5tuZsviLQnEQtY4sEnHl7oL1crOuIHjZfgZfoZ5CK+jqb2b0B9uIm/SMl6Kt8S +m6ZtK0QTjtUSIputPEYdLycdOpWDDtAHrWkTlRzKJoLG4hsywBAgQe7n9nLf7Zmi +DhXyXRKyJuuuG5mt7UZhjW95loFFVcGXHIxNmxVqNb1YaG3kEa9PdQMoOc0hRZb9 +77yaGfpLV8Vo4CB1eAuVU0UdNRyChrZK5dKXBN/0uZq5HgpI1GiK/C3YUuQI3t9p +zeJYD3jPGYCI9xxLaqt7whoOILPmZ1KW2UfXTvcMgBUMkFpZrqhTGscAEQEAAYkC +JQQYAQIADwUCVIGsMgIbDAUJA8JnAAAKCRAicOMMUic59oqeD/9SvgUx60AhyCPl +1G64eII9M2LU4vmHj8g6wnjh3xaWXvlQU1xnz/5I0XrlbHm31ExEHK+7Zla4AQ/P +OrJhMNZh9oes3iOh+pAEn/vtixddM/oiivLBxMcIzq31PS8lZWrAjqOX/FFYa8GM +NZI0bNWu92J7cL/bRVwsIVUXh2DkUu7wXwicNERYkKDTBaK7FE06C/hIGTwmENlR +b1+H7e00nzWqoHyd0fhG7d8RaF2IF95YH5+r+aS20cHVCTI/0Z32FmlnCA6QlkZx +JZiXKssHLpegeegAOOR3t2keB5rN4J/8KSzIEWUG5sjXkshMIM7w1a6urc/iE9PW +YGgbG7Wt1AcEO5cnU72DzoENrOxRKdFLZWemLbncLPTY2GERPutJgDSYvaxmwnQy +eGsnRIOmAMgN9+8NEs9wZnzrYpkvk/Vw1FwNcCCUYb0ZPYoRVRhP2UXYm7OxdKdk +zPXfS7Uqs9oto1FiD7iomhtBs+RW8ndaO9wHGoCn2/UAD9fxNIkTQvK61amyjGX3 +gdwrOwt73I+wjgt78jmZsKfnPWYnOIUg2/12P4iB6KhWD8MIIeFLl9TFfZ8f06WV +WIUTcA4cgSYgGOScxB0En+B3LDCkmVabu/JzBedT9N8rXvgdywk2UR4vKqiyJT1O +9ArEfToN7J0gclhUoadr0im67BGyMZkCDQRVXu6kARAAwR/cg0kJja6u1YToEM+g +SOOPZK6Bn745y0cvf6+YFVefLcManUCyI+/DWZhO+D/im569MApbTz1qdaLE54Kh +z2CtOJBlWP8cjlnVZ95hBK+Z9COuk60dXI7DySRn3DVryNpYjRCe+8SBTQJSj8b0 +JEk5VVYPYUOIc3L6g7LBL2/ycxV3LVFTQ/A9LGBev7y2emgC7lqkPPoDU1vJeO1N +4G0nFsIxuml81pfgi/2aMbGF8l7LVAI8qMc0c4RAjL/yTPzVX5qq5+zAaXMcyhgy +yqOvlXlCG9aisnmPCEiShxmLvGfGdPmi+apxZNUW3384vVcOxzl1VcU6sVZT30/a +Jaa8RxZqC6S5kOr7uPO8CD1wB1rXzD8SA4Adcq9SwOkVE7QfnQi6+BIgdrsLKUfg +2vBjcgA/IsLETlnp2792m3w01OKe2/w9Uq3N45lWVTNVx2UcbWAIz6bwWoMDJ1DN +B4XQHb5Ag+VI7lIGr45Ep4ohOfIcpBCMa1WVGyTYoQFc66mPZ2MotADOHtgGpm6v +ZyJEp2qWj0at+tDepf0bFPHmGGhVj+N4HTBWMzsu3sLCAh3QWStr+gkffUl2CsdG +Y3RL6kVkCCW0o/o+V0mc8ZV8kAtFPyYGllsP9HEvjeXkHg+DAvRFZhSPI1mxGkGg +gZlEtHqZ9Lofoco9wedCJPEAEQEAAbQlSm9uYXMgU2NobmVsbGkgPGRldkBqb25h +c3NjaG5lbGxpLmNoPokCPgQTAQIAKAUCVV7upAIbAwUJCWYBgAYLCQgHAwIGFQgC +CQoLBBYCAwECHgECF4AACgkQKdS8tkFvU+ytjhAAwQqTK7pSjSSK91QZAvsV+CgN +AzC8AydcdpWAnJpsE+nw76snAexMctDfae9uPSGSVM9PAgouUg2YJxNd9RzPCv7j +vx3bevO3ArNZxvdKSXffPVzt01j53z99/Ltmev5rpIcNQk2nqL3iZaZ5O7Vxre8k +H5KxncFCUxlnX/stLz9WOmnIN1X5qVq3lSzh8xvm7DuyOmi1Z94GHCW4BHN6wxtX +nXqYeI45jPcbuJWC8P8qtNicZ0N2XLjpAoLSvQ68VTrvvLN0X2HT9Ol9y5t7re8J +PEY52TvrPCLYz4hQD0fPe3w14LkcdbWTjJwQ3Y7KWd67SOn+l8VDPj2jT0yDBDG2 +YazByLqV29SgXm9WsfYXYF4FB9NSApbrAmhTWVa4K4DFXrLvcIpaIR4Ii3JQZDag +2tO1VTgxF+10S66qrwXwawBbGfDVchWgSi9T1hNn2wgLypsLN1ZDy7ixPCD+SHHd +xgTN8yv+/WNRNZ+LtUKNCIBHQmUBesNfN+wOrvOoWPAP6XjlUIlA2RIH6zKcNbDb +a4jjx1ENiHAlapVxzPTQiTfj0TDRXBdjboiswXfkN76upHdgdMdeFz9hiH0PSbxA +TmlmA7NrsENHLp89SB/gnGT2I/lLP5/DsoN3Qv8GCoy7aUNDT7abi1AeoBVVye2c +AL3d+hDPgOzJHjf0eJGJAhwEEAECAAYFAlZFyF4ACgkQInDjDFInOfZtGg//f4xQ +PvS6gQdIosesV458LtIUnrqdPx/8PGnIbkObSzjevEoj3RQ+D7PHvF57lj6m45aB +Tr6huXC2RQzOIjRXM9dYi6SVZzQ1xnjMep72ylVYawQS3VBeuQbhU2BgYTeLa55+ +0sHBA/hX9ufH7a3UvSTgvssX44SH5mGg2h4I3O+4cNQIDf/G7xkzkJKcQmATRmIR +10JaaBKtx4JVNVzCWTOpEqW6/QA8X94LapK8Rh/mhKyd38v3CEHI7hH0ex0o2mOF +kAsPY1vvfxWzGKMolJp1b/1FPcb7Fl+nCoqlfnv0cCnZYsQvYXrOs/1Kj0anv9yR +iutEp2DyaAnhadadrFpWjXQNUeYtFlJ1aC+6HO//uw2spKFqcQ4tTvu9HgHJO1gn +GTsmDskwXqHOYNvH9QjtwlhPhOWQdHgLPrWBiUBvkT9H8uoNRGWg0VGA4J51IkRh +0ZyoLmRgejpj7SOpwLX6gemprn0Z4fgohKyj6z4/Bop2gliXSPB37qdun6M92g8m +SkxaEXF2ZyIXdeVRT6Xgp+zoGDNbMG3PlhZiFFCvH3Hk8o9zAz/65de6D+14EHYj +WBRKfu7jaL2RSwUSRwRAAYKwu6kgRy8G7+4SihuSHT2k/90il6iwpzXdyY7qQXWG +VxfrmGWZLYT0u7d+EZ1pc02UKYCFptlVCIZtaQK5Ag0EVV7upAEQAKpWFoCqFFqQ +5xH6+TFvbUFWBb1dWy89GMXCkmqAsoy8Ss2Ru8gNuy7Xt4l1dQhVpN0QWiuVGkEO +f2PmXQhnLquaSz7XLZjjdO5E3kYzcwOpIbb2TCWH4QQtHEotowRslQAXAZ53jN9u +NIEQHCPPBNocj0CLQmZl+av1MqRJrRcYzgkPIs34mBo6iVoRrD5CkSohbz01BMWJ +ZLk0E+JvalML7+ttiwu+gI90uRGiKEz5xsDMtyx0mAcAm+/EjcuQbhGrD6p7dLKv +9nuUU/T743N2LoDTBMzvX/JXjoQ/uS1nzuiJrc/vYHqy9uucgviuYWFH/Q+LhwMr +6tjJYUiN4JIQ85OLvq6g71RnpWzy3ce25HL1YWbLNuzi8ZKIB/sL4LXG2iTwwSFk +tVjfAc4zP/VWpRC5VbxG76atRkPLatgA6b2sawgQ6L/7XB5Wd5F0bJc3ndwPBKos +FFXgzOBgOkI6kYERQo8h2GzWfU8LWxl0a420ZHEfUZoYmitg/evA3v+23FrCMGg6 +2cdNzU5/mqsQ5HWktTQ5BZQZyn5UT3zpNCOVyeZc/ezzGXcWbEXOLQwDcolxjatL +ED3eNA1OMQD8S++FPPGCukIzCyYiPq49zJCTMCWd3qTt2Bwea9xOQnoetCTU9goX +/eEGj/1zQDAXCGOVgdd34VrOX4qtpmp3ABEBAAGJAiUEGAECAA8FAlVe7qQCGwwF +CQlmAYAACgkQKdS8tkFvU+xj8Q//VNzFYM/kyHSa0xio4e8vBZA2vmR8IEUmtOSR +zr487Z8W1dapGxR7OLQ52oWdRZVpG1B5rCuJtsWbjdY94Y8RpcO6FBemneGebBhu +UKc60qwEanYnZva9PEFNyBzpj3xk3Ms7K4O2dZTcXPGj+hlep9Tjo09sklqbKfgW +2fCUu2EKXWwUrnZ2LZtb/Ya8WPCrsbJFk+WbrLhWt7jIsadVl4AfblcgBGb8aN98 +GxnYOh+TGSMJtq1NSfchQwLHrpTPYm4McAwOBBYDdA+ik3//eLbwRiX9szFk658p ++4LErMBJAKLreSluBkqOG3AzT22Hdffvl8G2U4WhPPG33NzWomb+wKohjjzMVUlx +YRCO57wkURqEW9/+a4riuBWGQqqRsW1wHEMu1lYdAhLJ5f0s3vO/fVe43ktaXNjW +6k+mXDlIdKkQgQ736sBk3DAUc+YcmWmStPr1+TtT91eC23GLWP7gVDnNGEOBOscw +U+m1bEOJN2duAMJSRK7U0r2ipmRKDcwK9XmVpJcTePfB2l+T3RdHEZIOlaTELEX6 +WJfpU4Kc1KJeKdp+l9gf2JD8eOZAlwxA4r2wxyzoCVg1Bk3XiBfoI7Gl78Wysp+/ +ChQcErPJWEUglBfrESpqmjxH/qSy6yjyNmd4Az2ii7IzWILfuheZR4drjHQj6mCA +S5rowLE= +=ZVPf +-----END PGP PUBLIC KEY BLOCK----- \ No newline at end of file diff --git a/contrib/gitian-downloader/laanwj-key.pgp b/contrib/gitian-keys/laanwj-key.pgp similarity index 100% rename from contrib/gitian-downloader/laanwj-key.pgp rename to contrib/gitian-keys/laanwj-key.pgp diff --git a/contrib/gitian-downloader/luke-jr-key.pgp b/contrib/gitian-keys/luke-jr-key.pgp similarity index 100% rename from contrib/gitian-downloader/luke-jr-key.pgp rename to contrib/gitian-keys/luke-jr-key.pgp diff --git a/contrib/gitian-keys/marcofalke-key.pgp b/contrib/gitian-keys/marcofalke-key.pgp new file mode 100644 index 000000000..ee626500a --- /dev/null +++ b/contrib/gitian-keys/marcofalke-key.pgp @@ -0,0 +1,69 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQINBFZu2toBEADGuBiRutibv2SlW/A7vBGeGA0n58coQaPkmi04QGMeGxdZyvad +h8olkPO1q5B0/5E1olEjs1YquHTjSjerLz8nUg8K5OEu14KtCGvFbmtSFW7fOUHD +/u+EykJrJczqcJJ31r4B51L8CdS1ODdBbinQRlTjtLq+pE/fJAjHI3iQ2E06vkpc +BRVA628fZKHIcd6uXZBrDyAcKtqq1TITlcYoVlYbvMrov9bPz1NW3P6pgnO1S+UK +RfkhG+N3bC8ttsTXo0aevz3klaVFEZ4Oo4N8TUcYoYDTZIfu/Gk23r0hBONI75IE +pbF8u+r0M5mpXxCHqmrUgmU33CBTeuCZon5r0iEsweF+ldh5rhEOhXWxHcUUz62S +64XoqzuOlorpWzIS53oyVTZcH6XszF+iLqSuMQCgOYhF/u47rt3Vh9D+TYJcnvGd +0ozRuajLIRGCdVlKt212ER9QLxZ6BTOePbb+g99I2DOx6heSUDzwXWKTxt00Lr89 +LyBFa9kj2fI0BNuzx9XI0l+GK5M9xkNi5LwL5gaLsPCJHEEPaG2pcBIBbw6hjIka +L1fgDWng6MQ/eml5JsyA3G3J07/xxoVPaN9vZ8LLO9BEiz7e3Oss8a3Mw+SfsMcH +mJJIFT/CguJCxW3FeKs16XiDpO2Eg2WRoMJMB+psdfgo8e2q7dXIE6kCtwARAQAB +tCNNYXJjbyBGYWxrZSA8ZmFsa2UubWFyY29AZ21haWwuY29tPokCOAQTAQIAIgUC +Vm7a2gIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQNkiogvQxa5vgkA// +Q200J62bnplhyuWMvKmpCNFG7lTtLHmwVtZmvBJiHsRwe42KRWKz6IaQgEHfBMCU +tSra4i2KY47j4s/kyTgWeQooH9Zxh7c4EMeyOrxpqPmnKF/0tFnDyk9SCqbrrUQ+ +VuL9/JrZ3zB74GtRikvWXS43cuBheKPZSwdGrGWtP74Z48eKXa8mOZtDfQJACqpZ +lF2Hv0GOFKDNfaol6BkANpeDv3orhnysY5TqE8iA4VuHAL2MDmWg68Rb9sjPoj7U +TIYyeqiok/R56SkN+WnGGI7l4+pk8pBqhkjZUjVTEEABR81Vu+Rn8OxTqpKu6gW3 +YACXnk/kXYY4I3Ri63eK0BQEeZ6Q8nrPhqHYK7fzlbwwL4Id5bDJpBZW+a6Hvlw+ +zQXpObhMSxtDJZzEonqq5PwJLlkLPU4sbS1tuinCdAII0Qz0Tv3Nwvcrr+KWiNqr +vf1ed7CecDcQpSqHfhhibgykLfdAJGNpGxyA4yhOUHax4TbYZctL3ZYXRWGrF//z +Gv33w+8DMb3zM+BP2SBR5D7MFTqE2X7bTn/0pRnfYObjgU7+pT0bed4SyEY2mnqb +ikPTKfz/g+xLL46lMaJKLgBdS14A6+k3qVUDaBNMb7crSQlutmU3fRhNYq1KW9IX +vEI7YuEfMa6vj4rLW+68CKYBu2pNBSQZ9LHedx1UM3u5AQ0EVm7hJQEIAMTDtNiw +0WJUO8T7G2vA4WFHbvBoGM4CH9LaOm0JpH3L0DQ+XD5EWGICwlpkoiQiRPpGSmSc +KAbAgtfS+a91z4GSWEgL+q9HqVZO22yQSeCbtbnJs44BMJzgMcVxiFOc0JQU0KPR +zrT2TtD/Z4ryOvI2nuepv3aRz0RSQEsBnhMx/aNIV9YbRJ0YofC8BPReK5hQ6rYT +V2C4P0RoPCdjeGx//0Ilg+xTbPSG1urSKVUEz6UCT21MaCBsyxN5Z+Wa2K9F/894 +y+TsWMQQcUYZ57DXFHM1dOkfDYorVATNOnv3dIJEjQDU0dYEE0yNUYG5nu+UjluJ +LG/ZTiXhkNQla+MAEQEAAYkDRAQYAQIADwUCVm7hJQIbAgUJAO1OAAEpCRA2SKiC +9DFrm8BdIAQZAQIABgUCVm7hJQAKCRAtfyNy5Q/hN0XMB/94V+GgGRgCxvwdAT92 +RCatOJcf1YJuw1aKWjAiib0FVeChZebZYqW+jwvMkXZwxlVFhcpFlUzAqCRwcJx/ +QoalF7u2yTL6DEEGcC8bUKrhtXQch4/D28BWJAJlR/7bItdWMIuw4WV/8s97t8Ca +Fn2Fc1T6/B20VclsxoeaAoXZUcWG9YIKRbEaogt3LxsRjgQLZiIicjRl0C5YpYDt +JvnENKuLwSRte6gKkuUi7Xw4iIP1aEwTTdZe0km6If6pVPwCK1cU9xMpsMftT1Fl +NdK/dJbfWoYrS24U30XvCxsFMogD5jJ+PiXUoXDBjPJmDiXrGUDR+je/RqsUKBH5 +zyKaI1oP/A5Dq/EU5ceIfMPaS8iK4DjgwKdh8zuprDQ+JSf4iD1b/HHlwcrXmGFG +4uRO0X/V0ybIdYj4U4qXRm2FTA20x7MDEDW0i/cJQKNrVZC7HQnvrdG7ggG0KVok +tTvsIWJTmpQ3MY47rTtWQrmRdiiSRWeTFyE4sPUy3XpuPA5ZKGF5vN7A1p1WYSZH +gl6NBv2vp3wjwplSpYumzh0q+o7W4bhdy9+BR+K8l5a9LKyCrwL92XKLqp3iAyvq +RdbCrTvfppYtNwJ06JBww/b+aO08vTFY08eYbMTOVxNJUtzpq+JUe9QHOzbBNCv5 +viIVqNRJEQw8ITQQ1AjgN3iWdnbVQEwYv3D6VNkpzDpZD6tzOmJwwbRc5rISCVL3 +DQQglc7BYIkcI47QHBdf979H8EvA39U4yFHW3DfApHBl/gzHcEbb5RoBYc5yb+02 +U8xGHxGJ7q4h40N+oLCc4S04gepqtCeIQ8cgCPjRdPKuP8o2O2wzDYvqr3RlzM1M +l+GWmv+3em/RWwhWggDIf/XhYkSbC/USJuPjQEYqJRcpx+60HYV7Ro6/RryOoLUA +0ZXu6IYs2qT+KEcLQ4D1XKNb0GFnHW+3SXqehl4qI0zdPUOLKpXhCpThhC8BlqV5 +O1aP/5jnogwcW1HF+tUc4h3nwrgvcajrikjffdBIrUidoDVEN04WuQENBFZu4oYB +CADQwtiaFcDxMms3bNyRrfaIA5gNWEhoTRFNXMKY5SacsavamWzlfNRBIlYMl27z +oMZK4hpxH568UKhwQyb/qLt7gI9hLBOdgRaWZuOCghNGX3MQCBodDLXTahnvUlXp +pXnUOtuQmODPjTDIjNXjcsZUUzSJoanQ+Zt8OWPBYumrFC9Xw5fFRcrNmSbWnllx +Nveyrm6mlOydSUXq8D1vh4vkNGtQ/0nrFuSTBGsl2vY+ClX4o8iYunaHmhEboqjp +BMEC4WdBql6N5CI64HQ0e2iGXVSTPiMHnpqQlnaOvx3gdaYPW15hjISgjPb6ygdp +uyGXyPRa+0X7TlTtGXLLcoB/ABEBAAGJAiUEGAECAA8FAlZu4oYCGwwFCQDtTgAA +CgkQNkiogvQxa5sE5w//VrTdVm1ak3RCtZU1D25D6yiSMKZ05j6PDyJfZNI/QubJ +5Qq/VKzITa4kr50LNnM/wZzQPxEM5K6HyA5Wk3tt4IXqmqyZ8VUS+55sl1b5Tg6q +NSLc2qXmY+BeVGmQZwke4nY8wvTNI3wGDekJTPd5a1rjkw64l8n2Xy5ErVaYlhkW +8KyD96PTKhsJgRqGmAtZjJ2i1e64oR/VYR1B9daghGzueV/uvdhD5DxH7UsKSBUZ +vb7lCeOK9Fuvs12/ULgMmymFxSvKeD5+etGUPsNA3gRpqwNcipp0QNhiQmm8nRq9 +vH8Kv9tPmaXL2JHWJB4pMXQXX/DIww3I2gaFfHL60Dr120Ddte3uqdG9KSYQHz7s +/bH+vFsvqr17CHflA/Ogto4rfrlL5qo3SaJVRQwI5vhA3Nx/K22WeH7l25Mu6mAw +kQo0c76fmSvOTpvCVC8aDvhLlm1nF1ao+dq4QafnCrKU3PTn1SlkZ2hwfFzRy/Ru +Vdep6Xd2M3tux3O82UoHLF7Z+4G+NgP69h87rMOSikszRsNiCi80xO3aT2CU8Yt/ +l3sduhFP5TqvfKjTJAK6EfUIukVC0JEL8ktpYCyxb9tN6DTPHEhCJUTXZI9Y60iT +ZIrV7MYY51HatEEJKhpUtLeYSyutj0ubbETfrt2b3cjHNfQh+OLEVUjaQwZXKdU= +=GC3s +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contrib/gitian-downloader/michagogo-key.pgp b/contrib/gitian-keys/michagogo-key.pgp similarity index 100% rename from contrib/gitian-downloader/michagogo-key.pgp rename to contrib/gitian-keys/michagogo-key.pgp diff --git a/contrib/gitian-downloader/petertodd-key.pgp b/contrib/gitian-keys/petertodd-key.pgp similarity index 100% rename from contrib/gitian-downloader/petertodd-key.pgp rename to contrib/gitian-keys/petertodd-key.pgp diff --git a/contrib/gitian-downloader/prab-key.pgp b/contrib/gitian-keys/prab-key.pgp similarity index 100% rename from contrib/gitian-downloader/prab-key.pgp rename to contrib/gitian-keys/prab-key.pgp diff --git a/contrib/gitian-downloader/sipa-key.pgp b/contrib/gitian-keys/sipa-key.pgp similarity index 78% rename from contrib/gitian-downloader/sipa-key.pgp rename to contrib/gitian-keys/sipa-key.pgp index ffa09bb4a..a1930ddee 100644 Binary files a/contrib/gitian-downloader/sipa-key.pgp and b/contrib/gitian-keys/sipa-key.pgp differ diff --git a/contrib/gitian-downloader/tcatm-key.pgp b/contrib/gitian-keys/tcatm-key.pgp similarity index 100% rename from contrib/gitian-downloader/tcatm-key.pgp rename to contrib/gitian-keys/tcatm-key.pgp diff --git a/contrib/gitian-downloader/wtogami-key.pgp b/contrib/gitian-keys/wtogami-key.pgp similarity index 100% rename from contrib/gitian-downloader/wtogami-key.pgp rename to contrib/gitian-keys/wtogami-key.pgp diff --git a/contrib/init/README.md b/contrib/init/README.md index 0d19da303..eb5d30acc 100644 --- a/contrib/init/README.md +++ b/contrib/init/README.md @@ -5,6 +5,7 @@ Upstart: bitcoind.conf OpenRC: bitcoind.openrc bitcoind.openrcconf CentOS: bitcoind.init +OS X: org.bitcoin.bitcoind.plist have been made available to assist packagers in creating node packages here. diff --git a/contrib/init/org.bitcoin.bitcoind.plist b/contrib/init/org.bitcoin.bitcoind.plist new file mode 100644 index 000000000..e94cd4466 --- /dev/null +++ b/contrib/init/org.bitcoin.bitcoind.plist @@ -0,0 +1,15 @@ + + + + + Label + org.bitcoin.bitcoind + ProgramArguments + + /usr/local/bin/bitcoind + -daemon + + RunAtLoad + + + diff --git a/contrib/macdeploy/Base.lproj/InfoPlist.strings b/contrib/macdeploy/Base.lproj/InfoPlist.strings deleted file mode 100644 index b259ea141..000000000 --- a/contrib/macdeploy/Base.lproj/InfoPlist.strings +++ /dev/null @@ -1 +0,0 @@ -{ CFBundleDisplayName = "Bitcoin Core"; CFBundleName = "Bitcoin Core"; } diff --git a/contrib/macdeploy/DS_Store b/contrib/macdeploy/DS_Store deleted file mode 100644 index db9d16f1d..000000000 Binary files a/contrib/macdeploy/DS_Store and /dev/null differ diff --git a/contrib/macdeploy/background.png b/contrib/macdeploy/background.png deleted file mode 100644 index f88a2ae74..000000000 Binary files a/contrib/macdeploy/background.png and /dev/null differ diff --git a/contrib/macdeploy/background.psd b/contrib/macdeploy/background.psd deleted file mode 100644 index fdc4f4ca4..000000000 Binary files a/contrib/macdeploy/background.psd and /dev/null differ diff --git a/contrib/macdeploy/background.svg b/contrib/macdeploy/background.svg new file mode 100644 index 000000000..9c330af45 --- /dev/null +++ b/contrib/macdeploy/background.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + PACKAGE_NAME + + + + + diff --git a/contrib/macdeploy/background.tiff b/contrib/macdeploy/background.tiff deleted file mode 100644 index 4b44ac672..000000000 Binary files a/contrib/macdeploy/background.tiff and /dev/null differ diff --git a/contrib/macdeploy/background@2x.png b/contrib/macdeploy/background@2x.png deleted file mode 100644 index 4858183f7..000000000 Binary files a/contrib/macdeploy/background@2x.png and /dev/null differ diff --git a/contrib/macdeploy/custom_dsstore.py b/contrib/macdeploy/custom_dsstore.py new file mode 100755 index 000000000..03e2325fc --- /dev/null +++ b/contrib/macdeploy/custom_dsstore.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# Copyright (c) 2013-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +from __future__ import division,print_function,unicode_literals +import biplist +from ds_store import DSStore +from mac_alias import Alias +import sys + +output_file = sys.argv[1] +package_name_ns = sys.argv[2] + +ds = DSStore.open(output_file, 'w+') +ds['.']['bwsp'] = { + 'ShowStatusBar': False, + 'WindowBounds': b'{{300, 280}, {500, 343}}', + 'ContainerShowSidebar': False, + 'SidebarWidth': 0, + 'ShowTabView': False, + 'PreviewPaneVisibility': False, + 'ShowToolbar': False, + 'ShowSidebar': False, + 'ShowPathbar': True +} + +icvp = { + 'gridOffsetX': 0.0, + 'textSize': 12.0, + 'viewOptionsVersion': 1, + '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\x07bitcoin\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', + 'backgroundColorBlue': 1.0, + 'iconSize': 96.0, + 'backgroundColorGreen': 1.0, + 'arrangeBy': 'none', + 'showIconPreview': True, + 'gridSpacing': 100.0, + 'gridOffsetY': 0.0, + 'showItemInfo': False, + 'labelOnBottom': True, + 'backgroundType': 2, + 'backgroundColorRed': 1.0 +} +alias = Alias.from_bytes(icvp['backgroundImageAlias']) +alias.volume.name = package_name_ns +alias.volume.posix_path = '/Volumes/' + package_name_ns +alias.volume.disk_image_alias.target.filename = package_name_ns + '.temp.dmg' +alias.volume.disk_image_alias.target.carbon_path = 'Macintosh HD:Users:\x00bitcoinuser:\x00Documents:\x00bitcoin:\x00bitcoin:\x00' + package_name_ns + '.temp.dmg' +alias.volume.disk_image_alias.target.posix_path = 'Users/bitcoinuser/Documents/bitcoin/bitcoin/' + package_name_ns + '.temp.dmg' +alias.target.carbon_path = package_name_ns + ':.background:\x00background.tiff' +icvp['backgroundImageAlias'] = biplist.Data(alias.to_bytes()) +ds['.']['icvp'] = icvp + +ds['.']['vSrn'] = ('long', 1) + +ds['Applications']['Iloc'] = (370, 156) +ds['Bitcoin-Qt.app']['Iloc'] = (128, 156) + +ds.flush() +ds.close() diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 2253c40af..685ed8e5b 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -1,5 +1,5 @@ #!/usr/bin/env python - +from __future__ import division, print_function, unicode_literals # # Copyright (C) 2011 Patrick "p2k" Schneider # @@ -201,7 +201,7 @@ class DeploymentInfo(object): def getFrameworks(binaryPath, verbose): if verbose >= 3: - print "Inspecting with otool: " + binaryPath + print("Inspecting with otool: " + binaryPath) otoolbin=os.getenv("OTOOL", "otool") otool = subprocess.Popen([otoolbin, "-L", binaryPath], stdout=subprocess.PIPE, stderr=subprocess.PIPE) o_stdout, o_stderr = otool.communicate() @@ -222,8 +222,8 @@ def getFrameworks(binaryPath, verbose): info = FrameworkInfo.fromOtoolLibraryLine(line.strip()) if info is not None: if verbose >= 3: - print "Found framework:" - print info + print("Found framework:") + print(info) libraries.append(info) return libraries @@ -234,24 +234,24 @@ def runInstallNameTool(action, *args): def changeInstallName(oldName, newName, binaryPath, verbose): if verbose >= 3: - print "Using install_name_tool:" - print " in", binaryPath - print " change reference", oldName - print " to", newName + print("Using install_name_tool:") + print(" in", binaryPath) + print(" change reference", oldName) + print(" to", newName) runInstallNameTool("change", oldName, newName, binaryPath) def changeIdentification(id, binaryPath, verbose): if verbose >= 3: - print "Using install_name_tool:" - print " change identification in", binaryPath - print " to", id + print("Using install_name_tool:") + print(" change identification in", binaryPath) + print(" to", id) runInstallNameTool("id", id, binaryPath) def runStrip(binaryPath, verbose): stripbin=os.getenv("STRIP", "strip") if verbose >= 3: - print "Using strip:" - print " stripped", binaryPath + print("Using strip:") + print(" stripped", binaryPath) subprocess.check_call([stripbin, "-x", binaryPath]) def copyFramework(framework, path, verbose): @@ -274,8 +274,8 @@ def copyFramework(framework, path, verbose): shutil.copy2(fromPath, toPath) if verbose >= 3: - print "Copied:", fromPath - print " to:", toPath + print("Copied:", fromPath) + print(" to:", toPath) permissions = os.stat(toPath) if not permissions.st_mode & stat.S_IWRITE: @@ -288,14 +288,14 @@ def copyFramework(framework, path, verbose): if not os.path.exists(linkfrom): os.symlink(linkto, linkfrom) if verbose >= 2: - print "Linked:", linkfrom, "->", linkto + print("Linked:", linkfrom, "->", linkto) fromResourcesDir = framework.sourceResourcesDirectory if os.path.exists(fromResourcesDir): toResourcesDir = os.path.join(path, framework.destinationResourcesDirectory) shutil.copytree(fromResourcesDir, toResourcesDir, symlinks=True) if verbose >= 3: - print "Copied resources:", fromResourcesDir - print " to:", toResourcesDir + print("Copied resources:", fromResourcesDir) + print(" to:", toResourcesDir) fromContentsDir = framework.sourceVersionContentsDirectory if not os.path.exists(fromContentsDir): fromContentsDir = framework.sourceContentsDirectory @@ -304,16 +304,16 @@ def copyFramework(framework, path, verbose): shutil.copytree(fromContentsDir, toContentsDir, symlinks=True) contentslinkfrom = os.path.join(path, framework.destinationContentsDirectory) if verbose >= 3: - print "Copied Contents:", fromContentsDir - print " to:", toContentsDir + print("Copied Contents:", fromContentsDir) + print(" to:", toContentsDir) elif framework.frameworkName.startswith("libQtGui"): # Copy qt_menu.nib (applies to non-framework layout) qtMenuNibSourcePath = os.path.join(framework.frameworkDirectory, "Resources", "qt_menu.nib") qtMenuNibDestinationPath = os.path.join(path, "Contents", "Resources", "qt_menu.nib") if os.path.exists(qtMenuNibSourcePath) and not os.path.exists(qtMenuNibDestinationPath): shutil.copytree(qtMenuNibSourcePath, qtMenuNibDestinationPath, symlinks=True) if verbose >= 3: - print "Copied for libQtGui:", qtMenuNibSourcePath - print " to:", qtMenuNibDestinationPath + print("Copied for libQtGui:", qtMenuNibSourcePath) + print(" to:", qtMenuNibDestinationPath) return toPath @@ -326,7 +326,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym deploymentInfo.deployedFrameworks.append(framework.frameworkName) if verbose >= 2: - print "Processing", framework.frameworkName, "..." + print("Processing", framework.frameworkName, "...") # Get the Qt path from one of the Qt frameworks if deploymentInfo.qtPath is None and framework.isQtFramework(): @@ -334,7 +334,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym if framework.installName.startswith("@executable_path") or framework.installName.startswith(bundlePath): if verbose >= 2: - print framework.frameworkName, "already deployed, skipping." + print(framework.frameworkName, "already deployed, skipping.") continue # install_name_tool the new id into the binary @@ -366,7 +366,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym def deployFrameworksForAppBundle(applicationBundle, strip, verbose): frameworks = getFrameworks(applicationBundle.binaryPath, verbose) if len(frameworks) == 0 and verbose >= 1: - print "Warning: Could not find any external frameworks to deploy in %s." % (applicationBundle.path) + print("Warning: Could not find any external frameworks to deploy in %s." % (applicationBundle.path)) return DeploymentInfo() else: return deployFrameworks(frameworks, applicationBundle.path, applicationBundle.binaryPath, strip, verbose) @@ -444,7 +444,7 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose): for pluginDirectory, pluginName in plugins: if verbose >= 2: - print "Processing plugin", os.path.join(pluginDirectory, pluginName), "..." + print("Processing plugin", os.path.join(pluginDirectory, pluginName), "...") sourcePath = os.path.join(deploymentInfo.pluginPath, pluginDirectory, pluginName) destinationDirectory = os.path.join(appBundleInfo.pluginPath, pluginDirectory) @@ -454,8 +454,8 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose): destinationPath = os.path.join(destinationDirectory, pluginName) shutil.copy2(sourcePath, destinationPath) if verbose >= 3: - print "Copied:", sourcePath - print " to:", destinationPath + print("Copied:", sourcePath) + print(" to:", destinationPath) if strip: runStrip(destinationPath, verbose) @@ -495,6 +495,7 @@ ap.add_argument("-fancy", nargs=1, metavar="plist", default=[], help="make a fan ap.add_argument("-add-qt-tr", nargs=1, metavar="languages", default=[], help="add Qt translation files to the bundle's ressources; the language list must be separated with commas, not with whitespace") ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translation files") ap.add_argument("-add-resources", nargs="+", metavar="path", default=[], help="list of additional files or folders to be copied into the bundle's resources; must be the last argument") +ap.add_argument("-volname", nargs=1, metavar="volname", default=[], help="custom volume name for dmg") config = ap.parse_args() @@ -524,7 +525,7 @@ if config.translations_dir and config.translations_dir[0]: for p in config.add_resources: if verbose >= 3: - print "Checking for \"%s\"..." % p + print("Checking for \"%s\"..." % p) if not os.path.exists(p): if verbose >= 1: sys.stderr.write("Error: Could not find additional resource file \"%s\"\n" % (p)) @@ -534,7 +535,7 @@ for p in config.add_resources: if len(config.fancy) == 1: if verbose >= 3: - print "Fancy: Importing plistlib..." + print("Fancy: Importing plistlib...") try: import plistlib except ImportError: @@ -544,7 +545,7 @@ if len(config.fancy) == 1: p = config.fancy[0] if verbose >= 3: - print "Fancy: Loading \"%s\"..." % p + print("Fancy: Loading \"%s\"..." % p) if not os.path.exists(p): if verbose >= 1: sys.stderr.write("Error: Could not find fancy disk image plist at \"%s\"\n" % (p)) @@ -558,23 +559,23 @@ if len(config.fancy) == 1: sys.exit(1) try: - assert not fancy.has_key("window_bounds") or (isinstance(fancy["window_bounds"], list) and len(fancy["window_bounds"]) == 4) - assert not fancy.has_key("background_picture") or isinstance(fancy["background_picture"], str) - assert not fancy.has_key("icon_size") or isinstance(fancy["icon_size"], int) - assert not fancy.has_key("applications_symlink") or isinstance(fancy["applications_symlink"], bool) - if fancy.has_key("items_position"): + assert "window_bounds" not in fancy or (isinstance(fancy["window_bounds"], list) and len(fancy["window_bounds"]) == 4) + assert "background_picture" not in fancy or isinstance(fancy["background_picture"], str) + assert "icon_size" not in fancy or isinstance(fancy["icon_size"], int) + assert "applications_symlink" not in fancy or isinstance(fancy["applications_symlink"], bool) + if "items_position" in fancy: assert isinstance(fancy["items_position"], dict) - for key, value in fancy["items_position"].iteritems(): + for key, value in fancy["items_position"].items(): assert isinstance(value, list) and len(value) == 2 and isinstance(value[0], int) and isinstance(value[1], int) except: if verbose >= 1: sys.stderr.write("Error: Bad format of fancy disk image plist at \"%s\"\n" % (p)) sys.exit(1) - if fancy.has_key("background_picture"): + if "background_picture" in fancy: bp = fancy["background_picture"] if verbose >= 3: - print "Fancy: Resolving background picture \"%s\"..." % bp + print("Fancy: Resolving background picture \"%s\"..." % bp) if not os.path.exists(bp): bp = os.path.join(os.path.dirname(p), bp) if not os.path.exists(bp): @@ -590,18 +591,25 @@ else: if os.path.exists("dist"): if verbose >= 2: - print "+ Removing old dist folder +" + print("+ Removing old dist folder +") shutil.rmtree("dist") # ------------------------------------------------ +if len(config.volname) == 1: + volname = config.volname[0] +else: + volname = app_bundle_name + +# ------------------------------------------------ + target = os.path.join("dist", "Bitcoin-Qt.app") if verbose >= 2: - print "+ Copying source bundle +" + print("+ Copying source bundle +") if verbose >= 3: - print app_bundle, "->", target + print(app_bundle, "->", target) os.mkdir("dist") shutil.copytree(app_bundle, target, symlinks=True) @@ -611,7 +619,7 @@ applicationBundle = ApplicationBundleInfo(target) # ------------------------------------------------ if verbose >= 2: - print "+ Deploying frameworks +" + print("+ Deploying frameworks +") try: deploymentInfo = deployFrameworksForAppBundle(applicationBundle, config.strip, verbose) @@ -630,7 +638,7 @@ except RuntimeError as e: if config.plugins: if verbose >= 2: - print "+ Deploying plugins +" + print("+ Deploying plugins +") try: deployPlugins(applicationBundle, deploymentInfo, config.strip, verbose) @@ -656,7 +664,7 @@ else: for lng_file in add_qt_tr: p = os.path.join(qt_tr_dir, lng_file) if verbose >= 3: - print "Checking for \"%s\"..." % p + print("Checking for \"%s\"..." % p) if not os.path.exists(p): if verbose >= 1: sys.stderr.write("Error: Could not find Qt translation file \"%s\"\n" % (lng_file)) @@ -665,7 +673,7 @@ else: # ------------------------------------------------ if verbose >= 2: - print "+ Installing qt.conf +" + print("+ Installing qt.conf +") f = open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") f.write(qt_conf) @@ -674,22 +682,22 @@ f.close() # ------------------------------------------------ if len(add_qt_tr) > 0 and verbose >= 2: - print "+ Adding Qt translations +" + print("+ Adding Qt translations +") for lng_file in add_qt_tr: if verbose >= 3: - print os.path.join(qt_tr_dir, lng_file), "->", os.path.join(applicationBundle.resourcesPath, lng_file) + print(os.path.join(qt_tr_dir, lng_file), "->", os.path.join(applicationBundle.resourcesPath, lng_file)) shutil.copy2(os.path.join(qt_tr_dir, lng_file), os.path.join(applicationBundle.resourcesPath, lng_file)) # ------------------------------------------------ if len(config.add_resources) > 0 and verbose >= 2: - print "+ Adding additional resources +" + print("+ Adding additional resources +") for p in config.add_resources: t = os.path.join(applicationBundle.resourcesPath, os.path.basename(p)) if verbose >= 3: - print p, "->", t + print(p, "->", t) if os.path.isdir(p): shutil.copytree(p, t, symlinks=True) else: @@ -698,10 +706,10 @@ for p in config.add_resources: # ------------------------------------------------ if config.sign and 'CODESIGNARGS' not in os.environ: - print "You must set the CODESIGNARGS environment variable. Skipping signing." + print("You must set the CODESIGNARGS environment variable. Skipping signing.") elif config.sign: if verbose >= 1: - print "Code-signing app bundle %s"%(target,) + print("Code-signing app bundle %s"%(target,)) subprocess.check_call("codesign --force %s %s"%(os.environ['CODESIGNARGS'], target), shell=True) # ------------------------------------------------ @@ -726,7 +734,7 @@ if config.dmg is not None: def runHDIUtil(verb, image_basename, **kwargs): hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"] - if kwargs.has_key("capture_stdout"): + if "capture_stdout" in kwargs: del kwargs["capture_stdout"] run = subprocess.check_output else: @@ -736,7 +744,7 @@ if config.dmg is not None: hdiutil_args.append("-verbose") run = subprocess.check_call - for key, value in kwargs.iteritems(): + for key, value in kwargs.items(): hdiutil_args.append("-" + key) if not value is True: hdiutil_args.append(str(value)) @@ -745,9 +753,9 @@ if config.dmg is not None: if verbose >= 2: if fancy is None: - print "+ Creating .dmg disk image +" + print("+ Creating .dmg disk image +") else: - print "+ Preparing .dmg disk image +" + print("+ Preparing .dmg disk image +") if config.dmg != "": dmg_name = config.dmg @@ -757,12 +765,12 @@ if config.dmg is not None: if fancy is None: try: - runHDIUtil("create", dmg_name, srcfolder="dist", format="UDBZ", volname="Bitcoin-Core", ov=True) + runHDIUtil("create", dmg_name, srcfolder="dist", format="UDBZ", volname=volname, ov=True) except subprocess.CalledProcessError as e: sys.exit(e.returncode) else: if verbose >= 3: - print "Determining size of \"dist\"..." + print("Determining size of \"dist\"...") size = 0 for path, dirs, files in os.walk("dist"): for file in files: @@ -770,14 +778,14 @@ if config.dmg is not None: size += int(size * 0.15) if verbose >= 3: - print "Creating temp image for modification..." + print("Creating temp image for modification...") try: - runHDIUtil("create", dmg_name + ".temp", srcfolder="dist", format="UDRW", size=size, volname="Bitcoin-Core", ov=True) + runHDIUtil("create", dmg_name + ".temp", srcfolder="dist", format="UDRW", size=size, volname=volname, ov=True) except subprocess.CalledProcessError as e: sys.exit(e.returncode) if verbose >= 3: - print "Attaching temp image..." + print("Attaching temp image...") try: output = runHDIUtil("attach", dmg_name + ".temp", readwrite=True, noverify=True, noautoopen=True, capture_stdout=True) except subprocess.CalledProcessError as e: @@ -788,13 +796,13 @@ if config.dmg is not None: disk_name = m.group(1) if verbose >= 2: - print "+ Applying fancy settings +" + print("+ Applying fancy settings +") - if fancy.has_key("background_picture"): + if "background_picture" in fancy: bg_path = os.path.join(disk_root, ".background", os.path.basename(fancy["background_picture"])) os.mkdir(os.path.dirname(bg_path)) if verbose >= 3: - print fancy["background_picture"], "->", bg_path + print(fancy["background_picture"], "->", bg_path) shutil.copy2(fancy["background_picture"], bg_path) else: bg_path = None @@ -831,21 +839,21 @@ if config.dmg is not None: itemscript = Template('set position of item "${item}" of container window to {${position}}') items_positions = [] - if fancy.has_key("items_position"): - for name, position in fancy["items_position"].iteritems(): + if "items_position" in fancy: + for name, position in fancy["items_position"].items(): params = { "item" : name, "position" : ",".join([str(p) for p in position]) } items_positions.append(itemscript.substitute(params)) params = { - "disk" : "Bitcoin-Core", + "disk" : volname, "window_bounds" : "300,300,800,620", "icon_size" : "96", "background_commands" : "", "items_positions" : "\n ".join(items_positions) } - if fancy.has_key("window_bounds"): + if "window_bounds" in fancy: params["window.bounds"] = ",".join([str(p) for p in fancy["window_bounds"]]) - if fancy.has_key("icon_size"): + if "icon_size" in fancy: params["icon_size"] = str(fancy["icon_size"]) if bg_path is not None: # Set background file, then call SetFile to make it invisible. @@ -865,7 +873,7 @@ if config.dmg is not None: print("Error running osascript.") if verbose >= 2: - print "+ Finalizing .dmg disk image +" + print("+ Finalizing .dmg disk image +") time.sleep(5) try: @@ -878,6 +886,6 @@ if config.dmg is not None: # ------------------------------------------------ if verbose >= 2: - print "+ Done +" + print("+ Done +") sys.exit(0) diff --git a/contrib/rpm/README.md b/contrib/rpm/README.md new file mode 100644 index 000000000..aecb3ba84 --- /dev/null +++ b/contrib/rpm/README.md @@ -0,0 +1,185 @@ +RPM Spec File Notes +------------------- + +The RPM spec file provided here is for Bitcoin-Core 0.12.0 and builds on CentOS +7 with either the CentOS provided OpenSSL library or with LibreSSL as packaged +at [LibreLAMP.com](https://librelamp.com/). It should hopefully not be too +difficult to port the RPM spec file to most RPM based Linux distributions. + +When porting the spec file to build for a particular distribution, there are +some important notes. + +## Sources + +It is considered good form for all sources to reference a URL where the source +can be downloaded. + +Sources 0-9 should be reserved for source code tarballs. `Source0` should +reference the release tarball available from https://bitcoin.org/bin/ and +`Source1` should reference the BerkeleyDB source. + +Sources 10-99 are for source files that are maintained in the +[Bitcoin git repository](https://github.com/bitcoin/bitcoin) but are not part of +the release tarball. Most of these will reside in the `contrib` sub-directory. + +Sources 10-19 should be reserved for miscellaneous configuration files. +Currently only `Source10` is used, for the example `bitcoin.conf` file. + +Sources 20-29 should be reserved for man pages. Currently only `Source20` +through `Source23` are used. + +Sources 30-39 should be reserved for SELinux related files. Currently only +`Source30` through `Source32` are used. Until those files are in a tagged +release, the full URL specified in the RPM spec file will not work. You can get +them from the git ropository where you retrieved this file. + +Sources 100+ are for files that are not source tarballs and are not maintained +in the bitcoin git repository. At present only an SVG version of the Bitcoin +icon is used. + +## Patches + +In general, patches should be avoided. When a packager feels a patch is +necessary, the packager should bring the problem to the attention of the bitcoin +developers so that an official fix to the issue can make it into the next +release. + +### Patch0 bitcoin-0.12.0-libressl.patch + +This patch is only needed if building against LibreSSL. LibreSSL is not the +standard TLS library on most Linux distributions. The patch will likely not be +needed when 0.12.1 is released, a proper fix is already in the Bitcoin git +master branch. + +## BuildRequires + +The packages specified in the `BuildRequires` are specified according to the +package naming convention currently used in CentOS 7 and EPEL for CentOS 7. You +may need to change some of the package names for other distributions. This is +most likely to be the case with the Qt packages. + +## BerkeleyDB + +The `build-unix.md` file recommends building against BerkeleyDB 4.8.30. Even if +that is the version your Linux distribution ships with, it probably is a good +idea to build Bitcoin Core against a static version of that library compiled +according to the instructions in the `build-unix.md` file so that any changes +the distribution may make in the future will not result in a problem for users. + +The problem that can exist, clients built against different versions of +BerkeleyDB may not be able read each other's `wallet.dat` file which can make it +difficult for a user to recover from backup in the event of a system failure. + +## Graphical User Interface and Qt Version + +The RPM spec file will by default build the GUI client linked against the Qt5 +libraries. If you wish instead to link against the Qt4 libraries you need to +pass the switch `-D '_use_qt4 1'` at build time to the `rpmbuild` or `mock` +command used to build the packages. + +If you would prefer not to build the GUI at all, you can pass the switch +`-D '_no_gui 1'` to the `rpmbuild` or `mock` build command. + +## Desktop and KDE Files + +The desktop and KDE meta files are created in the spec file itself with the +`cat` command. This is done to allow easy distribution specific changes without +needing to use any patches. A specific time stamp is given to the files so that +it does not they do not appear to have been updated every time the package is +built. If you do make changes to them, you probably should update time stamp +assigned to them in the `touch` command that specifies the time stamp. + +## SVG, PNG, and XPM Icons + +The `bitcoin.svg` file is from the source listed as `Source100`. It is used as +the source for the PNG and XPM files. The generated PNG and XPM files are given +the same time stamp as the source SVG file as a means of indicating they are +derived from it. + +## Systemd + +This spec file assumes the target distribution uses systemd. That really only +matters for the `bitcoin-server` package. At this point, most RPM based +distributions that still receive vendor updates do in fact use systemd. + +The files to control the service are created in the RPM spec file itself using +the `cat` command. This is done to make it easy to modify for other +distributions that may implement things differently without needing to patch +source. A specific time stamp is given to the files so that they do not appear +to have been updated every time the package is built. If you do make changes to +them, you probably should update the time stamp assigned to them in the `touch` +command that specifies the time stamp. + +## SELinux + +The `bitcoin-server` package should have SELinux support. How to properly do +that *may* vary by distribution and version of distribution. + +The SELinux stuff in this RPM spec file *should* be correct for CentOS, RHEL, +and Fedora but it would be a good idea to review it before building the package +on other distributions. + +## Tests + +The `%check` section takes a very long time to run. If your build system has a +time limit for package build, you may need to make an exception for this +package. On CentOS 7 the `%check` section completes successfully with both +OpenSSL and LibreSSL, a failure really does mean something is wrong. + +## LibreSSL Build Notes + +To build against LibreSSL you will need to pass the switch +`-D '_use_libressl 1'` to the `rpmbuild` or `mock` command or the spec file will +want the OpenSSL development files. + +### LibreSSL and Boost + +LibreSSL (and some newer builds of OpenSSL) do not have support for SSLv3. This +can cause issues with the Boost package if the Boost package has not been +patched accordingly. On those distributions, you will either need to build +Bitcoin-Core against OpenSSL or use a patched version of Boost in the build +system. + +As SSLv3 is no longer safe, distributions that have not patched Boost to work +with TLS libraries that do not support SSLv3 should have bug reports filed +against the Boost package. This bug report has already been filed for RHEL 7 but +it may need to be filed for other distributions. + +A patch for Boost: https://github.com/boostorg/asio/pull/23/files + +## ZeroMQ + +At this time, this RPM spec file does not support the ZeroMQ build options. A +suitable version of ZeroMQ is not available for the platform this spec file was +developed on (CentOS 7). + +## Legacy Credit + +This RPM spec file is largely based upon the work of Michael Hampton at +[Ringing Liberty](https://www.ringingliberty.com/bitcoin/). He has been +packaging Bitcoin for Fedora at least since 2012. + +Most of the differences between his packaging and this package are stylistic in +nature. The major differences: + +1. He builds from a github tagged release rather than a release tarball. This +should not result in different source code. + +2. He does not build BerkeleyDB but instead uses the BerkeleyDB provided by the +Linux distribution. For the distributions he packages for, they currently all +use the same version of BerkeleyDB so that difference is *probably* just +academic. + +3. As of his 10.11.2 package he did not allow for building against LibreSSL, +specifying a build without the Qt GUI, or specifying which version of the Qt +libraries to use. + +4. I renamed the `bitcoin` package that contains the Qt GUI to `bitcoin-core` as +that appears to be how the general population refers to it, in contrast to +`bitcoin-xt` or `bitcoin-classic`. I wanted to make sure the general population +knows what they are getting when installing the GUI package. + +As far as minor differences, I generally prefer to assign the file permissions +in the `%files` portion of an RPM spec file rather than specifying the +permissions of a file during `%install` and other minor things like that that +are largely just cosmetic. diff --git a/contrib/rpm/bitcoin-0.12.0-libressl.patch b/contrib/rpm/bitcoin-0.12.0-libressl.patch new file mode 100644 index 000000000..555614a06 --- /dev/null +++ b/contrib/rpm/bitcoin-0.12.0-libressl.patch @@ -0,0 +1,24 @@ +diff -ur bitcoin-0.12.0.orig/src/init.cpp bitcoin-0.12.0/src/init.cpp +--- bitcoin-0.12.0.orig/src/init.cpp 2015-12-31 16:00:00.000000000 -0800 ++++ bitcoin-0.12.0/src/init.cpp 2016-02-23 06:03:47.133227757 -0800 +@@ -1075,7 +1075,7 @@ + if (fPrintToDebugLog) + OpenDebugLog(); + +-#if (OPENSSL_VERSION_NUMBER < 0x10100000L) ++#if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L) + LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION)); + #else + LogPrintf("Using OpenSSL version %s\n", OpenSSL_version(OPENSSL_VERSION)); +diff -ur bitcoin-0.12.0.orig/src/qt/rpcconsole.cpp bitcoin-0.12.0/src/qt/rpcconsole.cpp +--- bitcoin-0.12.0.orig/src/qt/rpcconsole.cpp 2015-12-31 16:00:00.000000000 -0800 ++++ bitcoin-0.12.0/src/qt/rpcconsole.cpp 2016-02-23 15:09:42.881126841 -0800 +@@ -264,7 +264,7 @@ + + // set library version labels + +-#if (OPENSSL_VERSION_NUMBER < 0x10100000L) ++#if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L) + ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION)); + #else + ui->openSSLVersion->setText(OpenSSL_version(OPENSSL_VERSION)); diff --git a/contrib/rpm/bitcoin.fc b/contrib/rpm/bitcoin.fc new file mode 100644 index 000000000..6f5eef637 --- /dev/null +++ b/contrib/rpm/bitcoin.fc @@ -0,0 +1,8 @@ +/usr/bin/bitcoin-cli -- gen_context(system_u:object_r:bitcoin_exec_t,s0) +/usr/sbin/bitcoind -- gen_context(system_u:object_r:bitcoin_exec_t,s0) +/usr/lib(64)?/bitcoin/bitcoind -- gen_context(system_u:object_r:bitcoin_exec_t,s0) + +/etc/bitcoin(/.*)? gen_context(system_u:object_r:bitcoin_conf_t,s0) +/var/lib/bitcoin(/.*)? gen_context(system_u:object_r:bitcoin_var_lib_t,s0) + +(/var)?/run/bitcoind(/.*)? gen_context(system_u:object_r:bitcoin_var_run_t,s0) diff --git a/contrib/rpm/bitcoin.if b/contrib/rpm/bitcoin.if new file mode 100644 index 000000000..2b096c24d --- /dev/null +++ b/contrib/rpm/bitcoin.if @@ -0,0 +1,157 @@ + +## policy for bitcoin + + +######################################## +## +## Transition to bitcoin. +## +## +## +## Domain allowed to transition. +## +## +# +interface(`bitcoin_domtrans',` + gen_require(` + type bitcoin_t, bitcoin_exec_t; + ') + + corecmd_search_bin($1) + domtrans_pattern($1, bitcoin_exec_t, bitcoin_t) +') + + +######################################## +## +## Execute bitcoin server in the bitcoin domain. +## +## +## +## Domain allowed access. +## +## +# +interface(`bitcoin_initrc_domtrans',` + gen_require(` + type bitcoin_initrc_exec_t; + ') + + init_labeled_script_domtrans($1, bitcoin_initrc_exec_t) +') + + +######################################## +## +## Search bitcoin lib directories. +## +## +## +## Domain allowed access. +## +## +# +interface(`bitcoin_search_lib',` + gen_require(` + type bitcoin_var_lib_t; + ') + + allow $1 bitcoin_var_lib_t:dir search_dir_perms; + files_search_var_lib($1) +') + +######################################## +## +## Read bitcoin lib files. +## +## +## +## Domain allowed access. +## +## +# +interface(`bitcoin_read_lib_files',` + gen_require(` + type bitcoin_var_lib_t; + ') + + files_search_var_lib($1) + read_files_pattern($1, bitcoin_var_lib_t, bitcoin_var_lib_t) +') + +######################################## +## +## Manage bitcoin lib files. +## +## +## +## Domain allowed access. +## +## +# +interface(`bitcoin_manage_lib_files',` + gen_require(` + type bitcoin_var_lib_t; + ') + + files_search_var_lib($1) + manage_files_pattern($1, bitcoin_var_lib_t, bitcoin_var_lib_t) +') + +######################################## +## +## Manage bitcoin lib directories. +## +## +## +## Domain allowed access. +## +## +# +interface(`bitcoin_manage_lib_dirs',` + gen_require(` + type bitcoin_var_lib_t; + ') + + files_search_var_lib($1) + manage_dirs_pattern($1, bitcoin_var_lib_t, bitcoin_var_lib_t) +') + + +######################################## +## +## All of the rules required to administrate +## an bitcoin environment +## +## +## +## Domain allowed access. +## +## +## +## +## Role allowed access. +## +## +## +# +interface(`bitcoin_admin',` + gen_require(` + type bitcoin_t; + type bitcoin_initrc_exec_t; + type bitcoin_var_lib_t; + ') + + allow $1 bitcoin_t:process { ptrace signal_perms }; + ps_process_pattern($1, bitcoin_t) + + bitcoin_initrc_domtrans($1) + domain_system_change_exemption($1) + role_transition $2 bitcoin_initrc_exec_t system_r; + allow $2 system_r; + + files_search_var_lib($1) + admin_pattern($1, bitcoin_var_lib_t) + +') + diff --git a/contrib/rpm/bitcoin.spec b/contrib/rpm/bitcoin.spec new file mode 100644 index 000000000..38ae03818 --- /dev/null +++ b/contrib/rpm/bitcoin.spec @@ -0,0 +1,444 @@ +%define bdbv 4.8.30 +%global selinux_variants mls strict targeted + +%if 0%{?_no_gui:1} +%define _buildqt 0 +%define buildargs --with-gui=no +%else +%define _buildqt 1 +%if 0%{?_use_qt4} +%define buildargs --with-qrencode --with-gui=qt4 +%else +%define buildargs --with-qrencode --with-gui=qt5 +%endif +%endif + +Name: bitcoin +Version: 0.12.0 +Release: 2%{?dist} +Summary: Peer to Peer Cryptographic Currency + +Group: Applications/System +License: MIT +URL: https://bitcoin.org/ +Source0: https://bitcoin.org/bin/bitcoin-core-%{version}/bitcoin-%{version}.tar.gz +Source1: http://download.oracle.com/berkeley-db/db-%{bdbv}.NC.tar.gz + +Source10: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/examples/bitcoin.conf + +#man pages +Source20: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoind.1 +Source21: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoin-cli.1 +Source22: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoin-qt.1 +Source23: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoin.conf.5 + +#selinux +Source30: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/rpm/bitcoin.te +# Source31 - what about bitcoin-tx and bench_bitcoin ??? +Source31: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/rpm/bitcoin.fc +Source32: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/rpm/bitcoin.if + +Source100: https://upload.wikimedia.org/wikipedia/commons/4/46/Bitcoin.svg + +%if 0%{?_use_libressl:1} +BuildRequires: libressl-devel +%else +BuildRequires: openssl-devel +%endif +BuildRequires: boost-devel +BuildRequires: miniupnpc-devel +BuildRequires: autoconf automake libtool +BuildRequires: libevent-devel + + +Patch0: bitcoin-0.12.0-libressl.patch + + +%description +Bitcoin is a digital cryptographic currency that uses peer-to-peer technology to +operate with no central authority or banks; managing transactions and the +issuing of bitcoins is carried out collectively by the network. + +%if %{_buildqt} +%package core +Summary: Peer to Peer Cryptographic Currency +Group: Applications/System +Obsoletes: %{name} < %{version}-%{release} +Provides: %{name} = %{version}-%{release} +%if 0%{?_use_qt4} +BuildRequires: qt-devel +%else +BuildRequires: qt5-qtbase-devel +# for /usr/bin/lrelease-qt5 +BuildRequires: qt5-linguist +%endif +BuildRequires: protobuf-devel +BuildRequires: qrencode-devel +BuildRequires: %{_bindir}/desktop-file-validate +# for icon generation from SVG +BuildRequires: %{_bindir}/inkscape +BuildRequires: %{_bindir}/convert + +%description core +Bitcoin is a digital cryptographic currency that uses peer-to-peer technology to +operate with no central authority or banks; managing transactions and the +issuing of bitcoins is carried out collectively by the network. + +This package contains the Qt based graphical client and node. If you are looking +to run a Bitcoin wallet, this is probably the package you want. +%endif + + +%package libs +Summary: Bitcoin shared libraries +Group: System Environment/Libraries + +%description libs +This package provides the bitcoinconsensus shared libraries. These libraries +may be used by third party software to provide consensus verification +functionality. + +Unless you know need this package, you probably do not. + +%package devel +Summary: Development files for bitcoin +Group: Development/Libraries +Requires: %{name}-libs = %{version}-%{release} + +%description devel +This package contains the header files and static library for the +bitcoinconsensus shared library. If you are developing or compiling software +that wants to link against that library, then you need this package installed. + +Most people do not need this package installed. + +%package server +Summary: The bitcoin daemon +Group: System Environment/Daemons +Requires: bitcoin-utils = %{version}-%{release} +Requires: selinux-policy policycoreutils-python +Requires(pre): shadow-utils +Requires(post): %{_sbindir}/semodule %{_sbindir}/restorecon %{_sbindir}/fixfiles %{_sbindir}/sestatus +Requires(postun): %{_sbindir}/semodule %{_sbindir}/restorecon %{_sbindir}/fixfiles %{_sbindir}/sestatus +BuildRequires: systemd +BuildRequires: checkpolicy +BuildRequires: %{_datadir}/selinux/devel/Makefile + +%description server +This package provides a stand-alone bitcoin-core daemon. For most users, this +package is only needed if they need a full-node without the graphical client. + +Some third party wallet software will want this package to provide the actual +bitcoin-core node they use to connect to the network. + +If you use the graphical bitcoin-core client then you almost certainly do not +need this package. + +%package utils +Summary: Bitcoin utilities +Group: Applications/System + +%description utils +This package provides several command line utilities for interacting with a +bitcoin-core daemon. + +The bitcoin-cli utility allows you to communicate and control a bitcoin daemon +over RPC, the bitcoin-tx utility allows you to create a custom transaction, and +the bench_bitcoin utility can be used to perform some benchmarks. + +This package contains utilities needed by the bitcoin-server package. + + +%prep +%setup -q +%patch0 -p1 -b .libressl +cp -p %{SOURCE10} ./bitcoin.conf.example +tar -zxf %{SOURCE1} +cp -p db-%{bdbv}.NC/LICENSE ./db-%{bdbv}.NC-LICENSE +mkdir db4 SELinux +cp -p %{SOURCE30} %{SOURCE31} %{SOURCE32} SELinux/ + + +%build +CWD=`pwd` +cd db-%{bdbv}.NC/build_unix/ +../dist/configure --enable-cxx --disable-shared --with-pic --prefix=${CWD}/db4 +make install +cd ../.. + +./autogen.sh +%configure LDFLAGS="-L${CWD}/db4/lib/" CPPFLAGS="-I${CWD}/db4/include/" --with-miniupnpc --enable-glibc-back-compat %{buildargs} +make %{?_smp_mflags} + +pushd SELinux +for selinuxvariant in %{selinux_variants}; do + make NAME=${selinuxvariant} -f %{_datadir}/selinux/devel/Makefile + mv bitcoin.pp bitcoin.pp.${selinuxvariant} + make NAME=${selinuxvariant} -f %{_datadir}/selinux/devel/Makefile clean +done +popd + + +%install +make install DESTDIR=%{buildroot} + +mkdir -p -m755 %{buildroot}%{_sbindir} +mv %{buildroot}%{_bindir}/bitcoind %{buildroot}%{_sbindir}/bitcoind + +# systemd stuff +mkdir -p %{buildroot}%{_tmpfilesdir} +cat < %{buildroot}%{_tmpfilesdir}/bitcoin.conf +d /run/bitcoind 0750 bitcoin bitcoin - +EOF +touch -a -m -t 201504280000 %{buildroot}%{_tmpfilesdir}/bitcoin.conf + +mkdir -p %{buildroot}%{_sysconfdir}/sysconfig +cat < %{buildroot}%{_sysconfdir}/sysconfig/bitcoin +# Provide options to the bitcoin daemon here, for example +# OPTIONS="-testnet -disable-wallet" + +OPTIONS="" + +# System service defaults. +# Don't change these unless you know what you're doing. +CONFIG_FILE="%{_sysconfdir}/bitcoin/bitcoin.conf" +DATA_DIR="%{_localstatedir}/lib/bitcoin" +PID_FILE="/run/bitcoind/bitcoind.pid" +EOF +touch -a -m -t 201504280000 %{buildroot}%{_sysconfdir}/sysconfig/bitcoin + +mkdir -p %{buildroot}%{_unitdir} +cat < %{buildroot}%{_unitdir}/bitcoin.service +[Unit] +Description=Bitcoin daemon +After=syslog.target network.target + +[Service] +Type=forking +ExecStart=%{_sbindir}/bitcoind -daemon -conf=\${CONFIG_FILE} -datadir=\${DATA_DIR} -pid=\${PID_FILE} \$OPTIONS +EnvironmentFile=%{_sysconfdir}/sysconfig/bitcoin +User=bitcoin +Group=bitcoin + +Restart=on-failure +PrivateTmp=true +TimeoutStopSec=120 +TimeoutStartSec=60 +StartLimitInterval=240 +StartLimitBurst=5 + +[Install] +WantedBy=multi-user.target +EOF +touch -a -m -t 201504280000 %{buildroot}%{_unitdir}/bitcoin.service +#end systemd stuff + +mkdir %{buildroot}%{_sysconfdir}/bitcoin +mkdir -p %{buildroot}%{_localstatedir}/lib/bitcoin + +#SELinux +for selinuxvariant in %{selinux_variants}; do + install -d %{buildroot}%{_datadir}/selinux/${selinuxvariant} + install -p -m 644 SELinux/bitcoin.pp.${selinuxvariant} %{buildroot}%{_datadir}/selinux/${selinuxvariant}/bitcoin.pp +done + +%if %{_buildqt} +# qt icons +install -D -p share/pixmaps/bitcoin.ico %{buildroot}%{_datadir}/pixmaps/bitcoin.ico +install -p share/pixmaps/nsis-header.bmp %{buildroot}%{_datadir}/pixmaps/ +install -p share/pixmaps/nsis-wizard.bmp %{buildroot}%{_datadir}/pixmaps/ +install -p %{SOURCE100} %{buildroot}%{_datadir}/pixmaps/bitcoin.svg +%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/bitcoin16.png -w16 -h16 +%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/bitcoin32.png -w32 -h32 +%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/bitcoin64.png -w64 -h64 +%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/bitcoin128.png -w128 -h128 +%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/bitcoin256.png -w256 -h256 +%{_bindir}/convert -resize 16x16 %{buildroot}%{_datadir}/pixmaps/bitcoin256.png %{buildroot}%{_datadir}/pixmaps/bitcoin16.xpm +%{_bindir}/convert -resize 32x32 %{buildroot}%{_datadir}/pixmaps/bitcoin256.png %{buildroot}%{_datadir}/pixmaps/bitcoin32.xpm +%{_bindir}/convert -resize 64x64 %{buildroot}%{_datadir}/pixmaps/bitcoin256.png %{buildroot}%{_datadir}/pixmaps/bitcoin64.xpm +%{_bindir}/convert -resize 128x128 %{buildroot}%{_datadir}/pixmaps/bitcoin256.png %{buildroot}%{_datadir}/pixmaps/bitcoin128.xpm +%{_bindir}/convert %{buildroot}%{_datadir}/pixmaps/bitcoin256.png %{buildroot}%{_datadir}/pixmaps/bitcoin256.xpm +touch %{buildroot}%{_datadir}/pixmaps/*.png -r %{SOURCE100} +touch %{buildroot}%{_datadir}/pixmaps/*.xpm -r %{SOURCE100} + +# Desktop File - change the touch timestamp if modifying +mkdir -p %{buildroot}%{_datadir}/applications +cat < %{buildroot}%{_datadir}/applications/bitcoin-core.desktop +[Desktop Entry] +Encoding=UTF-8 +Name=Bitcoin +Comment=Bitcoin P2P Cryptocurrency +Comment[fr]=Bitcoin, monnaie virtuelle cryptographique pair à pair +Comment[tr]=Bitcoin, eşten eşe kriptografik sanal para birimi +Exec=bitcoin-qt %u +Terminal=false +Type=Application +Icon=bitcoin128 +MimeType=x-scheme-handler/bitcoin; +Categories=Office;Finance; +EOF +# change touch date when modifying desktop +touch -a -m -t 201511100546 %{buildroot}%{_datadir}/applications/bitcoin-core.desktop +%{_bindir}/desktop-file-validate %{buildroot}%{_datadir}/applications/bitcoin-core.desktop + +# KDE protocol - change the touch timestamp if modifying +mkdir -p %{buildroot}%{_datadir}/kde4/services +cat < %{buildroot}%{_datadir}/kde4/services/bitcoin-core.protocol +[Protocol] +exec=bitcoin-qt '%u' +protocol=bitcoin +input=none +output=none +helper=true +listing= +reading=false +writing=false +makedir=false +deleting=false +EOF +# change touch date when modifying protocol +touch -a -m -t 201511100546 %{buildroot}%{_datadir}/kde4/services/bitcoin-core.protocol +%endif + +# man pages +install -D -p %{SOURCE20} %{buildroot}%{_mandir}/man1/bitcoind.1 +install -p %{SOURCE21} %{buildroot}%{_mandir}/man1/bitcoin-cli.1 +%if %{_buildqt} +install -p %{SOURCE22} %{buildroot}%{_mandir}/man1/bitcoin-qt.1 +%endif +install -D -p %{SOURCE23} %{buildroot}%{_mandir}/man5/bitcoin.conf.5 + +# nuke these, we do extensive testing of binaries in %%check before packaging +rm -f %{buildroot}%{_bindir}/test_* + +%check +make check +pushd src +srcdir=. test/bitcoin-util-test.py +popd +qa/pull-tester/rpc-tests.py -extended + +%post libs -p /sbin/ldconfig + +%postun libs -p /sbin/ldconfig + +%pre server +getent group bitcoin >/dev/null || groupadd -r bitcoin +getent passwd bitcoin >/dev/null || + useradd -r -g bitcoin -d /var/lib/bitcoin -s /sbin/nologin \ + -c "Bitcoin wallet server" bitcoin +exit 0 + +%post server +%systemd_post bitcoin.service +# SELinux +if [ `%{_sbindir}/sestatus |grep -c "disabled"` -eq 0 ]; then +for selinuxvariant in %{selinux_variants}; do + %{_sbindir}/semodule -s ${selinuxvariant} -i %{_datadir}/selinux/${selinuxvariant}/bitcoin.pp &> /dev/null || : +done +%{_sbindir}/semanage port -a -t bitcoin_port_t -p tcp 8332 +%{_sbindir}/semanage port -a -t bitcoin_port_t -p tcp 8333 +%{_sbindir}/semanage port -a -t bitcoin_port_t -p tcp 18332 +%{_sbindir}/semanage port -a -t bitcoin_port_t -p tcp 18333 +%{_sbindir}/fixfiles -R bitcoin-server restore &> /dev/null || : +%{_sbindir}/restorecon -R %{_localstatedir}/lib/bitcoin || : +fi + +%posttrans server +%{_bindir}/systemd-tmpfiles --create + +%preun server +%systemd_preun bitcoin.service + +%postun server +%systemd_postun bitcoin.service +# SELinux +if [ $1 -eq 0 ]; then + if [ `%{_sbindir}/sestatus |grep -c "disabled"` -eq 0 ]; then + %{_sbindir}/semanage port -d -p tcp 8332 + %{_sbindir}/semanage port -d -p tcp 8333 + %{_sbindir}/semanage port -d -p tcp 18332 + %{_sbindir}/semanage port -d -p tcp 18333 + for selinuxvariant in %{selinux_variants}; do + %{_sbindir}/semodule -s ${selinuxvariant} -r bitcoin &> /dev/null || : + done + %{_sbindir}/fixfiles -R bitcoin-server restore &> /dev/null || : + [ -d %{_localstatedir}/lib/bitcoin ] && \ + %{_sbindir}/restorecon -R %{_localstatedir}/lib/bitcoin &> /dev/null || : + fi +fi + +%clean +rm -rf %{buildroot} + +%if %{_buildqt} +%files core +%defattr(-,root,root,-) +%license COPYING db-%{bdbv}.NC-LICENSE +%doc COPYING bitcoin.conf.example doc/README.md doc/bips.md doc/files.md doc/multiwallet-qt.md doc/reduce-traffic.md doc/release-notes.md doc/tor.md +%attr(0755,root,root) %{_bindir}/bitcoin-qt +%attr(0644,root,root) %{_datadir}/applications/bitcoin-core.desktop +%attr(0644,root,root) %{_datadir}/kde4/services/bitcoin-core.protocol +%attr(0644,root,root) %{_datadir}/pixmaps/*.ico +%attr(0644,root,root) %{_datadir}/pixmaps/*.bmp +%attr(0644,root,root) %{_datadir}/pixmaps/*.svg +%attr(0644,root,root) %{_datadir}/pixmaps/*.png +%attr(0644,root,root) %{_datadir}/pixmaps/*.xpm +%attr(0644,root,root) %{_mandir}/man1/bitcoin-qt.1* +%endif + +%files libs +%defattr(-,root,root,-) +%license COPYING +%doc COPYING doc/README.md doc/shared-libraries.md +%{_libdir}/lib*.so.* + +%files devel +%defattr(-,root,root,-) +%license COPYING +%doc COPYING doc/README.md doc/developer-notes.md doc/shared-libraries.md +%attr(0644,root,root) %{_includedir}/*.h +%{_libdir}/*.so +%{_libdir}/*.a +%{_libdir}/*.la +%attr(0644,root,root) %{_libdir}/pkgconfig/*.pc + +%files server +%defattr(-,root,root,-) +%license COPYING db-%{bdbv}.NC-LICENSE +%doc COPYING bitcoin.conf.example doc/README.md doc/REST-interface.md doc/bips.md doc/dnsseed-policy.md doc/files.md doc/reduce-traffic.md doc/release-notes.md doc/tor.md +%attr(0755,root,root) %{_sbindir}/bitcoind +%attr(0644,root,root) %{_tmpfilesdir}/bitcoin.conf +%attr(0644,root,root) %{_unitdir}/bitcoin.service +%dir %attr(0750,bitcoin,bitcoin) %{_sysconfdir}/bitcoin +%dir %attr(0750,bitcoin,bitcoin) %{_localstatedir}/lib/bitcoin +%config(noreplace) %attr(0600,root,root) %{_sysconfdir}/sysconfig/bitcoin +%attr(0644,root,root) %{_datadir}/selinux/*/*.pp +%attr(0644,root,root) %{_mandir}/man1/bitcoind.1* +%attr(0644,root,root) %{_mandir}/man5/bitcoin.conf.5* + +%files utils +%defattr(-,root,root,-) +%license COPYING +%doc COPYING bitcoin.conf.example doc/README.md +%attr(0755,root,root) %{_bindir}/bitcoin-cli +%attr(0755,root,root) %{_bindir}/bitcoin-tx +%attr(0755,root,root) %{_bindir}/bench_bitcoin +%attr(0644,root,root) %{_mandir}/man1/bitcoin-cli.1* +%attr(0644,root,root) %{_mandir}/man5/bitcoin.conf.5* + + + +%changelog +* Fri Feb 26 2016 Alice Wonder - 0.12.0-2 +- Rename Qt package from bitcoin to bitcoin-core +- Make building of the Qt package optional +- When building the Qt package, default to Qt5 but allow building +- against Qt4 +- Only run SELinux stuff in post scripts if it is not set to disabled + +* Wed Feb 24 2016 Alice Wonder - 0.12.0-1 +- Initial spec file for 0.12.0 release + +# This spec file is written from scratch but a lot of the packaging decisions are directly +# based upon the 0.11.2 package spec file from https://www.ringingliberty.com/bitcoin/ diff --git a/contrib/rpm/bitcoin.te b/contrib/rpm/bitcoin.te new file mode 100644 index 000000000..d6231c591 --- /dev/null +++ b/contrib/rpm/bitcoin.te @@ -0,0 +1,81 @@ +policy_module(bitcoin, 1.100.1) + +######################################## +# +# Declarations +# + +type bitcoin_t; +type bitcoin_exec_t; +init_daemon_domain(bitcoin_t, bitcoin_exec_t) + +permissive bitcoin_t; + +type bitcoin_initrc_exec_t; +init_script_file(bitcoin_initrc_exec_t) + +type bitcoin_conf_t; +files_type(bitcoin_conf_t) + +type bitcoin_var_lib_t; +files_type(bitcoin_var_lib_t) + +type bitcoin_var_run_t; +files_type(bitcoin_var_run_t) + +type bitcoin_port_t; +corenet_port(bitcoin_port_t) + +######################################## +# +# bitcoin local policy +# +allow bitcoin_t self:process { fork }; + +allow bitcoin_t self:fifo_file rw_fifo_file_perms; +allow bitcoin_t self:unix_stream_socket create_stream_socket_perms; + +manage_dirs_pattern(bitcoin_t, bitcoin_conf_t, bitcoin_conf_t) +manage_files_pattern(bitcoin_t, bitcoin_conf_t, bitcoin_conf_t) + +manage_dirs_pattern(bitcoin_t, bitcoin_var_lib_t, bitcoin_var_lib_t) +manage_files_pattern(bitcoin_t, bitcoin_var_lib_t, bitcoin_var_lib_t) +files_var_lib_filetrans(bitcoin_t, bitcoin_var_lib_t, { dir file }) + +manage_dirs_pattern(bitcoin_t, bitcoin_var_run_t, bitcoin_var_run_t) +manage_files_pattern(bitcoin_t, bitcoin_var_run_t, bitcoin_var_run_t) + +sysnet_dns_name_resolve(bitcoin_t) +corenet_all_recvfrom_unlabeled(bitcoin_t) + +allow bitcoin_t self:tcp_socket create_stream_socket_perms; +corenet_tcp_sendrecv_generic_if(bitcoin_t) +corenet_tcp_sendrecv_generic_node(bitcoin_t) +corenet_tcp_sendrecv_all_ports(bitcoin_t) +corenet_tcp_bind_generic_node(bitcoin_t) + +gen_require(` + type bitcoin_port_t; +') +allow bitcoin_t bitcoin_port_t:tcp_socket name_bind; + +gen_require(` + type bitcoin_port_t; +') +allow bitcoin_t bitcoin_port_t:tcp_socket name_connect; + +domain_use_interactive_fds(bitcoin_t) + +files_read_etc_files(bitcoin_t) + +miscfiles_read_localization(bitcoin_t) + +sysnet_dns_name_resolve(bitcoin_t) + +allow bitcoin_t bitcoin_exec_t:file execute_no_trans; +allow bitcoin_t self:process setsched; +corecmd_exec_ls(bitcoin_t) +corenet_tcp_connect_http_port(bitcoin_t) +dev_read_urand(bitcoin_t) +fs_getattr_xattr_fs(bitcoin_t) +kernel_read_system_state(bitcoin_t) diff --git a/contrib/seeds/README.md b/contrib/seeds/README.md index 63647fa11..c595f83eb 100644 --- a/contrib/seeds/README.md +++ b/contrib/seeds/README.md @@ -3,6 +3,9 @@ Utility to generate the seeds.txt list that is compiled into the client (see [src/chainparamsseeds.h](/src/chainparamsseeds.h) and other utilities in [contrib/seeds](/contrib/seeds)). -The 512 seeds compiled into the 0.10 release were created from sipa's DNS seed data, like this: +The seeds compiled into the release are created from sipa's DNS seed data, like this: + + curl -s http://bitcoin.sipa.be/seeds.txt > seeds_main.txt + python makeseeds.py < seeds_main.txt > nodes_main.txt + python generate-seeds.py . > ../../src/chainparamsseeds.h - curl -s http://bitcoin.sipa.be/seeds.txt | makeseeds.py diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py index 167c219c6..a3d035218 100755 --- a/contrib/seeds/generate-seeds.py +++ b/contrib/seeds/generate-seeds.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright (c) 2014 Wladmir J. van der Laan +# Copyright (c) 2014 Wladimir J. van der Laan # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' diff --git a/contrib/seeds/nodes_main.txt b/contrib/seeds/nodes_main.txt index 83ef1ffae..ed5059ffc 100644 --- a/contrib/seeds/nodes_main.txt +++ b/contrib/seeds/nodes_main.txt @@ -1 +1 @@ -52.27.78.56 +52.27.78.56:9246 diff --git a/contrib/test-patches/README.md b/contrib/test-patches/README.md deleted file mode 100644 index def40b0d6..000000000 --- a/contrib/test-patches/README.md +++ /dev/null @@ -1,7 +0,0 @@ -### Test Patches ### - -These patches are applied when the automated pull-tester -tests each pull and when master is tested using jenkins. -You can find more information about the tests run at -[http://jenkins.bluematt.me/pull-tester/files/ -](http://jenkins.bluematt.me/pull-tester/files/) \ No newline at end of file diff --git a/contrib/test-patches/temp-revert-2.patch b/contrib/test-patches/temp-revert-2.patch deleted file mode 100644 index 1cd043d0d..000000000 --- a/contrib/test-patches/temp-revert-2.patch +++ /dev/null @@ -1,20 +0,0 @@ -commit cfae26916dba311f6f75d444301c1f9362267c3e -Author: Matt Corallo -Date: Sun Mar 24 20:45:50 2013 -0400 - - Revert "Checkpoint at first block in 11 March chain fork" - - This reverts commit f817c496a1482d05b22c8e539de67f07db1c09d9. - -diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp -index 62234b9..9b11f0b 100644 ---- a/src/checkpoints.cpp -+++ b/src/checkpoints.cpp -@@ -44,7 +44,6 @@ namespace Checkpoints - (193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")) - (210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")) - (216116, uint256("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")) -- (225430, uint256("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")) - ; - static const CCheckpointData data = { - &mapCheckpoints, diff --git a/contrib/verify-commits/allow-revsig-commits b/contrib/verify-commits/allow-revsig-commits new file mode 100644 index 000000000..31aeb8f3d --- /dev/null +++ b/contrib/verify-commits/allow-revsig-commits @@ -0,0 +1,2 @@ +586a29253dabec3ca0f1ccba9091daabd16b8411 +eddaba7b5692288087a926da5733e86b47274e4e diff --git a/contrib/verify-commits/gpg.sh b/contrib/verify-commits/gpg.sh index 6b5137e7b..0218b82e1 100755 --- a/contrib/verify-commits/gpg.sh +++ b/contrib/verify-commits/gpg.sh @@ -1,15 +1,33 @@ #!/bin/sh INPUT=$(/dev/null); do - case "$LINE" in "[GNUPG:] VALIDSIG"*) + case "$LINE" in + "[GNUPG:] VALIDSIG "*) while read KEY; do case "$LINE" in "[GNUPG:] VALIDSIG $KEY "*) VALID=true;; esac done < ./contrib/verify-commits/trusted-keys + ;; + "[GNUPG:] REVKEYSIG "*) + [ "$BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG" != 1 ] && exit 1 + while read KEY; do + case "$LINE" in "[GNUPG:] REVKEYSIG ${KEY:24:40} "*) + REVSIG=true + GOODREVSIG="[GNUPG:] GOODSIG ${KEY:24:40} " + ;; + esac + done < ./contrib/verify-commits/trusted-keys + ;; esac done if ! $VALID; then exit 1 fi -echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null +if $VALID && $REVSIG; then + echo "$INPUT" | gpg --trust-model always "$@" | grep "\[GNUPG:\] \(NEWSIG\|SIG_ID\|VALIDSIG\)" 2>/dev/null + echo "$GOODREVSIG" +else + echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null +fi diff --git a/contrib/verify-commits/pre-push-hook.sh b/contrib/verify-commits/pre-push-hook.sh index 607c0cac4..c57222818 100755 --- a/contrib/verify-commits/pre-push-hook.sh +++ b/contrib/verify-commits/pre-push-hook.sh @@ -1,5 +1,5 @@ #!/bin/bash -if ! [[ "$2" =~ [git@]?[www.]?github.com[:|/]bitcoin/bitcoin[.git]? ]]; then +if ! [[ "$2" =~ ^(git@)?(www.)?github.com(:|/)bitcoin/bitcoin(.git)?$ ]]; then exit 0 fi diff --git a/contrib/verify-commits/trusted-keys b/contrib/verify-commits/trusted-keys index 658ad0375..a0d0f82db 100644 --- a/contrib/verify-commits/trusted-keys +++ b/contrib/verify-commits/trusted-keys @@ -3,3 +3,5 @@ 01CDF4627A3B88AAE4A571C87588242FBE38D3A8 AF8BE07C7049F3A26B239D5325B3083201782B2F 81291FA67D2C379A006A053FEAB5AF94D9E9ABE7 +3F1888C6DCA92A6499C4911FDBA1A67379A1A931 +32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC diff --git a/contrib/verify-commits/verify-commits.sh b/contrib/verify-commits/verify-commits.sh index 5841fa207..9ba781008 100755 --- a/contrib/verify-commits/verify-commits.sh +++ b/contrib/verify-commits/verify-commits.sh @@ -7,11 +7,23 @@ git log "$DIR" VERIFIED_ROOT=$(cat "${DIR}/trusted-git-root") +IS_REVSIG_ALLOWED () { + while read LINE; do + [ "$LINE" = "$1" ] && return 0 + done < "${DIR}/allow-revsig-commits" + return 1 +} + HAVE_FAILED=false IS_SIGNED () { if [ $1 = $VERIFIED_ROOT ]; then return 0; fi + if IS_REVSIG_ALLOWED "$1"; then + export BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG=1 + else + export BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG=0 + fi if ! git -c "gpg.program=${DIR}/gpg.sh" verify-commit $1 > /dev/null 2>&1; then return 1; fi diff --git a/contrib/verifysfbinaries/README.md b/contrib/verifysfbinaries/README.md index 8c038865b..1db3fe52f 100644 --- a/contrib/verifysfbinaries/README.md +++ b/contrib/verifysfbinaries/README.md @@ -1,6 +1,6 @@ -### Verify SF Binaries ### +### Verify Binaries ### This script attempts to download the signature file `SHA256SUMS.asc` from https://bitcoin.org. It first checks if the signature passes, and then downloads the files specified in the file, and checks if the hashes of these files match those that are specified in the signature file. -The script returns 0 if everything passes the checks. It returns 1 if either the signature check or the hash check doesn't pass. If an error occurs the return value is 2. \ No newline at end of file +The script returns 0 if everything passes the checks. It returns 1 if either the signature check or the hash check doesn't pass. If an error occurs the return value is 2. diff --git a/contrib/verifysfbinaries/verify.sh b/contrib/verifysfbinaries/verify.sh index 3eb469388..847c50755 100755 --- a/contrib/verifysfbinaries/verify.sh +++ b/contrib/verifysfbinaries/verify.sh @@ -17,15 +17,15 @@ function clean_up { WORKINGDIR="/tmp/bitcoin" TMPFILE="hashes.tmp" -#this URL is used if a version number is not specified as an argument to the script -SIGNATUREFILE="https://bitcoin.org/bin/0.9.2.1/SHA256SUMS.asc" - SIGNATUREFILENAME="SHA256SUMS.asc" RCSUBDIR="test/" BASEDIR="https://bitcoin.org/bin/" -VERSIONPREFIX="bitcoin-" +VERSIONPREFIX="bitcoin-core-" RCVERSIONSTRING="rc" +#this URL is used if a version number is not specified as an argument to the script +SIGNATUREFILE="$BASEDIR""$VERSIONPREFIX""0.10.4/""$RCSUBDIR""$SIGNATUREFILENAME" + if [ ! -d "$WORKINGDIR" ]; then mkdir "$WORKINGDIR" fi @@ -62,7 +62,7 @@ WGETOUT=$(wget -N "$BASEDIR$SIGNATUREFILENAME" 2>&1) #and then see if wget completed successfully if [ $? -ne 0 ]; then echo "Error: couldn't fetch signature file. Have you specified the version number in the following format?" - echo "[bitcoin-]-[rc[0-9]] (example: bitcoin-0.9.2-rc1)" + echo "[$VERSIONPREFIX]-[$RCVERSIONSTRING[0-9]] (example: "$VERSIONPREFIX"0.10.4-"$RCVERSIONSTRING"1)" echo "wget output:" echo "$WGETOUT"|sed 's/^/\t/g' exit 2 @@ -82,7 +82,7 @@ if [ $RET -ne 0 ]; then echo "Bad signature." elif [ $RET -eq 2 ]; then #or if a gpg error has occurred - echo "gpg error. Do you have Gavin's code signing key installed?" + echo "gpg error. Do you have the Bitcoin Core binary release signing key installed?" fi echo "gpg output:" @@ -116,4 +116,6 @@ fi #everything matches! clean up the mess clean_up $FILES $SIGNATUREFILENAME $TMPFILE +echo -e "Verified hashes of \n$FILES" + exit 0 diff --git a/depends/Makefile b/depends/Makefile index ef5a20e6c..3ddfc85a4 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -15,6 +15,8 @@ BASEDIR = $(CURDIR) HASH_LENGTH:=11 DOWNLOAD_CONNECT_TIMEOUT:=10 DOWNLOAD_RETRIES:=3 +HOST_ID_SALT ?= salt +BUILD_ID_SALT ?= salt host:=$(BUILD) ifneq ($(HOST),) @@ -73,6 +75,20 @@ include builders/$(build_os).mk include builders/default.mk include packages/packages.mk +build_id_string:=$(BUILD_ID_SALT) +build_id_string+=$(shell $(build_CC) --version 2>/dev/null) +build_id_string+=$(shell $(build_AR) --version 2>/dev/null) +build_id_string+=$(shell $(build_CXX) --version 2>/dev/null) +build_id_string+=$(shell $(build_RANLIB) --version 2>/dev/null) +build_id_string+=$(shell $(build_STRIP) --version 2>/dev/null) + +$(host_arch)_$(host_os)_id_string:=$(HOST_ID_SALT) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_CC) --version 2>/dev/null) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_AR) --version 2>/dev/null) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_CXX) --version 2>/dev/null) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_RANLIB) --version 2>/dev/null) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_STRIP) --version 2>/dev/null) + qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) qt_native_packages_$(NO_QT) = $(qt_native_packages) wallet_packages_$(NO_WALLET) = $(wallet_packages) @@ -90,7 +106,7 @@ include funcs.mk toolchain_path=$($($(host_arch)_$(host_os)_native_toolchain)_prefixbin) final_build_id_long+=$(shell $(build_SHA256SUM) config.site.in) -final_build_id+=$(shell echo -n $(final_build_id_long) | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH)) +final_build_id+=$(shell echo -n "$(final_build_id_long)" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH)) $(host_prefix)/.stamp_$(final_build_id): $(native_packages) $(packages) $(AT)rm -rf $(@D) $(AT)mkdir -p $(@D) @@ -131,9 +147,9 @@ endef define check_or_remove_sources mkdir -p $($(package)_source_dir); cd $($(package)_source_dir); \ - $(build_SHA256SUM) -c $($(package)_fetched) >/dev/null 2>/dev/null || \ - ( if test -f $($(package)_all_sources); then echo "Checksum missing or mismatched for $(package) source. Forcing re-download."; fi; \ - rm -f $($(package)_all_sources) $($(1)_fetched)) + test -f $($(package)_fetched) && ( $(build_SHA256SUM) -c $($(package)_fetched) >/dev/null 2>/dev/null || \ + ( echo "Checksum missing or mismatched for $(package) source. Forcing re-download."; \ + rm -f $($(package)_all_sources) $($(1)_fetched))) || true endef check-packages: diff --git a/depends/README.md b/depends/README.md index d85e652c6..271bbd80b 100644 --- a/depends/README.md +++ b/depends/README.md @@ -38,6 +38,8 @@ The following can be set when running make: make FOO=bar NO_WALLET: Don't download/build/cache libs needed to enable the wallet NO_UPNP: Don't download/build/cache packages needed for enabling upnp DEBUG: disable some optimizations and enable more runtime checking + HOST_ID_SALT: Optional salt to use when generating host package ids + BUILD_ID_SALT: Optional salt to use when generating build package ids If some packages are not built, for example `make NO_WALLET=1`, the appropriate options will be passed to bitcoin's configure. In this case, `--disable-wallet`. diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index b366460e6..200d6ed22 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -7,7 +7,7 @@ build_darwin_OTOOL: = $(shell xcrun -f otool) build_darwin_NM: = $(shell xcrun -f nm) build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) build_darwin_SHA256SUM = shasum -a 256 -build_darwin_DOWNLOAD = curl --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -o +build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o #darwin host on darwin builder. overrides darwin host preferences. darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) diff --git a/depends/builders/linux.mk b/depends/builders/linux.mk index 98d0e9de3..b03f42401 100644 --- a/depends/builders/linux.mk +++ b/depends/builders/linux.mk @@ -1,2 +1,2 @@ build_linux_SHA256SUM = sha256sum -build_linux_DOWNLOAD = wget --timeout=$(DOWNLOAD_CONNECT_TIMEOUT) --tries=$(DOWNLOAD_RETRIES) -nv -O +build_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o diff --git a/depends/config.guess b/depends/config.guess index 3c022c5bb..373a659a0 100755 --- a/depends/config.guess +++ b/depends/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2015 Free Software Foundation, Inc. +# Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2015-09-14' +timestamp='2016-02-11' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -27,7 +27,7 @@ timestamp='2015-09-14' # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2015 Free Software Foundation, Inc. +Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -237,6 +237,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; @@ -268,42 +272,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV4.5 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV5 (21164)") - UNAME_MACHINE="alphaev5" ;; + UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") - UNAME_MACHINE="alphaev56" ;; + UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") - UNAME_MACHINE="alphapca56" ;; + UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") - UNAME_MACHINE="alphapca57" ;; + UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") - UNAME_MACHINE="alphaev6" ;; + UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") - UNAME_MACHINE="alphaev67" ;; + UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") - UNAME_MACHINE="alphaev69" ;; + UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") - UNAME_MACHINE="alphaev7" ;; + UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") - UNAME_MACHINE="alphaev79" ;; + UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 @@ -376,16 +380,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build - SUN_ARCH="i386" + SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then - SUN_ARCH="x86_64" + SUN_ARCH=x86_64 fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` @@ -410,7 +414,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} @@ -635,13 +639,13 @@ EOF sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi @@ -684,7 +688,7 @@ EOF test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ ${HP_ARCH} = "hppa2.0w" ] + if [ ${HP_ARCH} = hppa2.0w ] then eval $set_cc_for_build @@ -700,9 +704,9 @@ EOF if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then - HP_ARCH="hppa2.0w" + HP_ARCH=hppa2.0w else - HP_ARCH="hppa64" + HP_ARCH=hppa64 fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} @@ -807,14 +811,14 @@ EOF echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) @@ -919,7 +923,7 @@ EOF EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) @@ -1123,7 +1127,7 @@ EOF # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configury will decide that + # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; @@ -1285,7 +1289,7 @@ EOF UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null @@ -1309,7 +1313,7 @@ EOF exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = "x86"; then + if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi @@ -1340,7 +1344,7 @@ EOF # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. - if test "$cputype" = "386"; then + if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" @@ -1393,6 +1397,9 @@ EOF x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; esac cat >&2 < $$($(1)_download_dir)/.$(4).hash && \ $(build_SHA256SUM) -c $$($(1)_download_dir)/.$(4).hash && \ mv $$($(1)_download_dir)/$(4).temp $$($(1)_source_dir)/$(4) && \ - rm -rf $$($(1)_download_dir) )) + rm -rf $$($(1)_download_dir) ) +endef + +define fetch_file + ( test -f $$($(1)_source_dir)/$(4) || \ + ( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \ + $(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5)))) endef define int_get_build_recipe_hash @@ -39,7 +43,7 @@ define int_get_build_id $(eval $(1)_dependencies += $($(1)_$(host_arch)_$(host_os)_dependencies) $($(1)_$(host_os)_dependencies)) $(eval $(1)_all_dependencies:=$(call int_get_all_dependencies,$(1),$($($(1)_type)_native_toolchain) $($(1)_dependencies))) $(foreach dep,$($(1)_all_dependencies),$(eval $(1)_build_id_deps+=$(dep)-$($(dep)_version)-$($(dep)_recipe_hash))) -$(eval $(1)_build_id_long:=$(1)-$($(1)_version)-$($(1)_recipe_hash)-$(release_type) $($(1)_build_id_deps)) +$(eval $(1)_build_id_long:=$(1)-$($(1)_version)-$($(1)_recipe_hash)-$(release_type) $($(1)_build_id_deps) $($($(1)_type)_id_string)) $(eval $(1)_build_id:=$(shell echo -n "$($(1)_build_id_long)" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH))) final_build_id_long+=$($(package)_build_id_long) diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk index 68841afdb..e2f85ad4f 100644 --- a/depends/packages/bdb.mk +++ b/depends/packages/bdb.mk @@ -12,7 +12,8 @@ $(package)_config_opts_linux=--with-pic endef define $(package)_preprocess_cmds - sed -i.old 's/__atomic_compare_exchange/__atomic_compare_exchange_db/' dbinc/atomic.h + sed -i.old 's/__atomic_compare_exchange/__atomic_compare_exchange_db/' dbinc/atomic.h && \ + 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 endef define $(package)_config_cmds diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index d27a70134..215c694b6 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,8 +1,8 @@ package=boost -$(package)_version=1_58_0 -$(package)_download_path=http://sourceforge.net/projects/boost/files/boost/1.58.0 +$(package)_version=1_59_0 +$(package)_download_path=http://sourceforge.net/projects/boost/files/boost/1.59.0 $(package)_file_name=$(package)_$($(package)_version).tar.bz2 -$(package)_sha256_hash=fdfc204fc33ec79c99b9a74944c3e54bd78be4f7f15e260c0e2700a36dc7d3e5 +$(package)_sha256_hash=727a932322d94287b62abb1bd2d41723eec4356a7728909e38adb65ca25241ca define $(package)_set_vars $(package)_config_opts_release=variant=release diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk index 77bae10c7..45fa03631 100644 --- a/depends/packages/miniupnpc.mk +++ b/depends/packages/miniupnpc.mk @@ -1,12 +1,12 @@ package=miniupnpc -$(package)_version=1.9.20151008 +$(package)_version=1.9.20160209 $(package)_download_path=http://miniupnp.free.fr/files $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=e444ac3b587ce82709c4d0cfca1fe71f44f9fc433e9f946b12b9e1bfe667a633 +$(package)_sha256_hash=572171eacc1d72537ce47b6f4571260757ab7bcfdaf54c3a55c7f88594d94b6f define $(package)_set_vars $(package)_build_opts=CC="$($(package)_cc)" -$(package)_build_opts_darwin=OS=Darwin +$(package)_build_opts_darwin=OS=Darwin LIBTOOL="$($(package)_libtool)" $(package)_build_opts_mingw32=-f Makefile.mingw $(package)_build_env+=CFLAGS="$($(package)_cflags) $($(package)_cppflags)" AR="$($(package)_ar)" endef diff --git a/depends/packages/native_biplist.mk b/depends/packages/native_biplist.mk new file mode 100644 index 000000000..eb8672d55 --- /dev/null +++ b/depends/packages/native_biplist.mk @@ -0,0 +1,15 @@ +package=native_biplist +$(package)_version=0.9 +$(package)_download_path=https://pypi.python.org/packages/source/b/biplist +$(package)_file_name=biplist-$($(package)_version).tar.gz +$(package)_sha256_hash=b57cadfd26e4754efdf89e9e37de87885f9b5c847b2615688ca04adfaf6ca604 +$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages + +define $(package)_build_cmds + python setup.py build +endef + +define $(package)_stage_cmds + mkdir -p $($(package)_install_libdir) && \ + python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) +endef diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk index 317674f79..cc76f9a79 100644 --- a/depends/packages/native_ccache.mk +++ b/depends/packages/native_ccache.mk @@ -1,8 +1,8 @@ package=native_ccache -$(package)_version=3.2.3 +$(package)_version=3.2.4 $(package)_download_path=http://samba.org/ftp/ccache $(package)_file_name=ccache-$($(package)_version).tar.bz2 -$(package)_sha256_hash=b07165d4949d107d17f2f84b90b52953617bf1abbf249d5cc20636f43337c98c +$(package)_sha256_hash=ffeb967edb549e67da0bd5f44f729a2022de9fdde65dfd80d2a7204d7f75332e define $(package)_set_vars $(package)_config_opts= diff --git a/depends/packages/native_cctools.mk b/depends/packages/native_cctools.mk index 1c1bcf199..b5603a8d4 100644 --- a/depends/packages/native_cctools.mk +++ b/depends/packages/native_cctools.mk @@ -17,6 +17,10 @@ $(call fetch_file,$(package),$($(package)_clang_download_path),$($(package)_clan endef define $(package)_extract_cmds + mkdir -p $($(package)_extract_dir) && \ + echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_clang_sha256_hash) $($(package)_source_dir)/$($(package)_clang_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ mkdir -p toolchain/bin toolchain/lib/clang/3.5/include && \ tar --strip-components=1 -C toolchain -xf $($(package)_source_dir)/$($(package)_clang_file_name) && \ echo "#!/bin/sh" > toolchain/bin/$(host)-dsymutil && \ diff --git a/depends/packages/native_ds_store.mk b/depends/packages/native_ds_store.mk new file mode 100644 index 000000000..8e902af1b --- /dev/null +++ b/depends/packages/native_ds_store.mk @@ -0,0 +1,17 @@ +package=native_ds_store +$(package)_version=c80c23706eae +$(package)_download_path=https://bitbucket.org/al45tair/ds_store/get +$(package)_download_file=$($(package)_version).tar.bz2 +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=ce1aa412211610c63d567bbe3e06213006a2d5ba5d76d89399c151b5472cb0da +$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages +$(package)_dependencies=native_biplist + +define $(package)_build_cmds + python setup.py build +endef + +define $(package)_stage_cmds + mkdir -p $($(package)_install_libdir) && \ + python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) +endef diff --git a/depends/packages/native_mac_alias.mk b/depends/packages/native_mac_alias.mk new file mode 100644 index 000000000..d117c1c9a --- /dev/null +++ b/depends/packages/native_mac_alias.mk @@ -0,0 +1,16 @@ +package=native_mac_alias +$(package)_version=1.1.0 +$(package)_download_path=https://bitbucket.org/al45tair/mac_alias/get +$(package)_download_file=v$($(package)_version).tar.bz2 +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=87ad827e66790028361e43fc754f68ed041a9bdb214cca03c853f079b04fb120 +$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages + +define $(package)_build_cmds + python setup.py build +endef + +define $(package)_stage_cmds + mkdir -p $($(package)_install_libdir) && \ + python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) +endef diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index 687aae668..c6452820a 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -17,6 +17,7 @@ $(package)_config_opts_arm_linux=linux-generic32 $(package)_config_opts_aarch64_linux=linux-generic64 $(package)_config_opts_mipsel_linux=linux-generic32 $(package)_config_opts_mips_linux=linux-generic32 +$(package)_config_opts_powerpc_linux=linux-generic32 $(package)_config_opts_x86_64_darwin=darwin64-x86_64-cc $(package)_config_opts_x86_64_mingw32=mingw64 $(package)_config_opts_i686_mingw32=mingw diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 02cc18842..59b009b66 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -15,6 +15,8 @@ wallet_packages=bdb upnp_packages=miniupnpc +darwin_native_packages = native_biplist native_ds_store native_mac_alias + ifneq ($(build_os),darwin) -darwin_native_packages=native_cctools native_cdrkit native_libdmg-hfsplus +darwin_native_packages += native_cctools native_cdrkit native_libdmg-hfsplus endif diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index cba2fbd15..77df77b73 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -8,7 +8,7 @@ $(package)_dependencies=openssl $(package)_linux_dependencies=freetype fontconfig dbus libxcb libX11 xproto libXext $(package)_build_subdir=qtbase $(package)_qt_libs=corelib network widgets gui plugins testlib -$(package)_patches=mac-qmake.conf fix-xcb-include-order.patch mingw-uuidof.patch +$(package)_patches=mac-qmake.conf fix-xcb-include-order.patch mingw-uuidof.patch pidlist_absolute.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) $(package)_qttranslations_sha256_hash=c4bd6db6e426965c6f8824c54e81f68bbd61e2bae1bcadc328c6e81c45902a0d @@ -108,8 +108,8 @@ endef define $(package)_extract_cmds mkdir -p $($(package)_extract_dir) && \ echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ - echo "$($(package)_qttranslations_sha256_hash) $($(package)_source_dir)/$($(package)_qttranslations_file_name)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ - echo "$($(package)_qttools_sha256_hash) $($(package)_source_dir)/$($(package)_qttools_file_name)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_qttranslations_sha256_hash) $($(package)_source_dir)/$($(package)_qttranslations_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_qttools_sha256_hash) $($(package)_source_dir)/$($(package)_qttools_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ mkdir qtbase && \ tar --strip-components=1 -xf $($(package)_source) -C qtbase && \ @@ -122,9 +122,6 @@ endef define $(package)_preprocess_cmds sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \ sed -i.old "s/src_plugins.depends = src_sql src_xml src_network/src_plugins.depends = src_xml src_network/" qtbase/src/src.pro && \ - sed -i.old "s/PIDLIST_ABSOLUTE/ITEMIDLIST */" qtbase/src/plugins/platforms/windows/qwindowscontext.h &&\ - sed -i.old "s/PIDLIST_ABSOLUTE/ITEMIDLIST */" qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp &&\ - sed -i.old "s/PCIDLIST_ABSOLUTE/const ITEMIDLIST */" qtbase/src/plugins/platforms/windows/qwindowscontext.h &&\ sed -i.old "s|X11/extensions/XIproto.h|X11/X.h|" qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp && \ sed -i.old 's/if \[ "$$$$XPLATFORM_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/if \[ "$$$$BUILD_ON_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/' qtbase/configure && \ mkdir -p qtbase/mkspecs/macx-clang-linux &&\ @@ -134,6 +131,7 @@ define $(package)_preprocess_cmds cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \ patch -p1 < $($(package)_patch_dir)/fix-xcb-include-order.patch && \ patch -p1 < $($(package)_patch_dir)/mingw-uuidof.patch && \ + patch -p1 < $($(package)_patch_dir)/pidlist_absolute.patch && \ echo "QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index 24e8e5f1c..7b866e9c0 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -1,8 +1,8 @@ package=zeromq -$(package)_version=4.0.4 +$(package)_version=4.0.7 $(package)_download_path=http://download.zeromq.org $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=1ef71d46e94f33e27dd5a1661ed626cd39be4d2d6967792a275040e34457d399 +$(package)_sha256_hash=e00b2967e074990d0538361cc79084a0a92892df2c6e7585da34e4c61ee47b03 define $(package)_set_vars $(package)_config_opts=--without-documentation --disable-shared diff --git a/depends/patches/boost/darwin_boost_atomic-1.patch b/depends/patches/boost/darwin_boost_atomic-1.patch deleted file mode 100644 index 97f59cb7e..000000000 --- a/depends/patches/boost/darwin_boost_atomic-1.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff --git a/include/boost/atomic/detail/cas128strong.hpp b/include/boost/atomic/detail/cas128strong.hpp -index 906c13e..dcb4d7d 100644 ---- a/include/boost/atomic/detail/cas128strong.hpp -+++ b/include/boost/atomic/detail/cas128strong.hpp -@@ -196,15 +196,17 @@ class base_atomic - - public: - BOOST_DEFAULTED_FUNCTION(base_atomic(void), {}) -- explicit base_atomic(value_type const& v) BOOST_NOEXCEPT : v_(0) -+ explicit base_atomic(value_type const& v) BOOST_NOEXCEPT - { -+ memset(&v_, 0, sizeof(v_)); - memcpy(&v_, &v, sizeof(value_type)); - } - - void - store(value_type const& value, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT - { -- storage_type value_s = 0; -+ storage_type value_s; -+ memset(&value_s, 0, sizeof(value_s)); - memcpy(&value_s, &value, sizeof(value_type)); - platform_fence_before_store(order); - platform_store128(value_s, &v_); -@@ -247,7 +249,9 @@ class base_atomic - memory_order success_order, - memory_order failure_order) volatile BOOST_NOEXCEPT - { -- storage_type expected_s = 0, desired_s = 0; -+ storage_type expected_s, desired_s; -+ memset(&expected_s, 0, sizeof(expected_s)); -+ memset(&desired_s, 0, sizeof(desired_s)); - memcpy(&expected_s, &expected, sizeof(value_type)); - memcpy(&desired_s, &desired, sizeof(value_type)); - diff --git a/depends/patches/boost/darwin_boost_atomic-2.patch b/depends/patches/boost/darwin_boost_atomic-2.patch deleted file mode 100644 index ca5076520..000000000 --- a/depends/patches/boost/darwin_boost_atomic-2.patch +++ /dev/null @@ -1,55 +0,0 @@ -diff --git a/include/boost/atomic/detail/gcc-atomic.hpp b/include/boost/atomic/detail/gcc-atomic.hpp -index a130590..4af99a1 100644 ---- a/include/boost/atomic/detail/gcc-atomic.hpp -+++ b/include/boost/atomic/detail/gcc-atomic.hpp -@@ -958,14 +958,16 @@ class base_atomic - - public: - BOOST_DEFAULTED_FUNCTION(base_atomic(void), {}) -- explicit base_atomic(value_type const& v) BOOST_NOEXCEPT : v_(0) -+ explicit base_atomic(value_type const& v) BOOST_NOEXCEPT - { -+ memset(&v_, 0, sizeof(v_)); - memcpy(&v_, &v, sizeof(value_type)); - } - - void store(value_type const& v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT - { -- storage_type tmp = 0; -+ storage_type tmp; -+ memset(&tmp, 0, sizeof(tmp)); - memcpy(&tmp, &v, sizeof(value_type)); - __atomic_store_n(&v_, tmp, atomics::detail::convert_memory_order_to_gcc(order)); - } -@@ -980,7 +982,8 @@ class base_atomic - - value_type exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT - { -- storage_type tmp = 0; -+ storage_type tmp; -+ memset(&tmp, 0, sizeof(tmp)); - memcpy(&tmp, &v, sizeof(value_type)); - tmp = __atomic_exchange_n(&v_, tmp, atomics::detail::convert_memory_order_to_gcc(order)); - value_type res; -@@ -994,7 +997,9 @@ class base_atomic - memory_order success_order, - memory_order failure_order) volatile BOOST_NOEXCEPT - { -- storage_type expected_s = 0, desired_s = 0; -+ storage_type expected_s, desired_s; -+ memset(&expected_s, 0, sizeof(expected_s)); -+ memset(&desired_s, 0, sizeof(desired_s)); - memcpy(&expected_s, &expected, sizeof(value_type)); - memcpy(&desired_s, &desired, sizeof(value_type)); - const bool success = __atomic_compare_exchange_n(&v_, &expected_s, desired_s, false, -@@ -1010,7 +1015,9 @@ class base_atomic - memory_order success_order, - memory_order failure_order) volatile BOOST_NOEXCEPT - { -- storage_type expected_s = 0, desired_s = 0; -+ storage_type expected_s, desired_s; -+ memset(&expected_s, 0, sizeof(expected_s)); -+ memset(&desired_s, 0, sizeof(desired_s)); - memcpy(&expected_s, &expected, sizeof(value_type)); - memcpy(&desired_s, &desired, sizeof(value_type)); - const bool success = __atomic_compare_exchange_n(&v_, &expected_s, desired_s, true, diff --git a/depends/patches/boost/gcc_5_no_cxx11.patch b/depends/patches/boost/gcc_5_no_cxx11.patch deleted file mode 100644 index 04514c593..000000000 --- a/depends/patches/boost/gcc_5_no_cxx11.patch +++ /dev/null @@ -1,37 +0,0 @@ -From eec808554936ae068b23df07ab54d4dc6302a695 Mon Sep 17 00:00:00 2001 -From: jzmaddock -Date: Sat, 23 Aug 2014 09:38:02 +0100 -Subject: [PATCH] Fix BOOST_NO_CXX11_VARIADIC_TEMPLATES definition - the - feature was introduced in GCC 4.4. - ---- - include/boost/config/compiler/gcc.hpp | 9 +-------- - 1 file changed, 1 insertion(+), 8 deletions(-) - -diff --git a/include/boost/config/compiler/gcc.hpp b/include/boost/config/compiler/gcc.hpp -index f37159d..97d8a18 100644 ---- a/include/boost/config/compiler/gcc.hpp -+++ b/include/boost/config/compiler/gcc.hpp -@@ -154,14 +154,6 @@ - # define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS - # define BOOST_NO_CXX11_RVALUE_REFERENCES - # define BOOST_NO_CXX11_STATIC_ASSERT -- --// Variadic templates compiler: --// http://www.generic-programming.org/~dgregor/cpp/variadic-templates.html --# if defined(__VARIADIC_TEMPLATES) || (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4) && defined(__GXX_EXPERIMENTAL_CXX0X__)) --# define BOOST_HAS_VARIADIC_TMPL --# else --# define BOOST_NO_CXX11_VARIADIC_TEMPLATES --# endif - #endif - - // C++0x features in 4.4.n and later -@@ -176,6 +168,7 @@ - # define BOOST_NO_CXX11_DELETED_FUNCTIONS - # define BOOST_NO_CXX11_TRAILING_RESULT_TYPES - # define BOOST_NO_CXX11_INLINE_NAMESPACES -+# define BOOST_NO_CXX11_VARIADIC_TEMPLATES - #endif - - #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) diff --git a/depends/patches/qt/pidlist_absolute.patch b/depends/patches/qt/pidlist_absolute.patch new file mode 100644 index 000000000..0b49c050d --- /dev/null +++ b/depends/patches/qt/pidlist_absolute.patch @@ -0,0 +1,37 @@ +diff -dur old/qtbase/src/plugins/platforms/windows/qwindowscontext.h new/qtbase/src/plugins/platforms/windows/qwindowscontext.h +--- old/qtbase/src/plugins/platforms/windows/qwindowscontext.h 2015-06-29 22:04:40.000000000 +0200 ++++ new/qtbase/src/plugins/platforms/windows/qwindowscontext.h 2015-11-01 12:55:59.751234846 +0100 +@@ -124,10 +124,18 @@ + inline void init(); + + typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **); ++#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) ++ typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, ITEMIDLIST **); ++#else + typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, PIDLIST_ABSOLUTE *); ++#endif + typedef HRESULT (WINAPI *SHGetStockIconInfo)(int , int , _SHSTOCKICONINFO *); + typedef HRESULT (WINAPI *SHGetImageList)(int, REFIID , void **); ++#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) ++ typedef HRESULT (WINAPI *SHCreateItemFromIDList)(const ITEMIDLIST *, REFIID, void **); ++#else + typedef HRESULT (WINAPI *SHCreateItemFromIDList)(PCIDLIST_ABSOLUTE, REFIID, void **); ++#endif + + SHCreateItemFromParsingName sHCreateItemFromParsingName; + SHGetKnownFolderIDList sHGetKnownFolderIDList; +diff -dur old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +--- old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp 2015-06-29 22:04:40.000000000 +0200 ++++ new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp 2015-11-01 13:41:09.503149772 +0100 +@@ -1008,7 +1008,11 @@ + qWarning() << __FUNCTION__ << ": Invalid CLSID: " << url.path(); + return Q_NULLPTR; + } ++#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) ++ ITEMIDLIST *idList; ++#else + PIDLIST_ABSOLUTE idList; ++#endif + HRESULT hr = QWindowsContext::shell32dll.sHGetKnownFolderIDList(uuid, 0, 0, &idList); + if (FAILED(hr)) { + qErrnoWarning("%s: SHGetKnownFolderIDList(%s)) failed", __FUNCTION__, qPrintable(url.toString())); diff --git a/doc/Doxyfile b/doc/Doxyfile index 925a33ee8..428fba98e 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -34,7 +34,7 @@ PROJECT_NAME = Bitcoin # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 0.11.99 +PROJECT_NUMBER = 0.12.99 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer diff --git a/doc/README.md b/doc/README.md index 08fd72435..cf475ef18 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,4 +1,4 @@ -Bitcoin Core 0.11.99 +Bitcoin Core 0.12.99 ===================== Setup @@ -28,7 +28,7 @@ Unpack the files into a directory, and then run bitcoin-qt.exe. ### OS X -Drag Bitcoin-Qt to your applications folder, and then run Bitcoin-Qt. +Drag Bitcoin-Core to your applications folder, and then run Bitcoin-Core. ### Need Help? @@ -43,11 +43,13 @@ The following are developer notes on how to build Bitcoin on your native platfor - [OS X Build Notes](build-osx.md) - [Unix Build Notes](build-unix.md) +- [Windows Build Notes](build-windows.md) +- [OpenBSD Build Notes](build-openbsd.md) - [Gitian Building Guide](gitian-building.md) Development --------------------- -The Bitcoin repo's [root README](https://github.com/bitcoin/bitcoin/blob/master/README.md) contains relevant information on the development process and automated testing. +The Bitcoin repo's [root README](/README.md) contains relevant information on the development process and automated testing. - [Developer Notes](developer-notes.md) - [Multiwallet Qt Development](multiwallet-qt.md) diff --git a/doc/README_osx.txt b/doc/README_osx.txt index f589bfc67..c13efaa14 100644 --- a/doc/README_osx.txt +++ b/doc/README_osx.txt @@ -63,9 +63,8 @@ functionality is broken. Only the compression feature is currently used. Ideally, the creation could be fixed and genisoimage would no longer be necessary. Background images and other features can be added to DMG files by inserting a -.DS_Store before creation. The easiest way to create this file is to build a -DMG without one, move it to a device running OS X, customize the layout, then -grab the .DS_Store file for later use. That is the approach taken here. +.DS_Store before creation. This is generated by the script +contrib/macdeploy/custom_dsstore.py. As of OS X Mavericks (10.9), using an Apple-blessed key to sign binaries is a requirement in order to satisfy the new Gatekeeper requirements. Because this diff --git a/doc/README_windows.txt b/doc/README_windows.txt index e4fd9bdf9..2d1c4503c 100644 --- a/doc/README_windows.txt +++ b/doc/README_windows.txt @@ -1,4 +1,4 @@ -Bitcoin Core 0.11.99 +Bitcoin Core 0.12.99 ===================== Intro diff --git a/doc/bips.md b/doc/bips.md index c84bd966f..b8efabbcf 100644 --- a/doc/bips.md +++ b/doc/bips.md @@ -14,6 +14,10 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.12.0**): * [`BIP 37`](https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki): The bloom filtering for transaction relaying, partial merkle trees for blocks, and the protocol version bump to 70001 (enabling low-bandwidth SPV clients) has been implemented since **v0.8.0** ([PR #1795](https://github.com/bitcoin/bitcoin/pull/1795)). * [`BIP 42`](https://github.com/bitcoin/bips/blob/master/bip-0042.mediawiki): The bug that would have caused the subsidy schedule to resume after block 13440000 was fixed in **v0.9.2** ([PR #3842](https://github.com/bitcoin/bitcoin/pull/3842)). * [`BIP 61`](https://github.com/bitcoin/bips/blob/master/bip-0061.mediawiki): The 'reject' protocol message (and the protocol version bump to 70002) was added in **v0.9.0** ([PR #3185](https://github.com/bitcoin/bitcoin/pull/3185)). +* [`BIP 65`](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki): The CHECKLOCKTIMEVERIFY softfork was merged in **v0.12.0** ([PR #6351](https://github.com/bitcoin/bitcoin/pull/6351)), and backported to **v0.11.2** and **v0.10.4**. Mempool-only CLTV was added in [PR #6124](https://github.com/bitcoin/bitcoin/pull/6124). * [`BIP 66`](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki): The strict DER rules and associated version 3 blocks have been implemented since **v0.10.0** ([PR #5713](https://github.com/bitcoin/bitcoin/pull/5713)). * [`BIP 70`](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki) [`71`](https://github.com/bitcoin/bips/blob/master/bip-0071.mediawiki) [`72`](https://github.com/bitcoin/bips/blob/master/bip-0072.mediawiki): Payment Protocol support has been available in Bitcoin Core GUI since **v0.9.0** ([PR #5216](https://github.com/bitcoin/bitcoin/pull/5216)). -* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, but only enforced for peer versions `>=70011` as of **v0.12.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579)). +* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, and enforced for all peer versions as of **v0.13.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579) and [PR #6641](https://github.com/bitcoin/bitcoin/pull/6641)). +* [`BIP 125`](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki): Opt-in full replace-by-fee signaling honoured in mempool and mining as of **v0.12.0** ([PR 6871](https://github.com/bitcoin/bitcoin/pull/6871)). +* [`BIP 130`](https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki): direct headers announcement is negotiated with peer versions `>=70012` as of **v0.12.0** ([PR 6494](https://github.com/bitcoin/bitcoin/pull/6494)). +* [`BIP 133`](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki): feefilter messages are respected and sent for peer versions `>=70013` as of **v0.13.0** ([PR 7542](https://github.com/bitcoin/bitcoin/pull/7542)). diff --git a/doc/build-osx.md b/doc/build-osx.md index 69c401b75..296e0aa1f 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -1,11 +1,11 @@ Mac OS X Build Instructions and Notes ==================================== -This guide will show you how to build bitcoind (headless client) for OS X. +This guide will show you how to build Bitcoin Core for OS X. Notes ----- -* Tested on OS X 10.7 through 10.10 on 64-bit Intel processors only. +* Tested on OS X 10.7 through 10.11 on 64-bit Intel processors only. * All of the commands should be executed in a Terminal application. The built-in one is located in `/Applications/Utilities`. @@ -24,7 +24,7 @@ be re-done or updated every time Xcode is updated. You will also need to install [Homebrew](http://brew.sh) in order to install library dependencies. -The installation of the actual dependencies is covered in the Instructions +The installation of the actual dependencies is covered in the instructions sections below. Instructions: Homebrew @@ -32,21 +32,23 @@ Instructions: Homebrew #### Install dependencies using Homebrew - brew install autoconf automake berkeley-db4 libtool boost miniupnpc openssl pkg-config protobuf qt5 libevent + brew install autoconf automake berkeley-db4 libtool boost miniupnpc openssl pkg-config protobuf qt5 libevent NOTE: Building with Qt4 is still supported, however, could result in a broken UI. As such, building with Qt5 is recommended. -### Building `bitcoind` +### Building `bitcoin` 1. Clone the GitHub tree to get the source code and go into the directory. git clone https://github.com/bitcoin/bitcoin.git cd bitcoin -2. Build bitcoind: +2. Build bitcoin-core: + This will configure and build the headless bitcoin binaries as well as the gui (if Qt is found). + You can disable the gui build by passing `--without-gui` to configure. ./autogen.sh - ./configure --with-gui=qt5 + ./configure make 3. It is also a good idea to build and run the unit tests: @@ -60,10 +62,10 @@ NOTE: Building with Qt4 is still supported, however, could result in a broken UI Use Qt Creator as IDE ------------------------ You can use Qt Creator as IDE, for debugging and for manipulating forms, etc. -Download Qt Creator from http://www.qt.io/download/. Download the "community edition" and only install Qt Creator (uncheck the rest during the installation process). +Download Qt Creator from https://www.qt.io/download/. Download the "community edition" and only install Qt Creator (uncheck the rest during the installation process). 1. Make sure you installed everything through Homebrew mentioned above -2. Do a proper ./configure --with-gui=qt5 --enable-debug +2. Do a proper ./configure --enable-debug 3. In Qt Creator do "New Project" -> Import Project -> Import Existing Project 4. Enter "bitcoin-qt" as project name, enter src/qt as location 5. Leave the file selection as it is @@ -79,7 +81,7 @@ You can ignore this section if you are building `bitcoind` for your own use. bitcoind/bitcoin-cli binaries are not included in the Bitcoin-Qt.app bundle. -If you are building `bitcoind` or `Bitcoin-Qt` for others, your build machine should be set up +If you are building `bitcoind` or `Bitcoin Core` for others, your build machine should be set up as follows for maximum compatibility: All dependencies should be compiled with these flags: @@ -88,7 +90,7 @@ All dependencies should be compiled with these flags: -arch x86_64 -isysroot $(xcode-select --print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk -Once dependencies are compiled, see [doc/release-process.md](release-process.md) for how the Bitcoin-Qt.app +Once dependencies are compiled, see [doc/release-process.md](release-process.md) for how the Bitcoin Core bundle is packaged and signed to create the .dmg disk image that is distributed. Running @@ -112,6 +114,16 @@ you can monitor its process by looking at the debug.log file, like this: Other commands: ------- - ./bitcoind -daemon # to start the bitcoin daemon. + ./bitcoind -daemon # to start the bitcoin daemon. ./bitcoin-cli --help # for a list of command-line options. ./bitcoin-cli help # When the daemon is running, to get a list of RPC commands + +Using Qt official installer while building +------------------------------------------ + +If you prefer to use the latest Qt installed from the official binary +installer over the brew version, you have to make several changes to +the installed tree and its binaries (all these changes are contained +in the brew version already). The changes needed are described in +[#7714](https://github.com/bitcoin/bitcoin/issues/7714). We do not +support building Bitcoin Core this way though. diff --git a/doc/build-unix.md b/doc/build-unix.md index a9a0028c4..dc754fc73 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -1,17 +1,17 @@ UNIX BUILD NOTES ==================== -Some notes on how to build Bitcoin in Unix. +Some notes on how to build Bitcoin Core in Unix. (for OpenBSD specific instructions, see [build-openbsd.md](build-openbsd.md)) Note --------------------- Always use absolute paths to configure and compile bitcoin and the dependencies, -for example, when specifying the the path of the dependency: +for example, when specifying the path of the dependency: ../dist/configure --enable-cxx --disable-shared --with-pic --prefix=$BDB_PREFIX -Here BDB_PREFIX must absolute path - it is defined using $(pwd) which ensures +Here BDB_PREFIX must be an absolute path - it is defined using $(pwd) which ensures the usage of the absolute path. To Build @@ -46,65 +46,77 @@ Optional dependencies: qt | GUI | GUI toolkit (only needed when GUI enabled) protobuf | Payments in GUI | Data interchange format used for payment protocol (only needed when GUI enabled) libqrencode | QR codes in GUI | Optional for generating QR codes (only needed when GUI enabled) + univalue | Utility | JSON parsing and encoding (bundled version will be used unless --with-system-univalue passed to configure) libzmq3 | ZMQ notification | Optional, allows generating ZMQ notifications (requires ZMQ version >= 4.x) For the versions used in the release, see [release-process.md](release-process.md) under *Fetch and build inputs*. -System requirements +Memory Requirements -------------------- -C++ compilers are memory-hungry. It is recommended to have at least 1 GB of -memory available when compiling Bitcoin Core. With 512MB of memory or less -compilation will take much longer due to swap thrashing. +C++ compilers are memory-hungry. It is recommended to have at least 1.5 GB of +memory available when compiling Bitcoin Core. On systems with less, gcc can be +tuned to conserve memory with additional CXXFLAGS: + + + ./configure CXXFLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768" Dependency Build Instructions: Ubuntu & Debian ---------------------------------------------- Build requirements: - sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev libevent-dev + sudo apt-get install build-essential libtool autotools-dev automake pkg-config libssl-dev libevent-dev bsdmainutils -For Ubuntu 12.04 and later or Debian 7 and later libboost-all-dev has to be installed: +Options when installing required Boost library files: - sudo apt-get install libboost-all-dev +1. On at least Ubuntu 14.04+ and Debian 7+ there are generic names for the +individual boost development packages, so the following can be used to only +install necessary parts of boost: - db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin). - You can add the repository using the following command: + sudo apt-get install libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev - sudo add-apt-repository ppa:bitcoin/bitcoin - sudo apt-get update +2. If that doesn't work, you can install all boost development packages with: - Ubuntu 12.04 and later have packages for libdb5.1-dev and libdb5.1++-dev, - but using these will break binary wallet compatibility, and is not recommended. + sudo apt-get install libboost-all-dev -For other Debian & Ubuntu (with ppa): +BerkeleyDB is required for the wallet. db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin). +You can add the repository and install using the following commands: - sudo apt-get install libdb4.8-dev libdb4.8++-dev + sudo add-apt-repository ppa:bitcoin/bitcoin + sudo apt-get update + sudo apt-get install libdb4.8-dev libdb4.8++-dev + +Ubuntu and Debian have their own libdb-dev and libdb++-dev packages, but these will install +BerkeleyDB 5.1 or later, which break binary wallet compatibility with the distributed executables which +are based on BerkeleyDB 4.8. If you do not care about wallet compatibility, +pass `--with-incompatible-bdb` to configure. + +See the section "Disable-wallet mode" to build Bitcoin Core without wallet. Optional: - sudo apt-get install libminiupnpc-dev (see --with-miniupnpc and --enable-upnp-default) + sudo apt-get install libminiupnpc-dev (see --with-miniupnpc and --enable-upnp-default) ZMQ dependencies: - sudo apt-get install libzmq3-dev (provides ZMQ API 4.x) - + sudo apt-get install libzmq3-dev (provides ZMQ API 4.x) Dependencies for the GUI: Ubuntu & Debian ----------------------------------------- If you want to build Bitcoin-Qt, make sure that the required packages for Qt development -are installed. Either Qt 4 or Qt 5 are necessary to build the GUI. -If both Qt 4 and Qt 5 are installed, Qt 4 will be used. Pass `--with-gui=qt5` to configure to choose Qt5. +are installed. Either Qt 5 or Qt 4 are necessary to build the GUI. +If both Qt 4 and Qt 5 are installed, Qt 5 will be used. Pass `--with-gui=qt4` to configure to choose Qt4. To build without GUI pass `--without-gui`. -To build with Qt 4 you need the following: - - sudo apt-get install libqt4-dev libprotobuf-dev protobuf-compiler - -For Qt 5 you need the following: +To build with Qt 5 (recommended) you need the following: sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler +Alternatively, to build with Qt 4 you need the following: + + sudo apt-get install libqt4-dev libprotobuf-dev protobuf-compiler + libqrencode (optional) can be installed with: sudo apt-get install libqrencode-dev @@ -129,14 +141,6 @@ turned off by default. See the configure options for upnp behavior desired: --disable-upnp-default (the default) UPnP support turned off by default at runtime --enable-upnp-default UPnP support turned on by default at runtime -To build: - - tar -xzvf miniupnpc-1.6.tar.gz - cd miniupnpc-1.6 - make - sudo su - make install - Berkeley DB ----------- @@ -207,6 +211,7 @@ Hardening enables the following features: scanelf -e ./bitcoin The output should contain: + TYPE ET_DYN @@ -237,3 +242,50 @@ In this case there is no dependency on Berkeley DB 4.8. Mining is also possible in disable-wallet mode, but only using the `getblocktemplate` RPC call not `getwork`. + +Additional Configure Flags +-------------------------- +A list of additional configure flags can be displayed with: + + ./configure --help + + +Setup and Build Example: Arch Linux +----------------------------------- +This example lists the steps necessary to setup and build a command line only, non-wallet distribution of the latest changes on Arch Linux: + + pacman -S git base-devel boost libevent python + git clone https://github.com/bitcoin/bitcoin.git + cd bitcoin/ + ./autogen.sh + ./configure --disable-wallet --without-gui --without-miniupnpc + make check + +Note: +Enabling wallet support requires either compiling against a Berkeley DB newer than 4.8 (package `db`) using `--with-incompatible-bdb`, +or building and depending on a local version of Berkeley DB 4.8. The readily available Arch Linux packages are currently built using +`--with-incompatible-bdb` according to the [PKGBUILD](https://projects.archlinux.org/svntogit/community.git/tree/bitcoin/trunk/PKGBUILD). +As mentioned above, when maintaining portability of the wallet between the standard Bitcoin Core distributions and independently built +node software is desired, Berkeley DB 4.8 must be used. + + +ARM Cross-compilation +------------------- +These steps can be performed on, for example, an Ubuntu VM. The depends system +will also work on other Linux distributions, however the commands for +installing the toolchain will be different. + +First install the toolchain: + + sudo apt-get install g++-arm-linux-gnueabihf + +To build executables for ARM: + + cd depends + make HOST=arm-linux-gnueabihf NO_QT=1 + cd .. + ./configure --prefix=$PWD/depends/arm-linux-gnueabihf --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++ + make + + +For further documentation on the depends system see [README.md](../depends/README.md) in the depends directory. diff --git a/doc/build-windows.md b/doc/build-windows.md new file mode 100644 index 000000000..2b9233d1e --- /dev/null +++ b/doc/build-windows.md @@ -0,0 +1,40 @@ +WINDOWS BUILD NOTES +==================== + +Some notes on how to build Bitcoin Core for Windows. + +Most developers use cross-compilation from Ubuntu to build executables for +Windows. This is also used to build the release binaries. + +Building on Windows itself is possible (for example using msys / mingw-w64), +but no one documented the steps to do this. If you are doing this, please contribute them. + +Cross-compilation +------------------- + +These steps can be performed on, for example, an Ubuntu VM. The depends system +will also work on other Linux distributions, however the commands for +installing the toolchain will be different. + +First install the toolchains: + + sudo apt-get install g++-mingw-w64-i686 mingw-w64-i686-dev g++-mingw-w64-x86-64 mingw-w64-x86-64-dev + +To build executables for Windows 32-bit: + + cd depends + make HOST=i686-w64-mingw32 -j4 + cd .. + ./configure --prefix=`pwd`/depends/i686-w64-mingw32 + make + +To build executables for Windows 64-bit: + + cd depends + make HOST=x86_64-w64-mingw32 -j4 + cd .. + ./configure --prefix=`pwd`/depends/x86_64-w64-mingw32 + make + +For further documentation on the depends system see [README.md](../depends/README.md) in the depends directory. + diff --git a/doc/developer-notes.md b/doc/developer-notes.md index 4189d2218..8affb2158 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -71,6 +71,12 @@ To describe a member or variable use: int var; //!< Detailed description after the member ``` +or +```cpp +//! Description before the member +int var; +``` + Also OK: ```c++ /// @@ -171,3 +177,205 @@ Threads - BitcoinMiner : Generates bitcoins (if wallet is enabled). - Shutdown : Does an orderly shutdown of everything. + +Ignoring IDE/editor files +-------------------------- + +In closed-source environments in which everyone uses the same IDE it is common +to add temporary files it produces to the project-wide `.gitignore` file. + +However, in open source software such as Bitcoin Core, where everyone uses +their own editors/IDE/tools, it is less common. Only you know what files your +editor produces and this may change from version to version. The canonical way +to do this is thus to create your local gitignore. Add this to `~/.gitconfig`: + +``` +[core] + excludesfile = /home/.../.gitignore_global +``` + +(alternatively, type the command `git config --global core.excludesfile ~/.gitignore_global` +on a terminal) + +Then put your favourite tool's temporary filenames in that file, e.g. +``` +# NetBeans +nbproject/ +``` + +Another option is to create a per-repository excludes file `.git/info/exclude`. +These are not committed but apply only to one repository. + +If a set of tools is used by the build system or scripts the repository (for +example, lcov) it is perfectly acceptable to add its files to `.gitignore` +and commit them. + +Development guidelines +============================ + +A few non-style-related recommendations for developers, as well as points to +pay attention to for reviewers of Bitcoin Core code. + +General Bitcoin Core +---------------------- + +- New features should be exposed on RPC first, then can be made available in the GUI + + - *Rationale*: RPC allows for better automatic testing. The test suite for + the GUI is very limited + +- Make sure pull requests pass Travis CI before merging + + - *Rationale*: Makes sure that they pass thorough testing, and that the tester will keep passing + on the master branch. Otherwise all new pull requests will start failing the tests, resulting in + confusion and mayhem + + - *Explanation*: If the test suite is to be updated for a change, this has to + be done first + +Wallet +------- + +- Make sure that no crashes happen with run-time option `-disablewallet`. + + - *Rationale*: In RPC code that conditionally uses the wallet (such as + `validateaddress`) it is easy to forget that global pointer `pwalletMain` + can be NULL. See `qa/rpc-tests/disablewallet.py` for functional tests + exercising the API with `-disablewallet` + +- Include `db_cxx.h` (BerkeleyDB header) only when `ENABLE_WALLET` is set + + - *Rationale*: Otherwise compilation of the disable-wallet build will fail in environments without BerkeleyDB + +General C++ +------------- + +- Assertions should not have side-effects + + - *Rationale*: Even though the source code is set to to refuse to compile + with assertions disabled, having side-effects in assertions is unexpected and + makes the code harder to understand + +- If you use the `.h`, you must link the `.cpp` + + - *Rationale*: Include files define the interface for the code in implementation files. Including one but + not linking the other is confusing. Please avoid that. Moving functions from + the `.h` to the `.cpp` should not result in build errors + +- Use the RAII (Resource Acquisition Is Initialization) paradigm where possible. For example by using + `scoped_pointer` for allocations in a function. + + - *Rationale*: This avoids memory and resource leaks, and ensures exception safety + +C++ data structures +-------------------- + +- Never use the `std::map []` syntax when reading from a map, but instead use `.find()` + + - *Rationale*: `[]` does an insert (of the default element) if the item doesn't + exist in the map yet. This has resulted in memory leaks in the past, as well as + race conditions (expecting read-read behavior). Using `[]` is fine for *writing* to a map + +- Do not compare an iterator from one data structure with an iterator of + another data structure (even if of the same type) + + - *Rationale*: Behavior is undefined. In C++ parlor this means "may reformat + the universe", in practice this has resulted in at least one hard-to-debug crash bug + +- Watch out for vector out-of-bounds exceptions. `&vch[0]` is illegal for an + empty vector, `&vch[vch.size()]` is always illegal. Use `begin_ptr(vch)` and + `end_ptr(vch)` to get the begin and end pointer instead (defined in + `serialize.h`) + +- Vector bounds checking is only enabled in debug mode. Do not rely on it + +- Make sure that constructors initialize all fields. If this is skipped for a + good reason (i.e., optimization on the critical path), add an explicit + comment about this + + - *Rationale*: Ensure determinism by avoiding accidental use of uninitialized + values. Also, static analyzers balk about this. + +- Use explicitly signed or unsigned `char`s, or even better `uint8_t` and + `int8_t`. Do not use bare `char` unless it is to pass to a third-party API. + This type can be signed or unsigned depending on the architecture, which can + lead to interoperability problems or dangerous conditions such as + out-of-bounds array accesses + +- Prefer explicit constructions over implicit ones that rely on 'magical' C++ behavior + + - *Rationale*: Easier to understand what is happening, thus easier to spot mistakes, even for those + that are not language lawyers + +Strings and formatting +------------------------ + +- Be careful of `LogPrint` versus `LogPrintf`. `LogPrint` takes a `category` argument, `LogPrintf` does not. + + - *Rationale*: Confusion of these can result in runtime exceptions due to + formatting mismatch, and it is easy to get wrong because of subtly similar naming + +- Use `std::string`, avoid C string manipulation functions + + - *Rationale*: C++ string handling is marginally safer, less scope for + buffer overflows and surprises with `\0` characters. Also some C string manipulations + tend to act differently depending on platform, or even the user locale + +- Use `ParseInt32`, `ParseInt64`, `ParseDouble` from `utilstrencodings.h` for number parsing + + - *Rationale*: These functions do overflow checking, and avoid pesky locale issues + +- For `strprintf`, `LogPrint`, `LogPrintf` formatting characters don't need size specifiers + + - *Rationale*: Bitcoin Core uses tinyformat, which is type safe. Leave them out to avoid confusion + +Threads and synchronization +---------------------------- + +- Build and run tests with `-DDEBUG_LOCKORDER` to verify that no potential + deadlocks are introduced. As of 0.12, this is defined by default when + configuring with `--enable-debug` + +- When using `LOCK`/`TRY_LOCK` be aware that the lock exists in the context of + the current scope, so surround the statement and the code that needs the lock + with braces + + OK: + +```c++ +{ + TRY_LOCK(cs_vNodes, lockNodes); + ... +} +``` + + Wrong: + +```c++ +TRY_LOCK(cs_vNodes, lockNodes); +{ + ... +} +``` + +Source code organization +-------------------------- + +- Implementation code should go into the `.cpp` file and not the `.h`, unless necessary due to template usage or + when performance due to inlining is critical + + - *Rationale*: Shorter and simpler header files are easier to read, and reduce compile time + +- Don't import anything into the global namespace (`using namespace ...`). Use + fully specified types such as `std::string`. + + - *Rationale*: Avoids symbol conflicts + +GUI +----- + +- Do not display or manipulate dialogs in model code (classes `*Model`) + + - *Rationale*: Model classes pass through events and data from the core, they + should not interact with the user. That's where View classes come in. The converse also + holds: try to not directly access core data structures from Views. diff --git a/doc/files.md b/doc/files.md index c083bcb03..f7eca57dc 100644 --- a/doc/files.md +++ b/doc/files.md @@ -12,6 +12,8 @@ * fee_estimates.dat: stores statistics used to estimate minimum transaction fees and priorities required for confirmation; since 0.10.0 * peers.dat: peer IP address database (custom format); since 0.7.0 * wallet.dat: personal wallet (BDB) with keys and transactions +* .cookie: session RPC authentication cookie (written at start when cookie authentication is used, deleted on shutdown): since 0.12.0 +* onion_private_key: cached Tor hidden service private key for `-listenonion`: since 0.12.0 Only used in pre-0.8.0 --------------------- diff --git a/doc/gitian-building.md b/doc/gitian-building.md index 00fdce82e..312621851 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -47,7 +47,7 @@ You can also install Gitian on actual hardware instead of using virtualization. Create a new VirtualBox VM --------------------------- -In the VirtualBox GUI click "Create" and choose the following parameters in the wizard: +In the VirtualBox GUI click "New" and choose the following parameters in the wizard: ![](gitian-building/create_new_vm.png) @@ -74,13 +74,6 @@ In the VirtualBox GUI click "Create" and choose the following parameters in the - File location and size: at least 40GB; as low as 20GB *may* be possible, but better to err on the safe side - Click `Create` -Get the [Debian 8.x net installer](http://cdimage.debian.org/debian-cd/8.2.0/amd64/iso-cd/debian-8.2.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)). -This DVD image can be validated using a SHA256 hashing tool, for example on -Unixy OSes by entering the following in a terminal: - - echo "d393d17ac6b3113c81186e545c416a00f28ed6e05774284bb5e8f0df39fcbcb9 debian-8.2.0-amd64-netinst.iso" | sha256sum -c - # (must return OK) - After creating the VM, we need to configure it. - Click the `Settings` button, then go to the `Network` tab. Adapter 1 should be attached to `NAT`. @@ -102,6 +95,13 @@ After creating the VM, we need to configure it. - Click `Ok` twice to save. +Get the [Debian 8.x net installer](http://cdimage.debian.org/debian-cd/8.4.0/amd64/iso-cd/debian-8.4.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)). +This DVD image can be validated using a SHA256 hashing tool, for example on +Unixy OSes by entering the following in a terminal: + + echo "7a6b418e6a4ee3ca75dda04d79ed96c9e2c33bb0c703ca7e40c6374ab4590748 debian-8.4.0-amd64-netinst.iso" | sha256sum -c + # (must return OK) + Then start the VM. On the first launch you will be asked for a CD or DVD image. Choose the downloaded iso. ![](gitian-building/select_startup_disk.png) @@ -160,6 +160,10 @@ To select a different button, press `Tab`. ![](gitian-building/debian_install_12_choose_disk.png) + - Partition Disks -> *All files in one partition* + +![](gitian-building/all_files_in_one_partition.png) + - Finish partitioning and write changes to disk -> *Yes* (`Tab`, `Enter` to select the `Yes` button) ![](gitian-building/debian_install_14_finish.png) @@ -252,22 +256,23 @@ First we need to log in as `root` to set up dependencies and make sure that our user can use the sudo command. Type/paste the following in the terminal: ```bash -apt-get install git ruby sudo apt-cacher-ng qemu-utils debootstrap lxc python-cheetah parted kpartx bridge-utils make ubuntu-archive-keyring +apt-get install git ruby sudo apt-cacher-ng qemu-utils debootstrap lxc python-cheetah parted kpartx bridge-utils make ubuntu-archive-keyring curl adduser debian sudo ``` Then set up LXC and the rest with the following, which is a complex jumble of settings and workarounds: ```bash -# the version of lxc-start in Debian 7.4 needs to run as root, so make sure +# the version of lxc-start in Debian needs to run as root, so make sure # that the build script can execute it without providing a password echo "%sudo ALL=NOPASSWD: /usr/bin/lxc-start" > /etc/sudoers.d/gitian-lxc -# add cgroup for LXC -echo "cgroup /sys/fs/cgroup cgroup defaults 0 0" >> /etc/fstab +echo "%sudo ALL=NOPASSWD: /usr/bin/lxc-execute" >> /etc/sudoers.d/gitian-lxc # make /etc/rc.local script that sets up bridge between guest and host echo '#!/bin/sh -e' > /etc/rc.local echo 'brctl addbr br0' >> /etc/rc.local echo 'ifconfig br0 10.0.3.2/24 up' >> /etc/rc.local +echo 'iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE' >> /etc/rc.local +echo 'echo 1 > /proc/sys/net/ipv4/ip_forward' >> /etc/rc.local echo 'exit 0' >> /etc/rc.local # make sure that USE_LXC is always set when logging in as debian, # and configure LXC IP addresses @@ -289,11 +294,11 @@ The rest of the steps in this guide will be performed as that user. There is no `python-vm-builder` package in Debian, so we need to install it from source ourselves, ```bash -wget http://archive.ubuntu.com/ubuntu/pool/universe/v/vm-builder/vm-builder_0.12.4+bzr489.orig.tar.gz -echo "ec12e0070a007989561bfee5862c89a32c301992dd2771c4d5078ef1b3014f03 vm-builder_0.12.4+bzr489.orig.tar.gz" | sha256sum -c +wget http://archive.ubuntu.com/ubuntu/pool/universe/v/vm-builder/vm-builder_0.12.4+bzr494.orig.tar.gz +echo "76cbf8c52c391160b2641e7120dbade5afded713afaa6032f733a261f13e6a8e vm-builder_0.12.4+bzr494.orig.tar.gz" | sha256sum -c # (verification -- must return OK) -tar -zxvf vm-builder_0.12.4+bzr489.orig.tar.gz -cd vm-builder-0.12.4+bzr489 +tar -zxvf vm-builder_0.12.4+bzr494.orig.tar.gz +cd vm-builder-0.12.4+bzr494 sudo python setup.py install cd .. ``` @@ -305,13 +310,14 @@ Clone the git repositories for bitcoin and Gitian. ```bash git clone https://github.com/devrandom/gitian-builder.git git clone https://github.com/bitcoin/bitcoin +git clone https://github.com/bitcoin/gitian.sigs.git ``` Setting up the Gitian image ------------------------- Gitian needs a virtual image of the operating system to build in. -Currently this is Ubuntu Precise x86_64. +Currently this is Ubuntu Trusty x86_64. This image will be copied and used every time that a build is started to make sure that the build is deterministic. Creating the image will take a while, but only has to be done once. @@ -320,7 +326,7 @@ Execute the following as user `debian`: ```bash cd gitian-builder -bin/make-base-vm --lxc --arch amd64 --suite precise +bin/make-base-vm --lxc --arch amd64 --suite trusty ``` There will be a lot of warnings printed during the build of the image. These can be ignored. @@ -361,7 +367,7 @@ Output from `gbuild` will look something like Resolving deltas: 100% (41590/41590), done. From https://github.com/bitcoin/bitcoin ... (new tags, new branch etc) - --- Building for precise amd64 --- + --- Building for trusty amd64 --- Stopping target if it is up Making a new image copy stdin: is not a tty @@ -410,14 +416,14 @@ So, if you use LXC: export PATH="$PATH":/path/to/gitian-builder/libexec export USE_LXC=1 cd /path/to/gitian-builder -./libexec/make-clean-vm --suite precise --arch amd64 +./libexec/make-clean-vm --suite trusty --arch amd64 -LXC_ARCH=amd64 LXC_SUITE=precise on-target -u root apt-get update -LXC_ARCH=amd64 LXC_SUITE=precise on-target -u root \ +LXC_ARCH=amd64 LXC_SUITE=trusty on-target -u root apt-get update +LXC_ARCH=amd64 LXC_SUITE=trusty on-target -u root \ -e DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends -y install \ $( sed -ne '/^packages:/,/[^-] .*/ {/^- .*/{s/"//g;s/- //;p}}' ../bitcoin/contrib/gitian-descriptors/*|sort|uniq ) -LXC_ARCH=amd64 LXC_SUITE=precise on-target -u root apt-get -q -y purge grub -LXC_ARCH=amd64 LXC_SUITE=precise on-target -u root -e DEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade +LXC_ARCH=amd64 LXC_SUITE=trusty on-target -u root apt-get -q -y purge grub +LXC_ARCH=amd64 LXC_SUITE=trusty on-target -u root -e DEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade ``` And then set offline mode for apt-cacher-ng: diff --git a/doc/gitian-building/all_files_in_one_partition.png b/doc/gitian-building/all_files_in_one_partition.png new file mode 100644 index 000000000..8cbb0d8ad Binary files /dev/null and b/doc/gitian-building/all_files_in_one_partition.png differ diff --git a/doc/gitian-building/create_vm_file_location_size.png b/doc/gitian-building/create_vm_file_location_size.png index 14aef5aba..5f77206b6 100644 Binary files a/doc/gitian-building/create_vm_file_location_size.png and b/doc/gitian-building/create_vm_file_location_size.png differ diff --git a/doc/gitian-building/select_startup_disk.png b/doc/gitian-building/select_startup_disk.png index 5acdc3fe1..59bc093e2 100644 Binary files a/doc/gitian-building/select_startup_disk.png and b/doc/gitian-building/select_startup_disk.png differ diff --git a/doc/init.md b/doc/init.md index d24c2d1db..e3db5b05e 100644 --- a/doc/init.md +++ b/doc/init.md @@ -13,8 +13,9 @@ can be found in the contrib/init folder. 1. Service User --------------------------------- -All three startup configurations assume the existence of a "bitcoin" user +All three Linux startup configurations assume the existence of a "bitcoin" user and group. They must be created before attempting to use these scripts. +The OS X configuration assumes bitcoind will be set up for the current user. 2. Configuration --------------------------------- @@ -48,6 +49,8 @@ see `contrib/debian/examples/bitcoin.conf`. 3. Paths --------------------------------- +3a) Linux + All three configurations assume several paths that might need to be adjusted. Binary: `/usr/bin/bitcoind` @@ -62,6 +65,13 @@ reasons to make the configuration file and data directory only readable by the bitcoin user and group. Access to bitcoin-cli and other bitcoind rpc clients can then be controlled by group membership. +3b) Mac OS X + +Binary: `/usr/local/bin/bitcoind` +Configuration file: `~/Library/Application Support/Bitcoin/bitcoin.conf` +Data directory: `~/Library/Application Support/Bitcoin` +Lock file: `~/Library/Application Support/Bitcoin/.lock` + 4. Installing Service Configuration ----------------------------------- @@ -97,6 +107,17 @@ Using this script, you can adjust the path and flags to the bitcoind program by setting the BITCOIND and FLAGS environment variables in the file /etc/sysconfig/bitcoind. You can also use the DAEMONOPTS environment variable here. +4e) Mac OS X + +Copy org.bitcoin.bitcoind.plist into ~/Library/LaunchAgents. Load the launch agent by +running `launchctl load ~/Library/LaunchAgents/org.bitcoin.bitcoind.plist`. + +This Launch Agent will cause bitcoind to start whenever the user logs in. + +NOTE: This approach is intended for those wanting to run bitcoind as the current user. +You will need to modify org.bitcoin.bitcoind.plist if you intend to use it as a +Launch Daemon with a dedicated bitcoin user. + 5. Auto-respawn ----------------------------------- diff --git a/doc/reduce-traffic.md b/doc/reduce-traffic.md new file mode 100644 index 000000000..2d86588eb --- /dev/null +++ b/doc/reduce-traffic.md @@ -0,0 +1,38 @@ +Reduce Traffic +============== + +Some node operators need to deal with bandwidth caps imposed by their ISPs. + +By default, bitcoin-core allows up to 125 connections to different peers, 8 of +which are outbound. You can therefore, have at most 117 inbound connections. + +The default settings can result in relatively significant traffic consumption. + +Ways to reduce traffic: + +## 1. Use `-maxuploadtarget=` + +A major component of the traffic is caused by serving historic blocks to other nodes +during the initial blocks download phase (syncing up a new node). +This option can be specified in MiB per day and is turned off by default. +This is *not* a hard limit; only a threshold to minimize the outbound +traffic. When the limit is about to be reached, the uploaded data is cut by no +longer serving historic blocks (blocks older than one week). +Keep in mind that new nodes require other nodes that are willing to serve +historic blocks. **The recommended minimum is 144 blocks per day (max. 144MB +per day)** + +Whitelisted peers will never be disconnected, although their traffic counts for +calculating the target. + +## 2. Disable "listening" (`-listen=0`) + +Disabling listening will result in fewer nodes connected (remember the maximum of 8 +outbound peers). Fewer nodes will result in less traffic usage as you are relaying +blocks and transactions to fewer nodes. + +## 3. Reduce maximum connections (`-maxconnections=`) + +Reducing the maximum connected nodes to a minimum could be desirable if traffic +limits are tiny. Keep in mind that bitcoin's trustless model works best if you are +connected to a handful of nodes. diff --git a/doc/release-notes.md b/doc/release-notes.md index e9b2d75a7..8360cc481 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,127 +4,31 @@ release-notes at release time) Notable changes =============== -SSL support for RPC dropped ----------------------------- +Example item +---------------- -SSL support for RPC, previously enabled by the option `rpcssl` has been dropped -from both the client and the server. This was done in preparation for removing -the dependency on OpenSSL for the daemon completely. -Trying to use `rpcssl` will result in an error: +bitcoin-cli: arguments privacy +-------------------------------- - Error: SSL mode for RPC (-rpcssl) is no longer supported. +The RPC command line client gained a new argument, `-stdin` +to read extra arguments from standard input, one per line until EOF/Ctrl-D. +For example: -If you are one of the few people that relies on this feature, a flexible -migration path is to use `stunnel`. This is an utility that can tunnel -arbitrary TCP connections inside SSL. On e.g. Ubuntu it can be installed with: + $ echo -e "mysecretcode\n120" | src/bitcoin-cli -stdin walletpassphrase - sudo apt-get install stunnel4 +It is recommended to use this for sensitive information such as wallet +passphrases, as command-line arguments can usually be read from the process +table by any user on the system. -Then, to tunnel a SSL connection on 28332 to a RPC server bound on localhost on port 18332 do: +RPC low-level changes +---------------------- - stunnel -d 28332 -r 127.0.0.1:18332 -p stunnel.pem -P '' +- `gettxoutsetinfo` UTXO hash (`hash_serialized`) has changed. There was a divergence between + 32-bit and 64-bit platforms, and the txids were missing in the hashed data. This has been + fixed, but this means that the output will be different than from previous versions. -It can also be set up system-wide in inetd style. - -Another way to re-attain SSL would be to setup a httpd reverse proxy. This solution -would allow the use of different authentication, loadbalancing, on-the-fly compression and -caching. A sample config for apache2 could look like: - - Listen 443 - - NameVirtualHost *:443 - - - SSLEngine On - SSLCertificateFile /etc/apache2/ssl/server.crt - SSLCertificateKeyFile /etc/apache2/ssl/server.key - - - ProxyPass http://127.0.0.1:8332/ - ProxyPassReverse http://127.0.0.1:8332/ - # optional enable digest auth - # AuthType Digest - # ... - - # optional bypass bitcoind rpc basic auth - # RequestHeader set Authorization "Basic " - # get the from the shell with: base64 <<< bitcoinrpc: - - - # Or, balance the load: - # ProxyPass / balancer://balancer_cluster_name - - - -Random-cookie RPC authentication ---------------------------------- - -When no `-rpcpassword` is specified, the daemon now uses a special 'cookie' -file for authentication. This file is generated with random content when the -daemon starts, and deleted when it exits. Its contents are used as -authentication token. Read access to this file controls who can access through -RPC. By default it is stored in the data directory but its location can be -overridden with the option `-rpccookiefile`. - -This is similar to Tor's CookieAuthentication: see -https://www.torproject.org/docs/tor-manual.html.en - -This allows running bitcoind without having to do any manual configuration. - -Low-level RPC API changes --------------------------- - -- Monetary amounts can be provided as strings. This means that for example the - argument to sendtoaddress can be "0.0001" instead of 0.0001. This can be an - advantage if a JSON library insists on using a lossy floating point type for - numbers, which would be dangerous for monetary amounts. - -Option parsing behavior ------------------------ - -Command line options are now parsed strictly in the order in which they are -specified. It used to be the case that `-X -noX` ends up, unintuitively, with X -set, as `-X` had precedence over `-noX`. This is no longer the case. Like for -other software, the last specified value for an option will hold. - -`NODE_BLOOM` service bit ------------------------- - -Support for the `NODE_BLOOM` service bit, as described in [BIP -111](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki), has been -added to the P2P protocol code. - -BIP 111 defines a service bit to allow peers to advertise that they support -bloom filters (such as used by SPV clients) explicitly. It also bumps the protocol -version to allow peers to identify old nodes which allow bloom filtering of the -connection despite lacking the new service bit. - -In this version, it is only enforced for peers that send protocol versions -`>=70011`. For the next major version it is planned that this restriction will be -removed. It is recommended to update SPV clients to check for the `NODE_BLOOM` -service bit for nodes that report versions newer than 70011. - -Any sequence of pushdatas in OP_RETURN outputs now allowed ----------------------------------------------------------- - -Previously OP_RETURN outputs with a payload were only relayed and mined if they -had a single pushdata. This restriction has been lifted to allow any -combination of data pushes and numeric constant opcodes (OP_1 to OP_16). The -limit on OP_RETURN output size is now applied to the entire serialized -scriptPubKey, 83 bytes by default. (the previous 80 byte default plus three -bytes overhead) - -Merkle branches removed from wallet ------------------------------------ - -Previously, every wallet transaction stored a Merkle branch to prove its -presence in blocks. This wasn't being used for more than an expensive -sanity check. Since 0.12, these are no longer stored. When loading a -0.12 wallet into an older version, it will automatically rescan to avoid -failed checks. - -0.12.0 Change log +0.13.0 Change log ================= Detailed release notes follow. This overview includes changes that affect @@ -134,39 +38,37 @@ git merge commit are mentioned. ### RPC and REST -Asm representations of scriptSig signatures now contain SIGHASH type decodes ----------------------------------------------------------------------------- +Asm script outputs now contain OP_CHECKLOCKTIMEVERIFY in place of OP_NOP2 +------------------------------------------------------------------------- -The `asm` property of each scriptSig now contains the decoded signature hash -type for each signature that provides a valid defined hash type. +OP_NOP2 has been renamed to OP_CHECKLOCKTIMEVERIFY by [BIP +65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) -The following items contain assembly representations of scriptSig signatures -and are affected by this change: - -- RPC `getrawtransaction` +The following outputs are affected by this change: +- RPC `getrawtransaction` (in verbose mode) - RPC `decoderawtransaction` +- RPC `decodescript` - REST `/rest/tx/` (JSON format) - REST `/rest/block/` (JSON format when including extended tx details) - `bitcoin-tx -json` -For example, the `scriptSig.asm` property of a transaction input that -previously showed an assembly representation of: - - 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001 - -now shows as: - - 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090[ALL] - -Note that the output of the RPC `decodescript` did not change because it is -configured specifically to process scriptPubKey and not scriptSig scripts. - ### Configuration and command-line options ### Block and transaction handling ### P2P protocol and network code +The p2p alert system has been removed in #7692 and the 'alert' message is no longer supported. + + +Fee filtering of invs (BIP 133) +------------------------------------ + +The optional new p2p message "feefilter" is implemented and the protocol +version is bumped to 70013. Upon receiving a feefilter message from a peer, +a node will not send invs for any transactions which do not meet the filter +feerate. [BIP 133](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki) + ### Validation ### Build system @@ -179,13 +81,3 @@ configured specifically to process scriptPubKey and not scriptSig scripts. ### Miscellaneous -- Removed bitrpc.py from contrib - -Addition of ZMQ-based Notifications -================================== - -Bitcoind can now (optionally) asynchronously notify clients through a -ZMQ-based PUB socket of the arrival of new transactions and blocks. -This feature requires installation of the ZMQ C API library 4.x and -configuring its use through the command line or configuration file. -Please see docs/zmq.md for details of operation. diff --git a/doc/release-notes/release-notes-0.10.4.md b/doc/release-notes/release-notes-0.10.4.md new file mode 100644 index 000000000..38a2c1347 --- /dev/null +++ b/doc/release-notes/release-notes-0.10.4.md @@ -0,0 +1,172 @@ +Bitcoin Core version 0.10.4 is now available from: + + + +This is a new minor version release, bringing bug fixes, the BIP65 +(CLTV) consensus change, and relay policy preparation for BIP113. It is +recommended to upgrade to this version as soon as possible. + +Please report bugs using the issue tracker at github: + + + +Upgrading and downgrading +========================= + +How to Upgrade +-------------- + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over /Applications/Bitcoin-Qt (on Mac) or +bitcoind/bitcoin-qt (on Linux). + +Downgrade warning +------------------ + +Because release 0.10.0 and later makes use of headers-first synchronization and +parallel block download (see further), the block files and databases are not +backwards-compatible with pre-0.10 versions of Bitcoin Core or other software: + +* Blocks will be stored on disk out of order (in the order they are +received, really), which makes it incompatible with some tools or +other programs. Reindexing using earlier versions will also not work +anymore as a result of this. + +* The block index database will now hold headers for which no block is +stored on disk, which earlier versions won't support. + +If you want to be able to downgrade smoothly, make a backup of your entire data +directory. Without this your node will need start syncing (or importing from +bootstrap.dat) anew afterwards. It is possible that the data from a completely +synchronised 0.10 node may be usable in older versions as-is, but this is not +supported and may break as soon as the older version attempts to reindex. + +This does not affect wallet forward or backward compatibility. There are no +known problems when downgrading from 0.11.x to 0.10.x. + +Notable changes since 0.10.3 +============================ + +BIP65 soft fork to enforce OP_CHECKLOCKTIMEVERIFY opcode +-------------------------------------------------------- + +This release includes several changes related to the [BIP65][] soft fork +which redefines the existing OP_NOP2 opcode as OP_CHECKLOCKTIMEVERIFY +(CLTV) so that a transaction output can be made unspendable until a +specified point in the future. + +1. This release will only relay and mine transactions spending a CLTV + output if they comply with the BIP65 rules as provided in code. + +2. This release will produce version 4 blocks by default. Please see the + *notice to miners* below. + +3. Once 951 out of a sequence of 1,001 blocks on the local node's best block + chain contain version 4 (or higher) blocks, this release will no + longer accept new version 3 blocks and it will only accept version 4 + blocks if they comply with the BIP65 rules for CLTV. + +For more information about the soft-forking change, please see + + +Graphs showing the progress towards block version 4 adoption may be +found at the URLs below: + +- Block versions over the last 50,000 blocks as progress towards BIP65 + consensus enforcement: + +- Block versions over the last 2,000 blocks showing the days to the + earliest possible BIP65 consensus-enforced block: + +**Notice to miners:** Bitcoin Core’s block templates are now for +version 4 blocks only, and any mining software relying on its +getblocktemplate must be updated in parallel to use libblkmaker either +version FIXME or any version from FIXME onward. + +- If you are solo mining, this will affect you the moment you upgrade + Bitcoin Core, which must be done prior to BIP65 achieving its 951/1001 + status. + +- If you are mining with the stratum mining protocol: this does not + affect you. + +- If you are mining with the getblocktemplate protocol to a pool: this + will affect you at the pool operator’s discretion, which must be no + later than BIP65 achieving its 951/1001 status. + +[BIP65]: https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki + +Windows bug fix for corrupted UTXO database on unclean shutdowns +---------------------------------------------------------------- + +Several Windows users reported that they often need to reindex the +entire blockchain after an unclean shutdown of Bitcoin Core on Windows +(or an unclean shutdown of Windows itself). Although unclean shutdowns +remain unsafe, this release no longer relies on memory-mapped files for +the UTXO database, which significantly reduced the frequency of unclean +shutdowns leading to required reindexes during testing. + +For more information, see: + +Other fixes for database corruption on Windows are expected in the +next major release. + +0.10.4 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, refactors and string updates. For convenience in locating +the code changes and accompanying discussion, both the pull request and +git merge commit are mentioned. + +- #6953 `8b3311f` alias -h for --help +- #6953 `97546fc` Change URLs to https in debian/control +- #6953 `38671bf` Update debian/changelog and slight tweak to debian/control +- #6953 `256321e` Correct spelling mistakes in doc folder +- #6953 `eae0350` Clarification of unit test build instructions +- #6953 `90897ab` Update bluematt-key, the old one is long-since revoked +- #6953 `a2f2fb6` build: disable -Wself-assign +- #6953 `cf67d8b` Bugfix: Allow mining on top of old tip blocks for testnet (fixes testnet-in-a-box use case) +- #6953 `b3964e3` Drop "with minimal dependencies" from description +- #6953 `43c2789` Split bitcoin-tx into its own package +- #6953 `dfe0d4d` Include bitcoin-tx binary on Debian/Ubuntu +- #6953 `612efe8` [Qt] Raise debug window when requested +- #6953 `3ad96bd` Fix locking in GetTransaction +- #6953 `9c81005` Fix spelling of Qt +- #6946 `94b67e5` Update LevelDB +- #6706 `5dc72f8` CLTV: Add more tests to improve coverage +- #6706 `6a1343b` Add RPC tests for the CHECKLOCKTIMEVERIFY (BIP65) soft-fork +- #6706 `4137248` Add CHECKLOCKTIMEVERIFY (BIP65) soft-fork logic +- #6706 `0e01d0f` Enable CHECKLOCKTIMEVERIFY as a standard script verify flag +- #6706 `6d01325` Replace NOP2 with CHECKLOCKTIMEVERIFY (BIP65) +- #6706 `750d54f` Move LOCKTIME_THRESHOLD to src/script/script.h +- #6706 `6897468` Make CScriptNum() take nMaxNumSize as an argument +- #6867 `5297194` Set TCP_NODELAY on P2P sockets +- #6836 `fb818b6` Bring historical release notes up to date +- #6852 `0b3fd07` build: make sure OpenSSL heeds noexecstack + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- Alex Morcos +- Daniel Cousens +- Diego Viola +- Eric Lombrozo +- Esteban Ordano +- Gregory Maxwell +- Luke Dashjr +- MarcoFalke +- Matt Corallo +- Micha +- Mitchell Cash +- Peter Todd +- Pieter Wuille +- Wladimir J. van der Laan +- Zak Wilcox + +And those who contributed additional code review and/or security research. + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). diff --git a/doc/release-notes/release-notes-0.11.2.md b/doc/release-notes/release-notes-0.11.2.md new file mode 100644 index 000000000..2351b8065 --- /dev/null +++ b/doc/release-notes/release-notes-0.11.2.md @@ -0,0 +1,217 @@ +Bitcoin Core version 0.11.2 is now available from: + + + +This is a new minor version release, bringing bug fixes, the BIP65 +(CLTV) consensus change, and relay policy preparation for BIP113. It is +recommended to upgrade to this version as soon as possible. + +Please report bugs using the issue tracker at github: + + + +Upgrading and downgrading +========================= + +How to Upgrade +-------------- + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over /Applications/Bitcoin-Qt (on Mac) or +bitcoind/bitcoin-qt (on Linux). + +Downgrade warning +------------------ + +Because release 0.10.0 and later makes use of headers-first synchronization and +parallel block download (see further), the block files and databases are not +backwards-compatible with pre-0.10 versions of Bitcoin Core or other software: + +* Blocks will be stored on disk out of order (in the order they are +received, really), which makes it incompatible with some tools or +other programs. Reindexing using earlier versions will also not work +anymore as a result of this. + +* The block index database will now hold headers for which no block is +stored on disk, which earlier versions won't support. + +If you want to be able to downgrade smoothly, make a backup of your entire data +directory. Without this your node will need start syncing (or importing from +bootstrap.dat) anew afterwards. It is possible that the data from a completely +synchronised 0.10 node may be usable in older versions as-is, but this is not +supported and may break as soon as the older version attempts to reindex. + +This does not affect wallet forward or backward compatibility. There are no +known problems when downgrading from 0.11.x to 0.10.x. + +Notable changes since 0.11.1 +============================ + +BIP65 soft fork to enforce OP_CHECKLOCKTIMEVERIFY opcode +-------------------------------------------------------- + +This release includes several changes related to the [BIP65][] soft fork +which redefines the existing OP_NOP2 opcode as OP_CHECKLOCKTIMEVERIFY +(CLTV) so that a transaction output can be made unspendable until a +specified point in the future. + +1. This release will only relay and mine transactions spending a CLTV + output if they comply with the BIP65 rules as provided in code. + +2. This release will produce version 4 blocks by default. Please see the + *notice to miners* below. + +3. Once 951 out of a sequence of 1,001 blocks on the local node's best block + chain contain version 4 (or higher) blocks, this release will no + longer accept new version 3 blocks and it will only accept version 4 + blocks if they comply with the BIP65 rules for CLTV. + +For more information about the soft-forking change, please see + + +Graphs showing the progress towards block version 4 adoption may be +found at the URLs below: + +- Block versions over the last 50,000 blocks as progress towards BIP65 + consensus enforcement: + +- Block versions over the last 2,000 blocks showing the days to the + earliest possible BIP65 consensus-enforced block: + +**Notice to miners:** Bitcoin Core’s block templates are now for +version 4 blocks only, and any mining software relying on its +getblocktemplate must be updated in parallel to use libblkmaker either +version 0.4.3 or any version from 0.5.2 onward. + +- If you are solo mining, this will affect you the moment you upgrade + Bitcoin Core, which must be done prior to BIP65 achieving its 951/1001 + status. + +- If you are mining with the stratum mining protocol: this does not + affect you. + +- If you are mining with the getblocktemplate protocol to a pool: this + will affect you at the pool operator’s discretion, which must be no + later than BIP65 achieving its 951/1001 status. + +[BIP65]: https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki + +BIP113 mempool-only locktime enforcement using GetMedianTimePast() +---------------------------------------------------------------- + +Bitcoin transactions currently may specify a locktime indicating when +they may be added to a valid block. Current consensus rules require +that blocks have a block header time greater than the locktime specified +in any transaction in that block. + +Miners get to choose what time they use for their header time, with the +consensus rule being that no node will accept a block whose time is more +than two hours in the future. This creates a incentive for miners to +set their header times to future values in order to include locktimed +transactions which weren't supposed to be included for up to two more +hours. + +The consensus rules also specify that valid blocks may have a header +time greater than that of the median of the 11 previous blocks. This +GetMedianTimePast() time has a key feature we generally associate with +time: it can't go backwards. + +[BIP113][] specifies a soft fork (**not enforced in this release**) that +weakens this perverse incentive for individual miners to use a future +time by requiring that valid blocks have a computed GetMedianTimePast() +greater than the locktime specified in any transaction in that block. + +Mempool inclusion rules currently require transactions to be valid for +immediate inclusion in a block in order to be accepted into the mempool. +This release begins applying the BIP113 rule to received transactions, +so transaction whose time is greater than the GetMedianTimePast() will +no longer be accepted into the mempool. + +**Implication for miners:** you will begin rejecting transactions that +would not be valid under BIP113, which will prevent you from producing +invalid blocks if/when BIP113 is enforced on the network. Any +transactions which are valid under the current rules but not yet valid +under the BIP113 rules will either be mined by other miners or delayed +until they are valid under BIP113. Note, however, that time-based +locktime transactions are more or less unseen on the network currently. + +**Implication for users:** GetMedianTimePast() always trails behind the +current time, so a transaction locktime set to the present time will be +rejected by nodes running this release until the median time moves +forward. To compensate, subtract one hour (3,600 seconds) from your +locktimes to allow those transactions to be included in mempools at +approximately the expected time. + +[BIP113]: https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki + +Windows bug fix for corrupted UTXO database on unclean shutdowns +---------------------------------------------------------------- + +Several Windows users reported that they often need to reindex the +entire blockchain after an unclean shutdown of Bitcoin Core on Windows +(or an unclean shutdown of Windows itself). Although unclean shutdowns +remain unsafe, this release no longer relies on memory-mapped files for +the UTXO database, which significantly reduced the frequency of unclean +shutdowns leading to required reindexes during testing. + +For more information, see: + +Other fixes for database corruption on Windows are expected in the +next major release. + +0.11.2 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, refactors and string updates. For convenience in locating +the code changes and accompanying discussion, both the pull request and +git merge commit are mentioned. + +- #6124 `684636b` Make CScriptNum() take nMaxNumSize as an argument +- #6124 `4fa7a04` Replace NOP2 with CHECKLOCKTIMEVERIFY (BIP65) +- #6124 `6ea5ca4` Enable CHECKLOCKTIMEVERIFY as a standard script verify flag +- #6351 `5e82e1c` Add CHECKLOCKTIMEVERIFY (BIP65) soft-fork logic +- #6353 `ba1da90` Show softfork status in getblockchaininfo +- #6351 `6af25b0` Add BIP65 to getblockchaininfo softforks list +- #6688 `01878c9` Fix locking in GetTransaction +- #6653 `b3eaa30` [Qt] Raise debug window when requested +- #6600 `1e672ae` Debian/Ubuntu: Include bitcoin-tx binary +- #6600 `2394f4d` Debian/Ubuntu: Split bitcoin-tx into its own package +- #5987 `33d6825` Bugfix: Allow mining on top of old tip blocks for testnet +- #6852 `21e58b8` build: make sure OpenSSL heeds noexecstack +- #6846 `af6edac` alias `-h` for `--help` +- #6867 `95a5039` Set TCP_NODELAY on P2P sockets. +- #6856 `dfe55bd` Do not allow blockfile pruning during reindex. +- #6566 `a1d3c6f` Add rules--presently disabled--for using GetMedianTimePast as end point for lock-time calculations +- #6566 `f720c5f` Enable policy enforcing GetMedianTimePast as the end point of lock-time constraints +- #6917 `0af5b8e` leveldb: Win32WritableFile without memory mapping +- #6948 `4e895b0` Always flush block and undo when switching to new file + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- Alex Morcos +- ฿tcDrak +- Chris Kleeschulte +- Daniel Cousens +- Diego Viola +- Eric Lombrozo +- Esteban Ordano +- Gregory Maxwell +- Luke Dashjr +- Marco Falke +- Mark Friedenbach +- Matt Corallo +- Micha +- Mitchell Cash +- Peter Todd +- Pieter Wuille +- Wladimir J. van der Laan +- Zak Wilcox + +And those who contributed additional code review and/or security research. + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). diff --git a/doc/release-notes/release-notes-0.12.0.md b/doc/release-notes/release-notes-0.12.0.md new file mode 100644 index 000000000..135cd68a7 --- /dev/null +++ b/doc/release-notes/release-notes-0.12.0.md @@ -0,0 +1,890 @@ +Bitcoin Core version 0.12.0 is now available from: + + + +This is a new major version release, bringing new features and other improvements. + +Please report bugs using the issue tracker at github: + + + +Upgrading and downgrading +========================= + +How to Upgrade +-------------- + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over /Applications/Bitcoin-Qt (on Mac) or +bitcoind/bitcoin-qt (on Linux). + +Downgrade warning +----------------- + +### Downgrade to a version < 0.10.0 + +Because release 0.10.0 and later makes use of headers-first synchronization and +parallel block download (see further), the block files and databases are not +backwards-compatible with pre-0.10 versions of Bitcoin Core or other software: + +* Blocks will be stored on disk out of order (in the order they are +received, really), which makes it incompatible with some tools or +other programs. Reindexing using earlier versions will also not work +anymore as a result of this. + +* The block index database will now hold headers for which no block is +stored on disk, which earlier versions won't support. + +If you want to be able to downgrade smoothly, make a backup of your entire data +directory. Without this your node will need start syncing (or importing from +bootstrap.dat) anew afterwards. It is possible that the data from a completely +synchronised 0.10 node may be usable in older versions as-is, but this is not +supported and may break as soon as the older version attempts to reindex. + +This does not affect wallet forward or backward compatibility. + +### Downgrade to a version < 0.12.0 + +Because release 0.12.0 and later will obfuscate the chainstate on every +fresh sync or reindex, the chainstate is not backwards-compatible with +pre-0.12 versions of Bitcoin Core or other software. + +If you want to downgrade after you have done a reindex with 0.12.0 or later, +you will need to reindex when you first start Bitcoin Core version 0.11 or +earlier. + +Notable changes +=============== + +Signature validation using libsecp256k1 +--------------------------------------- + +ECDSA signatures inside Bitcoin transactions now use validation using +[libsecp256k1](https://github.com/bitcoin/secp256k1) instead of OpenSSL. + +Depending on the platform, this means a significant speedup for raw signature +validation speed. The advantage is largest on x86_64, where validation is over +five times faster. In practice, this translates to a raw reindexing and new +block validation times that are less than half of what it was before. + +Libsecp256k1 has undergone very extensive testing and validation. + +A side effect of this change is that libconsensus no longer depends on OpenSSL. + +Reduce upload traffic +--------------------- + +A major part of the outbound traffic is caused by serving historic blocks to +other nodes in initial block download state. + +It is now possible to reduce the total upload traffic via the `-maxuploadtarget` +parameter. This is *not* a hard limit but a threshold to minimize the outbound +traffic. When the limit is about to be reached, the uploaded data is cut by not +serving historic blocks (blocks older than one week). +Moreover, any SPV peer is disconnected when they request a filtered block. + +This option can be specified in MiB per day and is turned off by default +(`-maxuploadtarget=0`). +The recommended minimum is 144 * MAX_BLOCK_SIZE (currently 144MB) per day. + +Whitelisted peers will never be disconnected, although their traffic counts for +calculating the target. + +A more detailed documentation about keeping traffic low can be found in +[/doc/reduce-traffic.md](/doc/reduce-traffic.md). + +Direct headers announcement (BIP 130) +------------------------------------- + +Between compatible peers, [BIP 130] +(https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki) +direct headers announcement is used. This means that blocks are advertised by +announcing their headers directly, instead of just announcing the hash. In a +reorganization, all new headers are sent, instead of just the new tip. This +can often prevent an extra roundtrip before the actual block is downloaded. + +With this change, pruning nodes are now able to relay new blocks to compatible +peers. + +Memory pool limiting +-------------------- + +Previous versions of Bitcoin Core had their mempool limited by checking +a transaction's fees against the node's minimum relay fee. There was no +upper bound on the size of the mempool and attackers could send a large +number of transactions paying just slighly more than the default minimum +relay fee to crash nodes with relatively low RAM. A temporary workaround +for previous versions of Bitcoin Core was to raise the default minimum +relay fee. + +Bitcoin Core 0.12 will have a strict maximum size on the mempool. The +default value is 300 MB and can be configured with the `-maxmempool` +parameter. Whenever a transaction would cause the mempool to exceed +its maximum size, the transaction that (along with in-mempool descendants) has +the lowest total feerate (as a package) will be evicted and the node's effective +minimum relay feerate will be increased to match this feerate plus the initial +minimum relay feerate. The initial minimum relay feerate is set to +1000 satoshis per kB. + +Bitcoin Core 0.12 also introduces new default policy limits on the length and +size of unconfirmed transaction chains that are allowed in the mempool +(generally limiting the length of unconfirmed chains to 25 transactions, with a +total size of 101 KB). These limits can be overriden using command line +arguments; see the extended help (`--help -help-debug`) for more information. + +Opt-in Replace-by-fee transactions +---------------------------------- + +It is now possible to replace transactions in the transaction memory pool of +Bitcoin Core 0.12 nodes. Bitcoin Core will only allow replacement of +transactions which have any of their inputs' `nSequence` number set to less +than `0xffffffff - 1`. Moreover, a replacement transaction may only be +accepted when it pays sufficient fee, as described in [BIP 125] +(https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki). + +Transaction replacement can be disabled with a new command line option, +`-mempoolreplacement=0`. Transactions signaling replacement under BIP125 will +still be allowed into the mempool in this configuration, but replacements will +be rejected. This option is intended for miners who want to continue the +transaction selection behavior of previous releases. + +The `-mempoolreplacement` option is *not recommended* for wallet users seeking +to avoid receipt of unconfirmed opt-in transactions, because this option does +not prevent transactions which are replaceable under BIP 125 from being accepted +(only subsequent replacements, which other nodes on the network that implement +BIP 125 are likely to relay and mine). Wallet users wishing to detect whether +a transaction is subject to replacement under BIP 125 should instead use the +updated RPC calls `gettransaction` and `listtransactions`, which now have an +additional field in the output indicating if a transaction is replaceable under +BIP125 ("bip125-replaceable"). + +Note that the wallet in Bitcoin Core 0.12 does not yet have support for +creating transactions that would be replaceable under BIP 125. + + +RPC: Random-cookie RPC authentication +------------------------------------- + +When no `-rpcpassword` is specified, the daemon now uses a special 'cookie' +file for authentication. This file is generated with random content when the +daemon starts, and deleted when it exits. Its contents are used as +authentication token. Read access to this file controls who can access through +RPC. By default it is stored in the data directory but its location can be +overridden with the option `-rpccookiefile`. + +This is similar to Tor's CookieAuthentication: see +https://www.torproject.org/docs/tor-manual.html.en + +This allows running bitcoind without having to do any manual configuration. + +Relay: Any sequence of pushdatas in OP_RETURN outputs now allowed +----------------------------------------------------------------- + +Previously OP_RETURN outputs with a payload were only relayed and mined if they +had a single pushdata. This restriction has been lifted to allow any +combination of data pushes and numeric constant opcodes (OP_1 to OP_16) after +the OP_RETURN. The limit on OP_RETURN output size is now applied to the entire +serialized scriptPubKey, 83 bytes by default. (the previous 80 byte default plus +three bytes overhead) + +Relay and Mining: Priority transactions +--------------------------------------- + +Bitcoin Core has a heuristic 'priority' based on coin value and age. This +calculation is used for relaying of transactions which do not pay the +minimum relay fee, and can be used as an alternative way of sorting +transactions for mined blocks. Bitcoin Core will relay transactions with +insufficient fees depending on the setting of `-limitfreerelay=` (default: +`r=15` kB per minute) and `-blockprioritysize=`. + +In Bitcoin Core 0.12, when mempool limit has been reached a higher minimum +relay fee takes effect to limit memory usage. Transactions which do not meet +this higher effective minimum relay fee will not be relayed or mined even if +they rank highly according to the priority heuristic. + +The mining of transactions based on their priority is also now disabled by +default. To re-enable it, simply set `-blockprioritysize=` where is the size +in bytes of your blocks to reserve for these transactions. The old default was +50k, so to retain approximately the same policy, you would set +`-blockprioritysize=50000`. + +Additionally, as a result of computational simplifications, the priority value +used for transactions received with unconfirmed inputs is lower than in prior +versions due to avoiding recomputing the amounts as input transactions confirm. + +External miner policy set via the `prioritisetransaction` RPC to rank +transactions already in the mempool continues to work as it has previously. +Note, however, that if mining priority transactions is left disabled, the +priority delta will be ignored and only the fee metric will be effective. + +This internal automatic prioritization handling is being considered for removal +entirely in Bitcoin Core 0.13, and it is at this time undecided whether the +more accurate priority calculation for chained unconfirmed transactions will be +restored. Community direction on this topic is particularly requested to help +set project priorities. + +Automatically use Tor hidden services +------------------------------------- + +Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket +API, to create and destroy 'ephemeral' hidden services programmatically. +Bitcoin Core has been updated to make use of this. + +This means that if Tor is running (and proper authorization is available), +Bitcoin Core automatically creates a hidden service to listen on, without +manual configuration. Bitcoin Core will also use Tor automatically to connect +to other .onion nodes if the control socket can be successfully opened. This +will positively affect the number of available .onion nodes and their usage. + +This new feature is enabled by default if Bitcoin Core is listening, and +a connection to Tor can be made. It can be configured with the `-listenonion`, +`-torcontrol` and `-torpassword` settings. To show verbose debugging +information, pass `-debug=tor`. + +Notifications through ZMQ +------------------------- + +Bitcoind can now (optionally) asynchronously notify clients through a +ZMQ-based PUB socket of the arrival of new transactions and blocks. +This feature requires installation of the ZMQ C API library 4.x and +configuring its use through the command line or configuration file. +Please see [docs/zmq.md](/doc/zmq.md) for details of operation. + +Wallet: Transaction fees +------------------------ + +Various improvements have been made to how the wallet calculates +transaction fees. + +Users can decide to pay a predefined fee rate by setting `-paytxfee=` +(or `settxfee ` rpc during runtime). A value of `n=0` signals Bitcoin +Core to use floating fees. By default, Bitcoin Core will use floating +fees. + +Based on past transaction data, floating fees approximate the fees +required to get into the `m`th block from now. This is configurable +with `-txconfirmtarget=` (default: `2`). + +Sometimes, it is not possible to give good estimates, or an estimate +at all. Therefore, a fallback value can be set with `-fallbackfee=` +(default: `0.0002` BTC/kB). + +At all times, Bitcoin Core will cap fees at `-maxtxfee=` (default: +0.10) BTC. +Furthermore, Bitcoin Core will never create transactions paying less than +the current minimum relay fee. +Finally, a user can set the minimum fee rate for all transactions with +`-mintxfee=`, which defaults to 1000 satoshis per kB. + +Wallet: Negative confirmations and conflict detection +----------------------------------------------------- + +The wallet will now report a negative number for confirmations that indicates +how deep in the block chain the conflict is found. For example, if a transaction +A has 5 confirmations and spends the same input as a wallet transaction B, B +will be reported as having -5 confirmations. If another wallet transaction C +spends an output from B, it will also be reported as having -5 confirmations. +To detect conflicts with historical transactions in the chain a one-time +`-rescan` may be needed. + +Unlike earlier versions, unconfirmed but non-conflicting transactions will never +get a negative confirmation count. They are not treated as spendable unless +they're coming from ourself (change) and accepted into our local mempool, +however. The new "trusted" field in the `listtransactions` RPC output +indicates whether outputs of an unconfirmed transaction are considered +spendable. + +Wallet: Merkle branches removed +------------------------------- + +Previously, every wallet transaction stored a Merkle branch to prove its +presence in blocks. This wasn't being used for more than an expensive +sanity check. Since 0.12, these are no longer stored. When loading a +0.12 wallet into an older version, it will automatically rescan to avoid +failed checks. + +Wallet: Pruning +--------------- + +With 0.12 it is possible to use wallet functionality in pruned mode. +This can reduce the disk usage from currently around 60 GB to +around 2 GB. + +However, rescans as well as the RPCs `importwallet`, `importaddress`, +`importprivkey` are disabled. + +To enable block pruning set `prune=` on the command line or in +`bitcoin.conf`, where `N` is the number of MiB to allot for +raw block & undo data. + +A value of 0 disables pruning. The minimal value above 0 is 550. Your +wallet is as secure with high values as it is with low ones. Higher +values merely ensure that your node will not shut down upon blockchain +reorganizations of more than 2 days - which are unlikely to happen in +practice. In future releases, a higher value may also help the network +as a whole: stored blocks could be served to other nodes. + +For further information about pruning, you may also consult the [release +notes of v0.11.0](https://github.com/bitcoin/bitcoin/blob/v0.11.0/doc/release-notes.md#block-file-pruning). + +`NODE_BLOOM` service bit +------------------------ + +Support for the `NODE_BLOOM` service bit, as described in [BIP +111](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki), has been +added to the P2P protocol code. + +BIP 111 defines a service bit to allow peers to advertise that they support +bloom filters (such as used by SPV clients) explicitly. It also bumps the protocol +version to allow peers to identify old nodes which allow bloom filtering of the +connection despite lacking the new service bit. + +In this version, it is only enforced for peers that send protocol versions +`>=70011`. For the next major version it is planned that this restriction will be +removed. It is recommended to update SPV clients to check for the `NODE_BLOOM` +service bit for nodes that report versions newer than 70011. + +Option parsing behavior +----------------------- + +Command line options are now parsed strictly in the order in which they are +specified. It used to be the case that `-X -noX` ends up, unintuitively, with X +set, as `-X` had precedence over `-noX`. This is no longer the case. Like for +other software, the last specified value for an option will hold. + +RPC: Low-level API changes +-------------------------- + +- Monetary amounts can be provided as strings. This means that for example the + argument to sendtoaddress can be "0.0001" instead of 0.0001. This can be an + advantage if a JSON library insists on using a lossy floating point type for + numbers, which would be dangerous for monetary amounts. + +* The `asm` property of each scriptSig now contains the decoded signature hash + type for each signature that provides a valid defined hash type. + +* OP_NOP2 has been renamed to OP_CHECKLOCKTIMEVERIFY by [BIP 65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) + +The following items contain assembly representations of scriptSig signatures +and are affected by this change: + +- RPC `getrawtransaction` +- RPC `decoderawtransaction` +- RPC `decodescript` +- REST `/rest/tx/` (JSON format) +- REST `/rest/block/` (JSON format when including extended tx details) +- `bitcoin-tx -json` + +For example, the `scriptSig.asm` property of a transaction input that +previously showed an assembly representation of: + + 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001 400000 OP_NOP2 + +now shows as: + + 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090[ALL] 400000 OP_CHECKLOCKTIMEVERIFY + +Note that the output of the RPC `decodescript` did not change because it is +configured specifically to process scriptPubKey and not scriptSig scripts. + +RPC: SSL support dropped +------------------------ + +SSL support for RPC, previously enabled by the option `rpcssl` has been dropped +from both the client and the server. This was done in preparation for removing +the dependency on OpenSSL for the daemon completely. + +Trying to use `rpcssl` will result in an error: + + Error: SSL mode for RPC (-rpcssl) is no longer supported. + +If you are one of the few people that relies on this feature, a flexible +migration path is to use `stunnel`. This is an utility that can tunnel +arbitrary TCP connections inside SSL. On e.g. Ubuntu it can be installed with: + + sudo apt-get install stunnel4 + +Then, to tunnel a SSL connection on 28332 to a RPC server bound on localhost on port 18332 do: + + stunnel -d 28332 -r 127.0.0.1:18332 -p stunnel.pem -P '' + +It can also be set up system-wide in inetd style. + +Another way to re-attain SSL would be to setup a httpd reverse proxy. This solution +would allow the use of different authentication, loadbalancing, on-the-fly compression and +caching. A sample config for apache2 could look like: + + Listen 443 + + NameVirtualHost *:443 + + + SSLEngine On + SSLCertificateFile /etc/apache2/ssl/server.crt + SSLCertificateKeyFile /etc/apache2/ssl/server.key + + + ProxyPass http://127.0.0.1:8332/ + ProxyPassReverse http://127.0.0.1:8332/ + # optional enable digest auth + # AuthType Digest + # ... + + # optional bypass bitcoind rpc basic auth + # RequestHeader set Authorization "Basic " + # get the from the shell with: base64 <<< bitcoinrpc: + + + # Or, balance the load: + # ProxyPass / balancer://balancer_cluster_name + + + +Mining Code Changes +------------------- + +The mining code in 0.12 has been optimized to be significantly faster and use less +memory. As part of these changes, consensus critical calculations are cached on a +transaction's acceptance into the mempool and the mining code now relies on the +consistency of the mempool to assemble blocks. However all blocks are still tested +for validity after assembly. + +Other P2P Changes +----------------- + +The list of banned peers is now stored on disk rather than in memory. +Restarting bitcoind will no longer clear out the list of banned peers; instead +a new RPC call (`clearbanned`) can be used to manually clear the list. The new +`setban` RPC call can also be used to manually ban or unban a peer. + +0.12.0 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, refactors and string updates. For convenience in locating +the code changes and accompanying discussion, both the pull request and +git merge commit are mentioned. + +### RPC and REST + +- #6121 `466f0ea` Convert entire source tree from json_spirit to UniValue (Jonas Schnelli) +- #6234 `d38cd47` fix rpcmining/getblocktemplate univalue transition logic error (Jonas Schnelli) +- #6239 `643114f` Don't go through double in AmountFromValue and ValueFromAmount (Wladimir J. van der Laan) +- #6266 `ebab5d3` Fix univalue handling of \u0000 characters. (Daniel Kraft) +- #6276 `f3d4dbb` Fix getbalance * 0 (Tom Harding) +- #6257 `5ebe7db` Add `paytxfee` and `errors` JSON fields where appropriate (Stephen) +- #6271 `754aae5` New RPC command disconnectnode (Alex van der Peet) +- #6158 `0abfa8a` Add setban/listbanned RPC commands (Jonas Schnelli) +- #6307 `7ecdcd9` rpcban fixes (Jonas Schnelli) +- #6290 `5753988` rpc: make `gettxoutsettinfo` run lock-free (Wladimir J. van der Laan) +- #6262 `247b914` Return all available information via RPC call "validateaddress" (dexX7) +- #6339 `c3f0490` UniValue: don't escape solidus, keep espacing of reverse solidus (Jonas Schnelli) +- #6353 `6bcb0a2` Show softfork status in getblockchaininfo (Wladimir J. van der Laan) +- #6247 `726e286` Add getblockheader RPC call (Peter Todd) +- #6362 `d6db115` Fix null id in RPC response during startup (Forrest Voight) +- #5486 `943b322` [REST] JSON support for /rest/headers (Jonas Schnelli) +- #6379 `c52e8b3` rpc: Accept scientific notation for monetary amounts in JSON (Wladimir J. van der Laan) +- #6388 `fd5dfda` rpc: Implement random-cookie based authentication (Wladimir J. van der Laan) +- #6457 `3c923e8` Include pruned state in chaininfo.json (Simon Males) +- #6456 `bfd807f` rpc: Avoid unnecessary parsing roundtrip in number formatting, fix locale issue (Wladimir J. van der Laan) +- #6380 `240b30e` rpc: Accept strings in AmountFromValue (Wladimir J. van der Laan) +- #6346 `6bb2805` Add OP_RETURN support in createrawtransaction RPC call, add tests. (paveljanik) +- #6013 `6feeec1` [REST] Add memory pool API (paveljanik) +- #6576 `da9beb2` Stop parsing JSON after first finished construct. (Daniel Kraft) +- #5677 `9aa9099` libevent-based http server (Wladimir J. van der Laan) +- #6633 `bbc2b39` Report minimum ping time in getpeerinfo (Matt Corallo) +- #6648 `cd381d7` Simplify logic of REST request suffix parsing. (Daniel Kraft) +- #6695 `5e21388` libevent http fixes (Wladimir J. van der Laan) +- #5264 `48efbdb` show scriptSig signature hash types in transaction decodes. fixes #3166 (mruddy) +- #6719 `1a9f19a` Make HTTP server shutdown more graceful (Wladimir J. van der Laan) +- #6859 `0fbfc51` http: Restrict maximum size of http + headers (Wladimir J. van der Laan) +- #5936 `bf7c195` [RPC] Add optional locktime to createrawtransaction (Tom Harding) +- #6877 `26f5b34` rpc: Add maxmempool and effective min fee to getmempoolinfo (Wladimir J. van der Laan) +- #6970 `92701b3` Fix crash in validateaddress with -disablewallet (Wladimir J. van der Laan) +- #5574 `755b4ba` Expose GUI labels in RPC as comments (Luke-Jr) +- #6990 `dbd2c13` http: speed up shutdown (Wladimir J. van der Laan) +- #7013 `36baa9f` Remove LOCK(cs_main) from decodescript (Peter Todd) +- #6999 `972bf9c` add (max)uploadtarget infos to getnettotals RPC help (Jonas Schnelli) +- #7011 `31de241` Add mediantime to getblockchaininfo (Peter Todd) +- #7065 `f91e29f` http: add Boost 1.49 compatibility (Wladimir J. van der Laan) +- #7087 `be281d8` [Net]Add -enforcenodebloom option (Patrick Strateman) +- #7044 `438ee59` RPC: Added additional config option for multiple RPC users. (Gregory Sanders) +- #7072 `c143c49` [RPC] Add transaction size to JSON output (Nikita Zhavoronkov) +- #7022 `9afbd96` Change default block priority size to 0 (Alex Morcos) +- #7141 `c0c08c7` rpc: Don't translate warning messages (Wladimir J. van der Laan) +- #7312 `fd4bd50` Add RPC call abandontransaction (Alex Morcos) +- #7222 `e25b158` RPC: indicate which transactions are replaceable (Suhas Daftuar) +- #7472 `b2f2b85` rpc: Add WWW-Authenticate header to 401 response (Wladimir J. van der Laan) +- #7469 `9cb31e6` net.h fix spelling: misbeha{b,v}ing (Matt) + +### Configuration and command-line options + +- #6164 `8d05ec7` Allow user to use -debug=1 to enable all debugging (lpescher) +- #5288 `4452205` Added `-whiteconnections=` option (Josh Lehan) +- #6284 `10ac38e` Fix argument parsing oddity with -noX (Wladimir J. van der Laan) +- #6489 `c9c017a` Give a better error message if system clock is bad (Casey Rodarmor) +- #6462 `c384800` implement uacomment config parameter which can add comments to user agent as per BIP-0014 (Pavol Rusnak) +- #6647 `a3babc8` Sanitize uacomment (MarcoFalke) +- #6742 `3b2d37c` Changed logging to make -logtimestamps to work also for -printtoconsole (arnuschky) +- #6846 `2cd020d` alias -h for -help (Daniel Cousens) +- #6622 `7939164` Introduce -maxuploadtarget (Jonas Schnelli) +- #6881 `2b62551` Debug: Add option for microsecond precision in debug.log (Suhas Daftuar) +- #6776 `e06c14f` Support -checkmempool=N, which runs checks once every N transactions (Pieter Wuille) +- #6896 `d482c0a` Make -checkmempool=1 not fail through int32 overflow (Pieter Wuille) +- #6993 `b632145` Add -blocksonly option (Patrick Strateman) +- #7323 `a344880` 0.12: Backport -bytespersigop option (Luke-Jr) +- #7386 `da83ecd` Add option `-permitrbf` to set transaction replacement policy (Wladimir J. van der Laan) +- #7290 `b16b5bc` Add missing options help (MarcoFalke) +- #7440 `c76bfff` Rename permitrbf to mempoolreplacement and provide minimal string-list forward compatibility (Luke-Jr) + +### Block and transaction handling + +- #6203 `f00b623` Remove P2SH coinbase flag, no longer interesting (Luke-Jr) +- #6222 `9c93ee5` Explicitly set tx.nVersion for the genesis block and mining tests (Mark Friedenbach) +- #5985 `3a1d3e8` Fix removing of orphan transactions (Alex Morcos) +- #6221 `dd8fe82` Prune: Support noncontiguous block files (Adam Weiss) +- #6124 `41076aa` Mempool only CHECKLOCKTIMEVERIFY (BIP65) verification, unparameterized version (Peter Todd) +- #6329 `d0a10c1` acceptnonstdtxn option to skip (most) "non-standard transaction" checks, for testnet/regtest only (Luke-Jr) +- #6410 `7cdefb9` Implement accurate memory accounting for mempool (Pieter Wuille) +- #6444 `24ce77d` Exempt unspendable transaction outputs from dust checks (dexX7) +- #5913 `a0625b8` Add absurdly high fee message to validation state (Shaul Kfir) +- #6177 `2f746c6` Prevent block.nTime from decreasing (Mark Friedenbach) +- #6377 `e545371` Handle no chain tip available in InvalidChainFound() (Ross Nicoll) +- #6551 `39ddaeb` Handle leveldb::DestroyDB() errors on wipe failure (Adam Weiss) +- #6654 `b0ce450` Mempool package tracking (Suhas Daftuar) +- #6715 `82d2aef` Fix mempool packages (Suhas Daftuar) +- #6680 `4f44530` use CBlockIndex instead of uint256 for UpdatedBlockTip signal (Jonas Schnelli) +- #6650 `4fac576` Obfuscate chainstate (James O'Beirne) +- #6777 `9caaf6e` Unobfuscate chainstate data in CCoinsViewDB::GetStats (James O'Beirne) +- #6722 `3b20e23` Limit mempool by throwing away the cheapest txn and setting min relay fee to it (Matt Corallo) +- #6889 `38369dd` fix locking issue with new mempool limiting (Jonas Schnelli) +- #6464 `8f3b3cd` Always clean up manual transaction prioritization (Casey Rodarmor) +- #6865 `d0badb9` Fix chainstate serialized_size computation (Pieter Wuille) +- #6566 `ff057f4` BIP-113: Mempool-only median time-past as endpoint for lock-time calculations (Mark Friedenbach) +- #6934 `3038eb6` Restores mempool only BIP113 enforcement (Gregory Maxwell) +- #6965 `de7d459` Benchmark sanity checks and fork checks in ConnectBlock (Matt Corallo) +- #6918 `eb6172a` Make sigcache faster, more efficient, larger (Pieter Wuille) +- #6771 `38ed190` Policy: Lower default limits for tx chains (Alex Morcos) +- #6932 `73fa5e6` ModifyNewCoins saves database lookups (Alex Morcos) +- #5967 `05d5918` Alter assumptions in CCoinsViewCache::BatchWrite (Alex Morcos) +- #6871 `0e93586` nSequence-based Full-RBF opt-in (Peter Todd) +- #7008 `eb77416` Lower bound priority (Alex Morcos) +- #6915 `2ef5ffa` [Mempool] Improve removal of invalid transactions after reorgs (Suhas Daftuar) +- #6898 `4077ad2` Rewrite CreateNewBlock (Alex Morcos) +- #6872 `bdda4d5` Remove UTXO cache entries when the tx they were added for is removed/does not enter mempool (Matt Corallo) +- #7062 `12c469b` [Mempool] Fix mempool limiting and replace-by-fee for PrioritiseTransaction (Suhas Daftuar) +- #7276 `76de36f` Report non-mandatory script failures correctly (Pieter Wuille) +- #7217 `e08b7cb` Mark blocks with too many sigops as failed (Suhas Daftuar) +- #7387 `f4b2ce8` Get rid of inaccurate ScriptSigArgsExpected (Pieter Wuille) + +### P2P protocol and network code + +- #6172 `88a7ead` Ignore getheaders requests when not synced (Suhas Daftuar) +- #5875 `9d60602` Be stricter in processing unrequested blocks (Suhas Daftuar) +- #6256 `8ccc07c` Use best header chain timestamps to detect partitioning (Gavin Andresen) +- #6283 `a903ad7` make CAddrMan::size() return the correct type of size_t (Diapolo) +- #6272 `40400d5` Improve proxy initialization (continues #4871) (Wladimir J. van der Laan, Diapolo) +- #6310 `66e5465` banlist.dat: store banlist on disk (Jonas Schnelli) +- #6412 `1a2de32` Test whether created sockets are select()able (Pieter Wuille) +- #6498 `219b916` Keep track of recently rejected transactions with a rolling bloom filter (cont'd) (Peter Todd) +- #6556 `70ec975` Fix masking of irrelevant bits in address groups. (Alex Morcos) +- #6530 `ea19c2b` Improve addrman Select() performance when buckets are nearly empty (Pieter Wuille) +- #6583 `af9305a` add support for miniupnpc api version 14 (Pavel Vasin) +- #6374 `69dc5b5` Connection slot exhaustion DoS mitigation (Patrick Strateman) +- #6636 `536207f` net: correctly initialize nMinPingUsecTime (Wladimir J. van der Laan) +- #6579 `0c27795` Add NODE_BLOOM service bit and bump protocol version (Matt Corallo) +- #6148 `999c8be` Relay blocks when pruning (Suhas Daftuar) +- #6588 `cf9bb11` In (strCommand == "tx"), return if AlreadyHave() (Tom Harding) +- #6974 `2f71b07` Always allow getheaders from whitelisted peers (Wladimir J. van der Laan) +- #6639 `bd629d7` net: Automatically create hidden service, listen on Tor (Wladimir J. van der Laan) +- #6984 `9ffc687` don't enforce maxuploadtarget's disconnect for whitelisted peers (Jonas Schnelli) +- #7046 `c322652` Net: Improve blocks only mode. (Patrick Strateman) +- #7090 `d6454f6` Connect to Tor hidden services by default (when listening on Tor) (Peter Todd) +- #7106 `c894fbb` Fix and improve relay from whitelisted peers (Pieter Wuille) +- #7129 `5d5ef3a` Direct headers announcement (rebase of #6494) (Pieter Wuille) +- #7079 `1b5118b` Prevent peer flooding inv request queue (redux) (redux) (Gregory Maxwell) +- #7166 `6ba25d2` Disconnect on mempool requests from peers when over the upload limit. (Gregory Maxwell) +- #7133 `f31955d` Replace setInventoryKnown with a rolling bloom filter (rebase of #7100) (Pieter Wuille) +- #7174 `82aff88` Don't do mempool lookups for "mempool" command without a filter (Matt Corallo) +- #7179 `44fef99` net: Fix sent reject messages for blocks and transactions (Wladimir J. van der Laan) +- #7181 `8fc174a` net: Add and document network messages in protocol.h (Wladimir J. van der Laan) +- #7125 `10b88be` Replace global trickle node with random delays (Pieter Wuille) +- #7415 `cb83beb` net: Hardcoded seeds update January 2016 (Wladimir J. van der Laan) +- #7438 `e2d9a58` Do not absolutely protect local peers; decide group ties based on time (Gregory Maxwell) +- #7439 `86755bc` Add whitelistforcerelay to control forced relaying. [#7099 redux] (Gregory Maxwell) +- #7482 `e16f5b4` Ensure headers count is correct (Suhas Daftuar) + +### Validation + +- #5927 `8d9f0a6` Reduce checkpoints' effect on consensus. (Pieter Wuille) +- #6299 `24f2489` Bugfix: Don't check the genesis block header before accepting it (Jorge Timón) +- #6361 `d7ada03` Use real number of cores for default -par, ignore virtual cores (Wladimir J. van der Laan) +- #6519 `87f37e2` Make logging for validation optional (Wladimir J. van der Laan) +- #6351 `2a1090d` CHECKLOCKTIMEVERIFY (BIP65) IsSuperMajority() soft-fork (Peter Todd) +- #6931 `54e8bfe` Skip BIP 30 verification where not necessary (Alex Morcos) +- #6954 `e54ebbf` Switch to libsecp256k1-based ECDSA validation (Pieter Wuille) +- #6508 `61457c2` Switch to a constant-space Merkle root/branch algorithm. (Pieter Wuille) +- #6914 `327291a` Add pre-allocated vector type and use it for CScript (Pieter Wuille) +- #7500 `889e5b3` Correctly report high-S violations (Pieter Wuille) + + +### Build system + +- #6210 `0e4f2a0` build: disable optional use of gmp in internal secp256k1 build (Wladimir J. van der Laan) +- #6214 `87406aa` [OSX] revert renaming of Bitcoin-Qt.app and use CFBundleDisplayName (partial revert of #6116) (Jonas Schnelli) +- #6218 `9d67b10` build/gitian misc updates (Cory Fields) +- #6269 `d4565b6` gitian: Use the new bitcoin-detached-sigs git repo for OSX signatures (Cory Fields) +- #6418 `d4a910c` Add autogen.sh to source tarball. (randy-waterhouse) +- #6373 `1ae3196` depends: non-qt bumps for 0.12 (Cory Fields) +- #6434 `059b352` Preserve user-passed CXXFLAGS with --enable-debug (Gavin Andresen) +- #6501 `fee6554` Misc build fixes (Cory Fields) +- #6600 `ef4945f` Include bitcoin-tx binary on Debian/Ubuntu (Zak Wilcox) +- #6619 `4862708` depends: bump miniupnpc and ccache (Michael Ford) +- #6801 `ae69a75` [depends] Latest config.guess and config.sub (Michael Ford) +- #6938 `193f7b5` build: If both Qt4 and Qt5 are installed, use Qt5 (Wladimir J. van der Laan) +- #7092 `348b281` build: Set osx permissions in the dmg to make Gatekeeper happy (Cory Fields) +- #6980 `eccd671` [Depends] Bump Boost, miniupnpc, ccache & zeromq (Michael Ford) +- #7424 `aa26ee0` Add security/export checks to gitian and fix current failures (Cory Fields) + +### Wallet + +- #6183 `87550ee` Fix off-by-one error w/ nLockTime in the wallet (Peter Todd) +- #6057 `ac5476e` re-enable wallet in autoprune (Jonas Schnelli) +- #6356 `9e6c33b` Delay initial pruning until after wallet init (Adam Weiss) +- #6088 `91389e5` fundrawtransaction (Matt Corallo) +- #6415 `ddd8d80` Implement watchonly support in fundrawtransaction (Matt Corallo) +- #6567 `0f0f323` Fix crash when mining with empty keypool. (Daniel Kraft) +- #6688 `4939eab` Fix locking in GetTransaction. (Alex Morcos) +- #6645 `4dbd43e` Enable wallet key imports without rescan in pruned mode. (Gregory Maxwell) +- #6550 `5b77244` Do not store Merkle branches in the wallet. (Pieter Wuille) +- #5924 `12a7712` Clean up change computation in CreateTransaction. (Daniel Kraft) +- #6906 `48b5b84` Reject invalid pubkeys when reading ckey items from the wallet. (Gregory Maxwell) +- #7010 `e0a5ef8` Fix fundrawtransaction handling of includeWatching (Peter Todd) +- #6851 `616d61b` Optimisation: Store transaction list order in memory rather than compute it every need (Luke-Jr) +- #6134 `e92377f` Improve usage of fee estimation code (Alex Morcos) +- #7103 `a775182` [wallet, rpc tests] Fix settxfee, paytxfee (MarcoFalke) +- #7105 `30c2d8c` Keep track of explicit wallet conflicts instead of using mempool (Pieter Wuille) +- #7096 `9490bd7` [Wallet] Improve minimum absolute fee GUI options (Jonas Schnelli) +- #6216 `83f06ca` Take the training wheels off anti-fee-sniping (Peter Todd) +- #4906 `96e8d12` Issue#1643: Coinselection prunes extraneous inputs from ApproximateBestSubset (Murch) +- #7200 `06c6a58` Checks for null data transaction before issuing error to debug.log (Andy Craze) +- #7296 `a36d79b` Add sane fallback for fee estimation (Alex Morcos) +- #7293 `ff9b610` Add regression test for vValue sort order (MarcoFalke) +- #7306 `4707797` Make sure conflicted wallet tx's update balances (Alex Morcos) +- #7381 `621bbd8` [walletdb] Fix syntax error in key parser (MarcoFalke) +- #7491 `00ec73e` wallet: Ignore MarkConflict if block hash is not known (Wladimir J. van der Laan) +- #7502 `1329963` Update the wallet best block marker before pruning (Pieter Wuille) + +### GUI + +- #6217 `c57e12a` disconnect peers from peers tab via context menu (Diapolo) +- #6209 `ab0ec67` extend rpc console peers tab (Diapolo) +- #6484 `1369d69` use CHashWriter also in SignVerifyMessageDialog (Pavel Vasin) +- #6487 `9848d42` Introduce PlatformStyle (Wladimir J. van der Laan) +- #6505 `100c9d3` cleanup icons (MarcoFalke) +- #4587 `0c465f5` allow users to set -onion via GUI (Diapolo) +- #6529 `c0f66ce` show client user agent in debug window (Diapolo) +- #6594 `878ea69` Disallow duplicate windows. (Casey Rodarmor) +- #5665 `6f55cdd` add verifySize() function to PaymentServer (Diapolo) +- #6317 `ca5e2a1` minor optimisations in peertablemodel (Diapolo) +- #6315 `e59d2a8` allow banning and unbanning over UI->peers table (Jonas Schnelli) +- #6653 `e04b2fa` Pop debug window in foreground when opened twice (MarcoFalke) +- #6864 `c702521` Use monospace font (MarcoFalke) +- #6887 `3694b74` Update coin control and smartfee labels (MarcoFalke) +- #7000 `814697c` add shortcurts for debug-/console-window (Jonas Schnelli) +- #6951 `03403d8` Use maxTxFee instead of 10000000 (MarcoFalke) +- #7051 `a190777` ui: Add "Copy raw transaction data" to transaction list context menu (Wladimir J. van der Laan) +- #6979 `776848a` simple mempool info in debug window (Jonas Schnelli) +- #7006 `26af1ac` add startup option to reset Qt settings (Jonas Schnelli) +- #6780 `2a94cd6` Call init's parameter interaction before we create the UI options model (Jonas Schnelli) +- #7112 `96b8025` reduce cs_main locks during tip update, more fluently update UI (Jonas Schnelli) +- #7206 `f43c2f9` Add "NODE_BLOOM" to guiutil so that peers don't get UNKNOWN[4] (Matt Corallo) +- #7282 `5cadf3e` fix coincontrol update issue when deleting a send coins entry (Jonas Schnelli) +- #7319 `1320300` Intro: Display required space (MarcoFalke) +- #7318 `9265e89` quickfix for RPC timer interface problem (Jonas Schnelli) +- #7327 `b16b5bc` [Wallet] Transaction View: LastMonth calculation fixed (crowning-) +- #7364 `7726c48` [qt] Windows: Make rpcconsole monospace font larger (MarcoFalke) +- #7384 `294f432` [qt] Peertable: Increase SUBVERSION_COLUMN_WIDTH (MarcoFalke) + +### Tests and QA + +- #6305 `9005c91` build: comparison tool swap (Cory Fields) +- #6318 `e307e13` build: comparison tool NPE fix (Cory Fields) +- #6337 `0564c5b` Testing infrastructure: mocktime fixes (Gavin Andresen) +- #6350 `60abba1` add unit tests for the decodescript rpc (mruddy) +- #5881 `3203a08` Fix and improve txn_doublespend.py test (Tom Harding) +- #6390 `6a73d66` tests: Fix bitcoin-tx signing test case (Wladimir J. van der Laan) +- #6368 `7fc25c2` CLTV: Add more tests to improve coverage (Esteban Ordano) +- #6414 `5121c68` Fix intermittent test failure, reduce test time (Tom Harding) +- #6417 `44fa82d` [QA] fix possible reorg issue in (fund)rawtransaction(s).py RPC test (Jonas Schnelli) +- #6398 `3d9362d` rpc: Remove chain-specific RequireRPCPassword (Wladimir J. van der Laan) +- #6428 `bb59e78` tests: Remove old sh-based test framework (Wladimir J. van der Laan) +- #5515 `d946e9a` RFC: Assert on probable deadlocks if the second lock isnt try_lock (Matt Corallo) +- #6287 `d2464df` Clang lock debug (Cory Fields) +- #6465 `410fd74` Don't share objects between TestInstances (Casey Rodarmor) +- #6534 `6c1c7fd` Fix test locking issues and un-revert the probable-deadlines assertions commit (Cory Fields) +- #6509 `bb4faee` Fix race condition on test node shutdown (Casey Rodarmor) +- #6523 `561f8af` Add p2p-fullblocktest.py (Casey Rodarmor) +- #6590 `981fd92` Fix stale socket rebinding and re-enable python tests for Windows (Cory Fields) +- #6730 `cb4d6d0` build: Remove dependency of bitcoin-cli on secp256k1 (Wladimir J. van der Laan) +- #6616 `5ab5dca` Regression Tests: Migrated rpc-tests.sh to all Python rpc-tests.py (Peter Tschipper) +- #6720 `d479311` Creates unittests for addrman, makes addrman more testable. (Ethan Heilman) +- #6853 `c834f56` Added fPowNoRetargeting field to Consensus::Params (Eric Lombrozo) +- #6827 `87e5539` [rpc-tests] Check return code (MarcoFalke) +- #6848 `f2c869a` Add DERSIG transaction test cases (Ross Nicoll) +- #6813 `5242bb3` Support gathering code coverage data for RPC tests with lcov (dexX7) +- #6888 `c8322ff` Clear strMiscWarning before running PartitionAlert (Eric Lombrozo) +- #6894 `2675276` [Tests] Fix BIP65 p2p test (Suhas Daftuar) +- #6863 `725539e` [Test Suite] Fix test for null tx input (Daniel Kraft) +- #6926 `a6d0d62` tests: Initialize networking on windows (Wladimir J. van der Laan) +- #6822 `9fa54a1` [tests] Be more strict checking dust (MarcoFalke) +- #6804 `5fcc14e` [tests] Add basic coverage reporting for RPC tests (James O'Beirne) +- #7045 `72dccfc` Bugfix: Use unique autostart filenames on Linux for testnet/regtest (Luke-Jr) +- #7095 `d8368a0` Replace scriptnum_test's normative ScriptNum implementation (Wladimir J. van der Laan) +- #7063 `6abf6eb` [Tests] Add prioritisetransaction RPC test (Suhas Daftuar) +- #7137 `16f4a6e` Tests: Explicitly set chain limits in replace-by-fee test (Suhas Daftuar) +- #7216 `9572e49` Removed offline testnet DNSSeed 'alexykot.me'. (tnull) +- #7209 `f3ad812` test: don't override BITCOIND and BITCOINCLI if they're set (Wladimir J. van der Laan) +- #7226 `301f16a` Tests: Add more tests to p2p-fullblocktest (Suhas Daftuar) +- #7153 `9ef7c54` [Tests] Add mempool_limit.py test (Jonas Schnelli) +- #7170 `453c567` tests: Disable Tor interaction (Wladimir J. van der Laan) +- #7229 `1ed938b` [qa] wallet: Check if maintenance changes the balance (MarcoFalke) +- #7308 `d513405` [Tests] Eliminate intermittent failures in sendheaders.py (Suhas Daftuar) +- #7468 `947c4ff` [rpc-tests] Change solve() to use rehash (Brad Andrews) + +### Miscellaneous + +- #6213 `e54ff2f` [init] add -blockversion help and extend -upnp help (Diapolo) +- #5975 `1fea667` Consensus: Decouple ContextualCheckBlockHeader from checkpoints (Jorge Timón) +- #6061 `eba2f06` Separate Consensus::CheckTxInputs and GetSpendHeight in CheckInputs (Jorge Timón) +- #5994 `786ed11` detach wallet from miner (Jonas Schnelli) +- #6387 `11576a5` [bitcoin-cli] improve error output (Jonas Schnelli) +- #6401 `6db53b4` Add BITCOIND_SIGTERM_TIMEOUT to OpenRC init scripts (Florian Schmaus) +- #6430 `b01981e` doc: add documentation for shared library libbitcoinconsensus (Braydon Fuller) +- #6372 `dcc495e` Update Linearize tool to support Windows paths; fix variable scope; update README and example configuration (Paul Georgiou) +- #6453 `8fe5cce` Separate core memory usage computation in core_memusage.h (Pieter Wuille) +- #6149 `633fe10` Buffer log messages and explicitly open logs (Adam Weiss) +- #6488 `7cbed7f` Avoid leaking file descriptors in RegisterLoad (Casey Rodarmor) +- #6497 `a2bf40d` Make sure LogPrintf strings are line-terminated (Wladimir J. van der Laan) +- #6504 `b6fee6b` Rationalize currency unit to "BTC" (Ross Nicoll) +- #6507 `9bb4dd8` Removed contrib/bitrpc (Casey Rodarmor) +- #6527 `41d650f` Use unique name for AlertNotify tempfile (Casey Rodarmor) +- #6561 `e08a7d9` limitedmap fixes and tests (Casey Rodarmor) +- #6565 `a6f2aff` Make sure we re-acquire lock if a task throws (Casey Rodarmor) +- #6599 `f4d88c4` Make sure LogPrint strings are line-terminated (Ross Nicoll) +- #6630 `195942d` Replace boost::reverse_lock with our own (Casey Rodarmor) +- #6103 `13b8282` Add ZeroMQ notifications (João Barbosa) +- #6692 `d5d1d2e` devtools: don't push if signing fails in github-merge (Wladimir J. van der Laan) +- #6728 `2b0567b` timedata: Prevent warning overkill (Wladimir J. van der Laan) +- #6713 `f6ce59c` SanitizeString: Allow hypen char (MarcoFalke) +- #5987 `4899a04` Bugfix: Fix testnet-in-a-box use case (Luke-Jr) +- #6733 `b7d78fd` Simple benchmarking framework (Gavin Andresen) +- #6854 `a092970` devtools: Add security-check.py (Wladimir J. van der Laan) +- #6790 `fa1d252` devtools: add clang-format.py (MarcoFalke) +- #7114 `f3d0fdd` util: Don't set strMiscWarning on every exception (Wladimir J. van der Laan) +- #7078 `93e0514` uint256::GetCheapHash bigendian compatibility (arowser) +- #7094 `34e02e0` Assert now > 0 in GetTime GetTimeMillis GetTimeMicros (Patrick Strateman) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- accraze +- Adam Weiss +- Alex Morcos +- Alex van der Peet +- AlSzacrel +- Altoidnerd +- Andriy Voskoboinyk +- antonio-fr +- Arne Brutschy +- Ashley Holman +- Bob McElrath +- Braydon Fuller +- BtcDrak +- Casey Rodarmor +- centaur1 +- Chris Kleeschulte +- Christian Decker +- Cory Fields +- crowning- +- daniel +- Daniel Cousens +- Daniel Kraft +- David Hill +- dexX7 +- Diego Viola +- Elias Rohrer +- Eric Lombrozo +- Erik Mossberg +- Esteban Ordano +- EthanHeilman +- Florian Schmaus +- Forrest Voight +- Gavin Andresen +- Gregory Maxwell +- Gregory Sanders / instagibbs +- Ian T +- Irving Ruan +- Jacob Welsh +- James O'Beirne +- Jeff Garzik +- Johnathan Corgan +- Jonas Schnelli +- Jonathan Cross +- João Barbosa +- Jorge Timón +- Josh Lehan +- J Ross Nicoll +- kazcw +- Kevin Cooper +- lpescher +- Luke Dashjr +- MarcoFalke +- Mark Friedenbach +- Matt +- Matt Bogosian +- Matt Corallo +- Matt Quinn +- Micha +- Michael +- Michael Ford / fanquake +- Midnight Magic +- Mitchell Cash +- mrbandrews +- mruddy +- Nick +- Patrick Strateman +- Paul Georgiou +- Paul Rabahy +- Pavel Janík / paveljanik +- Pavel Vasin +- Pavol Rusnak +- Peter Josling +- Peter Todd +- Philip Kaufmann +- Pieter Wuille +- ptschip +- randy-waterhouse +- rion +- Ross Nicoll +- Ryan Havar +- Shaul Kfir +- Simon Males +- Stephen +- Suhas Daftuar +- tailsjoin +- Thomas Kerin +- Tom Harding +- tulip +- unsystemizer +- Veres Lajos +- Wladimir J. van der Laan +- xor-freenet +- Zak Wilcox +- zathras-crypto + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). + diff --git a/doc/release-notes/release-notes-0.6.3.md b/doc/release-notes/release-notes-0.6.3.md index 28bb20e10..c27f607b5 100644 --- a/doc/release-notes/release-notes-0.6.3.md +++ b/doc/release-notes/release-notes-0.6.3.md @@ -23,7 +23,7 @@ hundreds of blocks long. Bitcoin-Qt no longer automatically selects the first address in the address book (Issue #1384). -Fixed minimize-to-dock behavior of Bitcon-Qt on the Mac. +Fixed minimize-to-dock behavior of Bitcoin-Qt on the Mac. Added a block checkpoint at block 185,333 to speed up initial blockchain download. diff --git a/doc/release-process.md b/doc/release-process.md index 9a2362cb8..5a6ac8482 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -3,6 +3,7 @@ Release Process * Update translations (ping wumpus, Diapolo or tcatm on IRC) see [translation_process.md](https://github.com/bitcoin/bitcoin/blob/master/doc/translation_process.md#syncing-with-transifex) * Update [bips.md](bips.md) to account for changes since the last release. +* Update hardcoded [seeds](/contrib/seeds) * * * @@ -19,8 +20,10 @@ Check out the source code in the following directory hierarchy. pushd ./bitcoin contrib/verifysfbinaries/verify.sh + configure.ac doc/README* - share/setup.nsi + doc/Doxyfile + contrib/gitian-descriptors/*.yml src/clientversion.h (change CLIENT_VERSION_IS_RELEASE to true) # tag version in git @@ -41,6 +44,7 @@ Check out the source code in the following directory hierarchy. pushd ./bitcoin export SIGNER=(your Gitian key, ie bluematt, sipa, etc) export VERSION=(new version, e.g. 0.8.0) + git fetch git checkout v${VERSION} popd @@ -83,25 +87,21 @@ NOTE: Offline builds must use the --url flag to ensure Gitian fetches only from ``` The gbuild invocations below DO NOT DO THIS by default. -###Build (and optionally verify) Bitcoin Core for Linux, Windows, and OS X: +###Build and sign Bitcoin Core for Linux, Windows, and OS X: ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml ./bin/gsign --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml - ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-linux ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml - mv build/out/bitcoin-*.tar.gz build/out/src/bitcoin-*.tar.gz ../ + mv build/out/bitcoin-*.tar.gz build/out/src/bitcoin-*.tar.gz ../ ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml ./bin/gsign --signer $SIGNER --release ${VERSION}-win-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win.yml - ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-win.yml - mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz - mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../ + mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz + mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../ ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml ./bin/gsign --signer $SIGNER --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml - ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml - mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz - mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../ - popd + mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz + mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../ Build output expected: @@ -111,6 +111,20 @@ The gbuild invocations below DO NOT DO THIS by default. 4. OS X unsigned installer and dist tarball (bitcoin-${VERSION}-osx-unsigned.dmg, bitcoin-${VERSION}-osx64.tar.gz) 5. Gitian signatures (in gitian.sigs/${VERSION}-/(your Gitian key)/ +###Verify other gitian builders signatures to your own. (Optional) + + Add other gitian builders keys to your gpg keyring + + gpg --import ../bitcoin/contrib/gitian-keys/*.pgp + + Verify the signatures + + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-linux ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-win.yml + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml + + popd + ###Next steps: Commit your signature to gitian.sigs: @@ -124,7 +138,6 @@ Commit your signature to gitian.sigs: popd Wait for Windows/OS X detached signatures: - Once the Windows/OS X builds each have 3 matching signatures, they will be signed with their respective release keys. Detached signatures will then be committed to the [bitcoin-detached-sigs](https://github.com/bitcoin/bitcoin-detached-sigs) repository, which can be combined with the unsigned apps to create signed binaries. @@ -197,7 +210,7 @@ Note: check that SHA256SUMS itself doesn't end up in SHA256SUMS, which is a spur - Optionally reddit /r/Bitcoin, ... but this will usually sort out itself -- Notify BlueMatt so that he can start building [https://launchpad.net/~bitcoin/+archive/ubuntu/bitcoin](the PPAs) +- Notify BlueMatt so that he can start building [the PPAs](https://launchpad.net/~bitcoin/+archive/ubuntu/bitcoin) - Add release notes for the new version to the directory `doc/release-notes` in git master diff --git a/doc/shared-libraries.md b/doc/shared-libraries.md index f4ff53d6e..ec6f16c8a 100644 --- a/doc/shared-libraries.md +++ b/doc/shared-libraries.md @@ -11,7 +11,7 @@ The interface is defined in the C header `bitcoinconsensus.h` located in `src/s #### Version -`bitcoinconsensus_version` returns an `unsigned int` with the the API version *(currently at an experimental `0`)*. +`bitcoinconsensus_version` returns an `unsigned int` with the API version *(currently at an experimental `0`)*. #### Script Validation diff --git a/doc/tor.md b/doc/tor.md index 594897f89..43e922718 100644 --- a/doc/tor.md +++ b/doc/tor.md @@ -3,7 +3,7 @@ TOR SUPPORT IN BITCOIN It is possible to run Bitcoin as a Tor hidden service, and connect to such services. -The following directions assume you have a Tor proxy running on port 9050. Many distributions default to having a SOCKS proxy listening on port 9050, but others may not. In particular, the Tor Browser Bundle defaults to listening on a random port. See [Tor Project FAQ:TBBSocksPort](https://www.torproject.org/docs/faq.html.en#TBBSocksPort) for how to properly +The following directions assume you have a Tor proxy running on port 9050. Many distributions default to having a SOCKS proxy listening on port 9050, but others may not. In particular, the Tor Browser Bundle defaults to listening on port 9150. See [Tor Project FAQ:TBBSocksPort](https://www.torproject.org/docs/faq.html.en#TBBSocksPort) for how to properly configure Tor. @@ -52,7 +52,7 @@ your bitcoind's P2P listen port (8333 by default). this option, and this can be a .onion address. Given the above configuration, you can find your onion address in /var/lib/tor/bitcoin-service/hostname. Onion addresses are given - preference for your node to advertize itself with, for connections + preference for your node to advertise itself with, for connections coming from unroutable addresses (such as 127.0.0.1, where the Tor proxy typically runs). @@ -87,3 +87,20 @@ If you only want to use Tor to reach onion addresses, but not use it as a proxy for normal IPv4/IPv6 communication, use: ./bitcoin -onion=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -discover + +3. Automatically listen on Tor +-------------------------------- + +Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket +API, to create and destroy 'ephemeral' hidden services programmatically. +Bitcoin Core has been updated to make use of this. + +This means that if Tor is running (and proper authorization is available), +Bitcoin Core automatically creates a hidden service to listen on, without +manual configuration. This will positively affect the number of available +.onion nodes. + +This new feature is enabled by default if Bitcoin Core is listening, and +a connection to Tor can be made. It can be configured with the `-listenonion`, +`-torcontrol` and `-torpassword` settings. To show verbose debugging +information, pass `-debug=tor`. diff --git a/doc/translation_process.md b/doc/translation_process.md index 6389c5ace..310d560b3 100644 --- a/doc/translation_process.md +++ b/doc/translation_process.md @@ -74,10 +74,10 @@ The Transifex Bitcoin project config file is included as part of the repo. It ca To assist in updating translations, we have created a script to help. 1. `python contrib/devtools/update-translations.py` -2. Update `src/qt/bitcoin.qrc` manually or via +2. Update `src/qt/bitcoin_locale.qrc` manually or via `ls src/qt/locale/*ts|xargs -n1 basename|sed 's/\(bitcoin_\(.*\)\).ts/locale\/\1.qm<\/file>/'` -3. Update `src/qt/Makefile.am` manually or via - `ls src/qt/locale/*ts|xargs -n1 basename|sed 's/\(bitcoin_\(.*\)\).ts/ locale\/\1.ts \\/'` +3. Update `src/Makefile.qt.include` manually or via + `ls src/qt/locale/*ts|xargs -n1 basename|sed 's/\(bitcoin_\(.*\)\).ts/ qt\/locale\/\1.ts \\/'` 4. `git add` new translations from `src/qt/locale/` **Do not directly download translations** one by one from the Transifex website, as we do a few post-processing steps before committing the translations. diff --git a/doc/translation_strings_policy.md b/doc/translation_strings_policy.md index 936a6112c..b95259cdc 100644 --- a/doc/translation_strings_policy.md +++ b/doc/translation_strings_policy.md @@ -52,7 +52,7 @@ Try to write translation strings in an understandable way, for both the user and ### Do not translate internal errors Do 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, -use a generic message, then log the detailed message to the log. E.g. "Error: A fatal internal error occurred, see debug.log for details". +use a translatable generic message, then log the detailed message to the log. E.g. "A fatal internal error occurred, see debug.log for details". This helps troubleshooting; if the error is the same for everyone, the likelihood is increased that it can be found using a search engine. ### Avoid fragments diff --git a/doc/travis-ci.txt b/doc/travis-ci.txt index 01f7d02a8..06410405d 100644 --- a/doc/travis-ci.txt +++ b/doc/travis-ci.txt @@ -27,7 +27,7 @@ In order to avoid rebuilding all dependencies for each build, the binaries are cached and re-used when possible. Changes in the dependency-generator will trigger cache-invalidation and rebuilds as necessary. -These caches can be manually removed if necessary. This is one of the the very few +These caches can be manually removed if necessary. This is one of the very few manual operations that is possible with Travis, and it can be done by the Bitcoin Core committer via the Travis web interface. diff --git a/doc/unit-tests.md b/doc/unit-tests.md index 72613054b..afaece829 100644 --- a/doc/unit-tests.md +++ b/doc/unit-tests.md @@ -1,18 +1,18 @@ Compiling/running unit tests ------------------------------------ -Unit tests will be automatically compiled if dependencies were met in configure +Unit tests will be automatically compiled if dependencies were met in `./configure` and tests weren't explicitly disabled. -After configuring, they can be run with 'make check'. +After configuring, they can be run with `make check`. -To run the bitcoind tests manually, launch src/test/test_bitcoin . +To run the bitcoind tests manually, launch `src/test/test_bitcoin`. To add more bitcoind tests, add `BOOST_AUTO_TEST_CASE` functions to the existing -.cpp files in the test/ directory or add new .cpp files that +.cpp files in the `test/` directory or add new .cpp files that implement new BOOST_AUTO_TEST_SUITE sections. -To run the bitcoin-qt tests manually, launch src/qt/test/test_bitcoin-qt +To run the bitcoin-qt tests manually, launch `src/qt/test/test_bitcoin-qt` To add more bitcoin-qt tests, add them to the `src/qt/test/` directory and the `src/qt/test/test_main.cpp` file. diff --git a/libbitcoinconsensus.pc.in b/libbitcoinconsensus.pc.in index 3ca1696a3..eb920c47e 100644 --- a/libbitcoinconsensus.pc.in +++ b/libbitcoinconsensus.pc.in @@ -3,7 +3,7 @@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ -Name: Bitcoin Core consensus library +Name: @PACKAGE_NAME@ consensus library Description: Library for the Bitcoin consensus protocol. Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lbitcoinconsensus diff --git a/qa/README.md b/qa/README.md new file mode 100644 index 000000000..2b476c4d8 --- /dev/null +++ b/qa/README.md @@ -0,0 +1,68 @@ +The [pull-tester](/qa/pull-tester/) folder contains a script to call +multiple tests from the [rpc-tests](/qa/rpc-tests/) folder. + +Every pull request to the bitcoin repository is built and run through +the regression test suite. You can also run all or only individual +tests locally. + +Test dependencies +================= +Before running the tests, the following must be installed. + +Unix +---- +The python-zmq library is required. On Ubuntu or Debian it can be installed via: +``` +sudo apt-get install python-zmq +``` + +Running tests +============= + +You can run any single test by calling `qa/pull-tester/rpc-tests.py `. + +Or you can run any combination of tests by calling `qa/pull-tester/rpc-tests.py ...` + +Run the regression test suite with `qa/pull-tester/rpc-tests.py` + +Run all possible tests with `qa/pull-tester/rpc-tests.py -extended` + +Possible options: + +``` + -h, --help show this help message and exit + --nocleanup Leave bitcoinds and test.* datadir on exit or error + --noshutdown Don't stop bitcoinds after the test execution + --srcdir=SRCDIR Source directory containing bitcoind/bitcoin-cli + (default: ../../src) + --tmpdir=TMPDIR Root directory for datadirs + --tracerpc Print out all RPC calls as they are made + --coveragedir=COVERAGEDIR + Write tested RPC commands into this directory +``` + +If you set the environment variable `PYTHON_DEBUG=1` you will get some debug +output (example: `PYTHON_DEBUG=1 qa/pull-tester/rpc-tests.py wallet`). + +A 200-block -regtest blockchain and wallets for four nodes +is created the first time a regression test is run and +is stored in the cache/ directory. Each node has 25 mature +blocks (25*50=1250 BTC) in its wallet. + +After the first run, the cache/ blockchain and wallets are +copied into a temporary directory and used as the initial +test state. + +If you get into a bad state, you should be able +to recover with: + +```bash +rm -rf cache +killall bitcoind +``` + +Writing tests +============= +You are encouraged to write tests for new or existing features. +Further information about the test framework and individual rpc +tests is found in [qa/rpc-tests](/qa/rpc-tests). diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index 8a431d718..6d3bda10e 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -1,43 +1,80 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -# -# Run Regression Test Suite -# +""" +Run Regression Test Suite + +This module calls down into individual test cases via subprocess. It will +forward all unrecognized arguments onto the individual test scripts, other +than: + + - `-extended`: run the "extended" test suite in addition to the basic one. + - `-win`: signal that this is running in a Windows environment, and we + should run the tests. + - `--coverage`: this generates a basic coverage report for the RPC + interface. + +For a description of arguments recognized by test scripts, see +`qa/pull-tester/test_framework/test_framework.py:BitcoinTestFramework.main`. + +""" import os +import time +import shutil import sys import subprocess +import tempfile import re + from tests_config import * -from sets import Set #If imported values are not defined then set to zero (or disabled) -if not vars().has_key('ENABLE_WALLET'): +if 'ENABLE_WALLET' not in vars(): ENABLE_WALLET=0 -if not vars().has_key('ENABLE_BITCOIND'): +if 'ENABLE_BITCOIND' not in vars(): ENABLE_BITCOIND=0 -if not vars().has_key('ENABLE_UTILS'): +if 'ENABLE_UTILS' not in vars(): ENABLE_UTILS=0 -if not vars().has_key('ENABLE_ZMQ'): +if 'ENABLE_ZMQ' not in vars(): ENABLE_ZMQ=0 + +# python-zmq may not be installed. Handle this gracefully and with some helpful info +if ENABLE_ZMQ: + try: + import zmq + except ImportError: + print("WARNING: \"import zmq\" failed. Setting ENABLE_ZMQ=0. " \ + "To run zmq tests, see dependency info in /qa/README.md.") + ENABLE_ZMQ=0 + +ENABLE_COVERAGE=0 #Create a set to store arguments and create the passOn string -opts = Set() +opts = set() passOn = "" p = re.compile("^--") -for i in range(1,len(sys.argv)): - if (p.match(sys.argv[i]) or sys.argv[i] == "-h"): - passOn += " " + sys.argv[i] + +bold = ("","") +if (os.name == 'posix'): + bold = ('\033[0m', '\033[1m') + +for arg in sys.argv[1:]: + if arg == '--coverage': + ENABLE_COVERAGE = 1 + elif (p.match(arg) or arg == "-h"): + passOn += " " + arg else: - opts.add(sys.argv[i]) + opts.add(arg) #Set env vars buildDir = BUILDDIR -os.environ["BITCOIND"] = buildDir + '/src/bitcoind' + EXEEXT -os.environ["BITCOINCLI"] = buildDir + '/src/bitcoin-cli' + EXEEXT +if "BITCOIND" not in os.environ: + os.environ["BITCOIND"] = buildDir + '/src/bitcoind' + EXEEXT +if "BITCOINCLI" not in os.environ: + os.environ["BITCOINCLI"] = buildDir + '/src/bitcoin-cli' + EXEEXT #Disable Windows tests by default if EXEEXT == ".exe" and "-win" not in opts: @@ -46,8 +83,10 @@ if EXEEXT == ".exe" and "-win" not in opts: #Tests testScripts = [ + 'bip68-112-113-p2p.py', 'wallet.py', 'listtransactions.py', + 'receivedby.py', 'mempool_resurrect_test.py', 'txn_doublespend.py --mineblock', 'txn_clone.py', @@ -55,8 +94,10 @@ testScripts = [ 'rawtransactions.py', 'rest.py', 'mempool_spendcoinbase.py', - 'mempool_coinbase_spends.py', + 'mempool_reorg.py', + 'mempool_limit.py', 'httpbasics.py', + 'multi_rpc.py', 'zapwallettxes.py', 'proxy_test.py', 'merkle_blocks.py', @@ -68,50 +109,167 @@ testScripts = [ 'decodescript.py', 'p2p-fullblocktest.py', 'blockchain.py', + 'disablewallet.py', + 'sendheaders.py', + 'keypool.py', + 'prioritise_transaction.py', + 'invalidblockrequest.py', + 'invalidtxrequest.py', + 'abandonconflict.py', + 'p2p-versionbits-warning.py', + 'importprunedfunds.py', ] testScriptsExt = [ + 'bip9-softforks.py', + 'bip65-cltv.py', + 'bip65-cltv-p2p.py', + 'bip68-sequence.py', 'bipdersig-p2p.py', 'bipdersig.py', 'getblocktemplate_longpoll.py', 'getblocktemplate_proposals.py', 'txn_doublespend.py', 'txn_clone.py --mineblock', - 'pruning.py', 'forknotify.py', 'invalidateblock.py', - 'keypool.py', - 'receivedby.py', # 'rpcbind_test.py', #temporary, bug in libevent, see #6655 -# 'script_test.py', #used for manual comparison of 2 binaries 'smartfees.py', 'maxblocksinflight.py', - 'invalidblockrequest.py', 'p2p-acceptblock.py', 'mempool_packages.py', + 'maxuploadtarget.py', + 'replace-by-fee.py', + 'p2p-feefilter.py', + 'pruning.py', # leave pruning last as it takes a REALLY long time ] #Enable ZMQ tests if ENABLE_ZMQ == 1: testScripts.append('zmq_test.py') -if(ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1): - rpcTestDir = buildDir + '/qa/rpc-tests/' - #Run Tests - for i in range(len(testScripts)): - if (len(opts) == 0 or (len(opts) == 1 and "-win" in opts ) or '-extended' in opts - or testScripts[i] in opts or re.sub(".py$", "", testScripts[i]) in opts ): - print "Running testscript " + testScripts[i] + "..." - subprocess.check_call(rpcTestDir + testScripts[i] + " --srcdir " + buildDir + '/src ' + passOn,shell=True) - #exit if help is called so we print just one set of instructions - p = re.compile(" -h| --help") - if p.match(passOn): - sys.exit(0) - #Run Extended Tests - for i in range(len(testScriptsExt)): - if ('-extended' in opts or testScriptsExt[i] in opts - or re.sub(".py$", "", testScriptsExt[i]) in opts): - print "Running 2nd level testscript " + testScriptsExt[i] + "..." - subprocess.check_call(rpcTestDir + testScriptsExt[i] + " --srcdir " + buildDir + '/src ' + passOn,shell=True) -else: - print "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled" +def runtests(): + coverage = None + + if ENABLE_COVERAGE: + coverage = RPCCoverage() + print("Initializing coverage directory at %s\n" % coverage.dir) + + if(ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1): + rpcTestDir = buildDir + '/qa/rpc-tests/' + run_extended = '-extended' in opts + cov_flag = coverage.flag if coverage else '' + flags = " --srcdir %s/src %s %s" % (buildDir, cov_flag, passOn) + + #Run Tests + for i in range(len(testScripts)): + if (len(opts) == 0 + or (len(opts) == 1 and "-win" in opts ) + or run_extended + or testScripts[i] in opts + or re.sub(".py$", "", testScripts[i]) in opts ): + + print("Running testscript %s%s%s ..." % (bold[1], testScripts[i], bold[0])) + time0 = time.time() + subprocess.check_call( + rpcTestDir + testScripts[i] + flags, shell=True) + print("Duration: %s s\n" % (int(time.time() - time0))) + + # exit if help is called so we print just one set of + # instructions + p = re.compile(" -h| --help") + if p.match(passOn): + sys.exit(0) + + # Run Extended Tests + for i in range(len(testScriptsExt)): + if (run_extended or testScriptsExt[i] in opts + or re.sub(".py$", "", testScriptsExt[i]) in opts): + + print( + "Running 2nd level testscript " + + "%s%s%s ..." % (bold[1], testScriptsExt[i], bold[0])) + time0 = time.time() + subprocess.check_call( + rpcTestDir + testScriptsExt[i] + flags, shell=True) + print("Duration: %s s\n" % (int(time.time() - time0))) + + if coverage: + coverage.report_rpc_coverage() + + print("Cleaning up coverage data") + coverage.cleanup() + + else: + print "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled" + + +class RPCCoverage(object): + """ + Coverage reporting utilities for pull-tester. + + Coverage calculation works by having each test script subprocess write + coverage files into a particular directory. These files contain the RPC + commands invoked during testing, as well as a complete listing of RPC + commands per `bitcoin-cli help` (`rpc_interface.txt`). + + After all tests complete, the commands run are combined and diff'd against + the complete list to calculate uncovered RPC commands. + + See also: qa/rpc-tests/test_framework/coverage.py + + """ + def __init__(self): + self.dir = tempfile.mkdtemp(prefix="coverage") + self.flag = '--coveragedir %s' % self.dir + + def report_rpc_coverage(self): + """ + Print out RPC commands that were unexercised by tests. + + """ + uncovered = self._get_uncovered_rpc_commands() + + if uncovered: + print("Uncovered RPC commands:") + print("".join((" - %s\n" % i) for i in sorted(uncovered))) + else: + print("All RPC commands covered.") + + def cleanup(self): + return shutil.rmtree(self.dir) + + def _get_uncovered_rpc_commands(self): + """ + Return a set of currently untested RPC commands. + + """ + # This is shared from `qa/rpc-tests/test-framework/coverage.py` + REFERENCE_FILENAME = 'rpc_interface.txt' + COVERAGE_FILE_PREFIX = 'coverage.' + + coverage_ref_filename = os.path.join(self.dir, REFERENCE_FILENAME) + coverage_filenames = set() + all_cmds = set() + covered_cmds = set() + + if not os.path.isfile(coverage_ref_filename): + raise RuntimeError("No coverage reference found") + + with open(coverage_ref_filename, 'r') as f: + all_cmds.update([i.strip() for i in f.readlines()]) + + for root, dirs, files in os.walk(self.dir): + for filename in files: + if filename.startswith(COVERAGE_FILE_PREFIX): + coverage_filenames.add(os.path.join(root, filename)) + + for filename in coverage_filenames: + with open(filename, 'r') as f: + covered_cmds.update([i.strip() for i in f.readlines()]) + + return all_cmds - covered_cmds + + +if __name__ == '__main__': + runtests() diff --git a/qa/rpc-tests/README.md b/qa/rpc-tests/README.md index d2db00362..651b01f18 100644 --- a/qa/rpc-tests/README.md +++ b/qa/rpc-tests/README.md @@ -1,10 +1,8 @@ Regression tests ================ -### [python-bitcoinrpc](https://github.com/jgarzik/python-bitcoinrpc) -Git subtree of [https://github.com/jgarzik/python-bitcoinrpc](https://github.com/jgarzik/python-bitcoinrpc). -Changes to python-bitcoinrpc should be made upstream, and then -pulled here using git subtree. +### [test_framework/authproxy.py](test_framework/authproxy.py) +Taken from the [python-bitcoinrpc repository](https://github.com/jgarzik/python-bitcoinrpc). ### [test_framework/test_framework.py](test_framework/test_framework.py) Base class for new regression tests. @@ -33,49 +31,6 @@ Helpers for script.py ### [test_framework/blocktools.py](test_framework/blocktools.py) Helper functions for creating blocks and transactions. - -Notes -===== - -You can run any single test by calling `qa/pull-tester/rpc-tests.py `. - -Or you can run any combination of tests by calling `qa/pull-tester/rpc-tests.py ...` - -Run the regression test suite with `qa/pull-tester/rpc-tests.py` - -Run all possible tests with `qa/pull-tester/rpc-tests.py -extended` - -Possible options: - -``` --h, --help show this help message and exit - --nocleanup Leave bitcoinds and test.* datadir on exit or error - --noshutdown Don't stop bitcoinds after the test execution - --srcdir=SRCDIR Source directory containing bitcoind/bitcoin-cli (default: - ../../src) - --tmpdir=TMPDIR Root directory for datadirs - --tracerpc Print out all RPC calls as they are made -``` - -If you set the environment variable `PYTHON_DEBUG=1` you will get some debug output (example: `PYTHON_DEBUG=1 qa/pull-tester/rpc-tests.py wallet`). - -A 200-block -regtest blockchain and wallets for four nodes -is created the first time a regression test is run and -is stored in the cache/ directory. Each node has 25 mature -blocks (25*50=1250 BTC) in its wallet. - -After the first run, the cache/ blockchain and wallets are -copied into a temporary directory and used as the initial -test state. - -If you get into a bad state, you should be able -to recover with: - -```bash -rm -rf cache -killall bitcoind -``` - P2P test design notes --------------------- @@ -92,10 +47,7 @@ implements the test logic. * ```NodeConn``` is the class used to connect to a bitcoind. If you implement a callback class that derives from ```NodeConnCB``` and pass that to the ```NodeConn``` object, your code will receive the appropriate callbacks when -events of interest arrive. NOTE: be sure to call -```self.create_callback_map()``` in your derived classes' ```__init__``` -function, so that the correct mappings are set up between p2p messages and your -callback functions. +events of interest arrive. * You can pass the same handler to multiple ```NodeConn```'s if you like, or pass different ones to each -- whatever makes the most sense for your test. diff --git a/qa/rpc-tests/abandonconflict.py b/qa/rpc-tests/abandonconflict.py new file mode 100755 index 000000000..a83aa97fc --- /dev/null +++ b/qa/rpc-tests/abandonconflict.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +try: + import urllib.parse as urlparse +except ImportError: + import urlparse + +class AbandonConflictTest(BitcoinTestFramework): + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.00001"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-logtimemicros"])) + connect_nodes(self.nodes[0], 1) + + def run_test(self): + self.nodes[1].generate(100) + sync_blocks(self.nodes) + balance = self.nodes[0].getbalance() + txA = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10")) + txB = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10")) + txC = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10")) + sync_mempools(self.nodes) + self.nodes[1].generate(1) + + sync_blocks(self.nodes) + newbalance = self.nodes[0].getbalance() + assert(balance - newbalance < Decimal("0.001")) #no more than fees lost + balance = newbalance + + url = urlparse.urlparse(self.nodes[1].url) + self.nodes[0].disconnectnode(url.hostname+":"+str(p2p_port(1))) + + # Identify the 10btc outputs + nA = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txA, 1)["vout"]) if vout["value"] == Decimal("10")) + nB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txB, 1)["vout"]) if vout["value"] == Decimal("10")) + nC = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txC, 1)["vout"]) if vout["value"] == Decimal("10")) + + inputs =[] + # spend 10btc outputs from txA and txB + inputs.append({"txid":txA, "vout":nA}) + inputs.append({"txid":txB, "vout":nB}) + outputs = {} + + outputs[self.nodes[0].getnewaddress()] = Decimal("14.99998") + outputs[self.nodes[1].getnewaddress()] = Decimal("5") + signed = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs)) + txAB1 = self.nodes[0].sendrawtransaction(signed["hex"]) + + # Identify the 14.99998btc output + nAB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txAB1, 1)["vout"]) if vout["value"] == Decimal("14.99998")) + + #Create a child tx spending AB1 and C + inputs = [] + inputs.append({"txid":txAB1, "vout":nAB}) + inputs.append({"txid":txC, "vout":nC}) + outputs = {} + outputs[self.nodes[0].getnewaddress()] = Decimal("24.9996") + signed2 = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs)) + txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"]) + + # In mempool txs from self should increase balance from change + newbalance = self.nodes[0].getbalance() + assert(newbalance == balance - Decimal("30") + Decimal("24.9996")) + balance = newbalance + + # Restart the node with a higher min relay fee so the parent tx is no longer in mempool + # TODO: redo with eviction + # Note had to make sure tx did not have AllowFree priority + stop_node(self.nodes[0],0) + self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.0001"]) + + # Verify txs no longer in mempool + assert(len(self.nodes[0].getrawmempool()) == 0) + + # Not in mempool txs from self should only reduce balance + # inputs are still spent, but change not received + newbalance = self.nodes[0].getbalance() + assert(newbalance == balance - Decimal("24.9996")) + # Unconfirmed received funds that are not in mempool, also shouldn't show + # up in unconfirmed balance + unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance() + assert(unconfbalance == newbalance) + # Also shouldn't show up in listunspent + assert(not txABC2 in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)]) + balance = newbalance + + # Abandon original transaction and verify inputs are available again + # including that the child tx was also abandoned + self.nodes[0].abandontransaction(txAB1) + newbalance = self.nodes[0].getbalance() + assert(newbalance == balance + Decimal("30")) + balance = newbalance + + # Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned + stop_node(self.nodes[0],0) + self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.00001"]) + assert(len(self.nodes[0].getrawmempool()) == 0) + assert(self.nodes[0].getbalance() == balance) + + # But if its received again then it is unabandoned + # And since now in mempool, the change is available + # But its child tx remains abandoned + self.nodes[0].sendrawtransaction(signed["hex"]) + newbalance = self.nodes[0].getbalance() + assert(newbalance == balance - Decimal("20") + Decimal("14.99998")) + balance = newbalance + + # Send child tx again so its unabandoned + self.nodes[0].sendrawtransaction(signed2["hex"]) + newbalance = self.nodes[0].getbalance() + assert(newbalance == balance - Decimal("10") - Decimal("14.99998") + Decimal("24.9996")) + balance = newbalance + + # Remove using high relay fee again + stop_node(self.nodes[0],0) + self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.0001"]) + assert(len(self.nodes[0].getrawmempool()) == 0) + newbalance = self.nodes[0].getbalance() + assert(newbalance == balance - Decimal("24.9996")) + balance = newbalance + + # Create a double spend of AB1 by spending again from only A's 10 output + # Mine double spend from node 1 + inputs =[] + inputs.append({"txid":txA, "vout":nA}) + outputs = {} + outputs[self.nodes[1].getnewaddress()] = Decimal("9.9999") + tx = self.nodes[0].createrawtransaction(inputs, outputs) + signed = self.nodes[0].signrawtransaction(tx) + self.nodes[1].sendrawtransaction(signed["hex"]) + self.nodes[1].generate(1) + + connect_nodes(self.nodes[0], 1) + sync_blocks(self.nodes) + + # Verify that B and C's 10 BTC outputs are available for spending again because AB1 is now conflicted + newbalance = self.nodes[0].getbalance() + assert(newbalance == balance + Decimal("20")) + balance = newbalance + + # There is currently a minor bug around this and so this test doesn't work. See Issue #7315 + # Invalidate the block with the double spend and B's 10 BTC output should no longer be available + # Don't think C's should either + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + newbalance = self.nodes[0].getbalance() + #assert(newbalance == balance - Decimal("10")) + print "If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer" + print "conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315" + print balance , " -> " , newbalance , " ?" + +if __name__ == '__main__': + AbandonConflictTest().main() diff --git a/qa/rpc-tests/bip65-cltv-p2p.py b/qa/rpc-tests/bip65-cltv-p2p.py new file mode 100755 index 000000000..99d74344a --- /dev/null +++ b/qa/rpc-tests/bip65-cltv-p2p.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +from test_framework.test_framework import ComparisonTestFramework +from test_framework.util import * +from test_framework.mininode import CTransaction, NetworkThread +from test_framework.blocktools import create_coinbase, create_block +from test_framework.comptool import TestInstance, TestManager +from test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP +from io import BytesIO +import time + +def cltv_invalidate(tx): + '''Modify the signature in vin 0 of the tx to fail CLTV + + Prepends -1 CLTV DROP in the scriptSig itself. + ''' + tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP] + + list(CScript(tx.vin[0].scriptSig))) + +''' +This test is meant to exercise BIP65 (CHECKLOCKTIMEVERIFY) +Connect to a single node. +Mine 2 (version 3) blocks (save the coinbases for later). +Generate 98 more version 3 blocks, verify the node accepts. +Mine 749 version 4 blocks, verify the node accepts. +Check that the new CLTV rules are not enforced on the 750th version 4 block. +Check that the new CLTV rules are enforced on the 751st version 4 block. +Mine 199 new version blocks. +Mine 1 old-version block. +Mine 1 new version block. +Mine 1 old version block, see that the node rejects. +''' + +class BIP65Test(ComparisonTestFramework): + + def __init__(self): + self.num_nodes = 1 + + def setup_network(self): + # Must set the blockversion for this test + self.nodes = start_nodes(1, self.options.tmpdir, + extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=3']], + binary=[self.options.testbinary]) + + def run_test(self): + test = TestManager(self, self.options.tmpdir) + test.add_all_connections(self.nodes) + NetworkThread().start() # Start up network handling in another thread + test.run() + + def create_transaction(self, node, coinbase, to_address, amount): + from_txid = node.getblock(coinbase)['tx'][0] + inputs = [{ "txid" : from_txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + signresult = node.signrawtransaction(rawtx) + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(signresult['hex'])) + tx.deserialize(f) + return tx + + def get_tests(self): + + self.coinbase_blocks = self.nodes[0].generate(2) + height = 3 # height of the next block to build + self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) + self.nodeaddress = self.nodes[0].getnewaddress() + self.last_block_time = int(time.time()) + + ''' 98 more version 3 blocks ''' + test_blocks = [] + for i in xrange(98): + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 3 + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance(test_blocks, sync_every_block=False) + + ''' Mine 749 version 4 blocks ''' + test_blocks = [] + for i in xrange(749): + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 4 + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance(test_blocks, sync_every_block=False) + + ''' + Check that the new CLTV rules are not enforced in the 750th + version 3 block. + ''' + spendtx = self.create_transaction(self.nodes[0], + self.coinbase_blocks[0], self.nodeaddress, 1.0) + cltv_invalidate(spendtx) + spendtx.rehash() + + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 4 + block.vtx.append(spendtx) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance([[block, True]]) + + ''' + Check that the new CLTV rules are enforced in the 751st version 4 + block. + ''' + spendtx = self.create_transaction(self.nodes[0], + self.coinbase_blocks[1], self.nodeaddress, 1.0) + cltv_invalidate(spendtx) + spendtx.rehash() + + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 4 + block.vtx.append(spendtx) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + self.last_block_time += 1 + yield TestInstance([[block, False]]) + + ''' Mine 199 new version blocks on last valid tip ''' + test_blocks = [] + for i in xrange(199): + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 4 + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance(test_blocks, sync_every_block=False) + + ''' Mine 1 old version block ''' + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 3 + block.rehash() + block.solve() + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance([[block, True]]) + + ''' Mine 1 new version block ''' + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 4 + block.rehash() + block.solve() + self.last_block_time += 1 + self.tip = block.sha256 + height += 1 + yield TestInstance([[block, True]]) + + ''' Mine 1 old version block, should be invalid ''' + block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1) + block.nVersion = 3 + block.rehash() + block.solve() + self.last_block_time += 1 + yield TestInstance([[block, False]]) + +if __name__ == '__main__': + BIP65Test().main() diff --git a/qa/rpc-tests/bip65-cltv.py b/qa/rpc-tests/bip65-cltv.py new file mode 100755 index 000000000..f666a07c9 --- /dev/null +++ b/qa/rpc-tests/bip65-cltv.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test the CHECKLOCKTIMEVERIFY (BIP65) soft-fork logic +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class BIP65Test(BitcoinTestFramework): + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, [])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=3"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=4"])) + connect_nodes(self.nodes[1], 0) + connect_nodes(self.nodes[2], 0) + self.is_network_split = False + self.sync_all() + + def run_test(self): + cnt = self.nodes[0].getblockcount() + + # Mine some old-version blocks + self.nodes[1].generate(100) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 100): + raise AssertionError("Failed to mine 100 version=3 blocks") + + # Mine 750 new-version blocks + for i in xrange(15): + self.nodes[2].generate(50) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 850): + raise AssertionError("Failed to mine 750 version=4 blocks") + + # TODO: check that new CHECKLOCKTIMEVERIFY rules are not enforced + + # Mine 1 new-version block + self.nodes[2].generate(1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 851): + raise AssertionError("Failed to mine a version=4 blocks") + + # TODO: check that new CHECKLOCKTIMEVERIFY rules are enforced + + # Mine 198 new-version blocks + for i in xrange(2): + self.nodes[2].generate(99) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1049): + raise AssertionError("Failed to mine 198 version=4 blocks") + + # Mine 1 old-version block + self.nodes[1].generate(1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1050): + raise AssertionError("Failed to mine a version=3 block after 949 version=4 blocks") + + # Mine 1 new-version blocks + self.nodes[2].generate(1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1051): + raise AssertionError("Failed to mine a version=4 block") + + # Mine 1 old-version blocks + try: + self.nodes[1].generate(1) + raise AssertionError("Succeeded to mine a version=3 block after 950 version=4 blocks") + except JSONRPCException: + pass + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1051): + raise AssertionError("Accepted a version=3 block after 950 version=4 blocks") + + # Mine 1 new-version blocks + self.nodes[2].generate(1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1052): + raise AssertionError("Failed to mine a version=4 block") + +if __name__ == '__main__': + BIP65Test().main() diff --git a/qa/rpc-tests/bip68-112-113-p2p.py b/qa/rpc-tests/bip68-112-113-p2p.py new file mode 100755 index 000000000..3bcfdabe2 --- /dev/null +++ b/qa/rpc-tests/bip68-112-113-p2p.py @@ -0,0 +1,539 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +from test_framework.test_framework import ComparisonTestFramework +from test_framework.util import * +from test_framework.mininode import ToHex, CTransaction, NetworkThread +from test_framework.blocktools import create_coinbase, create_block +from test_framework.comptool import TestInstance, TestManager +from test_framework.script import * +from io import BytesIO +import time + +''' +This test is meant to exercise activation of the first version bits soft fork +This soft fork will activate the following BIPS: +BIP 68 - nSequence relative lock times +BIP 112 - CHECKSEQUENCEVERIFY +BIP 113 - MedianTimePast semantics for nLockTime + +regtest lock-in with 108/144 block signalling +activation after a further 144 blocks + +mine 82 blocks whose coinbases will be used to generate inputs for our tests +mine 61 blocks to transition from DEFINED to STARTED +mine 144 blocks only 100 of which are signaling readiness in order to fail to change state this period +mine 144 blocks with 108 signaling and verify STARTED->LOCKED_IN +mine 140 blocks and seed block chain with the 82 inputs will use for our tests at height 572 +mine 3 blocks and verify still at LOCKED_IN and test that enforcement has not triggered +mine 1 block and test that enforcement has triggered (which triggers ACTIVE) +Test BIP 113 is enforced +Mine 4 blocks so next height is 580 and test BIP 68 is enforced for time and height +Mine 1 block so next height is 581 and test BIP 68 now passes time but not height +Mine 1 block so next height is 582 and test BIP 68 now passes time and height +Test that BIP 112 is enforced + +Various transactions will be used to test that the BIPs rules are not enforced before the soft fork activates +And that after the soft fork activates transactions pass and fail as they should according to the rules. +For each BIP, transactions of versions 1 and 2 will be tested. +---------------- +BIP 113: +bip113tx - modify the nLocktime variable + +BIP 68: +bip68txs - 16 txs with nSequence relative locktime of 10 with various bits set as per the relative_locktimes below + +BIP 112: +bip112txs_vary_nSequence - 16 txs with nSequence relative_locktimes of 10 evaluated against 10 OP_CSV OP_DROP +bip112txs_vary_nSequence_9 - 16 txs with nSequence relative_locktimes of 9 evaluated against 10 OP_CSV OP_DROP +bip112txs_vary_OP_CSV - 16 txs with nSequence = 10 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP +bip112txs_vary_OP_CSV_9 - 16 txs with nSequence = 9 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP +bip112tx_special - test negative argument to OP_CSV +''' + +base_relative_locktime = 10 +seq_disable_flag = 1<<31 +seq_random_high_bit = 1<<25 +seq_type_flag = 1<<22 +seq_random_low_bit = 1<<18 + +# b31,b25,b22,b18 represent the 31st, 25th, 22nd and 18th bits respectively in the nSequence field +# relative_locktimes[b31][b25][b22][b18] is a base_relative_locktime with the indicated bits set if their indices are 1 +relative_locktimes = [] +for b31 in xrange(2): + b25times = [] + for b25 in xrange(2): + b22times = [] + for b22 in xrange(2): + b18times = [] + for b18 in xrange(2): + rlt = base_relative_locktime + if (b31): + rlt = rlt | seq_disable_flag + if (b25): + rlt = rlt | seq_random_high_bit + if (b22): + rlt = rlt | seq_type_flag + if (b18): + rlt = rlt | seq_random_low_bit + b18times.append(rlt) + b22times.append(b18times) + b25times.append(b22times) + relative_locktimes.append(b25times) + +def all_rlt_txs(txarray): + txs = [] + for b31 in xrange(2): + for b25 in xrange(2): + for b22 in xrange(2): + for b18 in xrange(2): + txs.append(txarray[b31][b25][b22][b18]) + return txs + +class BIP68_112_113Test(ComparisonTestFramework): + def __init__(self): + self.num_nodes = 1 + + def setup_network(self): + # Must set the blockversion for this test + self.nodes = start_nodes(1, self.options.tmpdir, + extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=4']], + binary=[self.options.testbinary]) + + def run_test(self): + test = TestManager(self, self.options.tmpdir) + test.add_all_connections(self.nodes) + NetworkThread().start() # Start up network handling in another thread + test.run() + + def send_generic_input_tx(self, node, coinbases): + amount = Decimal("49.99") + return node.sendrawtransaction(ToHex(self.sign_transaction(node, self.create_transaction(node, node.getblock(coinbases.pop())['tx'][0], self.nodeaddress, amount)))) + + def create_transaction(self, node, txid, to_address, amount): + inputs = [{ "txid" : txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(rawtx)) + tx.deserialize(f) + return tx + + def sign_transaction(self, node, unsignedtx): + rawtx = ToHex(unsignedtx) + signresult = node.signrawtransaction(rawtx) + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(signresult['hex'])) + tx.deserialize(f) + return tx + + def generate_blocks(self, number, version, test_blocks = []): + for i in xrange(number): + block = self.create_test_block([], version) + test_blocks.append([block, True]) + self.last_block_time += 600 + self.tip = block.sha256 + self.tipheight += 1 + return test_blocks + + def create_test_block(self, txs, version = 536870912): + block = create_block(self.tip, create_coinbase(self.tipheight + 1), self.last_block_time + 600) + block.nVersion = version + block.vtx.extend(txs) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + return block + + def create_bip68txs(self, bip68inputs, txversion, locktime_delta = 0): + txs = [] + assert(len(bip68inputs) >= 16) + i = 0 + for b31 in xrange(2): + b25txs = [] + for b25 in xrange(2): + b22txs = [] + for b22 in xrange(2): + b18txs = [] + for b18 in xrange(2): + tx = self.create_transaction(self.nodes[0], bip68inputs[i], self.nodeaddress, Decimal("49.98")) + i += 1 + tx.nVersion = txversion + tx.vin[0].nSequence = relative_locktimes[b31][b25][b22][b18] + locktime_delta + b18txs.append(self.sign_transaction(self.nodes[0], tx)) + b22txs.append(b18txs) + b25txs.append(b22txs) + txs.append(b25txs) + return txs + + def create_bip112special(self, input, txversion): + tx = self.create_transaction(self.nodes[0], input, self.nodeaddress, Decimal("49.98")) + tx.nVersion = txversion + signtx = self.sign_transaction(self.nodes[0], tx) + signtx.vin[0].scriptSig = CScript([-1, OP_NOP3, OP_DROP] + list(CScript(signtx.vin[0].scriptSig))) + return signtx + + def create_bip112txs(self, bip112inputs, varyOP_CSV, txversion, locktime_delta = 0): + txs = [] + assert(len(bip112inputs) >= 16) + i = 0 + for b31 in xrange(2): + b25txs = [] + for b25 in xrange(2): + b22txs = [] + for b22 in xrange(2): + b18txs = [] + for b18 in xrange(2): + tx = self.create_transaction(self.nodes[0], bip112inputs[i], self.nodeaddress, Decimal("49.98")) + i += 1 + if (varyOP_CSV): # if varying OP_CSV, nSequence is fixed + tx.vin[0].nSequence = base_relative_locktime + locktime_delta + else: # vary nSequence instead, OP_CSV is fixed + tx.vin[0].nSequence = relative_locktimes[b31][b25][b22][b18] + locktime_delta + tx.nVersion = txversion + signtx = self.sign_transaction(self.nodes[0], tx) + if (varyOP_CSV): + signtx.vin[0].scriptSig = CScript([relative_locktimes[b31][b25][b22][b18], OP_NOP3, OP_DROP] + list(CScript(signtx.vin[0].scriptSig))) + else: + signtx.vin[0].scriptSig = CScript([base_relative_locktime, OP_NOP3, OP_DROP] + list(CScript(signtx.vin[0].scriptSig))) + b18txs.append(signtx) + b22txs.append(b18txs) + b25txs.append(b22txs) + txs.append(b25txs) + return txs + + def get_tests(self): + 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 + self.nodes[0].setmocktime(long_past_time - 100) # enough so that the generated blocks will still all be before long_past_time + self.coinbase_blocks = self.nodes[0].generate(1 + 16 + 2*32 + 1) # 82 blocks generated for inputs + self.nodes[0].setmocktime(0) # set time back to present so yielded blocks aren't in the future as we advance last_block_time + self.tipheight = 82 # height of the next block to build + self.last_block_time = long_past_time + self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) + self.nodeaddress = self.nodes[0].getnewaddress() + + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'defined') + test_blocks = self.generate_blocks(61, 4) + yield TestInstance(test_blocks, sync_every_block=False) # 1 + # Advanced from DEFINED to STARTED, height = 143 + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') + + # Fail to achieve LOCKED_IN 100 out of 144 signal bit 0 + # using a variety of bits to simulate multiple parallel softforks + test_blocks = self.generate_blocks(50, 536870913) # 0x20000001 (signalling ready) + test_blocks = self.generate_blocks(20, 4, test_blocks) # 0x00000004 (signalling not) + test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready) + test_blocks = self.generate_blocks(24, 536936448, test_blocks) # 0x20010000 (signalling not) + yield TestInstance(test_blocks, sync_every_block=False) # 2 + # Failed to advance past STARTED, height = 287 + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') + + # 108 out of 144 signal bit 0 to achieve lock-in + # using a variety of bits to simulate multiple parallel softforks + test_blocks = self.generate_blocks(58, 536870913) # 0x20000001 (signalling ready) + test_blocks = self.generate_blocks(26, 4, test_blocks) # 0x00000004 (signalling not) + test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready) + test_blocks = self.generate_blocks(10, 536936448, test_blocks) # 0x20010000 (signalling not) + yield TestInstance(test_blocks, sync_every_block=False) # 3 + # Advanced from STARTED to LOCKED_IN, height = 431 + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') + + # 140 more version 4 blocks + test_blocks = self.generate_blocks(140, 4) + yield TestInstance(test_blocks, sync_every_block=False) # 4 + + ### Inputs at height = 572 + # Put inputs for all tests in the chain at height 572 (tip now = 571) (time increases by 600s per block) + # Note we reuse inputs for v1 and v2 txs so must test these separately + # 16 normal inputs + bip68inputs = [] + for i in xrange(16): + bip68inputs.append(self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks)) + # 2 sets of 16 inputs with 10 OP_CSV OP_DROP (actually will be prepended to spending scriptSig) + bip112basicinputs = [] + for j in xrange(2): + inputs = [] + for i in xrange(16): + inputs.append(self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks)) + bip112basicinputs.append(inputs) + # 2 sets of 16 varied inputs with (relative_lock_time) OP_CSV OP_DROP (actually will be prepended to spending scriptSig) + bip112diverseinputs = [] + for j in xrange(2): + inputs = [] + for i in xrange(16): + inputs.append(self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks)) + bip112diverseinputs.append(inputs) + # 1 special input with -1 OP_CSV OP_DROP (actually will be prepended to spending scriptSig) + bip112specialinput = self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks) + # 1 normal input + bip113input = self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks) + + self.nodes[0].setmocktime(self.last_block_time + 600) + inputblockhash = self.nodes[0].generate(1)[0] # 1 block generated for inputs to be in chain at height 572 + self.nodes[0].setmocktime(0) + self.tip = int("0x" + inputblockhash + "L", 0) + self.tipheight += 1 + self.last_block_time += 600 + assert_equal(len(self.nodes[0].getblock(inputblockhash,True)["tx"]), 82+1) + + # 2 more version 4 blocks + test_blocks = self.generate_blocks(2, 4) + yield TestInstance(test_blocks, sync_every_block=False) # 5 + # Not yet advanced to ACTIVE, height = 574 (will activate for block 576, not 575) + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') + + # Test both version 1 and version 2 transactions for all tests + # BIP113 test transaction will be modified before each use to put in appropriate block time + bip113tx_v1 = self.create_transaction(self.nodes[0], bip113input, self.nodeaddress, Decimal("49.98")) + bip113tx_v1.vin[0].nSequence = 0xFFFFFFFE + bip113tx_v2 = self.create_transaction(self.nodes[0], bip113input, self.nodeaddress, Decimal("49.98")) + bip113tx_v2.vin[0].nSequence = 0xFFFFFFFE + bip113tx_v2.nVersion = 2 + + # For BIP68 test all 16 relative sequence locktimes + bip68txs_v1 = self.create_bip68txs(bip68inputs, 1) + bip68txs_v2 = self.create_bip68txs(bip68inputs, 2) + + # For BIP112 test: + # 16 relative sequence locktimes of 10 against 10 OP_CSV OP_DROP inputs + bip112txs_vary_nSequence_v1 = self.create_bip112txs(bip112basicinputs[0], False, 1) + bip112txs_vary_nSequence_v2 = self.create_bip112txs(bip112basicinputs[0], False, 2) + # 16 relative sequence locktimes of 9 against 10 OP_CSV OP_DROP inputs + bip112txs_vary_nSequence_9_v1 = self.create_bip112txs(bip112basicinputs[1], False, 1, -1) + bip112txs_vary_nSequence_9_v2 = self.create_bip112txs(bip112basicinputs[1], False, 2, -1) + # sequence lock time of 10 against 16 (relative_lock_time) OP_CSV OP_DROP inputs + bip112txs_vary_OP_CSV_v1 = self.create_bip112txs(bip112diverseinputs[0], True, 1) + bip112txs_vary_OP_CSV_v2 = self.create_bip112txs(bip112diverseinputs[0], True, 2) + # sequence lock time of 9 against 16 (relative_lock_time) OP_CSV OP_DROP inputs + bip112txs_vary_OP_CSV_9_v1 = self.create_bip112txs(bip112diverseinputs[1], True, 1, -1) + bip112txs_vary_OP_CSV_9_v2 = self.create_bip112txs(bip112diverseinputs[1], True, 2, -1) + # -1 OP_CSV OP_DROP input + bip112tx_special_v1 = self.create_bip112special(bip112specialinput, 1) + bip112tx_special_v2 = self.create_bip112special(bip112specialinput, 2) + + + ### TESTING ### + ################################## + ### Before Soft Forks Activate ### + ################################## + # All txs should pass + ### Version 1 txs ### + success_txs = [] + # add BIP113 tx and -1 CSV tx + bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block + bip113signed1 = self.sign_transaction(self.nodes[0], bip113tx_v1) + success_txs.append(bip113signed1) + success_txs.append(bip112tx_special_v1) + # add BIP 68 txs + success_txs.extend(all_rlt_txs(bip68txs_v1)) + # add BIP 112 with seq=10 txs + success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_v1)) + success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_v1)) + # try BIP 112 with seq=9 txs + success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v1)) + success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_9_v1)) + yield TestInstance([[self.create_test_block(success_txs), True]]) # 6 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + ### Version 2 txs ### + success_txs = [] + # add BIP113 tx and -1 CSV tx + bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block + bip113signed2 = self.sign_transaction(self.nodes[0], bip113tx_v2) + success_txs.append(bip113signed2) + success_txs.append(bip112tx_special_v2) + # add BIP 68 txs + success_txs.extend(all_rlt_txs(bip68txs_v2)) + # add BIP 112 with seq=10 txs + success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_v2)) + success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_v2)) + # try BIP 112 with seq=9 txs + success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v2)) + success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_9_v2)) + yield TestInstance([[self.create_test_block(success_txs), True]]) # 7 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + + # 1 more version 4 block to get us to height 575 so the fork should now be active for the next block + test_blocks = self.generate_blocks(1, 4) + yield TestInstance(test_blocks, sync_every_block=False) # 8 + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'active') + + + ################################# + ### After Soft Forks Activate ### + ################################# + ### BIP 113 ### + # BIP 113 tests should now fail regardless of version number if nLockTime isn't satisfied by new rules + bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block + bip113signed1 = self.sign_transaction(self.nodes[0], bip113tx_v1) + bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block + bip113signed2 = self.sign_transaction(self.nodes[0], bip113tx_v2) + for bip113tx in [bip113signed1, bip113signed2]: + yield TestInstance([[self.create_test_block([bip113tx]), False]]) # 9,10 + # BIP 113 tests should now pass if the locktime is < MTP + bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block + bip113signed1 = self.sign_transaction(self.nodes[0], bip113tx_v1) + bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block + bip113signed2 = self.sign_transaction(self.nodes[0], bip113tx_v2) + for bip113tx in [bip113signed1, bip113signed2]: + yield TestInstance([[self.create_test_block([bip113tx]), True]]) # 11,12 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + # Next block height = 580 after 4 blocks of random version + test_blocks = self.generate_blocks(4, 1234) + yield TestInstance(test_blocks, sync_every_block=False) # 13 + + ### BIP 68 ### + ### Version 1 txs ### + # All still pass + success_txs = [] + success_txs.extend(all_rlt_txs(bip68txs_v1)) + yield TestInstance([[self.create_test_block(success_txs), True]]) # 14 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + ### Version 2 txs ### + bip68success_txs = [] + # All txs with SEQUENCE_LOCKTIME_DISABLE_FLAG set pass + for b25 in xrange(2): + for b22 in xrange(2): + for b18 in xrange(2): + bip68success_txs.append(bip68txs_v2[1][b25][b22][b18]) + yield TestInstance([[self.create_test_block(bip68success_txs), True]]) # 15 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + # All txs without flag fail as we are at delta height = 8 < 10 and delta time = 8 * 600 < 10 * 512 + bip68timetxs = [] + for b25 in xrange(2): + for b18 in xrange(2): + bip68timetxs.append(bip68txs_v2[0][b25][1][b18]) + for tx in bip68timetxs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 16 - 19 + bip68heighttxs = [] + for b25 in xrange(2): + for b18 in xrange(2): + bip68heighttxs.append(bip68txs_v2[0][b25][0][b18]) + for tx in bip68heighttxs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 20 - 23 + + # Advance one block to 581 + test_blocks = self.generate_blocks(1, 1234) + yield TestInstance(test_blocks, sync_every_block=False) # 24 + + # Height txs should fail and time txs should now pass 9 * 600 > 10 * 512 + bip68success_txs.extend(bip68timetxs) + yield TestInstance([[self.create_test_block(bip68success_txs), True]]) # 25 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + for tx in bip68heighttxs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 26 - 29 + + # Advance one block to 582 + test_blocks = self.generate_blocks(1, 1234) + yield TestInstance(test_blocks, sync_every_block=False) # 30 + + # All BIP 68 txs should pass + bip68success_txs.extend(bip68heighttxs) + yield TestInstance([[self.create_test_block(bip68success_txs), True]]) # 31 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + + ### BIP 112 ### + ### Version 1 txs ### + # -1 OP_CSV tx should fail + yield TestInstance([[self.create_test_block([bip112tx_special_v1]), False]]) #32 + # If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 1 txs should still pass + success_txs = [] + for b25 in xrange(2): + for b22 in xrange(2): + for b18 in xrange(2): + success_txs.append(bip112txs_vary_OP_CSV_v1[1][b25][b22][b18]) + success_txs.append(bip112txs_vary_OP_CSV_9_v1[1][b25][b22][b18]) + yield TestInstance([[self.create_test_block(success_txs), True]]) # 33 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + # If SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV, version 1 txs should now fail + fail_txs = [] + fail_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_v1)) + fail_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v1)) + for b25 in xrange(2): + for b22 in xrange(2): + for b18 in xrange(2): + fail_txs.append(bip112txs_vary_OP_CSV_v1[0][b25][b22][b18]) + fail_txs.append(bip112txs_vary_OP_CSV_9_v1[0][b25][b22][b18]) + + for tx in fail_txs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 34 - 81 + + ### Version 2 txs ### + # -1 OP_CSV tx should fail + yield TestInstance([[self.create_test_block([bip112tx_special_v2]), False]]) #82 + + # If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 2 txs should pass (all sequence locks are met) + success_txs = [] + for b25 in xrange(2): + for b22 in xrange(2): + for b18 in xrange(2): + success_txs.append(bip112txs_vary_OP_CSV_v2[1][b25][b22][b18]) # 8/16 of vary_OP_CSV + success_txs.append(bip112txs_vary_OP_CSV_9_v2[1][b25][b22][b18]) # 8/16 of vary_OP_CSV_9 + + yield TestInstance([[self.create_test_block(success_txs), True]]) # 83 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + ## SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV for all remaining txs ## + # All txs with nSequence 9 should fail either due to earlier mismatch or failing the CSV check + fail_txs = [] + fail_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v2)) # 16/16 of vary_nSequence_9 + for b25 in xrange(2): + for b22 in xrange(2): + for b18 in xrange(2): + fail_txs.append(bip112txs_vary_OP_CSV_9_v2[0][b25][b22][b18]) # 16/16 of vary_OP_CSV_9 + + for tx in fail_txs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 84 - 107 + + # If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in nSequence, tx should fail + fail_txs = [] + for b25 in xrange(2): + for b22 in xrange(2): + for b18 in xrange(2): + fail_txs.append(bip112txs_vary_nSequence_v2[1][b25][b22][b18]) # 8/16 of vary_nSequence + for tx in fail_txs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 108-115 + + # If sequencelock types mismatch, tx should fail + fail_txs = [] + for b25 in xrange(2): + for b18 in xrange(2): + fail_txs.append(bip112txs_vary_nSequence_v2[0][b25][1][b18]) # 12/16 of vary_nSequence + fail_txs.append(bip112txs_vary_OP_CSV_v2[0][b25][1][b18]) # 12/16 of vary_OP_CSV + for tx in fail_txs: + yield TestInstance([[self.create_test_block([tx]), False]]) # 116-123 + + # Remaining txs should pass, just test masking works properly + success_txs = [] + for b25 in xrange(2): + for b18 in xrange(2): + success_txs.append(bip112txs_vary_nSequence_v2[0][b25][0][b18]) # 16/16 of vary_nSequence + success_txs.append(bip112txs_vary_OP_CSV_v2[0][b25][0][b18]) # 16/16 of vary_OP_CSV + yield TestInstance([[self.create_test_block(success_txs), True]]) # 124 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + # Additional test, of checking that comparison of two time types works properly + time_txs = [] + for b25 in xrange(2): + for b18 in xrange(2): + tx = bip112txs_vary_OP_CSV_v2[0][b25][1][b18] + tx.vin[0].nSequence = base_relative_locktime | seq_type_flag + signtx = self.sign_transaction(self.nodes[0], tx) + time_txs.append(signtx) + yield TestInstance([[self.create_test_block(time_txs), True]]) # 125 + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + ### Missing aspects of test + ## Testing empty stack fails + + +if __name__ == '__main__': + BIP68_112_113Test().main() diff --git a/qa/rpc-tests/bip68-sequence.py b/qa/rpc-tests/bip68-sequence.py new file mode 100755 index 000000000..33e05dfc5 --- /dev/null +++ b/qa/rpc-tests/bip68-sequence.py @@ -0,0 +1,424 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test BIP68 implementation +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.script import * +from test_framework.mininode import * +from test_framework.blocktools import * + +SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31) +SEQUENCE_LOCKTIME_TYPE_FLAG = (1<<22) # this means use time (0 means height) +SEQUENCE_LOCKTIME_GRANULARITY = 9 # this is a bit-shift +SEQUENCE_LOCKTIME_MASK = 0x0000ffff + +# RPC error for non-BIP68 final transactions +NOT_FINAL_ERROR = "64: non-BIP68-final" + +class BIP68Test(BitcoinTestFramework): + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-blockprioritysize=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-blockprioritysize=0", "-acceptnonstdtxn=0"])) + self.is_network_split = False + self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"] + connect_nodes(self.nodes[0], 1) + + def run_test(self): + # Generate some coins + self.nodes[0].generate(110) + + print "Running test disable flag" + self.test_disable_flag() + + print "Running test sequence-lock-confirmed-inputs" + self.test_sequence_lock_confirmed_inputs() + + print "Running test sequence-lock-unconfirmed-inputs" + self.test_sequence_lock_unconfirmed_inputs() + + print "Running test BIP68 not consensus before versionbits activation" + self.test_bip68_not_consensus() + + print "Verifying nVersion=2 transactions aren't standard" + self.test_version2_relay(before_activation=True) + + print "Activating BIP68 (and 112/113)" + self.activateCSV() + + print "Verifying nVersion=2 transactions are now standard" + self.test_version2_relay(before_activation=False) + + print "Passed\n" + + # Test that BIP68 is not in effect if tx version is 1, or if + # the first sequence bit is set. + def test_disable_flag(self): + # Create some unconfirmed inputs + new_addr = self.nodes[0].getnewaddress() + self.nodes[0].sendtoaddress(new_addr, 2) # send 2 BTC + + utxos = self.nodes[0].listunspent(0, 0) + assert(len(utxos) > 0) + + utxo = utxos[0] + + tx1 = CTransaction() + value = int(satoshi_round(utxo["amount"] - self.relayfee)*COIN) + + # Check that the disable flag disables relative locktime. + # If sequence locks were used, this would require 1 block for the + # input to mature. + sequence_value = SEQUENCE_LOCKTIME_DISABLE_FLAG | 1 + tx1.vin = [CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), nSequence=sequence_value)] + tx1.vout = [CTxOut(value, CScript([b'a']))] + + tx1_signed = self.nodes[0].signrawtransaction(ToHex(tx1))["hex"] + tx1_id = self.nodes[0].sendrawtransaction(tx1_signed) + tx1_id = int(tx1_id, 16) + + # This transaction will enable sequence-locks, so this transaction should + # fail + tx2 = CTransaction() + tx2.nVersion = 2 + sequence_value = sequence_value & 0x7fffffff + tx2.vin = [CTxIn(COutPoint(tx1_id, 0), nSequence=sequence_value)] + tx2.vout = [CTxOut(int(value-self.relayfee*COIN), CScript([b'a']))] + tx2.rehash() + + try: + self.nodes[0].sendrawtransaction(ToHex(tx2)) + except JSONRPCException as exp: + assert_equal(exp.error["message"], NOT_FINAL_ERROR) + else: + assert(False) + + # Setting the version back down to 1 should disable the sequence lock, + # so this should be accepted. + tx2.nVersion = 1 + + self.nodes[0].sendrawtransaction(ToHex(tx2)) + + # Calculate the median time past of a prior block ("confirmations" before + # the current tip). + def get_median_time_past(self, confirmations): + block_hash = self.nodes[0].getblockhash(self.nodes[0].getblockcount()-confirmations) + return self.nodes[0].getblockheader(block_hash)["mediantime"] + + # Test that sequence locks are respected for transactions spending confirmed inputs. + def test_sequence_lock_confirmed_inputs(self): + # Create lots of confirmed utxos, and use them to generate lots of random + # transactions. + max_outputs = 50 + addresses = [] + while len(addresses) < max_outputs: + addresses.append(self.nodes[0].getnewaddress()) + while len(self.nodes[0].listunspent()) < 200: + import random + random.shuffle(addresses) + num_outputs = random.randint(1, max_outputs) + outputs = {} + for i in xrange(num_outputs): + outputs[addresses[i]] = random.randint(1, 20)*0.01 + self.nodes[0].sendmany("", outputs) + self.nodes[0].generate(1) + + utxos = self.nodes[0].listunspent() + + # Try creating a lot of random transactions. + # Each time, choose a random number of inputs, and randomly set + # some of those inputs to be sequence locked (and randomly choose + # between height/time locking). Small random chance of making the locks + # all pass. + for i in xrange(400): + # Randomly choose up to 10 inputs + num_inputs = random.randint(1, 10) + random.shuffle(utxos) + + # Track whether any sequence locks used should fail + should_pass = True + + # Track whether this transaction was built with sequence locks + using_sequence_locks = False + + tx = CTransaction() + tx.nVersion = 2 + value = 0 + for j in xrange(num_inputs): + sequence_value = 0xfffffffe # this disables sequence locks + + # 50% chance we enable sequence locks + if random.randint(0,1): + using_sequence_locks = True + + # 10% of the time, make the input sequence value pass + input_will_pass = (random.randint(1,10) == 1) + sequence_value = utxos[j]["confirmations"] + if not input_will_pass: + sequence_value += 1 + should_pass = False + + # Figure out what the median-time-past was for the confirmed input + # Note that if an input has N confirmations, we're going back N blocks + # from the tip so that we're looking up MTP of the block + # PRIOR to the one the input appears in, as per the BIP68 spec. + orig_time = self.get_median_time_past(utxos[j]["confirmations"]) + cur_time = self.get_median_time_past(0) # MTP of the tip + + # can only timelock this input if it's not too old -- otherwise use height + can_time_lock = True + if ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY) >= SEQUENCE_LOCKTIME_MASK: + can_time_lock = False + + # if time-lockable, then 50% chance we make this a time lock + if random.randint(0,1) and can_time_lock: + # Find first time-lock value that fails, or latest one that succeeds + time_delta = sequence_value << SEQUENCE_LOCKTIME_GRANULARITY + if input_will_pass and time_delta > cur_time - orig_time: + sequence_value = ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY) + elif (not input_will_pass and time_delta <= cur_time - orig_time): + sequence_value = ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY)+1 + sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG + tx.vin.append(CTxIn(COutPoint(int(utxos[j]["txid"], 16), utxos[j]["vout"]), nSequence=sequence_value)) + value += utxos[j]["amount"]*COIN + # Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output + tx_size = len(ToHex(tx))//2 + 120*num_inputs + 50 + tx.vout.append(CTxOut(int(value-self.relayfee*tx_size*COIN/1000), CScript([b'a']))) + rawtx = self.nodes[0].signrawtransaction(ToHex(tx))["hex"] + + try: + self.nodes[0].sendrawtransaction(rawtx) + except JSONRPCException as exp: + assert(not should_pass and using_sequence_locks) + assert_equal(exp.error["message"], NOT_FINAL_ERROR) + else: + assert(should_pass or not using_sequence_locks) + # Recalculate utxos if we successfully sent the transaction + utxos = self.nodes[0].listunspent() + + # Test that sequence locks on unconfirmed inputs must have nSequence + # height or time of 0 to be accepted. + # Then test that BIP68-invalid transactions are removed from the mempool + # after a reorg. + def test_sequence_lock_unconfirmed_inputs(self): + # Store height so we can easily reset the chain at the end of the test + cur_height = self.nodes[0].getblockcount() + + # Create a mempool tx. + txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2) + tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid)) + tx1.rehash() + + # Anyone-can-spend mempool tx. + # Sequence lock of 0 should pass. + tx2 = CTransaction() + tx2.nVersion = 2 + tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)] + tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))] + tx2_raw = self.nodes[0].signrawtransaction(ToHex(tx2))["hex"] + tx2 = FromHex(tx2, tx2_raw) + tx2.rehash() + + self.nodes[0].sendrawtransaction(tx2_raw) + + # Create a spend of the 0th output of orig_tx with a sequence lock + # of 1, and test what happens when submitting. + # orig_tx.vout[0] must be an anyone-can-spend output + def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock): + sequence_value = 1 + if not use_height_lock: + sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG + + tx = CTransaction() + tx.nVersion = 2 + tx.vin = [CTxIn(COutPoint(orig_tx.sha256, 0), nSequence=sequence_value)] + tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee*COIN), CScript([b'a']))] + tx.rehash() + + try: + node.sendrawtransaction(ToHex(tx)) + except JSONRPCException as exp: + assert_equal(exp.error["message"], NOT_FINAL_ERROR) + assert(orig_tx.hash in node.getrawmempool()) + else: + # orig_tx must not be in mempool + assert(orig_tx.hash not in node.getrawmempool()) + return tx + + test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True) + test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False) + + # Now mine some blocks, but make sure tx2 doesn't get mined. + # Use prioritisetransaction to lower the effective feerate to 0 + self.nodes[0].prioritisetransaction(tx2.hash, -1e15, int(-self.relayfee*COIN)) + cur_time = int(time.time()) + for i in xrange(10): + self.nodes[0].setmocktime(cur_time + 600) + self.nodes[0].generate(1) + cur_time += 600 + + assert(tx2.hash in self.nodes[0].getrawmempool()) + + test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True) + test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False) + + # Mine tx2, and then try again + self.nodes[0].prioritisetransaction(tx2.hash, 1e15, int(self.relayfee*COIN)) + + # Advance the time on the node so that we can test timelocks + self.nodes[0].setmocktime(cur_time+600) + self.nodes[0].generate(1) + assert(tx2.hash not in self.nodes[0].getrawmempool()) + + # Now that tx2 is not in the mempool, a sequence locked spend should + # succeed + tx3 = test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False) + assert(tx3.hash in self.nodes[0].getrawmempool()) + + self.nodes[0].generate(1) + assert(tx3.hash not in self.nodes[0].getrawmempool()) + + # One more test, this time using height locks + tx4 = test_nonzero_locks(tx3, self.nodes[0], self.relayfee, use_height_lock=True) + assert(tx4.hash in self.nodes[0].getrawmempool()) + + # Now try combining confirmed and unconfirmed inputs + tx5 = test_nonzero_locks(tx4, self.nodes[0], self.relayfee, use_height_lock=True) + assert(tx5.hash not in self.nodes[0].getrawmempool()) + + utxos = self.nodes[0].listunspent() + tx5.vin.append(CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["vout"]), nSequence=1)) + tx5.vout[0].nValue += int(utxos[0]["amount"]*COIN) + raw_tx5 = self.nodes[0].signrawtransaction(ToHex(tx5))["hex"] + + try: + self.nodes[0].sendrawtransaction(raw_tx5) + except JSONRPCException as exp: + assert_equal(exp.error["message"], NOT_FINAL_ERROR) + else: + assert(False) + + # Test mempool-BIP68 consistency after reorg + # + # State of the transactions in the last blocks: + # ... -> [ tx2 ] -> [ tx3 ] + # tip-1 tip + # And currently tx4 is in the mempool. + # + # If we invalidate the tip, tx3 should get added to the mempool, causing + # tx4 to be removed (fails sequence-lock). + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + assert(tx4.hash not in self.nodes[0].getrawmempool()) + assert(tx3.hash in self.nodes[0].getrawmempool()) + + # Now mine 2 empty blocks to reorg out the current tip (labeled tip-1 in + # diagram above). + # This would cause tx2 to be added back to the mempool, which in turn causes + # tx3 to be removed. + tip = int(self.nodes[0].getblockhash(self.nodes[0].getblockcount()-1), 16) + height = self.nodes[0].getblockcount() + for i in xrange(2): + block = create_block(tip, create_coinbase(height), cur_time) + block.nVersion = 3 + block.rehash() + block.solve() + tip = block.sha256 + height += 1 + self.nodes[0].submitblock(ToHex(block)) + cur_time += 1 + + mempool = self.nodes[0].getrawmempool() + assert(tx3.hash not in mempool) + assert(tx2.hash in mempool) + + # Reset the chain and get rid of the mocktimed-blocks + self.nodes[0].setmocktime(0) + self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height+1)) + self.nodes[0].generate(10) + + # Make sure that BIP68 isn't being used to validate blocks, prior to + # versionbits activation. If more blocks are mined prior to this test + # being run, then it's possible the test has activated the soft fork, and + # this test should be moved to run earlier, or deleted. + def test_bip68_not_consensus(self): + assert(get_bip9_status(self.nodes[0], 'csv')['status'] != 'active') + txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2) + + tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid)) + tx1.rehash() + + # Make an anyone-can-spend transaction + tx2 = CTransaction() + tx2.nVersion = 1 + tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)] + tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))] + + # sign tx2 + tx2_raw = self.nodes[0].signrawtransaction(ToHex(tx2))["hex"] + tx2 = FromHex(tx2, tx2_raw) + tx2.rehash() + + self.nodes[0].sendrawtransaction(ToHex(tx2)) + + # Now make an invalid spend of tx2 according to BIP68 + sequence_value = 100 # 100 block relative locktime + + tx3 = CTransaction() + tx3.nVersion = 2 + tx3.vin = [CTxIn(COutPoint(tx2.sha256, 0), nSequence=sequence_value)] + tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))] + tx3.rehash() + + try: + self.nodes[0].sendrawtransaction(ToHex(tx3)) + except JSONRPCException as exp: + assert_equal(exp.error["message"], NOT_FINAL_ERROR) + else: + assert(False) + + # make a block that violates bip68; ensure that the tip updates + tip = int(self.nodes[0].getbestblockhash(), 16) + block = create_block(tip, create_coinbase(self.nodes[0].getblockcount()+1)) + block.nVersion = 3 + block.vtx.extend([tx1, tx2, tx3]) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + + self.nodes[0].submitblock(ToHex(block)) + assert_equal(self.nodes[0].getbestblockhash(), block.hash) + + def activateCSV(self): + # activation should happen at block height 432 (3 periods) + min_activation_height = 432 + height = self.nodes[0].getblockcount() + assert(height < 432) + self.nodes[0].generate(432-height) + assert(get_bip9_status(self.nodes[0], 'csv')['status'] == 'active') + sync_blocks(self.nodes) + + # Use self.nodes[1] to test standardness relay policy + def test_version2_relay(self, before_activation): + inputs = [ ] + outputs = { self.nodes[1].getnewaddress() : 1.0 } + rawtx = self.nodes[1].createrawtransaction(inputs, outputs) + rawtxfund = self.nodes[1].fundrawtransaction(rawtx)['hex'] + tx = FromHex(CTransaction(), rawtxfund) + tx.nVersion = 2 + tx_signed = self.nodes[1].signrawtransaction(ToHex(tx))["hex"] + try: + tx_id = self.nodes[1].sendrawtransaction(tx_signed) + assert(before_activation == False) + except: + assert(before_activation) + + +if __name__ == '__main__': + BIP68Test().main() diff --git a/qa/rpc-tests/bip9-softforks.py b/qa/rpc-tests/bip9-softforks.py new file mode 100755 index 000000000..ddca3c2e3 --- /dev/null +++ b/qa/rpc-tests/bip9-softforks.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +from test_framework.test_framework import ComparisonTestFramework +from test_framework.util import * +from test_framework.mininode import CTransaction, NetworkThread +from test_framework.blocktools import create_coinbase, create_block +from test_framework.comptool import TestInstance, TestManager +from test_framework.script import CScript, OP_1NEGATE, OP_NOP3, OP_DROP +from io import BytesIO +import time +import itertools + +''' +This test is meant to exercise BIP forks +Connect to a single node. +regtest lock-in with 108/144 block signalling +activation after a further 144 blocks +mine 2 block and save coinbases for later use +mine 141 blocks to transition from DEFINED to STARTED +mine 100 blocks signalling readiness and 44 not in order to fail to change state this period +mine 108 blocks signalling readiness and 36 blocks not signalling readiness (STARTED->LOCKED_IN) +mine a further 143 blocks (LOCKED_IN) +test that enforcement has not triggered (which triggers ACTIVE) +test that enforcement has triggered +''' + + +class BIP9SoftForksTest(ComparisonTestFramework): + + def __init__(self): + self.num_nodes = 1 + + def setup_network(self): + self.nodes = start_nodes(1, self.options.tmpdir, + extra_args=[['-debug', '-whitelist=127.0.0.1']], + binary=[self.options.testbinary]) + + def run_test(self): + self.test = TestManager(self, self.options.tmpdir) + self.test.add_all_connections(self.nodes) + NetworkThread().start() # Start up network handling in another thread + self.test.run() + + def create_transaction(self, node, coinbase, to_address, amount): + from_txid = node.getblock(coinbase)['tx'][0] + inputs = [{ "txid" : from_txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(rawtx)) + tx.deserialize(f) + tx.nVersion = 2 + return tx + + def sign_transaction(self, node, tx): + signresult = node.signrawtransaction(bytes_to_hex_str(tx.serialize())) + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(signresult['hex'])) + tx.deserialize(f) + return tx + + def generate_blocks(self, number, version, test_blocks = []): + for i in xrange(number): + block = create_block(self.tip, create_coinbase(self.height), self.last_block_time + 1) + block.nVersion = version + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + self.height += 1 + return test_blocks + + def get_bip9_status(self, key): + info = self.nodes[0].getblockchaininfo() + return info['bip9_softforks'][key] + + def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignature): + # generate some coins for later + self.coinbase_blocks = self.nodes[0].generate(2) + self.height = 3 # height of the next block to build + self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) + self.nodeaddress = self.nodes[0].getnewaddress() + self.last_block_time = int(time.time()) + + assert_equal(self.get_bip9_status(bipName)['status'], 'defined') + + # Test 1 + # Advance from DEFINED to STARTED + test_blocks = self.generate_blocks(141, 4) + yield TestInstance(test_blocks, sync_every_block=False) + + assert_equal(self.get_bip9_status(bipName)['status'], 'started') + + # Test 2 + # Fail to achieve LOCKED_IN 100 out of 144 signal bit 1 + # using a variety of bits to simulate multiple parallel softforks + test_blocks = self.generate_blocks(50, activated_version) # 0x20000001 (signalling ready) + test_blocks = self.generate_blocks(20, 4, test_blocks) # 0x00000004 (signalling not) + test_blocks = self.generate_blocks(50, activated_version, test_blocks) # 0x20000101 (signalling ready) + test_blocks = self.generate_blocks(24, 4, test_blocks) # 0x20010000 (signalling not) + yield TestInstance(test_blocks, sync_every_block=False) + + assert_equal(self.get_bip9_status(bipName)['status'], 'started') + + # Test 3 + # 108 out of 144 signal bit 1 to achieve LOCKED_IN + # using a variety of bits to simulate multiple parallel softforks + test_blocks = self.generate_blocks(58, activated_version) # 0x20000001 (signalling ready) + test_blocks = self.generate_blocks(26, 4, test_blocks) # 0x00000004 (signalling not) + test_blocks = self.generate_blocks(50, activated_version, test_blocks) # 0x20000101 (signalling ready) + test_blocks = self.generate_blocks(10, 4, test_blocks) # 0x20010000 (signalling not) + yield TestInstance(test_blocks, sync_every_block=False) + + assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in') + + # Test 4 + # 143 more version 536870913 blocks (waiting period-1) + test_blocks = self.generate_blocks(143, 4) + yield TestInstance(test_blocks, sync_every_block=False) + + assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in') + + # Test 5 + # Check that the new rule is enforced + spendtx = self.create_transaction(self.nodes[0], + self.coinbase_blocks[0], self.nodeaddress, 1.0) + invalidate(spendtx) + spendtx = self.sign_transaction(self.nodes[0], spendtx) + spendtx.rehash() + invalidatePostSignature(spendtx) + spendtx.rehash() + block = create_block(self.tip, create_coinbase(self.height), self.last_block_time + 1) + block.nVersion = activated_version + block.vtx.append(spendtx) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + + self.last_block_time += 1 + self.tip = block.sha256 + self.height += 1 + yield TestInstance([[block, True]]) + + assert_equal(self.get_bip9_status(bipName)['status'], 'active') + + # Test 6 + # Check that the new sequence lock rules are enforced + spendtx = self.create_transaction(self.nodes[0], + self.coinbase_blocks[1], self.nodeaddress, 1.0) + invalidate(spendtx) + spendtx = self.sign_transaction(self.nodes[0], spendtx) + spendtx.rehash() + invalidatePostSignature(spendtx) + spendtx.rehash() + + block = create_block(self.tip, create_coinbase(self.height), self.last_block_time + 1) + block.nVersion = 5 + block.vtx.append(spendtx) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + self.last_block_time += 1 + yield TestInstance([[block, False]]) + + # Restart all + stop_nodes(self.nodes) + wait_bitcoinds() + shutil.rmtree(self.options.tmpdir) + self.setup_chain() + self.setup_network() + self.test.clear_all_connections() + self.test.add_all_connections(self.nodes) + NetworkThread().start() # Start up network handling in another thread + + + def get_tests(self): + for test in itertools.chain( + self.test_BIP('csv', 536870913, self.sequence_lock_invalidate, self.donothing), + self.test_BIP('csv', 536870913, self.mtp_invalidate, self.donothing), + self.test_BIP('csv', 536870913, self.donothing, self.csv_invalidate) + ): + yield test + + def donothing(self, tx): + return + + def csv_invalidate(self, tx): + '''Modify the signature in vin 0 of the tx to fail CSV + Prepends -1 CSV DROP in the scriptSig itself. + ''' + tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_NOP3, OP_DROP] + + list(CScript(tx.vin[0].scriptSig))) + + def sequence_lock_invalidate(self, tx): + '''Modify the nSequence to make it fails once sequence lock rule is activated (high timespan) + ''' + tx.vin[0].nSequence = 0x00FFFFFF + tx.nLockTime = 0 + + def mtp_invalidate(self, tx): + '''Modify the nLockTime to make it fails once MTP rule is activated + ''' + # Disable Sequence lock, Activate nLockTime + tx.vin[0].nSequence = 0x90FFFFFF + tx.nLockTime = self.last_block_time + +if __name__ == '__main__': + BIP9SoftForksTest().main() diff --git a/qa/rpc-tests/bipdersig-p2p.py b/qa/rpc-tests/bipdersig-p2p.py index ec1678cc2..bba86a50c 100755 --- a/qa/rpc-tests/bipdersig-p2p.py +++ b/qa/rpc-tests/bipdersig-p2p.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# +# Copyright (c) 2015 The Bitcoin Core developers # Distributed under the MIT/X11 software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # @@ -10,8 +10,7 @@ from test_framework.mininode import CTransaction, NetworkThread from test_framework.blocktools import create_coinbase, create_block from test_framework.comptool import TestInstance, TestManager from test_framework.script import CScript -from binascii import hexlify, unhexlify -import cStringIO +from io import BytesIO import time # A canonical signature consists of: @@ -25,7 +24,7 @@ def unDERify(tx): newscript = [] for i in scriptSig: if (len(newscript) == 0): - newscript.append(i[0:-1] + '\0' + i[-1]) + newscript.append(i[0:-1] + b'\0' + i[-1:]) else: newscript.append(i) tx.vin[0].scriptSig = CScript(newscript) @@ -68,7 +67,7 @@ class BIP66Test(ComparisonTestFramework): rawtx = node.createrawtransaction(inputs, outputs) signresult = node.signrawtransaction(rawtx) tx = CTransaction() - f = cStringIO.StringIO(unhexlify(signresult['hex'])) + f = BytesIO(hex_str_to_bytes(signresult['hex'])) tx.deserialize(f) return tx @@ -78,7 +77,7 @@ class BIP66Test(ComparisonTestFramework): height = 3 # height of the next block to build self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) self.nodeaddress = self.nodes[0].getnewaddress() - self.last_block_time = time.time() + self.last_block_time = int(time.time()) ''' 98 more version 2 blocks ''' test_blocks = [] diff --git a/qa/rpc-tests/bipdersig.py b/qa/rpc-tests/bipdersig.py index 243f816f6..be9121c45 100755 --- a/qa/rpc-tests/bipdersig.py +++ b/qa/rpc-tests/bipdersig.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,8 +9,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -import os -import shutil class BIP66Test(BitcoinTestFramework): @@ -46,7 +44,7 @@ class BIP66Test(BitcoinTestFramework): self.nodes[2].generate(1) self.sync_all() if (self.nodes[0].getblockcount() != cnt + 851): - raise AssertionFailure("Failed to mine a version=3 blocks") + raise AssertionError("Failed to mine a version=3 blocks") # TODO: check that new DERSIG rules are enforced diff --git a/qa/rpc-tests/blockchain.py b/qa/rpc-tests/blockchain.py index a5c98b777..8f59ee741 100755 --- a/qa/rpc-tests/blockchain.py +++ b/qa/rpc-tests/blockchain.py @@ -1,27 +1,34 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # -# Test RPC calls related to blockchain state. +# Test RPC calls related to blockchain state. Tests correspond to code in +# rpc/blockchain.cpp. # -import decimal +from decimal import Decimal from test_framework.test_framework import BitcoinTestFramework +from test_framework.authproxy import JSONRPCException from test_framework.util import ( initialize_chain, assert_equal, + assert_raises, + assert_is_hex_string, + assert_is_hash_string, start_nodes, connect_nodes_bi, ) + class BlockchainTest(BitcoinTestFramework): """ Test blockchain-related RPC calls: - gettxoutsetinfo + - verifychain """ @@ -36,17 +43,47 @@ class BlockchainTest(BitcoinTestFramework): self.sync_all() def run_test(self): + self._test_gettxoutsetinfo() + self._test_getblockheader() + self.nodes[0].verifychain(4, 0) + + def _test_gettxoutsetinfo(self): node = self.nodes[0] res = node.gettxoutsetinfo() - assert_equal(res[u'total_amount'], decimal.Decimal('8725.00000000')) + assert_equal(res[u'total_amount'], Decimal('8725.00000000')) assert_equal(res[u'transactions'], 200) assert_equal(res[u'height'], 200) assert_equal(res[u'txouts'], 200) - assert_equal(res[u'bytes_serialized'], 13000), + assert_equal(res[u'bytes_serialized'], 13924), assert_equal(len(res[u'bestblock']), 64) assert_equal(len(res[u'hash_serialized']), 64) + def _test_getblockheader(self): + node = self.nodes[0] + + assert_raises( + JSONRPCException, lambda: node.getblockheader('nonsense')) + + besthash = node.getbestblockhash() + secondbesthash = node.getblockhash(199) + header = node.getblockheader(besthash) + + assert_equal(header['hash'], besthash) + assert_equal(header['height'], 200) + assert_equal(header['confirmations'], 1) + assert_equal(header['previousblockhash'], secondbesthash) + assert_is_hex_string(header['chainwork']) + assert_is_hash_string(header['hash']) + assert_is_hash_string(header['previousblockhash']) + assert_is_hash_string(header['merkleroot']) + assert_is_hash_string(header['bits'], length=None) + assert isinstance(header['time'], int) + assert isinstance(header['mediantime'], int) + assert isinstance(header['nonce'], int) + assert isinstance(header['version'], int) + assert isinstance(int(header['versionHex'], 16), int) + assert isinstance(header['difficulty'], Decimal) if __name__ == '__main__': BlockchainTest().main() diff --git a/qa/rpc-tests/decodescript.py b/qa/rpc-tests/decodescript.py index aa2c5a2a7..578844f2c 100755 --- a/qa/rpc-tests/decodescript.py +++ b/qa/rpc-tests/decodescript.py @@ -6,8 +6,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * from test_framework.mininode import * -from binascii import hexlify, unhexlify -from cStringIO import StringIO +from io import BytesIO class DecodeScriptTest(BitcoinTestFramework): """Tests decoding scripts via RPC command "decodescript".""" @@ -95,20 +94,20 @@ class DecodeScriptTest(BitcoinTestFramework): assert_equal('OP_RETURN ' + signature_imposter[2:], rpc_result['asm']) # 6) a CLTV redeem script. redeem scripts are in-effect scriptPubKey scripts, so adding a test here. - # OP_NOP3 is also known as OP_CHECKLOCKTIMEVERIFY. + # OP_NOP2 is also known as OP_CHECKLOCKTIMEVERIFY. # just imagine that the pub keys used below are different. # for our purposes here it does not matter that they are the same even though it is unrealistic. # # OP_IF # OP_CHECKSIGVERIFY # OP_ELSE - # OP_NOP3 OP_DROP + # OP_CHECKLOCKTIMEVERIFY OP_DROP # OP_ENDIF # OP_CHECKSIG # # lock until block 500,000 rpc_result = self.nodes[0].decodescript('63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac') - assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_NOP3 OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm']) + assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm']) def decoderawtransaction_asm_sighashtype(self): """Tests decoding scripts via RPC command "decoderawtransaction". @@ -131,7 +130,7 @@ class DecodeScriptTest(BitcoinTestFramework): assert_equal('OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm']) assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm']) txSave = CTransaction() - txSave.deserialize(StringIO(unhexlify(tx))) + txSave.deserialize(BytesIO(hex_str_to_bytes(tx))) # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000' @@ -147,7 +146,7 @@ class DecodeScriptTest(BitcoinTestFramework): # some more full transaction tests of varying specific scriptSigs. used instead of # tests in decodescript_script_sig because the decodescript RPC is specifically # for working on scriptPubKeys (argh!). - push_signature = hexlify(txSave.vin[0].scriptSig)[2:(0x48*2+4)] + push_signature = bytes_to_hex_str(txSave.vin[0].scriptSig)[2:(0x48*2+4)] signature = push_signature[2:] der_signature = signature[:-2] signature_sighash_decoded = der_signature + '[ALL]' @@ -156,25 +155,24 @@ class DecodeScriptTest(BitcoinTestFramework): signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]' # 1) P2PK scriptSig - txSave.vin[0].scriptSig = unhexlify(push_signature) - rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) + txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature) + rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize())) assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) # make sure that the sighash decodes come out correctly for a more complex / lesser used case. - txSave.vin[0].scriptSig = unhexlify(push_signature_2) - rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) + txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature_2) + rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize())) assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) # 2) multisig scriptSig - txSave.vin[0].scriptSig = unhexlify('00' + push_signature + push_signature_2) - rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) + txSave.vin[0].scriptSig = hex_str_to_bytes('00' + push_signature + push_signature_2) + rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize())) assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) # 3) test a scriptSig that contains more than push operations. # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it. - txSave.vin[0].scriptSig = unhexlify('6a143011020701010101010101020601010101010101') - rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) - print(hexlify('636174')) + txSave.vin[0].scriptSig = hex_str_to_bytes('6a143011020701010101010101020601010101010101') + rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize())) assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm']) def run_test(self): diff --git a/qa/rpc-tests/disablewallet.py b/qa/rpc-tests/disablewallet.py new file mode 100755 index 000000000..cb868029f --- /dev/null +++ b/qa/rpc-tests/disablewallet.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Exercise API with -disablewallet. +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + + +class DisableWalletTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self, split=False): + self.nodes = start_nodes(1, self.options.tmpdir, [['-disablewallet']]) + self.is_network_split = False + self.sync_all() + + def run_test (self): + # Check regression: https://github.com/bitcoin/bitcoin/issues/6963#issuecomment-154548880 + x = self.nodes[0].validateaddress('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy') + assert(x['isvalid'] == False) + x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ') + assert(x['isvalid'] == True) + + # Checking mining to an address without a wallet + try: + self.nodes[0].generatetoaddress(1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ') + except JSONRPCException as e: + assert("Invalid address" not in e.error['message']) + assert("ProcessNewBlock, block not accepted" not in e.error['message']) + assert("Couldn't create new block" not in e.error['message']) + + try: + self.nodes[0].generatetoaddress(1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy') + raise AssertionError("Must not mine to invalid address!") + except JSONRPCException as e: + assert("Invalid address" in e.error['message']) + +if __name__ == '__main__': + DisableWalletTest ().main () diff --git a/qa/rpc-tests/forknotify.py b/qa/rpc-tests/forknotify.py index 0acef8e30..20e6ce961 100755 --- a/qa/rpc-tests/forknotify.py +++ b/qa/rpc-tests/forknotify.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,8 +9,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -import os -import shutil class ForkNotifyTest(BitcoinTestFramework): diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py index 93d13faa0..496c7fe8b 100755 --- a/qa/rpc-tests/fundrawtransaction.py +++ b/qa/rpc-tests/fundrawtransaction.py @@ -1,12 +1,10 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -from pprint import pprint -from time import sleep # Create one-input, one-output, no-fee transaction: class RawTransactionsTest(BitcoinTestFramework): @@ -30,6 +28,11 @@ class RawTransactionsTest(BitcoinTestFramework): print "Mining blocks..." min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee'] + # This test is not meant to test fee estimation and we'd like + # to be sure all txs are sent at a consistent desired feerate + for node in self.nodes: + node.settxfee(min_relay_tx_fee) + # if the fee's positive delta is higher than this value tests will fail, # neg. delta always fail the tests. # The size of the signature of every input may be at most 2 bytes larger @@ -45,14 +48,14 @@ class RawTransactionsTest(BitcoinTestFramework): watchonly_address = self.nodes[0].getnewaddress() watchonly_pubkey = self.nodes[0].validateaddress(watchonly_address)["pubkey"] - watchonly_amount = 200 + watchonly_amount = Decimal(200) self.nodes[3].importpubkey(watchonly_pubkey, "", True) watchonly_txid = self.nodes[0].sendtoaddress(watchonly_address, watchonly_amount) - self.nodes[0].sendtoaddress(self.nodes[3].getnewaddress(), watchonly_amount / 10); + self.nodes[0].sendtoaddress(self.nodes[3].getnewaddress(), watchonly_amount / 10) - self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.5); - self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.0); - self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),5.0); + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.5) + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0) + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0) self.sync_all() self.nodes[0].generate(1) @@ -68,7 +71,7 @@ class RawTransactionsTest(BitcoinTestFramework): rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) - assert_equal(len(dec_tx['vin']) > 0, True) #test if we have enought inputs + assert(len(dec_tx['vin']) > 0) #test if we have enought inputs ############################## # simple test with two coins # @@ -81,7 +84,7 @@ class RawTransactionsTest(BitcoinTestFramework): rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) - assert_equal(len(dec_tx['vin']) > 0, True) #test if we have enough inputs + assert(len(dec_tx['vin']) > 0) #test if we have enough inputs ############################## # simple test with two coins # @@ -94,7 +97,7 @@ class RawTransactionsTest(BitcoinTestFramework): rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) - assert_equal(len(dec_tx['vin']) > 0, True) + assert(len(dec_tx['vin']) > 0) assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') @@ -113,7 +116,7 @@ class RawTransactionsTest(BitcoinTestFramework): for out in dec_tx['vout']: totalOut += out['value'] - assert_equal(len(dec_tx['vin']) > 0, True) + assert(len(dec_tx['vin']) > 0) assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') @@ -125,9 +128,9 @@ class RawTransactionsTest(BitcoinTestFramework): for aUtx in listunspent: if aUtx['amount'] == 5.0: utx = aUtx - break; + break - assert_equal(utx!=False, True) + assert(utx!=False) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] outputs = { self.nodes[0].getnewaddress() : 1.0 } @@ -145,7 +148,6 @@ class RawTransactionsTest(BitcoinTestFramework): assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee - ##################################################################### # test a fundrawtransaction with which will not get a change output # ##################################################################### @@ -154,9 +156,9 @@ class RawTransactionsTest(BitcoinTestFramework): for aUtx in listunspent: if aUtx['amount'] == 5.0: utx = aUtx - break; + break - assert_equal(utx!=False, True) + assert(utx!=False) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] outputs = { self.nodes[0].getnewaddress() : Decimal(5.0) - fee - feeTolerance } @@ -175,6 +177,82 @@ class RawTransactionsTest(BitcoinTestFramework): assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee + #################################################### + # test a fundrawtransaction with an invalid option # + #################################################### + utx = False + listunspent = self.nodes[2].listunspent() + for aUtx in listunspent: + if aUtx['amount'] == 5.0: + utx = aUtx + break + + assert_equal(utx!=False, True) + + inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ] + outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + + try: + self.nodes[2].fundrawtransaction(rawtx, {'foo': 'bar'}) + raise AssertionError("Accepted invalid option foo") + except JSONRPCException,e: + assert("Unexpected key foo" in e.error['message']) + + + ############################################################ + # test a fundrawtransaction with an invalid change address # + ############################################################ + utx = False + listunspent = self.nodes[2].listunspent() + for aUtx in listunspent: + if aUtx['amount'] == 5.0: + utx = aUtx + break + + assert_equal(utx!=False, True) + + inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ] + outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + + try: + self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': 'foobar'}) + raise AssertionError("Accepted invalid bitcoin address") + except JSONRPCException,e: + assert("changeAddress must be a valid bitcoin address" in e.error['message']) + + + + ############################################################ + # test a fundrawtransaction with a provided change address # + ############################################################ + utx = False + listunspent = self.nodes[2].listunspent() + for aUtx in listunspent: + if aUtx['amount'] == 5.0: + utx = aUtx + break + + assert_equal(utx!=False, True) + + inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ] + outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + + change = self.nodes[2].getnewaddress() + rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0}) + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + out = dec_tx['vout'][0]; + assert_equal(change, out['scriptPubKey']['addresses'][0]) + + ######################################################################### # test a fundrawtransaction with a VIN smaller than the required amount # @@ -184,9 +262,9 @@ class RawTransactionsTest(BitcoinTestFramework): for aUtx in listunspent: if aUtx['amount'] == 1.0: utx = aUtx - break; + break - assert_equal(utx!=False, True) + assert(utx!=False) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] outputs = { self.nodes[0].getnewaddress() : 1.0 } @@ -206,7 +284,7 @@ class RawTransactionsTest(BitcoinTestFramework): matchingOuts = 0 for i, out in enumerate(dec_tx['vout']): totalOut += out['value'] - if outputs.has_key(out['scriptPubKey']['addresses'][0]): + if out['scriptPubKey']['addresses'][0] in outputs: matchingOuts+=1 else: assert_equal(i, rawtxfund['changepos']) @@ -231,7 +309,7 @@ class RawTransactionsTest(BitcoinTestFramework): utx2 = aUtx - assert_equal(utx!=False, True) + assert(utx!=False) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ] outputs = { self.nodes[0].getnewaddress() : 6.0 } @@ -246,7 +324,7 @@ class RawTransactionsTest(BitcoinTestFramework): matchingOuts = 0 for out in dec_tx['vout']: totalOut += out['value'] - if outputs.has_key(out['scriptPubKey']['addresses'][0]): + if out['scriptPubKey']['addresses'][0] in outputs: matchingOuts+=1 assert_equal(matchingOuts, 1) @@ -273,7 +351,7 @@ class RawTransactionsTest(BitcoinTestFramework): utx2 = aUtx - assert_equal(utx!=False, True) + assert(utx!=False) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ] outputs = { self.nodes[0].getnewaddress() : 6.0, self.nodes[0].getnewaddress() : 1.0 } @@ -288,7 +366,7 @@ class RawTransactionsTest(BitcoinTestFramework): matchingOuts = 0 for out in dec_tx['vout']: totalOut += out['value'] - if outputs.has_key(out['scriptPubKey']['addresses'][0]): + if out['scriptPubKey']['addresses'][0] in outputs: matchingOuts+=1 assert_equal(matchingOuts, 2) @@ -303,14 +381,11 @@ class RawTransactionsTest(BitcoinTestFramework): rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) - errorString = "" try: rawtxfund = self.nodes[2].fundrawtransaction(rawtx) - except JSONRPCException,e: - errorString = e.error['message'] - - assert_equal("Insufficient" in errorString, True); - + raise AssertionError("Spent more than available") + except JSONRPCException as e: + assert("Insufficient" in e.error['message']) ############################################################ @@ -321,11 +396,11 @@ class RawTransactionsTest(BitcoinTestFramework): fundedTx = self.nodes[0].fundrawtransaction(rawTx) #create same transaction over sendtoaddress - txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1); + txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1) signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] #compare fee - feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee); + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert(feeDelta >= 0 and feeDelta <= feeTolerance) ############################################################ @@ -336,11 +411,11 @@ class RawTransactionsTest(BitcoinTestFramework): rawTx = self.nodes[0].createrawtransaction(inputs, outputs) fundedTx = self.nodes[0].fundrawtransaction(rawTx) #create same transaction over sendtoaddress - txId = self.nodes[0].sendmany("", outputs); + txId = self.nodes[0].sendmany("", outputs) signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] #compare fee - feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee); + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert(feeDelta >= 0 and feeDelta <= feeTolerance) ############################################################ @@ -363,11 +438,11 @@ class RawTransactionsTest(BitcoinTestFramework): fundedTx = self.nodes[0].fundrawtransaction(rawTx) #create same transaction over sendtoaddress - txId = self.nodes[0].sendtoaddress(mSigObj, 1.1); + txId = self.nodes[0].sendtoaddress(mSigObj, 1.1) signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] #compare fee - feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee); + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert(feeDelta >= 0 and feeDelta <= feeTolerance) ############################################################ @@ -396,11 +471,11 @@ class RawTransactionsTest(BitcoinTestFramework): fundedTx = self.nodes[0].fundrawtransaction(rawTx) #create same transaction over sendtoaddress - txId = self.nodes[0].sendtoaddress(mSigObj, 1.1); + txId = self.nodes[0].sendtoaddress(mSigObj, 1.1) signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] #compare fee - feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee); + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert(feeDelta >= 0 and feeDelta <= feeTolerance) ############################################################ @@ -419,7 +494,7 @@ class RawTransactionsTest(BitcoinTestFramework): # send 1.2 BTC to msig addr - txId = self.nodes[0].sendtoaddress(mSigObj, 1.2); + txId = self.nodes[0].sendtoaddress(mSigObj, 1.2) self.sync_all() self.nodes[1].generate(1) self.sync_all() @@ -447,6 +522,10 @@ class RawTransactionsTest(BitcoinTestFramework): wait_bitcoinds() self.nodes = start_nodes(4, self.options.tmpdir) + # This test is not meant to test fee estimation and we'd like + # to be sure all txs are sent at a consistent desired feerate + for node in self.nodes: + node.settxfee(min_relay_tx_fee) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) @@ -455,12 +534,11 @@ class RawTransactionsTest(BitcoinTestFramework): self.is_network_split=False self.sync_all() - error = False try: - self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2); - except: - error = True - assert(error) + self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2) + raise AssertionError("Wallet unlocked without passphrase") + except JSONRPCException as e: + assert('walletpassphrase' in e.error['message']) oldBalance = self.nodes[0].getbalance() @@ -481,19 +559,18 @@ class RawTransactionsTest(BitcoinTestFramework): assert_equal(oldBalance+Decimal('51.10000000'), self.nodes[0].getbalance()) - ############################################### # multiple (~19) inputs tx test | Compare fee # ############################################### #empty node1, send some small coins from node0 to node1 - self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True); + self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True) self.sync_all() self.nodes[0].generate(1) self.sync_all() for i in range(0,20): - self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01); + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) self.sync_all() self.nodes[0].generate(1) self.sync_all() @@ -505,11 +582,11 @@ class RawTransactionsTest(BitcoinTestFramework): fundedTx = self.nodes[1].fundrawtransaction(rawTx) #create same transaction over sendtoaddress - txId = self.nodes[1].sendmany("", outputs); + txId = self.nodes[1].sendmany("", outputs) signedFee = self.nodes[1].getrawmempool(True)[txId]['fee'] #compare fee - feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee); + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert(feeDelta >= 0 and feeDelta <= feeTolerance*19) #~19 inputs @@ -518,13 +595,13 @@ class RawTransactionsTest(BitcoinTestFramework): ############################################# #again, empty node1, send some small coins from node0 to node1 - self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True); + self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True) self.sync_all() self.nodes[0].generate(1) self.sync_all() for i in range(0,20): - self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01); + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) self.sync_all() self.nodes[0].generate(1) self.sync_all() @@ -568,12 +645,12 @@ class RawTransactionsTest(BitcoinTestFramework): outputs = {self.nodes[2].getnewaddress() : watchonly_amount / 2} rawtx = self.nodes[3].createrawtransaction(inputs, outputs) - result = self.nodes[3].fundrawtransaction(rawtx, True) + result = self.nodes[3].fundrawtransaction(rawtx, {'includeWatching': True }) res_dec = self.nodes[0].decoderawtransaction(result["hex"]) assert_equal(len(res_dec["vin"]), 1) assert_equal(res_dec["vin"][0]["txid"], watchonly_txid) - assert_equal("fee" in result.keys(), True) + assert("fee" in result.keys()) assert_greater_than(result["changepos"], -1) ############################################################### @@ -584,6 +661,7 @@ class RawTransactionsTest(BitcoinTestFramework): outputs = {self.nodes[2].getnewaddress() : watchonly_amount} rawtx = self.nodes[3].createrawtransaction(inputs, outputs) + # Backward compatibility test (2nd param is includeWatching) result = self.nodes[3].fundrawtransaction(rawtx, True) res_dec = self.nodes[0].decoderawtransaction(result["hex"]) assert_equal(len(res_dec["vin"]), 2) diff --git a/qa/rpc-tests/getblocktemplate_longpoll.py b/qa/rpc-tests/getblocktemplate_longpoll.py index aab456242..3e85957ae 100755 --- a/qa/rpc-tests/getblocktemplate_longpoll.py +++ b/qa/rpc-tests/getblocktemplate_longpoll.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -38,7 +38,7 @@ class LongpollThread(threading.Thread): self.longpollid = templat['longpollid'] # create a new connection to the node, we can't use the same # connection from two threads - self.node = AuthServiceProxy(node.url, timeout=600) + self.node = get_rpc_proxy(node.url, 1, timeout=600) def run(self): self.node.getblocktemplate({'longpollid':self.longpollid}) diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/qa/rpc-tests/getblocktemplate_proposals.py index aca0cd749..07bfe69c6 100755 --- a/qa/rpc-tests/getblocktemplate_proposals.py +++ b/qa/rpc-tests/getblocktemplate_proposals.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -120,10 +120,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework): # Test 3: Truncated final tx lastbyte = txlist[-1].pop() - try: - assert_template(node, tmpl, txlist, 'n/a') - except JSONRPCException: - pass # Expected + assert_raises(JSONRPCException, assert_template, node, tmpl, txlist, 'n/a') txlist[-1].append(lastbyte) # Test 4: Add an invalid tx to the end (duplicate of gen tx) @@ -133,7 +130,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework): # Test 5: Add an invalid tx to the end (non-duplicate) txlist.append(bytearray(txlist[0])) - txlist[-1][4+1] = b'\xff' + txlist[-1][4+1] = 0xff assert_template(node, tmpl, txlist, 'bad-txns-inputs-missingorspent') txlist.pop() @@ -144,10 +141,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework): # Test 7: Bad tx count txlist.append(b'') - try: - assert_template(node, tmpl, txlist, 'n/a') - except JSONRPCException: - pass # Expected + assert_raises(JSONRPCException, assert_template, node, tmpl, txlist, 'n/a') txlist.pop() # Test 8: Bad bits diff --git a/qa/rpc-tests/getchaintips.py b/qa/rpc-tests/getchaintips.py index 6a2bcb296..dd260836b 100755 --- a/qa/rpc-tests/getchaintips.py +++ b/qa/rpc-tests/getchaintips.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -23,8 +23,8 @@ class GetChainTipsTest (BitcoinTestFramework): # Split the network and build two chains of different lengths. self.split_network () - self.nodes[0].generate(10); - self.nodes[2].generate(20); + self.nodes[0].generate(10) + self.nodes[2].generate(20) self.sync_all () tips = self.nodes[1].getchaintips () diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py index b66533543..cf37976a4 100755 --- a/qa/rpc-tests/httpbasics.py +++ b/qa/rpc-tests/httpbasics.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,7 +9,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -import base64 try: import http.client as httplib @@ -31,71 +30,85 @@ class HTTPBasicsTest (BitcoinTestFramework): ################################################# url = urlparse.urlparse(self.nodes[0].url) authpair = url.username + ':' + url.password - headers = {"Authorization": "Basic " + base64.b64encode(authpair)} + headers = {"Authorization": "Basic " + str_to_b64str(authpair)} conn = httplib.HTTPConnection(url.hostname, url.port) conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - out1 = conn.getresponse().read(); - assert_equal('"error":null' in out1, True) - assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! + out1 = conn.getresponse().read() + assert(b'"error":null' in out1) + assert(conn.sock!=None) #according to http/1.1 connection must still be open! #send 2nd request without closing connection conn.request('POST', '/', '{"method": "getchaintips"}', headers) - out2 = conn.getresponse().read(); - assert_equal('"error":null' in out1, True) #must also response with a correct json-rpc message - assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! + out1 = conn.getresponse().read() + assert(b'"error":null' in out1) #must also response with a correct json-rpc message + assert(conn.sock!=None) #according to http/1.1 connection must still be open! conn.close() #same should be if we add keep-alive because this should be the std. behaviour - headers = {"Authorization": "Basic " + base64.b64encode(authpair), "Connection": "keep-alive"} + headers = {"Authorization": "Basic " + str_to_b64str(authpair), "Connection": "keep-alive"} conn = httplib.HTTPConnection(url.hostname, url.port) conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - out1 = conn.getresponse().read(); - assert_equal('"error":null' in out1, True) - assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! + out1 = conn.getresponse().read() + assert(b'"error":null' in out1) + assert(conn.sock!=None) #according to http/1.1 connection must still be open! #send 2nd request without closing connection conn.request('POST', '/', '{"method": "getchaintips"}', headers) - out2 = conn.getresponse().read(); - assert_equal('"error":null' in out1, True) #must also response with a correct json-rpc message - assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! + out1 = conn.getresponse().read() + assert(b'"error":null' in out1) #must also response with a correct json-rpc message + assert(conn.sock!=None) #according to http/1.1 connection must still be open! conn.close() #now do the same with "Connection: close" - headers = {"Authorization": "Basic " + base64.b64encode(authpair), "Connection":"close"} + headers = {"Authorization": "Basic " + str_to_b64str(authpair), "Connection":"close"} conn = httplib.HTTPConnection(url.hostname, url.port) conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - out1 = conn.getresponse().read(); - assert_equal('"error":null' in out1, True) - assert_equal(conn.sock!=None, False) #now the connection must be closed after the response + out1 = conn.getresponse().read() + assert(b'"error":null' in out1) + assert(conn.sock==None) #now the connection must be closed after the response #node1 (2nd node) is running with disabled keep-alive option urlNode1 = urlparse.urlparse(self.nodes[1].url) authpair = urlNode1.username + ':' + urlNode1.password - headers = {"Authorization": "Basic " + base64.b64encode(authpair)} + headers = {"Authorization": "Basic " + str_to_b64str(authpair)} conn = httplib.HTTPConnection(urlNode1.hostname, urlNode1.port) conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - out1 = conn.getresponse().read(); - assert_equal('"error":null' in out1, True) + out1 = conn.getresponse().read() + assert(b'"error":null' in out1) #node2 (third node) is running with standard keep-alive parameters which means keep-alive is on urlNode2 = urlparse.urlparse(self.nodes[2].url) authpair = urlNode2.username + ':' + urlNode2.password - headers = {"Authorization": "Basic " + base64.b64encode(authpair)} + headers = {"Authorization": "Basic " + str_to_b64str(authpair)} conn = httplib.HTTPConnection(urlNode2.hostname, urlNode2.port) conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - out1 = conn.getresponse().read(); - assert_equal('"error":null' in out1, True) - assert_equal(conn.sock!=None, True) #connection must be closed because bitcoind should use keep-alive by default + out1 = conn.getresponse().read() + assert(b'"error":null' in out1) + assert(conn.sock!=None) #connection must be closed because bitcoind should use keep-alive by default + + # Check excessive request size + conn = httplib.HTTPConnection(urlNode2.hostname, urlNode2.port) + conn.connect() + conn.request('GET', '/' + ('x'*1000), '', headers) + out1 = conn.getresponse() + assert_equal(out1.status, httplib.NOT_FOUND) + + conn = httplib.HTTPConnection(urlNode2.hostname, urlNode2.port) + conn.connect() + conn.request('GET', '/' + ('x'*10000), '', headers) + out1 = conn.getresponse() + assert_equal(out1.status, httplib.BAD_REQUEST) + if __name__ == '__main__': HTTPBasicsTest ().main () diff --git a/qa/rpc-tests/importprunedfunds.py b/qa/rpc-tests/importprunedfunds.py new file mode 100755 index 000000000..a9324196e --- /dev/null +++ b/qa/rpc-tests/importprunedfunds.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import decimal + +class ImportPrunedFundsTest(BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def setup_network(self, split=False): + self.nodes = start_nodes(2, self.options.tmpdir) + connect_nodes_bi(self.nodes,0,1) + self.is_network_split=False + self.sync_all() + + def run_test (self): + import time + begintime = int(time.time()) + + print "Mining blocks..." + self.nodes[0].generate(101) + + # sync + self.sync_all() + + # address + address1 = self.nodes[0].getnewaddress() + # pubkey + address2 = self.nodes[0].getnewaddress() + address2_pubkey = self.nodes[0].validateaddress(address2)['pubkey'] # Using pubkey + # privkey + address3 = self.nodes[0].getnewaddress() + address3_privkey = self.nodes[0].dumpprivkey(address3) # Using privkey + + #Check only one address + address_info = self.nodes[0].validateaddress(address1) + assert_equal(address_info['ismine'], True) + + self.sync_all() + + #Node 1 sync test + assert_equal(self.nodes[1].getblockcount(),101) + + #Address Test - before import + address_info = self.nodes[1].validateaddress(address1) + assert_equal(address_info['iswatchonly'], False) + assert_equal(address_info['ismine'], False) + + address_info = self.nodes[1].validateaddress(address2) + assert_equal(address_info['iswatchonly'], False) + assert_equal(address_info['ismine'], False) + + address_info = self.nodes[1].validateaddress(address3) + assert_equal(address_info['iswatchonly'], False) + assert_equal(address_info['ismine'], False) + + #Send funds to self + txnid1 = self.nodes[0].sendtoaddress(address1, 0.1) + self.nodes[0].generate(1) + rawtxn1 = self.nodes[0].gettransaction(txnid1)['hex'] + proof1 = self.nodes[0].gettxoutproof([txnid1]) + + txnid2 = self.nodes[0].sendtoaddress(address2, 0.05) + self.nodes[0].generate(1) + rawtxn2 = self.nodes[0].gettransaction(txnid2)['hex'] + proof2 = self.nodes[0].gettxoutproof([txnid2]) + + + txnid3 = self.nodes[0].sendtoaddress(address3, 0.025) + self.nodes[0].generate(1) + rawtxn3 = self.nodes[0].gettransaction(txnid3)['hex'] + proof3 = self.nodes[0].gettxoutproof([txnid3]) + + self.sync_all() + + #Import with no affiliated address + try: + result1 = self.nodes[1].importprunedfunds(rawtxn1, proof1, "") + except JSONRPCException as e: + assert('No addresses' in e.error['message']) + else: + assert(False) + + + balance1 = self.nodes[1].getbalance("", 0, True) + assert_equal(balance1, Decimal(0)) + + #Import with affiliated address with no rescan + self.nodes[1].importaddress(address2, "", False) + result2 = self.nodes[1].importprunedfunds(rawtxn2, proof2, "") + balance2 = Decimal(self.nodes[1].getbalance("", 0, True)) + assert_equal(balance2, Decimal('0.05')) + + #Import with private key with no rescan + self.nodes[1].importprivkey(address3_privkey, "", False) + result3 = self.nodes[1].importprunedfunds(rawtxn3, proof3, "") + balance3 = Decimal(self.nodes[1].getbalance("", 0, False)) + assert_equal(balance3, Decimal('0.025')) + balance3 = Decimal(self.nodes[1].getbalance("", 0, True)) + assert_equal(balance3, Decimal('0.075')) + + #Addresses Test - after import + address_info = self.nodes[1].validateaddress(address1) + assert_equal(address_info['iswatchonly'], False) + assert_equal(address_info['ismine'], False) + address_info = self.nodes[1].validateaddress(address2) + assert_equal(address_info['iswatchonly'], True) + assert_equal(address_info['ismine'], False) + address_info = self.nodes[1].validateaddress(address3) + assert_equal(address_info['iswatchonly'], False) + assert_equal(address_info['ismine'], True) + + #Remove transactions + + try: + self.nodes[1].removeprunedfunds(txnid1) + except JSONRPCException as e: + assert('does not exist' in e.error['message']) + else: + assert(False) + + + balance1 = Decimal(self.nodes[1].getbalance("", 0, True)) + assert_equal(balance1, Decimal('0.075')) + + + self.nodes[1].removeprunedfunds(txnid2) + balance2 = Decimal(self.nodes[1].getbalance("", 0, True)) + assert_equal(balance2, Decimal('0.025')) + + self.nodes[1].removeprunedfunds(txnid3) + balance3 = Decimal(self.nodes[1].getbalance("", 0, True)) + assert_equal(balance3, Decimal('0.0')) + +if __name__ == '__main__': + ImportPrunedFundsTest ().main () diff --git a/qa/rpc-tests/invalidateblock.py b/qa/rpc-tests/invalidateblock.py index 2b9c8154e..0e78a3c80 100755 --- a/qa/rpc-tests/invalidateblock.py +++ b/qa/rpc-tests/invalidateblock.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/qa/rpc-tests/invalidblockrequest.py b/qa/rpc-tests/invalidblockrequest.py index 6a7980cd4..de6be8d5b 100755 --- a/qa/rpc-tests/invalidblockrequest.py +++ b/qa/rpc-tests/invalidblockrequest.py @@ -1,15 +1,13 @@ #!/usr/bin/env python2 -# +# Copyright (c) 2015 The Bitcoin Core developers # Distributed under the MIT/X11 software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # from test_framework.test_framework import ComparisonTestFramework from test_framework.util import * -from test_framework.comptool import TestManager, TestInstance -from test_framework.mininode import * +from test_framework.comptool import TestManager, TestInstance, RejectResult from test_framework.blocktools import * -import logging import copy import time @@ -79,9 +77,9 @@ class InvalidBlockRequestTest(ComparisonTestFramework): block2 = create_block(self.tip, create_coinbase(height), self.block_time) self.block_time += 1 - # chr(81) is OP_TRUE - tx1 = create_transaction(self.block1.vtx[0], 0, chr(81), 50*100000000) - tx2 = create_transaction(tx1, 0, chr(81), 50*100000000) + # b'0x51' is OP_TRUE + tx1 = create_transaction(self.block1.vtx[0], 0, b'\x51', 50 * COIN) + tx2 = create_transaction(tx1, 0, b'\x51', 50 * COIN) block2.vtx.extend([tx1, tx2]) block2.hashMerkleRoot = block2.calc_merkle_root() @@ -97,7 +95,7 @@ class InvalidBlockRequestTest(ComparisonTestFramework): assert(block2_orig.vtx != block2.vtx) self.tip = block2.sha256 - yield TestInstance([[block2, False], [block2_orig, True]]) + yield TestInstance([[block2, RejectResult(16, b'bad-txns-duplicate')], [block2_orig, True]]) height += 1 ''' @@ -105,14 +103,14 @@ class InvalidBlockRequestTest(ComparisonTestFramework): ''' block3 = create_block(self.tip, create_coinbase(height), self.block_time) self.block_time += 1 - block3.vtx[0].vout[0].nValue = 100*100000000 # Too high! + block3.vtx[0].vout[0].nValue = 100 * COIN # Too high! block3.vtx[0].sha256=None block3.vtx[0].calc_sha256() block3.hashMerkleRoot = block3.calc_merkle_root() block3.rehash() block3.solve() - yield TestInstance([[block3, False]]) + yield TestInstance([[block3, RejectResult(16, b'bad-cb-amount')]]) if __name__ == '__main__': diff --git a/qa/rpc-tests/invalidtxrequest.py b/qa/rpc-tests/invalidtxrequest.py new file mode 100755 index 000000000..7b8199bab --- /dev/null +++ b/qa/rpc-tests/invalidtxrequest.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +from test_framework.test_framework import ComparisonTestFramework +from test_framework.comptool import TestManager, TestInstance, RejectResult +from test_framework.blocktools import * +import time + + +''' +In this test we connect to one node over p2p, and test tx requests. +''' + +# Use the ComparisonTestFramework with 1 node: only use --testbinary. +class InvalidTxRequestTest(ComparisonTestFramework): + + ''' Can either run this test as 1 node with expected answers, or two and compare them. + Change the "outcome" variable from each TestInstance object to only do the comparison. ''' + def __init__(self): + self.num_nodes = 1 + + def run_test(self): + test = TestManager(self, self.options.tmpdir) + test.add_all_connections(self.nodes) + self.tip = None + self.block_time = None + NetworkThread().start() # Start up network handling in another thread + test.run() + + def get_tests(self): + if self.tip is None: + self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) + self.block_time = int(time.time())+1 + + ''' + Create a new block with an anyone-can-spend coinbase + ''' + height = 1 + block = create_block(self.tip, create_coinbase(height), self.block_time) + self.block_time += 1 + block.solve() + # Save the coinbase for later + self.block1 = block + self.tip = block.sha256 + height += 1 + yield TestInstance([[block, True]]) + + ''' + Now we need that block to mature so we can spend the coinbase. + ''' + test = TestInstance(sync_every_block=False) + for i in xrange(100): + block = create_block(self.tip, create_coinbase(height), self.block_time) + block.solve() + self.tip = block.sha256 + self.block_time += 1 + test.blocks_and_transactions.append([block, True]) + height += 1 + yield test + + # b'\x64' is OP_NOTIF + # Transaction will be rejected with code 16 (REJECT_INVALID) + tx1 = create_transaction(self.block1.vtx[0], 0, b'\x64', 50 * COIN - 12000) + yield TestInstance([[tx1, RejectResult(16, b'mandatory-script-verify-flag-failed')]]) + + # TODO: test further transactions... + +if __name__ == '__main__': + InvalidTxRequestTest().main() diff --git a/qa/rpc-tests/keypool.py b/qa/rpc-tests/keypool.py index 5a6722002..5253d49c3 100755 --- a/qa/rpc-tests/keypool.py +++ b/qa/rpc-tests/keypool.py @@ -1,20 +1,13 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # Exercise the wallet keypool, and interaction with wallet encryption/locking # Add python-bitcoinrpc to module search path: -import os -import sys - -import json -import shutil -import subprocess -import tempfile -import traceback +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * @@ -39,107 +32,67 @@ def check_array_result(object_array, to_match, expected): if num_matched == 0: raise AssertionError("No objects matched %s"%(str(to_match))) -def run_test(nodes, tmpdir): - # Encrypt wallet and wait to terminate - nodes[0].encryptwallet('test') - bitcoind_processes[0].wait() - # Restart node 0 - nodes[0] = start_node(0, tmpdir) - # Keep creating keys - addr = nodes[0].getnewaddress() - try: +class KeyPoolTest(BitcoinTestFramework): + + def run_test(self): + nodes = self.nodes + # Encrypt wallet and wait to terminate + nodes[0].encryptwallet('test') + bitcoind_processes[0].wait() + # Restart node 0 + nodes[0] = start_node(0, self.options.tmpdir) + # Keep creating keys addr = nodes[0].getnewaddress() - raise AssertionError('Keypool should be exhausted after one address') - except JSONRPCException,e: - assert(e.error['code']==-12) + try: + addr = nodes[0].getnewaddress() + raise AssertionError('Keypool should be exhausted after one address') + except JSONRPCException as e: + assert(e.error['code']==-12) - # put three new keys in the keypool - nodes[0].walletpassphrase('test', 12000) - nodes[0].keypoolrefill(3) - nodes[0].walletlock() + # put three new keys in the keypool + nodes[0].walletpassphrase('test', 12000) + nodes[0].keypoolrefill(3) + nodes[0].walletlock() - # drain the keys - addr = set() - addr.add(nodes[0].getrawchangeaddress()) - addr.add(nodes[0].getrawchangeaddress()) - addr.add(nodes[0].getrawchangeaddress()) - addr.add(nodes[0].getrawchangeaddress()) - # assert that four unique addresses were returned - assert(len(addr) == 4) - # the next one should fail - try: - addr = nodes[0].getrawchangeaddress() - raise AssertionError('Keypool should be exhausted after three addresses') - except JSONRPCException,e: - assert(e.error['code']==-12) + # drain the keys + addr = set() + addr.add(nodes[0].getrawchangeaddress()) + addr.add(nodes[0].getrawchangeaddress()) + addr.add(nodes[0].getrawchangeaddress()) + addr.add(nodes[0].getrawchangeaddress()) + # assert that four unique addresses were returned + assert(len(addr) == 4) + # the next one should fail + try: + addr = nodes[0].getrawchangeaddress() + raise AssertionError('Keypool should be exhausted after three addresses') + except JSONRPCException as e: + assert(e.error['code']==-12) - # refill keypool with three new addresses - nodes[0].walletpassphrase('test', 12000) - nodes[0].keypoolrefill(3) - nodes[0].walletlock() + # refill keypool with three new addresses + nodes[0].walletpassphrase('test', 1) + nodes[0].keypoolrefill(3) + # test walletpassphrase timeout + time.sleep(1.1) + assert_equal(nodes[0].getwalletinfo()["unlocked_until"], 0) - # drain them by mining - nodes[0].generate(1) - nodes[0].generate(1) - nodes[0].generate(1) - nodes[0].generate(1) - try: + # drain them by mining nodes[0].generate(1) - raise AssertionError('Keypool should be exhausted after three addesses') - except JSONRPCException,e: - assert(e.error['code']==-12) + nodes[0].generate(1) + nodes[0].generate(1) + nodes[0].generate(1) + try: + nodes[0].generate(1) + raise AssertionError('Keypool should be exhausted after three addesses') + except JSONRPCException as e: + assert(e.error['code']==-12) -def main(): - import optparse + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain(self.options.tmpdir) - parser = optparse.OptionParser(usage="%prog [options]") - parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true", - help="Leave bitcoinds and test.* datadir on exit or error") - parser.add_option("--srcdir", dest="srcdir", default="../../src", - help="Source directory containing bitcoind/bitcoin-cli (default: %default%)") - parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"), - help="Root directory for datadirs") - (options, args) = parser.parse_args() - - os.environ['PATH'] = options.srcdir+":"+os.environ['PATH'] - - check_json_precision() - - success = False - nodes = [] - try: - print("Initializing test directory "+options.tmpdir) - if not os.path.isdir(options.tmpdir): - os.makedirs(options.tmpdir) - initialize_chain(options.tmpdir) - - nodes = start_nodes(1, options.tmpdir) - - run_test(nodes, options.tmpdir) - - success = True - - except AssertionError as e: - print("Assertion failed: "+e.message) - except JSONRPCException as e: - print("JSONRPC error: "+e.error['message']) - traceback.print_tb(sys.exc_info()[2]) - except Exception as e: - print("Unexpected exception caught during testing: "+str(sys.exc_info()[0])) - traceback.print_tb(sys.exc_info()[2]) - - if not options.nocleanup: - print("Cleaning up") - stop_nodes(nodes) - wait_bitcoinds() - shutil.rmtree(options.tmpdir) - - if success: - print("Tests successful") - sys.exit(0) - else: - print("Failed") - sys.exit(1) + def setup_network(self): + self.nodes = start_nodes(1, self.options.tmpdir) if __name__ == '__main__': - main() + KeyPoolTest().main() diff --git a/qa/rpc-tests/listtransactions.py b/qa/rpc-tests/listtransactions.py index b30a6bc9d..0783a1f3d 100755 --- a/qa/rpc-tests/listtransactions.py +++ b/qa/rpc-tests/listtransactions.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,7 +7,14 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * +from test_framework.mininode import CTransaction, COIN +from io import BytesIO +def txFromHex(hexstring): + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(hexstring)) + tx.deserialize(f) + return tx def check_array_result(object_array, to_match, expected): """ @@ -32,6 +39,11 @@ def check_array_result(object_array, to_match, expected): class ListTransactionsTest(BitcoinTestFramework): + def setup_nodes(self): + #This test requires mocktime + enable_mocktime() + return start_nodes(4, self.options.tmpdir) + def run_test(self): # Simple send, 0 to 1: txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) @@ -103,6 +115,107 @@ class ListTransactionsTest(BitcoinTestFramework): {"category":"receive","amount":Decimal("0.1")}, {"txid":txid, "account" : "watchonly"} ) + self.run_rbf_opt_in_test() + + # Check that the opt-in-rbf flag works properly, for sent and received + # transactions. + def run_rbf_opt_in_test(self): + # Check whether a transaction signals opt-in RBF itself + def is_opt_in(node, txid): + rawtx = node.getrawtransaction(txid, 1) + for x in rawtx["vin"]: + if x["sequence"] < 0xfffffffe: + return True + return False + + # Find an unconfirmed output matching a certain txid + def get_unconfirmed_utxo_entry(node, txid_to_match): + utxo = node.listunspent(0, 0) + for i in utxo: + if i["txid"] == txid_to_match: + return i + return None + + # 1. Chain a few transactions that don't opt-in. + txid_1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) + assert(not is_opt_in(self.nodes[0], txid_1)) + check_array_result(self.nodes[0].listtransactions(), {"txid": txid_1}, {"bip125-replaceable":"no"}) + sync_mempools(self.nodes) + check_array_result(self.nodes[1].listtransactions(), {"txid": txid_1}, {"bip125-replaceable":"no"}) + + # Tx2 will build off txid_1, still not opting in to RBF. + utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1) + + # Create tx2 using createrawtransaction + inputs = [{"txid":utxo_to_use["txid"], "vout":utxo_to_use["vout"]}] + outputs = {self.nodes[0].getnewaddress(): 0.999} + tx2 = self.nodes[1].createrawtransaction(inputs, outputs) + tx2_signed = self.nodes[1].signrawtransaction(tx2)["hex"] + txid_2 = self.nodes[1].sendrawtransaction(tx2_signed) + + # ...and check the result + assert(not is_opt_in(self.nodes[1], txid_2)) + check_array_result(self.nodes[1].listtransactions(), {"txid": txid_2}, {"bip125-replaceable":"no"}) + sync_mempools(self.nodes) + check_array_result(self.nodes[0].listtransactions(), {"txid": txid_2}, {"bip125-replaceable":"no"}) + + # Tx3 will opt-in to RBF + utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[0], txid_2) + inputs = [{"txid": txid_2, "vout":utxo_to_use["vout"]}] + outputs = {self.nodes[1].getnewaddress(): 0.998} + tx3 = self.nodes[0].createrawtransaction(inputs, outputs) + tx3_modified = txFromHex(tx3) + tx3_modified.vin[0].nSequence = 0 + tx3 = bytes_to_hex_str(tx3_modified.serialize()) + tx3_signed = self.nodes[0].signrawtransaction(tx3)['hex'] + txid_3 = self.nodes[0].sendrawtransaction(tx3_signed) + + assert(is_opt_in(self.nodes[0], txid_3)) + check_array_result(self.nodes[0].listtransactions(), {"txid": txid_3}, {"bip125-replaceable":"yes"}) + sync_mempools(self.nodes) + check_array_result(self.nodes[1].listtransactions(), {"txid": txid_3}, {"bip125-replaceable":"yes"}) + + # Tx4 will chain off tx3. Doesn't signal itself, but depends on one + # that does. + utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_3) + inputs = [{"txid": txid_3, "vout":utxo_to_use["vout"]}] + outputs = {self.nodes[0].getnewaddress(): 0.997} + tx4 = self.nodes[1].createrawtransaction(inputs, outputs) + tx4_signed = self.nodes[1].signrawtransaction(tx4)["hex"] + txid_4 = self.nodes[1].sendrawtransaction(tx4_signed) + + assert(not is_opt_in(self.nodes[1], txid_4)) + check_array_result(self.nodes[1].listtransactions(), {"txid": txid_4}, {"bip125-replaceable":"yes"}) + sync_mempools(self.nodes) + check_array_result(self.nodes[0].listtransactions(), {"txid": txid_4}, {"bip125-replaceable":"yes"}) + + # Replace tx3, and check that tx4 becomes unknown + tx3_b = tx3_modified + tx3_b.vout[0].nValue -= int(Decimal("0.004") * COIN) # bump the fee + tx3_b = bytes_to_hex_str(tx3_b.serialize()) + tx3_b_signed = self.nodes[0].signrawtransaction(tx3_b)['hex'] + txid_3b = self.nodes[0].sendrawtransaction(tx3_b_signed, True) + assert(is_opt_in(self.nodes[0], txid_3b)) + + check_array_result(self.nodes[0].listtransactions(), {"txid": txid_4}, {"bip125-replaceable":"unknown"}) + sync_mempools(self.nodes) + check_array_result(self.nodes[1].listtransactions(), {"txid": txid_4}, {"bip125-replaceable":"unknown"}) + + # Check gettransaction as well: + for n in self.nodes[0:2]: + assert_equal(n.gettransaction(txid_1)["bip125-replaceable"], "no") + assert_equal(n.gettransaction(txid_2)["bip125-replaceable"], "no") + assert_equal(n.gettransaction(txid_3)["bip125-replaceable"], "yes") + assert_equal(n.gettransaction(txid_3b)["bip125-replaceable"], "yes") + assert_equal(n.gettransaction(txid_4)["bip125-replaceable"], "unknown") + + # After mining a transaction, it's no longer BIP125-replaceable + self.nodes[0].generate(1) + assert(txid_3b not in self.nodes[0].getrawmempool()) + assert_equal(self.nodes[0].gettransaction(txid_3b)["bip125-replaceable"], "no") + assert_equal(self.nodes[0].gettransaction(txid_4)["bip125-replaceable"], "unknown") + + if __name__ == '__main__': ListTransactionsTest().main() diff --git a/qa/rpc-tests/maxblocksinflight.py b/qa/rpc-tests/maxblocksinflight.py index a601147ce..ad633f661 100755 --- a/qa/rpc-tests/maxblocksinflight.py +++ b/qa/rpc-tests/maxblocksinflight.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# +# Copyright (c) 2015 The Bitcoin Core developers # Distributed under the MIT/X11 software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # @@ -34,7 +34,6 @@ class TestManager(NodeConnCB): def __init__(self): NodeConnCB.__init__(self) self.log = logging.getLogger("BlockRelayTest") - self.create_callback_map() def add_new_connection(self, connection): self.connection = connection @@ -42,40 +41,36 @@ class TestManager(NodeConnCB): self.disconnectOkay = False def run(self): - try: - fail = False - self.connection.rpc.generate(1) # Leave IBD + self.connection.rpc.generate(1) # Leave IBD - numBlocksToGenerate = [ 8, 16, 128, 1024 ] - for count in range(len(numBlocksToGenerate)): - current_invs = [] - for i in range(numBlocksToGenerate[count]): - current_invs.append(CInv(2, random.randrange(0, 1<<256))) - if len(current_invs) >= 50000: - self.connection.send_message(msg_inv(current_invs)) - current_invs = [] - if len(current_invs) > 0: + numBlocksToGenerate = [8, 16, 128, 1024] + for count in range(len(numBlocksToGenerate)): + current_invs = [] + for i in range(numBlocksToGenerate[count]): + current_invs.append(CInv(2, random.randrange(0, 1 << 256))) + if len(current_invs) >= 50000: self.connection.send_message(msg_inv(current_invs)) - - # Wait and see how many blocks were requested - time.sleep(2) + current_invs = [] + if len(current_invs) > 0: + self.connection.send_message(msg_inv(current_invs)) - total_requests = 0 - with mininode_lock: - for key in self.blockReqCounts: - total_requests += self.blockReqCounts[key] - if self.blockReqCounts[key] > 1: - raise AssertionError("Error, test failed: block %064x requested more than once" % key) - if total_requests > MAX_REQUESTS: - raise AssertionError("Error, too many blocks (%d) requested" % total_requests) - print "Round %d: success (total requests: %d)" % (count, total_requests) - except AssertionError as e: - print "TEST FAILED: ", e.args + # Wait and see how many blocks were requested + time.sleep(2) + + total_requests = 0 + with mininode_lock: + for key in self.blockReqCounts: + total_requests += self.blockReqCounts[key] + if self.blockReqCounts[key] > 1: + raise AssertionError("Error, test failed: block %064x requested more than once" % key) + if total_requests > MAX_REQUESTS: + raise AssertionError("Error, too many blocks (%d) requested" % total_requests) + print "Round %d: success (total requests: %d)" % (count, total_requests) self.disconnectOkay = True self.connection.disconnect_node() - + class MaxBlocksInFlightTest(BitcoinTestFramework): def add_options(self, parser): parser.add_option("--testbinary", dest="testbinary", @@ -87,7 +82,7 @@ class MaxBlocksInFlightTest(BitcoinTestFramework): initialize_chain_clean(self.options.tmpdir, 1) def setup_network(self): - self.nodes = start_nodes(1, self.options.tmpdir, + self.nodes = start_nodes(1, self.options.tmpdir, extra_args=[['-debug', '-whitelist=127.0.0.1']], binary=[self.options.testbinary]) diff --git a/qa/rpc-tests/maxuploadtarget.py b/qa/rpc-tests/maxuploadtarget.py new file mode 100755 index 000000000..be45fecb5 --- /dev/null +++ b/qa/rpc-tests/maxuploadtarget.py @@ -0,0 +1,265 @@ +#!/usr/bin/env python2 +# +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +from test_framework.mininode import * +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import time + +''' +Test behavior of -maxuploadtarget. + +* Verify that getdata requests for old blocks (>1week) are dropped +if uploadtarget has been reached. +* Verify that getdata requests for recent blocks are respecteved even +if uploadtarget has been reached. +* Verify that the upload counters are reset after 24 hours. +''' + +# TestNode: bare-bones "peer". Used mostly as a conduit for a test to sending +# p2p messages to a node, generating the messages in the main testing logic. +class TestNode(NodeConnCB): + def __init__(self): + NodeConnCB.__init__(self) + self.connection = None + self.ping_counter = 1 + self.last_pong = msg_pong() + self.block_receive_map = {} + + def add_connection(self, conn): + self.connection = conn + self.peer_disconnected = False + + def on_inv(self, conn, message): + pass + + # Track the last getdata message we receive (used in the test) + def on_getdata(self, conn, message): + self.last_getdata = message + + def on_block(self, conn, message): + message.block.calc_sha256() + try: + self.block_receive_map[message.block.sha256] += 1 + except KeyError as e: + self.block_receive_map[message.block.sha256] = 1 + + # Spin until verack message is received from the node. + # We use this to signal that our test can begin. This + # is called from the testing thread, so it needs to acquire + # the global lock. + def wait_for_verack(self): + def veracked(): + return self.verack_received + return wait_until(veracked, timeout=10) + + def wait_for_disconnect(self): + def disconnected(): + return self.peer_disconnected + return wait_until(disconnected, timeout=10) + + # Wrapper for the NodeConn's send_message function + def send_message(self, message): + self.connection.send_message(message) + + def on_pong(self, conn, message): + self.last_pong = message + + def on_close(self, conn): + self.peer_disconnected = True + + # Sync up with the node after delivery of a block + def sync_with_ping(self, timeout=30): + def received_pong(): + return (self.last_pong.nonce == self.ping_counter) + self.connection.send_message(msg_ping(nonce=self.ping_counter)) + success = wait_until(received_pong, timeout) + self.ping_counter += 1 + return success + +class MaxUploadTest(BitcoinTestFramework): + def __init__(self): + self.utxo = [] + self.txouts = gen_return_txouts() + + def add_options(self, parser): + parser.add_option("--testbinary", dest="testbinary", + default=os.getenv("BITCOIND", "bitcoind"), + help="bitcoind binary to test") + + def setup_chain(self): + initialize_chain_clean(self.options.tmpdir, 2) + + def setup_network(self): + # Start a node with maxuploadtarget of 200 MB (/24h) + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-maxuploadtarget=200", "-blockmaxsize=999000"])) + + def mine_full_block(self, node, address): + # Want to create a full block + # We'll generate a 66k transaction below, and 14 of them is close to the 1MB block limit + for j in xrange(14): + if len(self.utxo) < 14: + self.utxo = node.listunspent() + inputs=[] + outputs = {} + t = self.utxo.pop() + inputs.append({ "txid" : t["txid"], "vout" : t["vout"]}) + remchange = t["amount"] - Decimal("0.001000") + outputs[address]=remchange + # Create a basic transaction that will send change back to ourself after account for a fee + # And then insert the 128 generated transaction outs in the middle rawtx[92] is where the # + # of txouts is stored and is the only thing we overwrite from the original transaction + rawtx = node.createrawtransaction(inputs, outputs) + newtx = rawtx[0:92] + newtx = newtx + self.txouts + newtx = newtx + rawtx[94:] + # Appears to be ever so slightly faster to sign with SIGHASH_NONE + signresult = node.signrawtransaction(newtx,None,None,"NONE") + txid = node.sendrawtransaction(signresult["hex"], True) + # Mine a full sized block which will be these transactions we just created + node.generate(1) + + def run_test(self): + # Before we connect anything, we first set the time on the node + # to be in the past, otherwise things break because the CNode + # time counters can't be reset backward after initialization + old_time = int(time.time() - 2*60*60*24*7) + self.nodes[0].setmocktime(old_time) + + # Generate some old blocks + self.nodes[0].generate(130) + + # test_nodes[0] will only request old blocks + # test_nodes[1] will only request new blocks + # test_nodes[2] will test resetting the counters + test_nodes = [] + connections = [] + + for i in xrange(3): + test_nodes.append(TestNode()) + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_nodes[i])) + test_nodes[i].add_connection(connections[i]) + + NetworkThread().start() # Start up network handling in another thread + [x.wait_for_verack() for x in test_nodes] + + # Test logic begins here + + # Now mine a big block + self.mine_full_block(self.nodes[0], self.nodes[0].getnewaddress()) + + # Store the hash; we'll request this later + big_old_block = self.nodes[0].getbestblockhash() + old_block_size = self.nodes[0].getblock(big_old_block, True)['size'] + big_old_block = int(big_old_block, 16) + + # Advance to two days ago + self.nodes[0].setmocktime(int(time.time()) - 2*60*60*24) + + # Mine one more block, so that the prior block looks old + self.mine_full_block(self.nodes[0], self.nodes[0].getnewaddress()) + + # We'll be requesting this new block too + big_new_block = self.nodes[0].getbestblockhash() + new_block_size = self.nodes[0].getblock(big_new_block)['size'] + big_new_block = int(big_new_block, 16) + + # test_nodes[0] will test what happens if we just keep requesting the + # the same big old block too many times (expect: disconnect) + + getdata_request = msg_getdata() + getdata_request.inv.append(CInv(2, big_old_block)) + + max_bytes_per_day = 200*1024*1024 + daily_buffer = 144 * MAX_BLOCK_SIZE + max_bytes_available = max_bytes_per_day - daily_buffer + success_count = max_bytes_available // old_block_size + + # 144MB will be reserved for relaying new blocks, so expect this to + # succeed for ~70 tries. + for i in xrange(success_count): + test_nodes[0].send_message(getdata_request) + test_nodes[0].sync_with_ping() + assert_equal(test_nodes[0].block_receive_map[big_old_block], i+1) + + assert_equal(len(self.nodes[0].getpeerinfo()), 3) + # At most a couple more tries should succeed (depending on how long + # the test has been running so far). + for i in xrange(3): + test_nodes[0].send_message(getdata_request) + test_nodes[0].wait_for_disconnect() + assert_equal(len(self.nodes[0].getpeerinfo()), 2) + print "Peer 0 disconnected after downloading old block too many times" + + # Requesting the current block on test_nodes[1] should succeed indefinitely, + # even when over the max upload target. + # We'll try 200 times + getdata_request.inv = [CInv(2, big_new_block)] + for i in xrange(200): + test_nodes[1].send_message(getdata_request) + test_nodes[1].sync_with_ping() + assert_equal(test_nodes[1].block_receive_map[big_new_block], i+1) + + print "Peer 1 able to repeatedly download new block" + + # But if test_nodes[1] tries for an old block, it gets disconnected too. + getdata_request.inv = [CInv(2, big_old_block)] + test_nodes[1].send_message(getdata_request) + test_nodes[1].wait_for_disconnect() + assert_equal(len(self.nodes[0].getpeerinfo()), 1) + + print "Peer 1 disconnected after trying to download old block" + + print "Advancing system time on node to clear counters..." + + # If we advance the time by 24 hours, then the counters should reset, + # and test_nodes[2] should be able to retrieve the old block. + self.nodes[0].setmocktime(int(time.time())) + test_nodes[2].sync_with_ping() + test_nodes[2].send_message(getdata_request) + test_nodes[2].sync_with_ping() + assert_equal(test_nodes[2].block_receive_map[big_old_block], 1) + + print "Peer 2 able to download old block" + + [c.disconnect_node() for c in connections] + + #stop and start node 0 with 1MB maxuploadtarget, whitelist 127.0.0.1 + print "Restarting nodes with -whitelist=127.0.0.1" + stop_node(self.nodes[0], 0) + self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"]) + + #recreate/reconnect 3 test nodes + test_nodes = [] + connections = [] + + for i in xrange(3): + test_nodes.append(TestNode()) + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_nodes[i])) + test_nodes[i].add_connection(connections[i]) + + NetworkThread().start() # Start up network handling in another thread + [x.wait_for_verack() for x in test_nodes] + + #retrieve 20 blocks which should be enough to break the 1MB limit + getdata_request.inv = [CInv(2, big_new_block)] + for i in xrange(20): + test_nodes[1].send_message(getdata_request) + test_nodes[1].sync_with_ping() + assert_equal(test_nodes[1].block_receive_map[big_new_block], i+1) + + getdata_request.inv = [CInv(2, big_old_block)] + test_nodes[1].send_message(getdata_request) + test_nodes[1].wait_for_disconnect() + assert_equal(len(self.nodes[0].getpeerinfo()), 3) #node is still connected because of the whitelist + + print "Peer 1 still connected after trying to download old block (whitelisted)" + + [c.disconnect_node() for c in connections] + +if __name__ == '__main__': + MaxUploadTest().main() diff --git a/qa/rpc-tests/mempool_limit.py b/qa/rpc-tests/mempool_limit.py new file mode 100755 index 000000000..c19a63c69 --- /dev/null +++ b/qa/rpc-tests/mempool_limit.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# Test mempool limiting together/eviction with the wallet + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class MempoolLimitTest(BitcoinTestFramework): + + def __init__(self): + self.txouts = gen_return_txouts() + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-maxmempool=5", "-spendzeroconfchange=0", "-debug"])) + self.is_network_split = False + self.sync_all() + self.relayfee = self.nodes[0].getnetworkinfo()['relayfee'] + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 2) + + def run_test(self): + txids = [] + utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], 90) + + #create a mempool tx that will be evicted + us0 = utxos.pop() + inputs = [{ "txid" : us0["txid"], "vout" : us0["vout"]}] + outputs = {self.nodes[0].getnewaddress() : 0.0001} + tx = self.nodes[0].createrawtransaction(inputs, outputs) + self.nodes[0].settxfee(self.relayfee) # specifically fund this tx with low fee + txF = self.nodes[0].fundrawtransaction(tx) + self.nodes[0].settxfee(0) # return to automatic fee selection + txFS = self.nodes[0].signrawtransaction(txF['hex']) + txid = self.nodes[0].sendrawtransaction(txFS['hex']) + + relayfee = self.nodes[0].getnetworkinfo()['relayfee'] + base_fee = relayfee*100 + for i in xrange (4): + txids.append([]) + txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[30*i:30*i+30], (i+1)*base_fee) + + # by now, the tx should be evicted, check confirmation state + assert(txid not in self.nodes[0].getrawmempool()) + txdata = self.nodes[0].gettransaction(txid) + assert(txdata['confirmations'] == 0) #confirmation should still be 0 + +if __name__ == '__main__': + MempoolLimitTest().main() diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py index 6bc6e43f0..bc3f9e051 100755 --- a/qa/rpc-tests/mempool_packages.py +++ b/qa/rpc-tests/mempool_packages.py @@ -7,9 +7,10 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * +from test_framework.mininode import COIN -def satoshi_round(amount): - return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) +MAX_ANCESTORS = 25 +MAX_DESCENDANTS = 25 class MempoolPackagesTest(BitcoinTestFramework): @@ -45,36 +46,68 @@ class MempoolPackagesTest(BitcoinTestFramework): value = utxo[0]['amount'] fee = Decimal("0.0001") - # 100 transactions off a confirmed tx should be fine + # MAX_ANCESTORS transactions off a confirmed tx should be fine chain = [] - for i in xrange(100): + for i in xrange(MAX_ANCESTORS): (txid, sent_value) = self.chain_transaction(self.nodes[0], txid, 0, value, fee, 1) value = sent_value chain.append(txid) - # Check mempool has 100 transactions in it, and descendant + # Check mempool has MAX_ANCESTORS transactions in it, and descendant # count and fees should look correct mempool = self.nodes[0].getrawmempool(True) - assert_equal(len(mempool), 100) + assert_equal(len(mempool), MAX_ANCESTORS) descendant_count = 1 descendant_fees = 0 descendant_size = 0 - SATOSHIS = 100000000 for x in reversed(chain): assert_equal(mempool[x]['descendantcount'], descendant_count) descendant_fees += mempool[x]['fee'] - assert_equal(mempool[x]['descendantfees'], SATOSHIS*descendant_fees) + assert_equal(mempool[x]['modifiedfee'], mempool[x]['fee']) + assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN) descendant_size += mempool[x]['size'] assert_equal(mempool[x]['descendantsize'], descendant_size) descendant_count += 1 + # Check that descendant modified fees includes fee deltas from + # prioritisetransaction + self.nodes[0].prioritisetransaction(chain[-1], 0, 1000) + mempool = self.nodes[0].getrawmempool(True) + + descendant_fees = 0 + for x in reversed(chain): + descendant_fees += mempool[x]['fee'] + assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 1000) + # Adding one more transaction on to the chain should fail. try: self.chain_transaction(self.nodes[0], txid, vout, value, fee, 1) except JSONRPCException as e: print "too-long-ancestor-chain successfully rejected" + # Check that prioritising a tx before it's added to the mempool works + # First clear the mempool by mining a block. + self.nodes[0].generate(1) + sync_blocks(self.nodes) + assert_equal(len(self.nodes[0].getrawmempool()), 0) + # Prioritise a transaction that has been mined, then add it back to the + # mempool by using invalidateblock. + self.nodes[0].prioritisetransaction(chain[-1], 0, 2000) + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + # Keep node1's tip synced with node0 + self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash()) + + # Now check that the transaction is in the mempool, with the right modified fee + mempool = self.nodes[0].getrawmempool(True) + + descendant_fees = 0 + for x in reversed(chain): + descendant_fees += mempool[x]['fee'] + if (x == chain[-1]): + assert_equal(mempool[x]['modifiedfee'], mempool[x]['fee']+satoshi_round(0.00002)) + assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 2000) + # TODO: check that node1's mempool is as expected # TODO: test ancestor size limits @@ -91,18 +124,18 @@ class MempoolPackagesTest(BitcoinTestFramework): for i in xrange(10): transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value}) - for i in xrange(1000): + for i in xrange(MAX_DESCENDANTS): utxo = transaction_package.pop(0) try: (txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10) for j in xrange(10): transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value}) - if i == 998: + if i == MAX_DESCENDANTS - 2: mempool = self.nodes[0].getrawmempool(True) - assert_equal(mempool[parent_transaction]['descendantcount'], 1000) + assert_equal(mempool[parent_transaction]['descendantcount'], MAX_DESCENDANTS) except JSONRPCException as e: print e.error['message'] - assert_equal(i, 999) + assert_equal(i, MAX_DESCENDANTS - 1) print "tx that would create too large descendant package successfully rejected" # TODO: check that node1's mempool is as expected diff --git a/qa/rpc-tests/mempool_coinbase_spends.py b/qa/rpc-tests/mempool_reorg.py similarity index 62% rename from qa/rpc-tests/mempool_coinbase_spends.py rename to qa/rpc-tests/mempool_reorg.py index c64a15b9f..5e9856e5d 100755 --- a/qa/rpc-tests/mempool_coinbase_spends.py +++ b/qa/rpc-tests/mempool_reorg.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,8 +10,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -import os -import shutil # Create one-input, one-output, no-fee transaction: class MempoolCoinbaseTest(BitcoinTestFramework): @@ -25,15 +23,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework): self.nodes.append(start_node(1, self.options.tmpdir, args)) connect_nodes(self.nodes[1], 0) self.is_network_split = False - self.sync_all - - def create_tx(self, from_txid, to_address, amount): - inputs = [{ "txid" : from_txid, "vout" : 0}] - outputs = { to_address : amount } - rawtx = self.nodes[0].createrawtransaction(inputs, outputs) - signresult = self.nodes[0].signrawtransaction(rawtx) - assert_equal(signresult["complete"], True) - return signresult["hex"] + self.sync_all() def run_test(self): start_count = self.nodes[0].getblockcount() @@ -52,24 +42,34 @@ class MempoolCoinbaseTest(BitcoinTestFramework): # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1 # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase), # and make sure the mempool code behaves correctly. - b = [ self.nodes[0].getblockhash(n) for n in range(102, 105) ] + b = [ self.nodes[0].getblockhash(n) for n in range(101, 105) ] coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ] - spend_101_raw = self.create_tx(coinbase_txids[0], node1_address, 50) - spend_102_raw = self.create_tx(coinbase_txids[1], node0_address, 50) - spend_103_raw = self.create_tx(coinbase_txids[2], node0_address, 50) + spend_101_raw = create_tx(self.nodes[0], coinbase_txids[1], node1_address, 49.99) + spend_102_raw = create_tx(self.nodes[0], coinbase_txids[2], node0_address, 49.99) + spend_103_raw = create_tx(self.nodes[0], coinbase_txids[3], node0_address, 49.99) + + # Create a block-height-locked transaction which will be invalid after reorg + timelock_tx = self.nodes[0].createrawtransaction([{"txid": coinbase_txids[0], "vout": 0}], {node0_address: 49.99}) + # Set the time lock + timelock_tx = timelock_tx.replace("ffffffff", "11111111", 1) + timelock_tx = timelock_tx[:-8] + hex(self.nodes[0].getblockcount() + 2)[2:] + "000000" + timelock_tx = self.nodes[0].signrawtransaction(timelock_tx)["hex"] + assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx) # Broadcast and mine spend_102 and 103: spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw) spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw) self.nodes[0].generate(1) + assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx) # Create 102_1 and 103_1: - spend_102_1_raw = self.create_tx(spend_102_id, node1_address, 50) - spend_103_1_raw = self.create_tx(spend_103_id, node1_address, 50) + spend_102_1_raw = create_tx(self.nodes[0], spend_102_id, node1_address, 49.98) + spend_103_1_raw = create_tx(self.nodes[0], spend_103_id, node1_address, 49.98) # Broadcast and mine 103_1: spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw) - self.nodes[0].generate(1) + last_block = self.nodes[0].generate(1) + timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx) # ... now put spend_101 and spend_102_1 in memory pools: spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw) @@ -77,7 +77,11 @@ class MempoolCoinbaseTest(BitcoinTestFramework): self.sync_all() - assert_equal(set(self.nodes[0].getrawmempool()), set([ spend_101_id, spend_102_1_id ])) + assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, timelock_tx_id}) + + for node in self.nodes: + node.invalidateblock(last_block[0]) + assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, spend_103_1_id}) # Use invalidateblock to re-org back and make all those coinbase spends # immature/invalid: diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/qa/rpc-tests/mempool_resurrect_test.py index 19c74bb75..0ba46e6f5 100755 --- a/qa/rpc-tests/mempool_resurrect_test.py +++ b/qa/rpc-tests/mempool_resurrect_test.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,8 +10,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -import os -import shutil # Create one-input, one-output, no-fee transaction: class MempoolCoinbaseTest(BitcoinTestFramework): @@ -23,14 +21,6 @@ class MempoolCoinbaseTest(BitcoinTestFramework): self.nodes.append(start_node(0, self.options.tmpdir, args)) self.is_network_split = False - def create_tx(self, from_txid, to_address, amount): - inputs = [{ "txid" : from_txid, "vout" : 0}] - outputs = { to_address : amount } - rawtx = self.nodes[0].createrawtransaction(inputs, outputs) - signresult = self.nodes[0].signrawtransaction(rawtx) - assert_equal(signresult["complete"], True) - return signresult["hex"] - def run_test(self): node0_address = self.nodes[0].getnewaddress() # Spend block 1/2/3's coinbase transactions @@ -45,13 +35,13 @@ class MempoolCoinbaseTest(BitcoinTestFramework): b = [ self.nodes[0].getblockhash(n) for n in range(1, 4) ] coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ] - spends1_raw = [ self.create_tx(txid, node0_address, 50) for txid in coinbase_txids ] + spends1_raw = [ create_tx(self.nodes[0], txid, node0_address, 49.99) for txid in coinbase_txids ] spends1_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends1_raw ] blocks = [] blocks.extend(self.nodes[0].generate(1)) - spends2_raw = [ self.create_tx(txid, node0_address, 49.99) for txid in spends1_id ] + spends2_raw = [ create_tx(self.nodes[0], txid, node0_address, 49.98) for txid in spends1_id ] spends2_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw ] blocks.extend(self.nodes[0].generate(1)) diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/qa/rpc-tests/mempool_spendcoinbase.py index fc17c5069..507b5ff41 100755 --- a/qa/rpc-tests/mempool_spendcoinbase.py +++ b/qa/rpc-tests/mempool_spendcoinbase.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,8 +15,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -import os -import shutil # Create one-input, one-output, no-fee transaction: class MempoolSpendCoinbaseTest(BitcoinTestFramework): @@ -28,14 +26,6 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework): self.nodes.append(start_node(0, self.options.tmpdir, args)) self.is_network_split = False - def create_tx(self, from_txid, to_address, amount): - inputs = [{ "txid" : from_txid, "vout" : 0}] - outputs = { to_address : amount } - rawtx = self.nodes[0].createrawtransaction(inputs, outputs) - signresult = self.nodes[0].signrawtransaction(rawtx) - assert_equal(signresult["complete"], True) - return signresult["hex"] - def run_test(self): chain_height = self.nodes[0].getblockcount() assert_equal(chain_height, 200) @@ -46,7 +36,7 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework): # is too immature to spend. b = [ self.nodes[0].getblockhash(n) for n in range(101, 103) ] coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ] - spends_raw = [ self.create_tx(txid, node0_address, 50) for txid in coinbase_txids ] + spends_raw = [ create_tx(self.nodes[0], txid, node0_address, 49.99) for txid in coinbase_txids ] spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0]) diff --git a/qa/rpc-tests/merkle_blocks.py b/qa/rpc-tests/merkle_blocks.py index 72a80ce6c..eb718f39e 100755 --- a/qa/rpc-tests/merkle_blocks.py +++ b/qa/rpc-tests/merkle_blocks.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,8 +9,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -import os -import shutil class MerkleBlockTest(BitcoinTestFramework): @@ -44,9 +42,9 @@ class MerkleBlockTest(BitcoinTestFramework): assert_equal(self.nodes[2].getbalance(), 0) node0utxos = self.nodes[0].listunspent(1) - tx1 = self.nodes[0].createrawtransaction([node0utxos.pop()], {self.nodes[1].getnewaddress(): 50}) + tx1 = self.nodes[0].createrawtransaction([node0utxos.pop()], {self.nodes[1].getnewaddress(): 49.99}) txid1 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx1)["hex"]) - tx2 = self.nodes[0].createrawtransaction([node0utxos.pop()], {self.nodes[1].getnewaddress(): 50}) + tx2 = self.nodes[0].createrawtransaction([node0utxos.pop()], {self.nodes[1].getnewaddress(): 49.99}) txid2 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx2)["hex"]) assert_raises(JSONRPCException, self.nodes[0].gettxoutproof, [txid1]) @@ -64,7 +62,7 @@ class MerkleBlockTest(BitcoinTestFramework): assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2], blockhash)), txlist) txin_spent = self.nodes[1].listunspent(1).pop() - tx3 = self.nodes[1].createrawtransaction([txin_spent], {self.nodes[0].getnewaddress(): 50}) + tx3 = self.nodes[1].createrawtransaction([txin_spent], {self.nodes[0].getnewaddress(): 49.98}) self.nodes[0].sendrawtransaction(self.nodes[1].signrawtransaction(tx3)["hex"]) self.nodes[0].generate(1) self.sync_all() @@ -72,7 +70,7 @@ class MerkleBlockTest(BitcoinTestFramework): txid_spent = txin_spent["txid"] txid_unspent = txid1 if txin_spent["txid"] != txid1 else txid2 - # We cant find the block from a fully-spent tx + # We can't find the block from a fully-spent tx assert_raises(JSONRPCException, self.nodes[2].gettxoutproof, [txid_spent]) # ...but we can if we specify the block assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_spent], blockhash)), [txid_spent]) diff --git a/qa/rpc-tests/multi_rpc.py b/qa/rpc-tests/multi_rpc.py new file mode 100755 index 000000000..afb18cf3d --- /dev/null +++ b/qa/rpc-tests/multi_rpc.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test mulitple rpc user config option rpcauth +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import base64 + +try: + import http.client as httplib +except ImportError: + import httplib +try: + import urllib.parse as urlparse +except ImportError: + import urlparse + +class HTTPBasicsTest (BitcoinTestFramework): + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir) + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain(self.options.tmpdir) + #Append rpcauth to bitcoin.conf before initialization + rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144" + rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e" + with open(os.path.join(self.options.tmpdir+"/node0", "bitcoin.conf"), 'a') as f: + f.write(rpcauth+"\n") + f.write(rpcauth2+"\n") + + def run_test(self): + + ################################################## + # Check correctness of the rpcauth config option # + ################################################## + url = urlparse.urlparse(self.nodes[0].url) + + #Old authpair + authpair = url.username + ':' + url.password + + #New authpair generated via share/rpcuser tool + rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144" + password = "cA773lm788buwYe4g4WT+05pKyNruVKjQ25x3n0DQcM=" + + #Second authpair with different username + rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e" + password2 = "8/F3uMDw4KSEbw96U3CA1C4X05dkHDN2BPFjTgZW4KI=" + authpairnew = "rt:"+password + + headers = {"Authorization": "Basic " + str_to_b64str(authpair)} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, False) + conn.close() + + #Use new authpair to confirm both work + headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, False) + conn.close() + + #Wrong login name with rt's password + authpairnew = "rtwrong:"+password + headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, True) + conn.close() + + #Wrong password for rt + authpairnew = "rt:"+password+"wrong" + headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, True) + conn.close() + + #Correct for rt2 + authpairnew = "rt2:"+password2 + headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, False) + conn.close() + + #Wrong password for rt2 + authpairnew = "rt2:"+password2+"wrong" + headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, True) + conn.close() + + +if __name__ == '__main__': + HTTPBasicsTest ().main () diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py index e383a3a12..c6c8c436e 100755 --- a/qa/rpc-tests/nodehandling.py +++ b/qa/rpc-tests/nodehandling.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,7 +9,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -import base64 try: import http.client as httplib @@ -54,7 +53,7 @@ class NodeHandlingTest (BitcoinTestFramework): self.nodes[2].setban("127.0.0.0/24", "add") self.nodes[2].setban("192.168.0.1", "add", 1) #ban for 1 seconds self.nodes[2].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) #ban for 1000 seconds - listBeforeShutdown = self.nodes[2].listbanned(); + listBeforeShutdown = self.nodes[2].listbanned() assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) #must be here time.sleep(2) #make 100% sure we expired 192.168.0.1 node time @@ -62,7 +61,7 @@ class NodeHandlingTest (BitcoinTestFramework): stop_node(self.nodes[2], 2) self.nodes[2] = start_node(2, self.options.tmpdir) - listAfterShutdown = self.nodes[2].listbanned(); + listAfterShutdown = self.nodes[2].listbanned() assert_equal("127.0.0.0/24", listAfterShutdown[0]['address']) assert_equal("127.0.0.0/32", listAfterShutdown[1]['address']) assert_equal("/19" in listAfterShutdown[2]['address'], True) diff --git a/qa/rpc-tests/p2p-acceptblock.py b/qa/rpc-tests/p2p-acceptblock.py index 700deab20..e429fcc5f 100755 --- a/qa/rpc-tests/p2p-acceptblock.py +++ b/qa/rpc-tests/p2p-acceptblock.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# +# Copyright (c) 2015 The Bitcoin Core developers # Distributed under the MIT/X11 software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # @@ -62,7 +62,6 @@ The test: class TestNode(NodeConnCB): def __init__(self): NodeConnCB.__init__(self) - self.create_callback_map() self.connection = None self.ping_counter = 1 self.last_pong = msg_pong() @@ -151,7 +150,7 @@ class AcceptBlockTest(BitcoinTestFramework): # 2. Send one block that builds on each tip. # This should be accepted. blocks_h2 = [] # the height 2 blocks on each node's chain - block_time = time.time() + 1 + block_time = int(time.time()) + 1 for i in xrange(2): blocks_h2.append(create_block(tips[i], create_coinbase(2), block_time)) blocks_h2[i].solve() diff --git a/qa/rpc-tests/p2p-feefilter.py b/qa/rpc-tests/p2p-feefilter.py new file mode 100755 index 000000000..281b6ca37 --- /dev/null +++ b/qa/rpc-tests/p2p-feefilter.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python2 +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +from test_framework.mininode import * +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import time + +''' +FeeFilterTest -- test processing of feefilter messages +''' + +def hashToHex(hash): + return format(hash, '064x') + +# Wait up to 60 secs to see if the testnode has received all the expected invs +def allInvsMatch(invsExpected, testnode): + for x in xrange(60): + with mininode_lock: + if (sorted(invsExpected) == sorted(testnode.txinvs)): + return True; + time.sleep(1) + return False; + +# TestNode: bare-bones "peer". Used to track which invs are received from a node +# and to send the node feefilter messages. +class TestNode(SingleNodeConnCB): + def __init__(self): + SingleNodeConnCB.__init__(self) + self.txinvs = [] + + def on_inv(self, conn, message): + for i in message.inv: + if (i.type == 1): + self.txinvs.append(hashToHex(i.hash)) + + def clear_invs(self): + with mininode_lock: + self.txinvs = [] + + def send_filter(self, feerate): + self.send_message(msg_feefilter(feerate)) + self.sync_with_ping() + +class FeeFilterTest(BitcoinTestFramework): + def setup_network(self): + # Node1 will be used to generate txs which should be relayed from Node0 + # to our test node + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-logtimemicros"])) + connect_nodes(self.nodes[0], 1) + + def run_test(self): + node1 = self.nodes[1] + # Get out of IBD + node1.generate(1) + sync_blocks(self.nodes) + + # Setup the p2p connections and start up the network thread. + test_node = TestNode() + connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node) + test_node.add_connection(connection) + NetworkThread().start() + test_node.wait_for_verack() + + # Test that invs are received for all txs at feerate of 20 sat/byte + node1.settxfee(Decimal("0.00020000")) + txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)] + assert(allInvsMatch(txids, test_node)) + test_node.clear_invs() + + # Set a filter of 15 sat/byte + test_node.send_filter(15000) + + # Test that txs are still being received (paying 20 sat/byte) + txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)] + assert(allInvsMatch(txids, test_node)) + test_node.clear_invs() + + # Change tx fee rate to 10 sat/byte and test they are no longer received + node1.settxfee(Decimal("0.00010000")) + [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)] + sync_mempools(self.nodes) # must be sure node 0 has received all txs + time.sleep(10) # wait 10 secs to be sure its doesn't relay any + assert(allInvsMatch([], test_node)) + test_node.clear_invs() + + # Remove fee filter and check that txs are received again + test_node.send_filter(0) + txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)] + assert(allInvsMatch(txids, test_node)) + test_node.clear_invs() + +if __name__ == '__main__': + FeeFilterTest().main() diff --git a/qa/rpc-tests/p2p-fullblocktest.py b/qa/rpc-tests/p2p-fullblocktest.py index 9555940ce..ae82d9dca 100755 --- a/qa/rpc-tests/p2p-fullblocktest.py +++ b/qa/rpc-tests/p2p-fullblocktest.py @@ -1,21 +1,16 @@ #!/usr/bin/env python2 - -# +# Copyright (c) 2015 The Bitcoin Core developers # Distributed under the MIT/X11 software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # from test_framework.test_framework import ComparisonTestFramework from test_framework.util import * -from test_framework.comptool import TestManager, TestInstance -from test_framework.mininode import * +from test_framework.comptool import TestManager, TestInstance, RejectResult from test_framework.blocktools import * -import logging -import copy import time -import numbers from test_framework.key import CECKey -from test_framework.script import CScript, CScriptOp, SignatureHash, SIGHASH_ALL, OP_TRUE +from test_framework.script import CScript, SignatureHash, SIGHASH_ALL, OP_TRUE, OP_FALSE class PreviousSpendableOutput(object): def __init__(self, tx = CTransaction(), n = -1): @@ -38,7 +33,7 @@ class FullBlockTest(ComparisonTestFramework): self.num_nodes = 1 self.block_heights = {} self.coinbase_key = CECKey() - self.coinbase_key.set_secretbytes(bytes("horsebattery")) + self.coinbase_key.set_secretbytes(b"horsebattery") self.coinbase_pubkey = self.coinbase_key.get_pubkey() self.block_time = int(time.time())+1 self.tip = None @@ -75,7 +70,7 @@ class FullBlockTest(ComparisonTestFramework): block = create_block(base_block_hash, coinbase, self.block_time) if (spend != None): tx = CTransaction() - tx.vin.append(CTxIn(COutPoint(spend.tx.sha256, spend.n), "", 0xffffffff)) # no signature yet + tx.vin.append(CTxIn(COutPoint(spend.tx.sha256, spend.n), b"", 0xffffffff)) # no signature yet # This copies the java comparison tool testing behavior: the first # txout has a garbage scriptPubKey, "to make sure we're not # pre-verifying too much" (?) @@ -85,7 +80,7 @@ class FullBlockTest(ComparisonTestFramework): else: tx.vout.append(CTxOut(1, script)) # Now sign it if necessary - scriptSig = "" + scriptSig = b"" scriptPubKey = bytearray(spend.tx.vout[spend.n].scriptPubKey) if (scriptPubKey[0] == OP_TRUE): # looks like an anyone-can-spend scriptSig = CScript([OP_TRUE]) @@ -122,13 +117,29 @@ class FullBlockTest(ComparisonTestFramework): return TestInstance([[self.tip, True]]) # returns a test case that asserts that the current tip was rejected - def rejected(): - return TestInstance([[self.tip, False]]) + def rejected(reject = None): + if reject is None: + return TestInstance([[self.tip, False]]) + else: + return TestInstance([[self.tip, reject]]) # move the tip back to a previous block def tip(number): self.tip = self.blocks[number] + # add transactions to a block produced by next_block + def update_block(block_number, new_transactions): + block = self.blocks[block_number] + old_hash = block.sha256 + self.add_transactions_to_block(block, new_transactions) + block.solve() + # Update the internal state just like in next_block + self.tip = block + self.block_heights[block.sha256] = self.block_heights[old_hash] + del self.block_heights[old_hash] + self.blocks[block_number] = block + return block + # creates a new block and advances the tip to that block block = self.next_block @@ -141,14 +152,15 @@ class FullBlockTest(ComparisonTestFramework): # Now we need that block to mature so we can spend the coinbase. test = TestInstance(sync_every_block=False) - for i in range(100): + for i in range(99): block(1000 + i) test.blocks_and_transactions.append([self.tip, True]) save_spendable_output() yield test - # Start by bulding a couple of blocks on top (which output is spent is in parentheses): + # Start by building a couple of blocks on top (which output is spent is + # in parentheses): # genesis -> b1 (0) -> b2 (1) out0 = get_spendable_output() block(1, spend=out0) @@ -156,8 +168,7 @@ class FullBlockTest(ComparisonTestFramework): yield accepted() out1 = get_spendable_output() - block(2, spend=out1) - # Inv again, then deliver twice (shouldn't break anything). + b2 = block(2, spend=out1) yield accepted() @@ -168,8 +179,8 @@ class FullBlockTest(ComparisonTestFramework): # # Nothing should happen at this point. We saw b2 first so it takes priority. tip(1) - block(3, spend=out1) - # Deliver twice (should still not break anything) + b3 = block(3, spend=out1) + txout_b3 = PreviousSpendableOutput(b3.vtx[1], 1) yield rejected() @@ -214,7 +225,7 @@ class FullBlockTest(ComparisonTestFramework): # \-> b3 (1) -> b4 (2) tip(6) block(9, spend=out4, additional_coinbase_value=1) - yield rejected() + yield rejected(RejectResult(16, b'bad-cb-amount')) # Create a fork that ends in a block with too much fee (the one that causes the reorg) @@ -226,7 +237,7 @@ class FullBlockTest(ComparisonTestFramework): yield rejected() block(11, spend=out4, additional_coinbase_value=1) - yield rejected() + yield rejected(RejectResult(16, b'bad-cb-amount')) # Try again, but with a valid fork first @@ -252,9 +263,13 @@ class FullBlockTest(ComparisonTestFramework): yield TestInstance([[b12, True, b13.sha256]]) # New tip should be b13. + # Add a block with MAX_BLOCK_SIGOPS and one with one more sigop + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) -> b16 (6) + # \-> b3 (1) -> b4 (2) # Test that a block with a lot of checksigs is okay - lots_of_checksigs = CScript([OP_CHECKSIG] * (1000000 / 50 - 1)) + lots_of_checksigs = CScript([OP_CHECKSIG] * (1000000 // 50 - 1)) tip(13) block(15, spend=out5, script=lots_of_checksigs) yield accepted() @@ -262,10 +277,123 @@ class FullBlockTest(ComparisonTestFramework): # Test that a block with too many checksigs is rejected out6 = get_spendable_output() - too_many_checksigs = CScript([OP_CHECKSIG] * (1000000 / 50)) + too_many_checksigs = CScript([OP_CHECKSIG] * (1000000 // 50)) block(16, spend=out6, script=too_many_checksigs) + yield rejected(RejectResult(16, b'bad-blk-sigops')) + + + # Attempt to spend a transaction created on a different fork + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) -> b17 (b3.vtx[1]) + # \-> b3 (1) -> b4 (2) + tip(15) + block(17, spend=txout_b3) + yield rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) + + # Attempt to spend a transaction created on a different fork (on a fork this time) + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) + # \-> b18 (b3.vtx[1]) -> b19 (6) + # \-> b3 (1) -> b4 (2) + tip(13) + block(18, spend=txout_b3) yield rejected() + block(19, spend=out6) + yield rejected() + + # Attempt to spend a coinbase at depth too low + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) -> b20 (7) + # \-> b3 (1) -> b4 (2) + tip(15) + out7 = get_spendable_output() + block(20, spend=out7) + yield rejected(RejectResult(16, b'bad-txns-premature-spend-of-coinbase')) + + # Attempt to spend a coinbase at depth too low (on a fork this time) + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) + # \-> b21 (6) -> b22 (5) + # \-> b3 (1) -> b4 (2) + tip(13) + block(21, spend=out6) + yield rejected() + + block(22, spend=out5) + yield rejected() + + # Create a block on either side of MAX_BLOCK_SIZE and make sure its accepted/rejected + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) + # \-> b24 (6) -> b25 (7) + # \-> b3 (1) -> b4 (2) + tip(15) + b23 = block(23, spend=out6) + old_hash = b23.sha256 + tx = CTransaction() + script_length = MAX_BLOCK_SIZE - len(b23.serialize()) - 69 + script_output = CScript([b'\x00' * script_length]) + tx.vout.append(CTxOut(0, script_output)) + tx.vin.append(CTxIn(COutPoint(b23.vtx[1].sha256, 1))) + b23 = update_block(23, [tx]) + # Make sure the math above worked out to produce a max-sized block + assert_equal(len(b23.serialize()), MAX_BLOCK_SIZE) + yield accepted() + + # Make the next block one byte bigger and check that it fails + tip(15) + b24 = block(24, spend=out6) + script_length = MAX_BLOCK_SIZE - len(b24.serialize()) - 69 + script_output = CScript([b'\x00' * (script_length+1)]) + tx.vout = [CTxOut(0, script_output)] + b24 = update_block(24, [tx]) + assert_equal(len(b24.serialize()), MAX_BLOCK_SIZE+1) + yield rejected(RejectResult(16, b'bad-blk-length')) + + b25 = block(25, spend=out7) + yield rejected() + + # Create blocks with a coinbase input script size out of range + # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) + # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7) + # \-> ... (6) -> ... (7) + # \-> b3 (1) -> b4 (2) + tip(15) + b26 = block(26, spend=out6) + b26.vtx[0].vin[0].scriptSig = b'\x00' + b26.vtx[0].rehash() + # update_block causes the merkle root to get updated, even with no new + # transactions, and updates the required state. + b26 = update_block(26, []) + yield rejected(RejectResult(16, b'bad-cb-length')) + + # Extend the b26 chain to make sure bitcoind isn't accepting b26 + b27 = block(27, spend=out7) + yield rejected() + + # Now try a too-large-coinbase script + tip(15) + b28 = block(28, spend=out6) + b28.vtx[0].vin[0].scriptSig = b'\x00' * 101 + b28.vtx[0].rehash() + b28 = update_block(28, []) + yield rejected(RejectResult(16, b'bad-cb-length')) + + # Extend the b28 chain to make sure bitcoind isn't accepted b28 + b29 = block(29, spend=out7) + # TODO: Should get a reject message back with "bad-prevblk", except + # there's a bug that prevents this from being detected. Just note + # failure for now, and add the reject result later. + yield rejected() + + # b30 has a max-sized coinbase scriptSig. + tip(23) + b30 = block(30) + b30.vtx[0].vin[0].scriptSig = b'\x00' * 100 + b30.vtx[0].rehash() + b30 = update_block(30, []) + yield accepted() if __name__ == '__main__': diff --git a/qa/rpc-tests/p2p-versionbits-warning.py b/qa/rpc-tests/p2p-versionbits-warning.py new file mode 100755 index 000000000..061dcbf0e --- /dev/null +++ b/qa/rpc-tests/p2p-versionbits-warning.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python2 +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +from test_framework.mininode import * +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import time +from test_framework.blocktools import create_block, create_coinbase + +''' +Test version bits' warning system. + +Generate chains with block versions that appear to be signalling unknown +soft-forks, and test that warning alerts are generated. +''' + +VB_PERIOD = 144 # versionbits period length for regtest +VB_THRESHOLD = 108 # versionbits activation threshold for regtest +VB_TOP_BITS = 0x20000000 +VB_UNKNOWN_BIT = 27 # Choose a bit unassigned to any deployment + +# TestNode: bare-bones "peer". Used mostly as a conduit for a test to sending +# p2p messages to a node, generating the messages in the main testing logic. +class TestNode(NodeConnCB): + def __init__(self): + NodeConnCB.__init__(self) + self.connection = None + self.ping_counter = 1 + self.last_pong = msg_pong() + + def add_connection(self, conn): + self.connection = conn + + def on_inv(self, conn, message): + pass + + # Wrapper for the NodeConn's send_message function + def send_message(self, message): + self.connection.send_message(message) + + def on_pong(self, conn, message): + self.last_pong = message + + # Sync up with the node after delivery of a block + def sync_with_ping(self, timeout=30): + self.connection.send_message(msg_ping(nonce=self.ping_counter)) + received_pong = False + sleep_time = 0.05 + while not received_pong and timeout > 0: + time.sleep(sleep_time) + timeout -= sleep_time + with mininode_lock: + if self.last_pong.nonce == self.ping_counter: + received_pong = True + self.ping_counter += 1 + return received_pong + + +class VersionBitsWarningTest(BitcoinTestFramework): + def setup_chain(self): + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self): + self.nodes = [] + self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt") + # Open and close to create zero-length file + with open(self.alert_filename, 'w') as f: + pass + self.node_options = ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""] + self.nodes.append(start_node(0, self.options.tmpdir, self.node_options)) + + import re + self.vb_pattern = re.compile("^Warning.*versionbit") + + # Send numblocks blocks via peer with nVersionToUse set. + def send_blocks_with_version(self, peer, numblocks, nVersionToUse): + tip = self.nodes[0].getbestblockhash() + height = self.nodes[0].getblockcount() + block_time = self.nodes[0].getblockheader(tip)["time"]+1 + tip = int(tip, 16) + + for i in xrange(numblocks): + block = create_block(tip, create_coinbase(height+1), block_time) + block.nVersion = nVersionToUse + block.solve() + peer.send_message(msg_block(block)) + block_time += 1 + height += 1 + tip = block.sha256 + peer.sync_with_ping() + + def test_versionbits_in_alert_file(self): + with open(self.alert_filename, 'r') as f: + alert_text = f.read() + assert(self.vb_pattern.match(alert_text)) + + def run_test(self): + # Setup the p2p connection and start up the network thread. + test_node = TestNode() + + connections = [] + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node)) + test_node.add_connection(connections[0]) + + NetworkThread().start() # Start up network handling in another thread + + # Test logic begins here + test_node.wait_for_verack() + + # 1. Have the node mine one period worth of blocks + self.nodes[0].generate(VB_PERIOD) + + # 2. Now build one period of blocks on the tip, with < VB_THRESHOLD + # blocks signaling some unknown bit. + nVersion = VB_TOP_BITS | (1<= VB_THRESHOLD blocks signaling + # some unknown bit + self.send_blocks_with_version(test_node, VB_THRESHOLD, nVersion) + self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD) + # Might not get a versionbits-related alert yet, as we should + # have gotten a different alert due to more than 51/100 blocks + # being of unexpected version. + # Check that getinfo() shows some kind of error. + assert(len(self.nodes[0].getinfo()["errors"]) != 0) + + # Mine a period worth of expected blocks so the generic block-version warning + # is cleared, and restart the node. This should move the versionbit state + # to ACTIVE. + self.nodes[0].generate(VB_PERIOD) + stop_node(self.nodes[0], 0) + wait_bitcoinds() + # Empty out the alert file + with open(self.alert_filename, 'w') as f: + pass + self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]) + + # Connecting one block should be enough to generate an error. + self.nodes[0].generate(1) + assert(len(self.nodes[0].getinfo()["errors"]) != 0) + stop_node(self.nodes[0], 0) + wait_bitcoinds() + self.test_versionbits_in_alert_file() + + # Test framework expects the node to still be running... + self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]) + + +if __name__ == '__main__': + VersionBitsWarningTest().main() diff --git a/qa/rpc-tests/prioritise_transaction.py b/qa/rpc-tests/prioritise_transaction.py new file mode 100755 index 000000000..f8d9063b4 --- /dev/null +++ b/qa/rpc-tests/prioritise_transaction.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test PrioritiseTransaction code +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.mininode import COIN, MAX_BLOCK_SIZE + +class PrioritiseTransactionTest(BitcoinTestFramework): + + def __init__(self): + self.txouts = gen_return_txouts() + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self): + self.nodes = [] + self.is_network_split = False + + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-printpriority=1"])) + self.relayfee = self.nodes[0].getnetworkinfo()['relayfee'] + + def run_test(self): + utxo_count = 90 + utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], utxo_count) + base_fee = self.relayfee*100 # our transactions are smaller than 100kb + txids = [] + + # Create 3 batches of transactions at 3 different fee rate levels + range_size = utxo_count // 3 + for i in xrange(3): + txids.append([]) + start_range = i * range_size + end_range = start_range + range_size + txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[start_range:end_range], (i+1)*base_fee) + + # Make sure that the size of each group of transactions exceeds + # MAX_BLOCK_SIZE -- otherwise the test needs to be revised to create + # more transactions. + mempool = self.nodes[0].getrawmempool(True) + sizes = [0, 0, 0] + for i in xrange(3): + for j in txids[i]: + assert(j in mempool) + sizes[i] += mempool[j]['size'] + assert(sizes[i] > MAX_BLOCK_SIZE) # Fail => raise utxo_count + + # add a fee delta to something in the cheapest bucket and make sure it gets mined + # also check that a different entry in the cheapest bucket is NOT mined (lower + # the priority to ensure its not mined due to priority) + self.nodes[0].prioritisetransaction(txids[0][0], 0, int(3*base_fee*COIN)) + self.nodes[0].prioritisetransaction(txids[0][1], -1e15, 0) + + self.nodes[0].generate(1) + + mempool = self.nodes[0].getrawmempool() + print "Assert that prioritised transaction was mined" + assert(txids[0][0] not in mempool) + assert(txids[0][1] in mempool) + + high_fee_tx = None + for x in txids[2]: + if x not in mempool: + high_fee_tx = x + + # Something high-fee should have been mined! + assert(high_fee_tx != None) + + # Add a prioritisation before a tx is in the mempool (de-prioritising a + # high-fee transaction so that it's now low fee). + self.nodes[0].prioritisetransaction(high_fee_tx, -1e15, -int(2*base_fee*COIN)) + + # Add everything back to mempool + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + # Check to make sure our high fee rate tx is back in the mempool + mempool = self.nodes[0].getrawmempool() + assert(high_fee_tx in mempool) + + # Now verify the modified-high feerate transaction isn't mined before + # the other high fee transactions. Keep mining until our mempool has + # decreased by all the high fee size that we calculated above. + while (self.nodes[0].getmempoolinfo()['bytes'] > sizes[0] + sizes[1]): + self.nodes[0].generate(1) + + # High fee transaction should not have been mined, but other high fee rate + # transactions should have been. + mempool = self.nodes[0].getrawmempool() + print "Assert that de-prioritised transaction is still in mempool" + assert(high_fee_tx in mempool) + for x in txids[2]: + if (x != high_fee_tx): + assert(x not in mempool) + + # Create a free, low priority transaction. Should be rejected. + utxo_list = self.nodes[0].listunspent() + assert(len(utxo_list) > 0) + utxo = utxo_list[0] + + inputs = [] + outputs = {} + inputs.append({"txid" : utxo["txid"], "vout" : utxo["vout"]}) + outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee + raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) + tx_hex = self.nodes[0].signrawtransaction(raw_tx)["hex"] + txid = self.nodes[0].sendrawtransaction(tx_hex) + + # A tx that spends an in-mempool tx has 0 priority, so we can use it to + # test the effect of using prioritise transaction for mempool acceptance + inputs = [] + inputs.append({"txid": txid, "vout": 0}) + outputs = {} + outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee + raw_tx2 = self.nodes[0].createrawtransaction(inputs, outputs) + tx2_hex = self.nodes[0].signrawtransaction(raw_tx2)["hex"] + tx2_id = self.nodes[0].decoderawtransaction(tx2_hex)["txid"] + + try: + self.nodes[0].sendrawtransaction(tx2_hex) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) # insufficient fee + assert(tx2_id not in self.nodes[0].getrawmempool()) + else: + assert(False) + + # This is a less than 1000-byte transaction, so just set the fee + # to be the minimum for a 1000 byte transaction and check that it is + # accepted. + self.nodes[0].prioritisetransaction(tx2_id, 0, int(self.relayfee*COIN)) + + print "Assert that prioritised free transaction is accepted to mempool" + assert_equal(self.nodes[0].sendrawtransaction(tx2_hex), tx2_id) + assert(tx2_id in self.nodes[0].getrawmempool()) + +if __name__ == '__main__': + PrioritiseTransactionTest().main() diff --git a/qa/rpc-tests/proxy_test.py b/qa/rpc-tests/proxy_test.py index 3623c1616..91c871ddc 100755 --- a/qa/rpc-tests/proxy_test.py +++ b/qa/rpc-tests/proxy_test.py @@ -3,13 +3,11 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. import socket -import traceback, sys -from binascii import hexlify -import time, os from test_framework.socks5 import Socks5Configuration, Socks5Command, Socks5Server, AddressType from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * +from test_framework.netutil import test_ipv6_local ''' Test plan: - Start bitcoind's with different proxy configurations @@ -34,8 +32,10 @@ addnode connect to onion addnode connect to generic DNS name ''' -class ProxyTest(BitcoinTestFramework): + +class ProxyTest(BitcoinTestFramework): def __init__(self): + self.have_ipv6 = test_ipv6_local() # Create two proxies on different ports # ... one unauthenticated self.conf1 = Socks5Configuration() @@ -47,29 +47,36 @@ class ProxyTest(BitcoinTestFramework): self.conf2.addr = ('127.0.0.1', 14000 + (os.getpid() % 1000)) self.conf2.unauth = True self.conf2.auth = True - # ... one on IPv6 with similar configuration - self.conf3 = Socks5Configuration() - self.conf3.af = socket.AF_INET6 - self.conf3.addr = ('::1', 15000 + (os.getpid() % 1000)) - self.conf3.unauth = True - self.conf3.auth = True + if self.have_ipv6: + # ... one on IPv6 with similar configuration + self.conf3 = Socks5Configuration() + self.conf3.af = socket.AF_INET6 + self.conf3.addr = ('::1', 15000 + (os.getpid() % 1000)) + self.conf3.unauth = True + self.conf3.auth = True + else: + print "Warning: testing without local IPv6 support" self.serv1 = Socks5Server(self.conf1) self.serv1.start() self.serv2 = Socks5Server(self.conf2) self.serv2.start() - self.serv3 = Socks5Server(self.conf3) - self.serv3.start() + if self.have_ipv6: + self.serv3 = Socks5Server(self.conf3) + self.serv3.start() def setup_nodes(self): # Note: proxies are not used to connect to local nodes # this is because the proxy to use is based on CService.GetNetwork(), which return NET_UNROUTABLE for localhost - return start_nodes(4, self.options.tmpdir, extra_args=[ + args = [ ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'], ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'], ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'], - ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion'] - ]) + [] + ] + if self.have_ipv6: + args[3] = ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion'] + return start_nodes(4, self.options.tmpdir, extra_args=args) def node_test(self, node, proxies, auth, test_onion=True): rv = [] @@ -79,25 +86,26 @@ class ProxyTest(BitcoinTestFramework): assert(isinstance(cmd, Socks5Command)) # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6 assert_equal(cmd.atyp, AddressType.DOMAINNAME) - assert_equal(cmd.addr, "15.61.23.23") + assert_equal(cmd.addr, b"15.61.23.23") assert_equal(cmd.port, 1234) if not auth: assert_equal(cmd.username, None) assert_equal(cmd.password, None) rv.append(cmd) - # Test: outgoing IPv6 connection through node - node.addnode("[1233:3432:2434:2343:3234:2345:6546:4534]:5443", "onetry") - cmd = proxies[1].queue.get() - assert(isinstance(cmd, Socks5Command)) - # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6 - assert_equal(cmd.atyp, AddressType.DOMAINNAME) - assert_equal(cmd.addr, "1233:3432:2434:2343:3234:2345:6546:4534") - assert_equal(cmd.port, 5443) - if not auth: - assert_equal(cmd.username, None) - assert_equal(cmd.password, None) - rv.append(cmd) + if self.have_ipv6: + # Test: outgoing IPv6 connection through node + node.addnode("[1233:3432:2434:2343:3234:2345:6546:4534]:5443", "onetry") + cmd = proxies[1].queue.get() + assert(isinstance(cmd, Socks5Command)) + # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6 + assert_equal(cmd.atyp, AddressType.DOMAINNAME) + assert_equal(cmd.addr, b"1233:3432:2434:2343:3234:2345:6546:4534") + assert_equal(cmd.port, 5443) + if not auth: + assert_equal(cmd.username, None) + assert_equal(cmd.password, None) + rv.append(cmd) if test_onion: # Test: outgoing onion connection through node @@ -105,7 +113,7 @@ class ProxyTest(BitcoinTestFramework): cmd = proxies[2].queue.get() assert(isinstance(cmd, Socks5Command)) assert_equal(cmd.atyp, AddressType.DOMAINNAME) - assert_equal(cmd.addr, "bitcoinostk4e4re.onion") + assert_equal(cmd.addr, b"bitcoinostk4e4re.onion") assert_equal(cmd.port, 8333) if not auth: assert_equal(cmd.username, None) @@ -117,7 +125,7 @@ class ProxyTest(BitcoinTestFramework): cmd = proxies[3].queue.get() assert(isinstance(cmd, Socks5Command)) assert_equal(cmd.atyp, AddressType.DOMAINNAME) - assert_equal(cmd.addr, "node.noumenon") + assert_equal(cmd.addr, b"node.noumenon") assert_equal(cmd.port, 8333) if not auth: assert_equal(cmd.username, None) @@ -137,10 +145,11 @@ class ProxyTest(BitcoinTestFramework): rv = self.node_test(self.nodes[2], [self.serv2, self.serv2, self.serv2, self.serv2], True) # Check that credentials as used for -proxyrandomize connections are unique credentials = set((x.username,x.password) for x in rv) - assert_equal(len(credentials), 4) + assert_equal(len(credentials), len(rv)) - # proxy on IPv6 localhost - self.node_test(self.nodes[3], [self.serv3, self.serv3, self.serv3, self.serv3], False, False) + if self.have_ipv6: + # proxy on IPv6 localhost + self.node_test(self.nodes[3], [self.serv3, self.serv3, self.serv3, self.serv3], False, False) def networks_dict(d): r = {} @@ -169,11 +178,12 @@ class ProxyTest(BitcoinTestFramework): assert_equal(n2[net]['proxy_randomize_credentials'], True) assert_equal(n2['onion']['reachable'], True) - n3 = networks_dict(self.nodes[3].getnetworkinfo()) - for net in ['ipv4','ipv6']: - assert_equal(n3[net]['proxy'], '[%s]:%i' % (self.conf3.addr)) - assert_equal(n3[net]['proxy_randomize_credentials'], False) - assert_equal(n3['onion']['reachable'], False) + if self.have_ipv6: + n3 = networks_dict(self.nodes[3].getnetworkinfo()) + for net in ['ipv4','ipv6']: + assert_equal(n3[net]['proxy'], '[%s]:%i' % (self.conf3.addr)) + assert_equal(n3[net]['proxy_randomize_credentials'], False) + assert_equal(n3['onion']['reachable'], False) if __name__ == '__main__': ProxyTest().main() diff --git a/qa/rpc-tests/pruning.py b/qa/rpc-tests/pruning.py index 21f8d6938..eccd157e5 100755 --- a/qa/rpc-tests/pruning.py +++ b/qa/rpc-tests/pruning.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,34 +13,16 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -import os.path def calc_usage(blockdir): - return sum(os.path.getsize(blockdir+f) for f in os.listdir(blockdir) if os.path.isfile(blockdir+f))/(1024*1024) + return sum(os.path.getsize(blockdir+f) for f in os.listdir(blockdir) if os.path.isfile(blockdir+f)) / (1024. * 1024.) class PruneTest(BitcoinTestFramework): def __init__(self): self.utxo = [] self.address = ["",""] - - # Some pre-processing to create a bunch of OP_RETURN txouts to insert into transactions we create - # So we have big transactions and full blocks to fill up our block files - - # create one script_pubkey - script_pubkey = "6a4d0200" #OP_RETURN OP_PUSH2 512 bytes - for i in xrange (512): - script_pubkey = script_pubkey + "01" - # concatenate 128 txouts of above script_pubkey which we'll insert before the txout for change - self.txouts = "81" - for k in xrange(128): - # add txout value - self.txouts = self.txouts + "0000000000000000" - # add length of script_pubkey - self.txouts = self.txouts + "fd0402" - # add script_pubkey - self.txouts = self.txouts + script_pubkey - + self.txouts = gen_return_txouts() def setup_chain(self): print("Initializing test directory "+self.options.tmpdir) @@ -74,7 +56,7 @@ class PruneTest(BitcoinTestFramework): self.nodes[1].generate(200) sync_blocks(self.nodes[0:2]) self.nodes[0].generate(150) - # Then mine enough full blocks to create more than 550MB of data + # Then mine enough full blocks to create more than 550MiB of data for i in xrange(645): self.mine_full_block(self.nodes[0], self.address[0]) @@ -84,7 +66,7 @@ class PruneTest(BitcoinTestFramework): if not os.path.isfile(self.prunedir+"blk00000.dat"): raise AssertionError("blk00000.dat is missing, pruning too early") print "Success" - print "Though we're already using more than 550MB, current usage:", calc_usage(self.prunedir) + print "Though we're already using more than 550MiB, current usage:", calc_usage(self.prunedir) print "Mining 25 more blocks should cause the first block file to be pruned" # Pruning doesn't run until we're allocating another chunk, 20 full blocks past the height cutoff will ensure this for i in xrange(25): @@ -329,7 +311,7 @@ class PruneTest(BitcoinTestFramework): # \ \ # ++...++(1044) .. # - # N0 ********************(1032) @@...@@@(1552) + # N0 ********************(1032) @@...@@@(1552) # \ # *...**(1320) diff --git a/qa/rpc-tests/rawtransactions.py b/qa/rpc-tests/rawtransactions.py index 173faf736..e38ef6c8b 100755 --- a/qa/rpc-tests/rawtransactions.py +++ b/qa/rpc-tests/rawtransactions.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,8 +10,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -from pprint import pprint -from time import sleep # Create one-input, one-output, no-fee transaction: class RawTransactionsTest(BitcoinTestFramework): @@ -43,9 +41,9 @@ class RawTransactionsTest(BitcoinTestFramework): self.sync_all() self.nodes[0].generate(101) self.sync_all() - self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.5); - self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.0); - self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),5.0); + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.5) + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.0) + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),5.0) self.sync_all() self.nodes[0].generate(5) self.sync_all() @@ -58,13 +56,13 @@ class RawTransactionsTest(BitcoinTestFramework): rawtx = self.nodes[2].createrawtransaction(inputs, outputs) rawtx = self.nodes[2].signrawtransaction(rawtx) - errorString = "" try: rawtx = self.nodes[2].sendrawtransaction(rawtx['hex']) - except JSONRPCException,e: - errorString = e.error['message'] + except JSONRPCException as e: + assert("Missing inputs" in e.error['message']) + else: + assert(False) - assert_equal("Missing inputs" in errorString, True); ######################### # RAW TX MULTISIG TESTS # @@ -83,15 +81,13 @@ class RawTransactionsTest(BitcoinTestFramework): bal = self.nodes[2].getbalance() # send 1.2 BTC to msig adr - txId = self.nodes[0].sendtoaddress(mSigObj, 1.2); + txId = self.nodes[0].sendtoaddress(mSigObj, 1.2) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), bal+Decimal('1.20000000')) #node2 has both keys of the 2of2 ms addr., tx should affect the balance - - # 2of3 test from different nodes bal = self.nodes[2].getbalance() addr1 = self.nodes[1].getnewaddress() @@ -105,7 +101,7 @@ class RawTransactionsTest(BitcoinTestFramework): mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']]) mSigObjValid = self.nodes[2].validateaddress(mSigObj) - txId = self.nodes[0].sendtoaddress(mSigObj, 2.2); + txId = self.nodes[0].sendtoaddress(mSigObj, 2.2) decTx = self.nodes[0].gettransaction(txId) rawTx = self.nodes[0].decoderawtransaction(decTx['hex']) sPK = rawTx['vout'][0]['scriptPubKey']['hex'] @@ -123,7 +119,7 @@ class RawTransactionsTest(BitcoinTestFramework): for outpoint in rawTx['vout']: if outpoint['value'] == Decimal('2.20000000'): vout = outpoint - break; + break bal = self.nodes[0].getbalance() inputs = [{ "txid" : txId, "vout" : vout['n'], "scriptPubKey" : vout['scriptPubKey']['hex']}] diff --git a/qa/rpc-tests/receivedby.py b/qa/rpc-tests/receivedby.py index 16d6bd4cf..606426b39 100755 --- a/qa/rpc-tests/receivedby.py +++ b/qa/rpc-tests/receivedby.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -53,6 +53,11 @@ def check_array_result(object_array, to_match, expected, should_not_find = False class ReceivedByTest(BitcoinTestFramework): + def setup_nodes(self): + #This test requires mocktime + enable_mocktime() + return start_nodes(4, self.options.tmpdir) + def run_test(self): ''' listreceivedbyaddress Test diff --git a/qa/rpc-tests/reindex.py b/qa/rpc-tests/reindex.py index f2e3f248e..321c2fe42 100755 --- a/qa/rpc-tests/reindex.py +++ b/qa/rpc-tests/reindex.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,7 +8,6 @@ # from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -import os.path class ReindexTest(BitcoinTestFramework): diff --git a/qa/rpc-tests/replace-by-fee.py b/qa/rpc-tests/replace-by-fee.py new file mode 100755 index 000000000..4c8ef6de2 --- /dev/null +++ b/qa/rpc-tests/replace-by-fee.py @@ -0,0 +1,585 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test replace by fee code +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.script import * +from test_framework.mininode import * + +MAX_REPLACEMENT_LIMIT = 100 + +def txToHex(tx): + return bytes_to_hex_str(tx.serialize()) + +def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])): + """Create a txout with a given amount and scriptPubKey + + Mines coins as needed. + + confirmed - txouts created will be confirmed in the blockchain; + unconfirmed otherwise. + """ + fee = 1*COIN + while node.getbalance() < satoshi_round((amount + fee)/COIN): + node.generate(100) + #print (node.getbalance(), amount, fee) + + new_addr = node.getnewaddress() + #print new_addr + txid = node.sendtoaddress(new_addr, satoshi_round((amount+fee)/COIN)) + tx1 = node.getrawtransaction(txid, 1) + txid = int(txid, 16) + i = None + + for i, txout in enumerate(tx1['vout']): + #print i, txout['scriptPubKey']['addresses'] + if txout['scriptPubKey']['addresses'] == [new_addr]: + #print i + break + assert i is not None + + tx2 = CTransaction() + tx2.vin = [CTxIn(COutPoint(txid, i))] + tx2.vout = [CTxOut(amount, scriptPubKey)] + tx2.rehash() + + signed_tx = node.signrawtransaction(txToHex(tx2)) + + txid = node.sendrawtransaction(signed_tx['hex'], True) + + # If requested, ensure txouts are confirmed. + if confirmed: + mempool_size = len(node.getrawmempool()) + while mempool_size > 0: + node.generate(1) + new_size = len(node.getrawmempool()) + # Error out if we have something stuck in the mempool, as this + # would likely be a bug. + assert(new_size < mempool_size) + mempool_size = new_size + + return COutPoint(int(txid, 16), 0) + +class ReplaceByFeeTest(BitcoinTestFramework): + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug", + "-relaypriority=0", "-whitelist=127.0.0.1", + "-limitancestorcount=50", + "-limitancestorsize=101", + "-limitdescendantcount=200", + "-limitdescendantsize=101" + ])) + self.is_network_split = False + + def run_test(self): + make_utxo(self.nodes[0], 1*COIN) + + print "Running test simple doublespend..." + self.test_simple_doublespend() + + print "Running test doublespend chain..." + self.test_doublespend_chain() + + print "Running test doublespend tree..." + self.test_doublespend_tree() + + print "Running test replacement feeperkb..." + self.test_replacement_feeperkb() + + print "Running test spends of conflicting outputs..." + self.test_spends_of_conflicting_outputs() + + print "Running test new unconfirmed inputs..." + self.test_new_unconfirmed_inputs() + + print "Running test too many replacements..." + self.test_too_many_replacements() + + print "Running test opt-in..." + self.test_opt_in() + + print "Running test prioritised transactions..." + self.test_prioritised_transactions() + + print "Passed\n" + + def test_simple_doublespend(self): + """Simple doublespend""" + tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) + + tx1a = CTransaction() + tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx1a_hex = txToHex(tx1a) + tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) + + # Should fail because we haven't changed the fee + tx1b = CTransaction() + tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1b.vout = [CTxOut(1*COIN, CScript([b'b']))] + tx1b_hex = txToHex(tx1b) + + try: + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) # insufficient fee + else: + assert(False) + + # Extra 0.1 BTC fee + tx1b = CTransaction() + tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))] + tx1b_hex = txToHex(tx1b) + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + + mempool = self.nodes[0].getrawmempool() + + assert (tx1a_txid not in mempool) + assert (tx1b_txid in mempool) + + assert_equal(tx1b_hex, self.nodes[0].getrawtransaction(tx1b_txid)) + + def test_doublespend_chain(self): + """Doublespend of a long chain""" + + initial_nValue = 50*COIN + tx0_outpoint = make_utxo(self.nodes[0], initial_nValue) + + prevout = tx0_outpoint + remaining_value = initial_nValue + chain_txids = [] + while remaining_value > 10*COIN: + remaining_value -= 1*COIN + tx = CTransaction() + tx.vin = [CTxIn(prevout, nSequence=0)] + tx.vout = [CTxOut(remaining_value, CScript([1]))] + tx_hex = txToHex(tx) + txid = self.nodes[0].sendrawtransaction(tx_hex, True) + chain_txids.append(txid) + prevout = COutPoint(int(txid, 16), 0) + + # Whether the double-spend is allowed is evaluated by including all + # child fees - 40 BTC - so this attempt is rejected. + dbl_tx = CTransaction() + dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)] + dbl_tx.vout = [CTxOut(initial_nValue - 30*COIN, CScript([1]))] + dbl_tx_hex = txToHex(dbl_tx) + + try: + self.nodes[0].sendrawtransaction(dbl_tx_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) # insufficient fee + else: + assert(False) # transaction mistakenly accepted! + + # Accepted with sufficient fee + dbl_tx = CTransaction() + dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)] + dbl_tx.vout = [CTxOut(1*COIN, CScript([1]))] + dbl_tx_hex = txToHex(dbl_tx) + self.nodes[0].sendrawtransaction(dbl_tx_hex, True) + + mempool = self.nodes[0].getrawmempool() + for doublespent_txid in chain_txids: + assert(doublespent_txid not in mempool) + + def test_doublespend_tree(self): + """Doublespend of a big tree of transactions""" + + initial_nValue = 50*COIN + tx0_outpoint = make_utxo(self.nodes[0], initial_nValue) + + def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001*COIN, _total_txs=None): + if _total_txs is None: + _total_txs = [0] + if _total_txs[0] >= max_txs: + return + + txout_value = (initial_value - fee) // tree_width + if txout_value < fee: + return + + vout = [CTxOut(txout_value, CScript([i+1])) + for i in range(tree_width)] + tx = CTransaction() + tx.vin = [CTxIn(prevout, nSequence=0)] + tx.vout = vout + tx_hex = txToHex(tx) + + assert(len(tx.serialize()) < 100000) + txid = self.nodes[0].sendrawtransaction(tx_hex, True) + yield tx + _total_txs[0] += 1 + + txid = int(txid, 16) + + for i, txout in enumerate(tx.vout): + for x in branch(COutPoint(txid, i), txout_value, + max_txs, + tree_width=tree_width, fee=fee, + _total_txs=_total_txs): + yield x + + fee = int(0.0001*COIN) + n = MAX_REPLACEMENT_LIMIT + tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee)) + assert_equal(len(tree_txs), n) + + # Attempt double-spend, will fail because too little fee paid + dbl_tx = CTransaction() + dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)] + dbl_tx.vout = [CTxOut(initial_nValue - fee*n, CScript([1]))] + dbl_tx_hex = txToHex(dbl_tx) + try: + self.nodes[0].sendrawtransaction(dbl_tx_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) # insufficient fee + else: + assert(False) + + # 1 BTC fee is enough + dbl_tx = CTransaction() + dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)] + dbl_tx.vout = [CTxOut(initial_nValue - fee*n - 1*COIN, CScript([1]))] + dbl_tx_hex = txToHex(dbl_tx) + self.nodes[0].sendrawtransaction(dbl_tx_hex, True) + + mempool = self.nodes[0].getrawmempool() + + for tx in tree_txs: + tx.rehash() + assert (tx.hash not in mempool) + + # Try again, but with more total transactions than the "max txs + # double-spent at once" anti-DoS limit. + for n in (MAX_REPLACEMENT_LIMIT+1, MAX_REPLACEMENT_LIMIT*2): + fee = int(0.0001*COIN) + tx0_outpoint = make_utxo(self.nodes[0], initial_nValue) + tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee)) + assert_equal(len(tree_txs), n) + + dbl_tx = CTransaction() + dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)] + dbl_tx.vout = [CTxOut(initial_nValue - 2*fee*n, CScript([1]))] + dbl_tx_hex = txToHex(dbl_tx) + try: + self.nodes[0].sendrawtransaction(dbl_tx_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + assert_equal("too many potential replacements" in exp.error['message'], True) + else: + assert(False) + + for tx in tree_txs: + tx.rehash() + self.nodes[0].getrawtransaction(tx.hash) + + def test_replacement_feeperkb(self): + """Replacement requires fee-per-KB to be higher""" + tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) + + tx1a = CTransaction() + tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx1a_hex = txToHex(tx1a) + tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) + + # Higher fee, but the fee per KB is much lower, so the replacement is + # rejected. + tx1b = CTransaction() + tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1b.vout = [CTxOut(int(0.001*COIN), CScript([b'a'*999000]))] + tx1b_hex = txToHex(tx1b) + + try: + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) # insufficient fee + else: + assert(False) + + def test_spends_of_conflicting_outputs(self): + """Replacements that spend conflicting tx outputs are rejected""" + utxo1 = make_utxo(self.nodes[0], int(1.2*COIN)) + utxo2 = make_utxo(self.nodes[0], 3*COIN) + + tx1a = CTransaction() + tx1a.vin = [CTxIn(utxo1, nSequence=0)] + tx1a.vout = [CTxOut(int(1.1*COIN), CScript([b'a']))] + tx1a_hex = txToHex(tx1a) + tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) + + tx1a_txid = int(tx1a_txid, 16) + + # Direct spend an output of the transaction we're replacing. + tx2 = CTransaction() + tx2.vin = [CTxIn(utxo1, nSequence=0), CTxIn(utxo2, nSequence=0)] + tx2.vin.append(CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)) + tx2.vout = tx1a.vout + tx2_hex = txToHex(tx2) + + try: + tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + assert(False) + + # Spend tx1a's output to test the indirect case. + tx1b = CTransaction() + tx1b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)] + tx1b.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx1b_hex = txToHex(tx1b) + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + tx1b_txid = int(tx1b_txid, 16) + + tx2 = CTransaction() + tx2.vin = [CTxIn(utxo1, nSequence=0), CTxIn(utxo2, nSequence=0), + CTxIn(COutPoint(tx1b_txid, 0))] + tx2.vout = tx1a.vout + tx2_hex = txToHex(tx2) + + try: + tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + assert(False) + + def test_new_unconfirmed_inputs(self): + """Replacements that add new unconfirmed inputs are rejected""" + confirmed_utxo = make_utxo(self.nodes[0], int(1.1*COIN)) + unconfirmed_utxo = make_utxo(self.nodes[0], int(0.1*COIN), False) + + tx1 = CTransaction() + tx1.vin = [CTxIn(confirmed_utxo)] + tx1.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx1_hex = txToHex(tx1) + tx1_txid = self.nodes[0].sendrawtransaction(tx1_hex, True) + + tx2 = CTransaction() + tx2.vin = [CTxIn(confirmed_utxo), CTxIn(unconfirmed_utxo)] + tx2.vout = tx1.vout + tx2_hex = txToHex(tx2) + + try: + tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + assert(False) + + def test_too_many_replacements(self): + """Replacements that evict too many transactions are rejected""" + # Try directly replacing more than MAX_REPLACEMENT_LIMIT + # transactions + + # Start by creating a single transaction with many outputs + initial_nValue = 10*COIN + utxo = make_utxo(self.nodes[0], initial_nValue) + fee = int(0.0001*COIN) + split_value = int((initial_nValue-fee)/(MAX_REPLACEMENT_LIMIT+1)) + actual_fee = initial_nValue - split_value*(MAX_REPLACEMENT_LIMIT+1) + + outputs = [] + for i in range(MAX_REPLACEMENT_LIMIT+1): + outputs.append(CTxOut(split_value, CScript([1]))) + + splitting_tx = CTransaction() + splitting_tx.vin = [CTxIn(utxo, nSequence=0)] + splitting_tx.vout = outputs + splitting_tx_hex = txToHex(splitting_tx) + + txid = self.nodes[0].sendrawtransaction(splitting_tx_hex, True) + txid = int(txid, 16) + + # Now spend each of those outputs individually + for i in range(MAX_REPLACEMENT_LIMIT+1): + tx_i = CTransaction() + tx_i.vin = [CTxIn(COutPoint(txid, i), nSequence=0)] + tx_i.vout = [CTxOut(split_value-fee, CScript([b'a']))] + tx_i_hex = txToHex(tx_i) + self.nodes[0].sendrawtransaction(tx_i_hex, True) + + # Now create doublespend of the whole lot; should fail. + # Need a big enough fee to cover all spending transactions and have + # a higher fee rate + double_spend_value = (split_value-100*fee)*(MAX_REPLACEMENT_LIMIT+1) + inputs = [] + for i in range(MAX_REPLACEMENT_LIMIT+1): + inputs.append(CTxIn(COutPoint(txid, i), nSequence=0)) + double_tx = CTransaction() + double_tx.vin = inputs + double_tx.vout = [CTxOut(double_spend_value, CScript([b'a']))] + double_tx_hex = txToHex(double_tx) + + try: + self.nodes[0].sendrawtransaction(double_tx_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + assert_equal("too many potential replacements" in exp.error['message'], True) + else: + assert(False) + + # If we remove an input, it should pass + double_tx = CTransaction() + double_tx.vin = inputs[0:-1] + double_tx.vout = [CTxOut(double_spend_value, CScript([b'a']))] + double_tx_hex = txToHex(double_tx) + self.nodes[0].sendrawtransaction(double_tx_hex, True) + + def test_opt_in(self): + """ Replacing should only work if orig tx opted in """ + tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) + + # Create a non-opting in transaction + tx1a = CTransaction() + tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0xffffffff)] + tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx1a_hex = txToHex(tx1a) + tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) + + # Shouldn't be able to double-spend + tx1b = CTransaction() + tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))] + tx1b_hex = txToHex(tx1b) + + try: + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + print tx1b_txid + assert(False) + + tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) + + # Create a different non-opting in transaction + tx2a = CTransaction() + tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0xfffffffe)] + tx2a.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx2a_hex = txToHex(tx2a) + tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, True) + + # Still shouldn't be able to double-spend + tx2b = CTransaction() + tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)] + tx2b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))] + tx2b_hex = txToHex(tx2b) + + try: + tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + assert(False) + + # Now create a new transaction that spends from tx1a and tx2a + # opt-in on one of the inputs + # Transaction should be replaceable on either input + + tx1a_txid = int(tx1a_txid, 16) + tx2a_txid = int(tx2a_txid, 16) + + tx3a = CTransaction() + tx3a.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0xffffffff), + CTxIn(COutPoint(tx2a_txid, 0), nSequence=0xfffffffd)] + tx3a.vout = [CTxOut(int(0.9*COIN), CScript([b'c'])), CTxOut(int(0.9*COIN), CScript([b'd']))] + tx3a_hex = txToHex(tx3a) + + self.nodes[0].sendrawtransaction(tx3a_hex, True) + + tx3b = CTransaction() + tx3b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)] + tx3b.vout = [CTxOut(int(0.5*COIN), CScript([b'e']))] + tx3b_hex = txToHex(tx3b) + + tx3c = CTransaction() + tx3c.vin = [CTxIn(COutPoint(tx2a_txid, 0), nSequence=0)] + tx3c.vout = [CTxOut(int(0.5*COIN), CScript([b'f']))] + tx3c_hex = txToHex(tx3c) + + self.nodes[0].sendrawtransaction(tx3b_hex, True) + # If tx3b was accepted, tx3c won't look like a replacement, + # but make sure it is accepted anyway + self.nodes[0].sendrawtransaction(tx3c_hex, True) + + def test_prioritised_transactions(self): + # Ensure that fee deltas used via prioritisetransaction are + # correctly used by replacement logic + + # 1. Check that feeperkb uses modified fees + tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) + + tx1a = CTransaction() + tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx1a_hex = txToHex(tx1a) + tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) + + # Higher fee, but the actual fee per KB is much lower. + tx1b = CTransaction() + tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] + tx1b.vout = [CTxOut(int(0.001*COIN), CScript([b'a'*740000]))] + tx1b_hex = txToHex(tx1b) + + # Verify tx1b cannot replace tx1a. + try: + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + assert(False) + + # Use prioritisetransaction to set tx1a's fee to 0. + self.nodes[0].prioritisetransaction(tx1a_txid, 0, int(-0.1*COIN)) + + # Now tx1b should be able to replace tx1a + tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) + + assert(tx1b_txid in self.nodes[0].getrawmempool()) + + # 2. Check that absolute fee checks use modified fee. + tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) + + tx2a = CTransaction() + tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0)] + tx2a.vout = [CTxOut(1*COIN, CScript([b'a']))] + tx2a_hex = txToHex(tx2a) + tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, True) + + # Lower fee, but we'll prioritise it + tx2b = CTransaction() + tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)] + tx2b.vout = [CTxOut(int(1.01*COIN), CScript([b'a']))] + tx2b.rehash() + tx2b_hex = txToHex(tx2b) + + # Verify tx2b cannot replace tx2a. + try: + tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True) + except JSONRPCException as exp: + assert_equal(exp.error['code'], -26) + else: + assert(False) + + # Now prioritise tx2b to have a higher modified fee + self.nodes[0].prioritisetransaction(tx2b.hash, 0, int(0.1*COIN)) + + # tx2b should now be accepted + tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True) + + assert(tx2b_txid in self.nodes[0].getrawmempool()) + +if __name__ == '__main__': + ReplaceByFeeTest().main() diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py index e084ad55a..359f9239f 100755 --- a/qa/rpc-tests/rest.py +++ b/qa/rpc-tests/rest.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,10 +11,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * from struct import * +from io import BytesIO +from codecs import encode import binascii -import json -import StringIO -import decimal try: import http.client as httplib @@ -40,7 +39,7 @@ def http_get_call(host, port, path, response_object = 0): if response_object: return conn.getresponse() - return conn.getresponse().read() + return conn.getresponse().read().decode('utf-8') #allows simple http post calls with a request body def http_post_call(host, port, path, requestdata = '', response_object = 0): @@ -142,13 +141,13 @@ class RESTTest (BitcoinTestFramework): bb_hash = self.nodes[0].getbestblockhash() binaryRequest = b'\x01\x02' - binaryRequest += binascii.unhexlify(txid) - binaryRequest += pack("i", n); - binaryRequest += binascii.unhexlify(vintx); - binaryRequest += pack("i", 0); + binaryRequest += hex_str_to_bytes(txid) + binaryRequest += pack("i", n) + binaryRequest += hex_str_to_bytes(vintx) + binaryRequest += pack("i", 0) bin_response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'bin', binaryRequest) - output = StringIO.StringIO() + output = BytesIO() output.write(bin_response) output.seek(0) chainHeight = unpack("i", output.read(4))[0] @@ -206,7 +205,7 @@ class RESTTest (BitcoinTestFramework): json_request = '/checkmempool/' for x in range(0, 15): json_request += txid+'-'+str(n)+'/' - json_request = json_request.rstrip("/"); + json_request = json_request.rstrip("/") response = http_post_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True) assert_equal(response.status, 200) #must be a 500 because we exceeding the limits @@ -235,7 +234,7 @@ class RESTTest (BitcoinTestFramework): assert_equal(response_hex.status, 200) assert_greater_than(int(response_hex.getheader('content-length')), 160) response_hex_str = response_hex.read() - assert_equal(response_str.encode("hex")[0:160], response_hex_str[0:160]) + assert_equal(encode(response_str, "hex_codec")[0:160], response_hex_str[0:160]) # compare with hex block header response_header_hex = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"hex", True) @@ -243,7 +242,7 @@ class RESTTest (BitcoinTestFramework): assert_greater_than(int(response_header_hex.getheader('content-length')), 160) response_header_hex_str = response_header_hex.read() assert_equal(response_hex_str[0:160], response_header_hex_str[0:160]) - assert_equal(response_header_str.encode("hex")[0:160], response_header_hex_str[0:160]) + assert_equal(encode(response_header_str, "hex_codec")[0:160], response_header_hex_str[0:160]) # check json format block_json_string = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+'json') @@ -253,8 +252,8 @@ class RESTTest (BitcoinTestFramework): # compare with json block header response_header_json = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"json", True) assert_equal(response_header_json.status, 200) - response_header_json_str = response_header_json.read() - json_obj = json.loads(response_header_json_str, parse_float=decimal.Decimal) + response_header_json_str = response_header_json.read().decode('utf-8') + json_obj = json.loads(response_header_json_str, parse_float=Decimal) assert_equal(len(json_obj), 1) #ensure that there is one header in the json response assert_equal(json_obj[0]['hash'], bb_hash) #request/response hash should be the same @@ -277,12 +276,12 @@ class RESTTest (BitcoinTestFramework): self.sync_all() response_header_json = http_get_call(url.hostname, url.port, '/rest/headers/5/'+bb_hash+self.FORMAT_SEPARATOR+"json", True) assert_equal(response_header_json.status, 200) - response_header_json_str = response_header_json.read() + response_header_json_str = response_header_json.read().decode('utf-8') json_obj = json.loads(response_header_json_str) assert_equal(len(json_obj), 5) #now we should have 5 header objects # do tx test - tx_hash = block_json_obj['tx'][0]['txid']; + tx_hash = block_json_obj['tx'][0]['txid'] json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"json") json_obj = json.loads(json_string) assert_equal(json_obj['txid'], tx_hash) @@ -293,7 +292,6 @@ class RESTTest (BitcoinTestFramework): assert_greater_than(int(response.getheader('content-length')), 10) - # check block tx details # let's make 3 tx and mine them on node 1 txs = [] diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py index 04110c283..10a48b555 100755 --- a/qa/rpc-tests/rpcbind_test.py +++ b/qa/rpc-tests/rpcbind_test.py @@ -1,17 +1,12 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # Test for -rpcbind, as well as -rpcallowip and -rpcconnect -# Add python-bitcoinrpc to module search path: -import os -import sys +# TODO extend this test from the test framework (like all other tests) -import json -import shutil -import subprocess import tempfile import traceback @@ -47,7 +42,7 @@ def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport): try: # connect to node through non-loopback interface url = "http://rt:rt@%s:%d" % (rpchost, rpcport,) - node = AuthServiceProxy(url) + node = get_rpc_proxy(url, 1) node.getinfo() finally: node = None # make sure connection will be garbage collected and closed diff --git a/qa/rpc-tests/script_test.py b/qa/rpc-tests/script_test.py deleted file mode 100755 index afc44b51b..000000000 --- a/qa/rpc-tests/script_test.py +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/env python2 -# -# Distributed under the MIT/X11 software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. -# - -''' -Test notes: -This test uses the script_valid and script_invalid tests from the unittest -framework to do end-to-end testing where we compare that two nodes agree on -whether blocks containing a given test script are valid. - -We generally ignore the script flags associated with each test (since we lack -the precision to test each script using those flags in this framework), but -for tests with SCRIPT_VERIFY_P2SH, we can use a block time after the BIP16 -switchover date to try to test with that flag enabled (and for tests without -that flag, we use a block time before the switchover date). - -NOTE: This test is very slow and may take more than 40 minutes to run. -''' - -from test_framework.test_framework import ComparisonTestFramework -from test_framework.util import * -from test_framework.comptool import TestInstance, TestManager -from test_framework.mininode import * -from test_framework.blocktools import * -from test_framework.script import * -import logging -import copy -import json - -script_valid_file = "../../src/test/data/script_valid.json" -script_invalid_file = "../../src/test/data/script_invalid.json" - -# Pass in a set of json files to open. -class ScriptTestFile(object): - - def __init__(self, files): - self.files = files - self.index = -1 - self.data = [] - - def load_files(self): - for f in self.files: - self.data.extend(json.loads(open(os.path.dirname(os.path.abspath(__file__))+"/"+f).read())) - - # Skip over records that are not long enough to be tests - def get_records(self): - while (self.index < len(self.data)): - if len(self.data[self.index]) >= 3: - yield self.data[self.index] - self.index += 1 - - -# Helper for parsing the flags specified in the .json files -SCRIPT_VERIFY_NONE = 0 -SCRIPT_VERIFY_P2SH = 1 -SCRIPT_VERIFY_STRICTENC = 1 << 1 -SCRIPT_VERIFY_DERSIG = 1 << 2 -SCRIPT_VERIFY_LOW_S = 1 << 3 -SCRIPT_VERIFY_NULLDUMMY = 1 << 4 -SCRIPT_VERIFY_SIGPUSHONLY = 1 << 5 -SCRIPT_VERIFY_MINIMALDATA = 1 << 6 -SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = 1 << 7 -SCRIPT_VERIFY_CLEANSTACK = 1 << 8 - -flag_map = { - "": SCRIPT_VERIFY_NONE, - "NONE": SCRIPT_VERIFY_NONE, - "P2SH": SCRIPT_VERIFY_P2SH, - "STRICTENC": SCRIPT_VERIFY_STRICTENC, - "DERSIG": SCRIPT_VERIFY_DERSIG, - "LOW_S": SCRIPT_VERIFY_LOW_S, - "NULLDUMMY": SCRIPT_VERIFY_NULLDUMMY, - "SIGPUSHONLY": SCRIPT_VERIFY_SIGPUSHONLY, - "MINIMALDATA": SCRIPT_VERIFY_MINIMALDATA, - "DISCOURAGE_UPGRADABLE_NOPS": SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS, - "CLEANSTACK": SCRIPT_VERIFY_CLEANSTACK, -} - -def ParseScriptFlags(flag_string): - flags = 0 - for x in flag_string.split(","): - if x in flag_map: - flags |= flag_map[x] - else: - print "Error: unrecognized script flag: ", x - return flags - -''' -Given a string that is a scriptsig or scriptpubkey from the .json files above, -convert it to a CScript() -''' -# Replicates behavior from core_read.cpp -def ParseScript(json_script): - script = json_script.split(" ") - parsed_script = CScript() - for x in script: - if len(x) == 0: - # Empty string, ignore. - pass - elif x.isdigit() or (len(x) >= 1 and x[0] == "-" and x[1:].isdigit()): - # Number - n = int(x, 0) - if (n == -1) or (n >= 1 and n <= 16): - parsed_script = CScript(bytes(parsed_script) + bytes(CScript([n]))) - else: - parsed_script += CScriptNum(int(x, 0)) - elif x.startswith("0x"): - # Raw hex data, inserted NOT pushed onto stack: - for i in xrange(2, len(x), 2): - parsed_script = CScript(bytes(parsed_script) + bytes(chr(int(x[i:i+2],16)))) - elif x.startswith("'") and x.endswith("'") and len(x) >= 2: - # Single-quoted string, pushed as data. - parsed_script += CScript([x[1:-1]]) - else: - # opcode, e.g. OP_ADD or ADD: - tryopname = "OP_" + x - if tryopname in OPCODES_BY_NAME: - parsed_script += CScriptOp(OPCODES_BY_NAME["OP_" + x]) - else: - print "ParseScript: error parsing '%s'" % x - return "" - return parsed_script - -class TestBuilder(object): - def create_credit_tx(self, scriptPubKey, height): - # self.tx1 is a coinbase transaction, modeled after the one created by script_tests.cpp - # This allows us to reuse signatures created in the unit test framework. - self.tx1 = create_coinbase(height) # this has a bip34 scriptsig, - self.tx1.vin[0].scriptSig = CScript([0, 0]) # but this matches the unit tests - self.tx1.vout[0].nValue = 0 - self.tx1.vout[0].scriptPubKey = scriptPubKey - self.tx1.rehash() - def create_spend_tx(self, scriptSig): - self.tx2 = create_transaction(self.tx1, 0, CScript(), 0) - self.tx2.vin[0].scriptSig = scriptSig - self.tx2.vout[0].scriptPubKey = CScript() - self.tx2.rehash() - def rehash(self): - self.tx1.rehash() - self.tx2.rehash() - -# This test uses the (default) two nodes provided by ComparisonTestFramework, -# specified on the command line with --testbinary and --refbinary. -# See comptool.py -class ScriptTest(ComparisonTestFramework): - - def run_test(self): - # Set up the comparison tool TestManager - test = TestManager(self, self.options.tmpdir) - test.add_all_connections(self.nodes) - - # Load scripts - self.scripts = ScriptTestFile([script_valid_file, script_invalid_file]) - self.scripts.load_files() - - # Some variables we re-use between test instances (to build blocks) - self.tip = None - self.block_time = None - - NetworkThread().start() # Start up network handling in another thread - test.run() - - def generate_test_instance(self, pubkeystring, scriptsigstring): - scriptpubkey = ParseScript(pubkeystring) - scriptsig = ParseScript(scriptsigstring) - - test = TestInstance(sync_every_block=False) - test_build = TestBuilder() - test_build.create_credit_tx(scriptpubkey, self.height) - test_build.create_spend_tx(scriptsig) - test_build.rehash() - - block = create_block(self.tip, test_build.tx1, self.block_time) - self.block_time += 1 - block.solve() - self.tip = block.sha256 - self.height += 1 - test.blocks_and_transactions = [[block, True]] - - for i in xrange(100): - block = create_block(self.tip, create_coinbase(self.height), self.block_time) - self.block_time += 1 - block.solve() - self.tip = block.sha256 - self.height += 1 - test.blocks_and_transactions.append([block, True]) - - block = create_block(self.tip, create_coinbase(self.height), self.block_time) - self.block_time += 1 - block.vtx.append(test_build.tx2) - block.hashMerkleRoot = block.calc_merkle_root() - block.rehash() - block.solve() - test.blocks_and_transactions.append([block, None]) - return test - - # This generates the tests for TestManager. - def get_tests(self): - self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) - self.block_time = 1333230000 # before the BIP16 switchover - self.height = 1 - - ''' - Create a new block with an anyone-can-spend coinbase - ''' - block = create_block(self.tip, create_coinbase(self.height), self.block_time) - self.block_time += 1 - block.solve() - self.tip = block.sha256 - self.height += 1 - yield TestInstance(objects=[[block, True]]) - - ''' - Build out to 100 blocks total, maturing the coinbase. - ''' - test = TestInstance(objects=[], sync_every_block=False, sync_every_tx=False) - for i in xrange(100): - b = create_block(self.tip, create_coinbase(self.height), self.block_time) - b.solve() - test.blocks_and_transactions.append([b, True]) - self.tip = b.sha256 - self.block_time += 1 - self.height += 1 - yield test - - ''' Iterate through script tests. ''' - counter = 0 - for script_test in self.scripts.get_records(): - ''' Reset the blockchain to genesis block + 100 blocks. ''' - if self.nodes[0].getblockcount() > 101: - self.nodes[0].invalidateblock(self.nodes[0].getblockhash(102)) - self.nodes[1].invalidateblock(self.nodes[1].getblockhash(102)) - - self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) - self.height = 102 - - [scriptsig, scriptpubkey, flags] = script_test[0:3] - flags = ParseScriptFlags(flags) - - # We can use block time to determine whether the nodes should be - # enforcing BIP16. - # - # We intentionally let the block time grow by 1 each time. - # This forces the block hashes to differ between tests, so that - # a call to invalidateblock doesn't interfere with a later test. - if (flags & SCRIPT_VERIFY_P2SH): - self.block_time = 1333238400 + counter # Advance to enforcing BIP16 - else: - self.block_time = 1333230000 + counter # Before the BIP16 switchover - - print "Script test: [%s]" % script_test - - yield self.generate_test_instance(scriptpubkey, scriptsig) - counter += 1 - -if __name__ == '__main__': - ScriptTest().main() diff --git a/qa/rpc-tests/sendheaders.py b/qa/rpc-tests/sendheaders.py new file mode 100755 index 000000000..2bc32584b --- /dev/null +++ b/qa/rpc-tests/sendheaders.py @@ -0,0 +1,517 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014-2015 The Bitcoin Core developers +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +from test_framework.mininode import * +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.blocktools import create_block, create_coinbase + +''' +SendHeadersTest -- test behavior of headers messages to announce blocks. + +Setup: + +- Two nodes, two p2p connections to node0. One p2p connection should only ever + receive inv's (omitted from testing description below, this is our control). + Second node is used for creating reorgs. + +Part 1: No headers announcements before "sendheaders" +a. node mines a block [expect: inv] + send getdata for the block [expect: block] +b. node mines another block [expect: inv] + send getheaders and getdata [expect: headers, then block] +c. node mines another block [expect: inv] + peer mines a block, announces with header [expect: getdata] +d. node mines another block [expect: inv] + +Part 2: After "sendheaders", headers announcements should generally work. +a. peer sends sendheaders [expect: no response] + peer sends getheaders with current tip [expect: no response] +b. node mines a block [expect: tip header] +c. for N in 1, ..., 10: + * for announce-type in {inv, header} + - peer mines N blocks, announces with announce-type + [ expect: getheaders/getdata or getdata, deliver block(s) ] + - node mines a block [ expect: 1 header ] + +Part 3: Headers announcements stop after large reorg and resume after getheaders or inv from peer. +- For response-type in {inv, getheaders} + * node mines a 7 block reorg [ expect: headers announcement of 8 blocks ] + * node mines an 8-block reorg [ expect: inv at tip ] + * peer responds with getblocks/getdata [expect: inv, blocks ] + * node mines another block [ expect: inv at tip, peer sends getdata, expect: block ] + * node mines another block at tip [ expect: inv ] + * peer responds with getheaders with an old hashstop more than 8 blocks back [expect: headers] + * peer requests block [ expect: block ] + * node mines another block at tip [ expect: inv, peer sends getdata, expect: block ] + * peer sends response-type [expect headers if getheaders, getheaders/getdata if mining new block] + * node mines 1 block [expect: 1 header, peer responds with getdata] + +Part 4: Test direct fetch behavior +a. Announce 2 old block headers. + Expect: no getdata requests. +b. Announce 3 new blocks via 1 headers message. + Expect: one getdata request for all 3 blocks. + (Send blocks.) +c. Announce 1 header that forks off the last two blocks. + Expect: no response. +d. Announce 1 more header that builds on that fork. + Expect: one getdata request for two blocks. +e. Announce 16 more headers that build on that fork. + Expect: getdata request for 14 more blocks. +f. Announce 1 more header that builds on that fork. + Expect: no response. +''' + +class BaseNode(NodeConnCB): + def __init__(self): + NodeConnCB.__init__(self) + self.connection = None + self.last_inv = None + self.last_headers = None + self.last_block = None + self.ping_counter = 1 + self.last_pong = msg_pong(0) + self.last_getdata = None + self.sleep_time = 0.05 + self.block_announced = False + + def clear_last_announcement(self): + with mininode_lock: + self.block_announced = False + self.last_inv = None + self.last_headers = None + + def add_connection(self, conn): + self.connection = conn + + # Request data for a list of block hashes + def get_data(self, block_hashes): + msg = msg_getdata() + for x in block_hashes: + msg.inv.append(CInv(2, x)) + self.connection.send_message(msg) + + def get_headers(self, locator, hashstop): + msg = msg_getheaders() + msg.locator.vHave = locator + msg.hashstop = hashstop + self.connection.send_message(msg) + + def send_block_inv(self, blockhash): + msg = msg_inv() + msg.inv = [CInv(2, blockhash)] + self.connection.send_message(msg) + + # Wrapper for the NodeConn's send_message function + def send_message(self, message): + self.connection.send_message(message) + + def on_inv(self, conn, message): + self.last_inv = message + self.block_announced = True + + def on_headers(self, conn, message): + self.last_headers = message + self.block_announced = True + + def on_block(self, conn, message): + self.last_block = message.block + self.last_block.calc_sha256() + + def on_getdata(self, conn, message): + self.last_getdata = message + + def on_pong(self, conn, message): + self.last_pong = message + + # Test whether the last announcement we received had the + # right header or the right inv + # inv and headers should be lists of block hashes + def check_last_announcement(self, headers=None, inv=None): + expect_headers = headers if headers != None else [] + expect_inv = inv if inv != None else [] + test_function = lambda: self.block_announced + self.sync(test_function) + with mininode_lock: + self.block_announced = False + + success = True + compare_inv = [] + if self.last_inv != None: + compare_inv = [x.hash for x in self.last_inv.inv] + if compare_inv != expect_inv: + success = False + + hash_headers = [] + if self.last_headers != None: + # treat headers as a list of block hashes + hash_headers = [ x.sha256 for x in self.last_headers.headers ] + if hash_headers != expect_headers: + success = False + + self.last_inv = None + self.last_headers = None + return success + + # Syncing helpers + def sync(self, test_function, timeout=60): + while timeout > 0: + with mininode_lock: + if test_function(): + return + time.sleep(self.sleep_time) + timeout -= self.sleep_time + raise AssertionError("Sync failed to complete") + + def sync_with_ping(self, timeout=60): + self.send_message(msg_ping(nonce=self.ping_counter)) + test_function = lambda: self.last_pong.nonce == self.ping_counter + self.sync(test_function, timeout) + self.ping_counter += 1 + return + + def wait_for_block(self, blockhash, timeout=60): + test_function = lambda: self.last_block != None and self.last_block.sha256 == blockhash + self.sync(test_function, timeout) + return + + def wait_for_getdata(self, hash_list, timeout=60): + if hash_list == []: + return + + test_function = lambda: self.last_getdata != None and [x.hash for x in self.last_getdata.inv] == hash_list + self.sync(test_function, timeout) + return + + def send_header_for_blocks(self, new_blocks): + headers_message = msg_headers() + headers_message.headers = [ CBlockHeader(b) for b in new_blocks ] + self.send_message(headers_message) + + def send_getblocks(self, locator): + getblocks_message = msg_getblocks() + getblocks_message.locator.vHave = locator + self.send_message(getblocks_message) + +# InvNode: This peer should only ever receive inv's, because it doesn't ever send a +# "sendheaders" message. +class InvNode(BaseNode): + def __init__(self): + BaseNode.__init__(self) + +# TestNode: This peer is the one we use for most of the testing. +class TestNode(BaseNode): + def __init__(self): + BaseNode.__init__(self) + +class SendHeadersTest(BitcoinTestFramework): + def setup_chain(self): + initialize_chain_clean(self.options.tmpdir, 2) + + def setup_network(self): + self.nodes = [] + self.nodes = start_nodes(2, self.options.tmpdir, [["-debug", "-logtimemicros=1"]]*2) + connect_nodes(self.nodes[0], 1) + + # mine count blocks and return the new tip + def mine_blocks(self, count): + # Clear out last block announcement from each p2p listener + [ x.clear_last_announcement() for x in self.p2p_connections ] + self.nodes[0].generate(count) + return int(self.nodes[0].getbestblockhash(), 16) + + # mine a reorg that invalidates length blocks (replacing them with + # length+1 blocks). + # Note: we clear the state of our p2p connections after the + # to-be-reorged-out blocks are mined, so that we don't break later tests. + # return the list of block hashes newly mined + def mine_reorg(self, length): + self.nodes[0].generate(length) # make sure all invalidated blocks are node0's + sync_blocks(self.nodes, wait=0.1) + [x.clear_last_announcement() for x in self.p2p_connections] + + tip_height = self.nodes[1].getblockcount() + hash_to_invalidate = self.nodes[1].getblockhash(tip_height-(length-1)) + self.nodes[1].invalidateblock(hash_to_invalidate) + all_hashes = self.nodes[1].generate(length+1) # Must be longer than the orig chain + sync_blocks(self.nodes, wait=0.1) + return [int(x, 16) for x in all_hashes] + + def run_test(self): + # Setup the p2p connections and start up the network thread. + inv_node = InvNode() + test_node = TestNode() + + self.p2p_connections = [inv_node, test_node] + + connections = [] + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], inv_node)) + # Set nServices to 0 for test_node, so no block download will occur outside of + # direct fetching + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node, services=0)) + inv_node.add_connection(connections[0]) + test_node.add_connection(connections[1]) + + NetworkThread().start() # Start up network handling in another thread + + # Test logic begins here + inv_node.wait_for_verack() + test_node.wait_for_verack() + + tip = int(self.nodes[0].getbestblockhash(), 16) + + # PART 1 + # 1. Mine a block; expect inv announcements each time + print "Part 1: headers don't start before sendheaders message..." + for i in xrange(4): + old_tip = tip + tip = self.mine_blocks(1) + assert_equal(inv_node.check_last_announcement(inv=[tip]), True) + assert_equal(test_node.check_last_announcement(inv=[tip]), True) + # Try a few different responses; none should affect next announcement + if i == 0: + # first request the block + test_node.get_data([tip]) + test_node.wait_for_block(tip, timeout=5) + elif i == 1: + # next try requesting header and block + test_node.get_headers(locator=[old_tip], hashstop=tip) + test_node.get_data([tip]) + test_node.wait_for_block(tip) + test_node.clear_last_announcement() # since we requested headers... + elif i == 2: + # this time announce own block via headers + height = self.nodes[0].getblockcount() + last_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + block_time = last_time + 1 + new_block = create_block(tip, create_coinbase(height+1), block_time) + new_block.solve() + test_node.send_header_for_blocks([new_block]) + test_node.wait_for_getdata([new_block.sha256], timeout=5) + test_node.send_message(msg_block(new_block)) + test_node.sync_with_ping() # make sure this block is processed + inv_node.clear_last_announcement() + test_node.clear_last_announcement() + + print "Part 1: success!" + print "Part 2: announce blocks with headers after sendheaders message..." + # PART 2 + # 2. Send a sendheaders message and test that headers announcements + # commence and keep working. + test_node.send_message(msg_sendheaders()) + prev_tip = int(self.nodes[0].getbestblockhash(), 16) + test_node.get_headers(locator=[prev_tip], hashstop=0L) + test_node.sync_with_ping() + + # Now that we've synced headers, headers announcements should work + tip = self.mine_blocks(1) + assert_equal(inv_node.check_last_announcement(inv=[tip]), True) + assert_equal(test_node.check_last_announcement(headers=[tip]), True) + + height = self.nodes[0].getblockcount()+1 + block_time += 10 # Advance far enough ahead + for i in xrange(10): + # Mine i blocks, and alternate announcing either via + # inv (of tip) or via headers. After each, new blocks + # mined by the node should successfully be announced + # with block header, even though the blocks are never requested + for j in xrange(2): + blocks = [] + for b in xrange(i+1): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + if j == 0: + # Announce via inv + test_node.send_block_inv(tip) + test_node.wait_for_getdata([tip], timeout=5) + # Test that duplicate inv's won't result in duplicate + # getdata requests, or duplicate headers announcements + inv_node.send_block_inv(tip) + # Should have received a getheaders as well! + test_node.send_header_for_blocks(blocks) + test_node.wait_for_getdata([x.sha256 for x in blocks[0:-1]], timeout=5) + [ inv_node.send_block_inv(x.sha256) for x in blocks[0:-1] ] + inv_node.sync_with_ping() + else: + # Announce via headers + test_node.send_header_for_blocks(blocks) + test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=5) + # Test that duplicate headers won't result in duplicate + # getdata requests (the check is further down) + inv_node.send_header_for_blocks(blocks) + inv_node.sync_with_ping() + [ test_node.send_message(msg_block(x)) for x in blocks ] + test_node.sync_with_ping() + inv_node.sync_with_ping() + # This block should not be announced to the inv node (since it also + # broadcast it) + assert_equal(inv_node.last_inv, None) + assert_equal(inv_node.last_headers, None) + tip = self.mine_blocks(1) + assert_equal(inv_node.check_last_announcement(inv=[tip]), True) + assert_equal(test_node.check_last_announcement(headers=[tip]), True) + height += 1 + block_time += 1 + + print "Part 2: success!" + + print "Part 3: headers announcements can stop after large reorg, and resume after headers/inv from peer..." + + # PART 3. Headers announcements can stop after large reorg, and resume after + # getheaders or inv from peer. + for j in xrange(2): + # First try mining a reorg that can propagate with header announcement + new_block_hashes = self.mine_reorg(length=7) + tip = new_block_hashes[-1] + assert_equal(inv_node.check_last_announcement(inv=[tip]), True) + assert_equal(test_node.check_last_announcement(headers=new_block_hashes), True) + + block_time += 8 + + # Mine a too-large reorg, which should be announced with a single inv + new_block_hashes = self.mine_reorg(length=8) + tip = new_block_hashes[-1] + assert_equal(inv_node.check_last_announcement(inv=[tip]), True) + assert_equal(test_node.check_last_announcement(inv=[tip]), True) + + block_time += 9 + + fork_point = self.nodes[0].getblock("%02x" % new_block_hashes[0])["previousblockhash"] + fork_point = int(fork_point, 16) + + # Use getblocks/getdata + test_node.send_getblocks(locator = [fork_point]) + assert_equal(test_node.check_last_announcement(inv=new_block_hashes), True) + test_node.get_data(new_block_hashes) + test_node.wait_for_block(new_block_hashes[-1]) + + for i in xrange(3): + # Mine another block, still should get only an inv + tip = self.mine_blocks(1) + assert_equal(inv_node.check_last_announcement(inv=[tip]), True) + assert_equal(test_node.check_last_announcement(inv=[tip]), True) + if i == 0: + # Just get the data -- shouldn't cause headers announcements to resume + test_node.get_data([tip]) + test_node.wait_for_block(tip) + elif i == 1: + # Send a getheaders message that shouldn't trigger headers announcements + # to resume (best header sent will be too old) + test_node.get_headers(locator=[fork_point], hashstop=new_block_hashes[1]) + test_node.get_data([tip]) + test_node.wait_for_block(tip) + elif i == 2: + test_node.get_data([tip]) + test_node.wait_for_block(tip) + # This time, try sending either a getheaders to trigger resumption + # of headers announcements, or mine a new block and inv it, also + # triggering resumption of headers announcements. + if j == 0: + test_node.get_headers(locator=[tip], hashstop=0L) + test_node.sync_with_ping() + else: + test_node.send_block_inv(tip) + test_node.sync_with_ping() + # New blocks should now be announced with header + tip = self.mine_blocks(1) + assert_equal(inv_node.check_last_announcement(inv=[tip]), True) + assert_equal(test_node.check_last_announcement(headers=[tip]), True) + + print "Part 3: success!" + + print "Part 4: Testing direct fetch behavior..." + tip = self.mine_blocks(1) + height = self.nodes[0].getblockcount() + 1 + last_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + block_time = last_time + 1 + + # Create 2 blocks. Send the blocks, then send the headers. + blocks = [] + for b in xrange(2): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + inv_node.send_message(msg_block(blocks[-1])) + + inv_node.sync_with_ping() # Make sure blocks are processed + test_node.last_getdata = None + test_node.send_header_for_blocks(blocks) + test_node.sync_with_ping() + # should not have received any getdata messages + with mininode_lock: + assert_equal(test_node.last_getdata, None) + + # This time, direct fetch should work + blocks = [] + for b in xrange(3): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + + test_node.send_header_for_blocks(blocks) + test_node.sync_with_ping() + test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=test_node.sleep_time) + + [ test_node.send_message(msg_block(x)) for x in blocks ] + + test_node.sync_with_ping() + + # Now announce a header that forks the last two blocks + tip = blocks[0].sha256 + height -= 1 + blocks = [] + + # Create extra blocks for later + for b in xrange(20): + blocks.append(create_block(tip, create_coinbase(height), block_time)) + blocks[-1].solve() + tip = blocks[-1].sha256 + block_time += 1 + height += 1 + + # Announcing one block on fork should not trigger direct fetch + # (less work than tip) + test_node.last_getdata = None + test_node.send_header_for_blocks(blocks[0:1]) + test_node.sync_with_ping() + with mininode_lock: + assert_equal(test_node.last_getdata, None) + + # Announcing one more block on fork should trigger direct fetch for + # both blocks (same work as tip) + test_node.send_header_for_blocks(blocks[1:2]) + test_node.sync_with_ping() + test_node.wait_for_getdata([x.sha256 for x in blocks[0:2]], timeout=test_node.sleep_time) + + # Announcing 16 more headers should trigger direct fetch for 14 more + # blocks + test_node.send_header_for_blocks(blocks[2:18]) + test_node.sync_with_ping() + test_node.wait_for_getdata([x.sha256 for x in blocks[2:16]], timeout=test_node.sleep_time) + + # Announcing 1 more header should not trigger any response + test_node.last_getdata = None + test_node.send_header_for_blocks(blocks[18:19]) + test_node.sync_with_ping() + with mininode_lock: + assert_equal(test_node.last_getdata, None) + + print "Part 4: success!" + + # Finally, check that the inv node never received a getdata request, + # throughout the test + assert_equal(inv_node.last_getdata, None) + +if __name__ == '__main__': + SendHeadersTest().main() diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py index c15c5fda0..2c064ad8a 100755 --- a/qa/rpc-tests/smartfees.py +++ b/qa/rpc-tests/smartfees.py @@ -19,9 +19,6 @@ P2SH_2 = "2NBdpwq8Aoo1EEKEXPNrKvr5xQr3M9UfcZA" # P2SH of "OP_2 OP_DROP" # 4 bytes of OP_TRUE and push 2-byte redeem script of "OP_1 OP_DROP" or "OP_2 OP_DROP" SCRIPT_SIG = ["0451025175", "0451025275"] -def satoshi_round(amount): - return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) - def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee_increment): ''' Create and send a transaction with a random fee. @@ -108,7 +105,7 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True): print([str(all_estimates[e-1]) for e in [1,2,3,6,15,25]]) delta = 1.0e-6 # account for rounding error last_e = max(fees_seen) - for e in filter(lambda x: x >= 0, all_estimates): + for e in [x for x in all_estimates if x >= 0]: # Estimates should be within the bounds of what transactions fees actually were: if float(e)+delta < min(fees_seen) or float(e)-delta > max(fees_seen): raise AssertionError("Estimated fee (%f) out of range (%f,%f)" @@ -120,15 +117,26 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True): last_e = e valid_estimate = False invalid_estimates = 0 - for e in all_estimates: + for i,e in enumerate(all_estimates): # estimate is for i+1 if e >= 0: valid_estimate = True + # estimatesmartfee should return the same result + assert_equal(node.estimatesmartfee(i+1)["feerate"], e) + else: invalid_estimates += 1 - # Once we're at a high enough confirmation count that we can give an estimate - # We should have estimates for all higher confirmation counts - if valid_estimate and e < 0: - raise AssertionError("Invalid estimate appears at higher confirm count than valid estimate") + + # estimatesmartfee should still be valid + approx_estimate = node.estimatesmartfee(i+1)["feerate"] + answer_found = node.estimatesmartfee(i+1)["blocks"] + assert(approx_estimate > 0) + assert(answer_found > i+1) + + # Once we're at a high enough confirmation count that we can give an estimate + # We should have estimates for all higher confirmation counts + if valid_estimate: + raise AssertionError("Invalid estimate appears at higher confirm count than valid estimate") + # Check on the expected number of different confirmation counts # that we might not have valid estimates for if invalid_estimates > max_invalid: @@ -184,13 +192,13 @@ class EstimateFeeTest(BitcoinTestFramework): # NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes, # (17k is room enough for 110 or so transactions) self.nodes.append(start_node(1, self.options.tmpdir, - ["-blockprioritysize=1500", "-blockmaxsize=18000", + ["-blockprioritysize=1500", "-blockmaxsize=17000", "-maxorphantx=1000", "-relaypriority=0", "-debug=estimatefee"])) connect_nodes(self.nodes[1], 0) # Node2 is a stingy miner, that - # produces too small blocks (room for only 70 or so transactions) - node2args = ["-blockprioritysize=0", "-blockmaxsize=12000", "-maxorphantx=1000", "-relaypriority=0"] + # produces too small blocks (room for only 55 or so transactions) + node2args = ["-blockprioritysize=0", "-blockmaxsize=8000", "-maxorphantx=1000", "-relaypriority=0"] self.nodes.append(start_node(2, self.options.tmpdir, node2args)) connect_nodes(self.nodes[0], 2) @@ -211,7 +219,7 @@ class EstimateFeeTest(BitcoinTestFramework): from_index = random.randint(1,2) (txhex, fee) = small_txpuzzle_randfee(self.nodes[from_index], self.confutxo, self.memutxo, Decimal("0.005"), min_fee, min_fee) - tx_kbytes = (len(txhex)/2)/1000.0 + tx_kbytes = (len(txhex) // 2) / 1000.0 self.fees_per_kb.append(float(fee)/tx_kbytes) sync_mempools(self.nodes[0:3],.1) mined = mining_node.getblock(mining_node.generate(1)[0],True)["tx"] @@ -229,22 +237,19 @@ class EstimateFeeTest(BitcoinTestFramework): self.fees_per_kb = [] self.memutxo = [] self.confutxo = self.txouts # Start with the set of confirmed txouts after splitting - print("Checking estimates for 1/2/3/6/15/25 blocks") - print("Creating transactions and mining them with a huge block size") - # Create transactions and mine 20 big blocks with node 0 such that the mempool is always emptied - self.transact_and_mine(30, self.nodes[0]) - check_estimates(self.nodes[1], self.fees_per_kb, 1) + print("Will output estimates for 1/2/3/6/15/25 blocks") - print("Creating transactions and mining them with a block size that can't keep up") - # Create transactions and mine 30 small blocks with node 2, but create txs faster than we can mine - self.transact_and_mine(20, self.nodes[2]) - check_estimates(self.nodes[1], self.fees_per_kb, 3) + for i in xrange(2): + print("Creating transactions and mining them with a block size that can't keep up") + # Create transactions and mine 10 small blocks with node 2, but create txs faster than we can mine + self.transact_and_mine(10, self.nodes[2]) + check_estimates(self.nodes[1], self.fees_per_kb, 14) - print("Creating transactions and mining them at a block size that is just big enough") - # Generate transactions while mining 40 more blocks, this time with node1 - # which mines blocks with capacity just above the rate that transactions are being created - self.transact_and_mine(40, self.nodes[1]) - check_estimates(self.nodes[1], self.fees_per_kb, 2) + print("Creating transactions and mining them at a block size that is just big enough") + # Generate transactions while mining 10 more blocks, this time with node1 + # which mines blocks with capacity just above the rate that transactions are being created + self.transact_and_mine(10, self.nodes[1]) + check_estimates(self.nodes[1], self.fees_per_kb, 2) # Finish by mining a normal-sized block: while len(self.nodes[1].getrawmempool()) > 0: diff --git a/qa/rpc-tests/test_framework/authproxy.py b/qa/rpc-tests/test_framework/authproxy.py index 33014dc13..e5f7ab365 100644 --- a/qa/rpc-tests/test_framework/authproxy.py +++ b/qa/rpc-tests/test_framework/authproxy.py @@ -61,7 +61,7 @@ class JSONRPCException(Exception): def EncodeDecimal(o): if isinstance(o, decimal.Decimal): - return round(o, 8) + return str(o) raise TypeError(repr(o) + " is not JSON serializable") class AuthServiceProxy(object): @@ -69,7 +69,7 @@ class AuthServiceProxy(object): def __init__(self, service_url, service_name=None, timeout=HTTP_TIMEOUT, connection=None): self.__service_url = service_url - self.__service_name = service_name + self._service_name = service_name self.__url = urlparse.urlparse(service_url) if self.__url.port is None: port = 80 @@ -92,18 +92,17 @@ class AuthServiceProxy(object): self.__conn = connection elif self.__url.scheme == 'https': self.__conn = httplib.HTTPSConnection(self.__url.hostname, port, - None, None, False, - timeout) + timeout=timeout) else: self.__conn = httplib.HTTPConnection(self.__url.hostname, port, - False, timeout) + timeout=timeout) def __getattr__(self, name): if name.startswith('__') and name.endswith('__'): # Python internal stuff raise AttributeError - if self.__service_name is not None: - name = "%s.%s" % (self.__service_name, name) + if self._service_name is not None: + name = "%s.%s" % (self._service_name, name) return AuthServiceProxy(self.__service_url, name, connection=self.__conn) def _request(self, method, path, postdata): @@ -129,10 +128,10 @@ class AuthServiceProxy(object): def __call__(self, *args): AuthServiceProxy.__id_count += 1 - log.debug("-%s-> %s %s"%(AuthServiceProxy.__id_count, self.__service_name, + log.debug("-%s-> %s %s"%(AuthServiceProxy.__id_count, self._service_name, json.dumps(args, default=EncodeDecimal))) postdata = json.dumps({'version': '1.1', - 'method': self.__service_name, + 'method': self._service_name, 'params': args, 'id': AuthServiceProxy.__id_count}, default=EncodeDecimal) response = self._request('POST', self.__url.path, postdata) @@ -155,6 +154,11 @@ class AuthServiceProxy(object): raise JSONRPCException({ 'code': -342, 'message': 'missing HTTP response from server'}) + content_type = http_response.getheader('Content-Type') + if content_type != 'application/json': + raise JSONRPCException({ + 'code': -342, 'message': 'non-JSON HTTP response with \'%i %s\' from server' % (http_response.status, http_response.reason)}) + responsedata = http_response.read().decode('utf8') response = json.loads(responsedata, parse_float=decimal.Decimal) if "error" in response and response["error"] is None: diff --git a/qa/rpc-tests/test_framework/blockstore.py b/qa/rpc-tests/test_framework/blockstore.py index b9775b477..73d9ffbb2 100644 --- a/qa/rpc-tests/test_framework/blockstore.py +++ b/qa/rpc-tests/test_framework/blockstore.py @@ -3,8 +3,9 @@ # and for constructing a getheaders message # -from mininode import * +from .mininode import * import dbm +from io import BytesIO class BlockStore(object): def __init__(self, datadir): @@ -21,7 +22,7 @@ class BlockStore(object): serialized_block = self.blockDB[repr(blockhash)] except KeyError: return None - f = cStringIO.StringIO(serialized_block) + f = BytesIO(serialized_block) ret = CBlock() ret.deserialize(f) ret.calc_sha256() @@ -115,7 +116,7 @@ class TxStore(object): serialized_tx = self.txDB[repr(txhash)] except KeyError: return None - f = cStringIO.StringIO(serialized_tx) + f = BytesIO(serialized_tx) ret = CTransaction() ret.deserialize(f) ret.calc_sha256() diff --git a/qa/rpc-tests/test_framework/blocktools.py b/qa/rpc-tests/test_framework/blocktools.py index 59aa8c15c..384f40e62 100644 --- a/qa/rpc-tests/test_framework/blocktools.py +++ b/qa/rpc-tests/test_framework/blocktools.py @@ -1,11 +1,11 @@ # blocktools.py - utilities for manipulating blocks and transactions -# +# Copyright (c) 2015 The Bitcoin Core developers # Distributed under the MIT/X11 software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # -from mininode import * -from script import CScript, CScriptOp, OP_TRUE, OP_CHECKSIG +from .mininode import * +from .script import CScript, OP_TRUE, OP_CHECKSIG # Create a block (with regtest difficulty) def create_block(hashprev, coinbase, nTime=None): @@ -29,7 +29,7 @@ def serialize_script_num(value): neg = value < 0 absvalue = -value if neg else value while (absvalue): - r.append(chr(absvalue & 0xff)) + r.append(int(absvalue & 0xff)) absvalue >>= 8 if r[-1] & 0x80: r.append(0x80 if neg else 0) @@ -45,7 +45,7 @@ def create_coinbase(height, pubkey = None): coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff), ser_string(serialize_script_num(height)), 0xffffffff)) coinbaseoutput = CTxOut() - coinbaseoutput.nValue = 50*100000000 + coinbaseoutput.nValue = 50 * COIN halvings = int(height/150) # regtest coinbaseoutput.nValue >>= halvings if (pubkey != None): @@ -62,6 +62,6 @@ def create_transaction(prevtx, n, sig, value): tx = CTransaction() assert(n < len(prevtx.vout)) tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), sig, 0xffffffff)) - tx.vout.append(CTxOut(value, "")) + tx.vout.append(CTxOut(value, b"")) tx.calc_sha256() return tx diff --git a/qa/rpc-tests/test_framework/comptool.py b/qa/rpc-tests/test_framework/comptool.py index e0b3ce040..17626cf8d 100755 --- a/qa/rpc-tests/test_framework/comptool.py +++ b/qa/rpc-tests/test_framework/comptool.py @@ -1,12 +1,12 @@ #!/usr/bin/env python2 -# +# Copyright (c) 2015 The Bitcoin Core developers # Distributed under the MIT/X11 software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # -from mininode import * -from blockstore import BlockStore, TxStore -from util import p2p_port +from .mininode import * +from .blockstore import BlockStore, TxStore +from .util import p2p_port ''' This is a tool for comparing two or more bitcoinds to each other @@ -27,31 +27,32 @@ generator that returns TestInstance objects. See below for definition. global mininode_lock -def wait_until(predicate, attempts=float('inf'), timeout=float('inf')): - attempt = 0 - elapsed = 0 - - while attempt < attempts and elapsed < timeout: - with mininode_lock: - if predicate(): - return True - attempt += 1 - elapsed += 0.05 - time.sleep(0.05) - - return False +class RejectResult(object): + ''' + Outcome that expects rejection of a transaction or block. + ''' + def __init__(self, code, reason=b''): + self.code = code + self.reason = reason + def match(self, other): + if self.code != other.code: + return False + return other.reason.startswith(self.reason) + def __repr__(self): + return '%i:%s' % (self.code,self.reason or '*') class TestNode(NodeConnCB): def __init__(self, block_store, tx_store): NodeConnCB.__init__(self) - self.create_callback_map() self.conn = None self.bestblockhash = None self.block_store = block_store self.block_request_map = {} self.tx_store = tx_store self.tx_request_map = {} + self.block_reject_map = {} + self.tx_reject_map = {} # When the pingmap is non-empty we're waiting for # a response @@ -95,6 +96,12 @@ class TestNode(NodeConnCB): except KeyError: raise AssertionError("Got pong for unknown ping [%s]" % repr(message)) + def on_reject(self, conn, message): + if message.message == b'tx': + self.tx_reject_map[message.data] = RejectResult(message.code, message.reason) + if message.message == b'block': + self.block_reject_map[message.data] = RejectResult(message.code, message.reason) + def send_inv(self, obj): mtype = 2 if isinstance(obj, CBlock) else 1 self.conn.send_message(msg_inv([CInv(mtype, obj.sha256)])) @@ -172,6 +179,10 @@ class TestManager(object): # associated NodeConn test_node.add_connection(self.connections[-1]) + def clear_all_connections(self): + self.connections = [] + self.test_nodes = [] + def wait_for_disconnections(self): def disconnected(): return all(node.closed for node in self.test_nodes) @@ -244,6 +255,15 @@ class TestManager(object): if outcome is None: if c.cb.bestblockhash != self.connections[0].cb.bestblockhash: return False + elif isinstance(outcome, RejectResult): # Check that block was rejected w/ code + if c.cb.bestblockhash == blockhash: + return False + if blockhash not in c.cb.block_reject_map: + print 'Block not in reject map: %064x' % (blockhash) + return False + if not outcome.match(c.cb.block_reject_map[blockhash]): + print 'Block rejected with %s instead of expected %s: %064x' % (c.cb.block_reject_map[blockhash], outcome, blockhash) + return False elif ((c.cb.bestblockhash == blockhash) != outcome): # print c.cb.bestblockhash, blockhash, outcome return False @@ -263,6 +283,15 @@ class TestManager(object): if c.cb.lastInv != self.connections[0].cb.lastInv: # print c.rpc.getrawmempool() return False + elif isinstance(outcome, RejectResult): # Check that tx was rejected w/ code + if txhash in c.cb.lastInv: + return False + if txhash not in c.cb.tx_reject_map: + print 'Tx not in reject map: %064x' % (txhash) + return False + if not outcome.match(c.cb.tx_reject_map[txhash]): + print 'Tx rejected with %s instead of expected %s: %064x' % (c.cb.tx_reject_map[txhash], outcome, txhash) + return False elif ((txhash in c.cb.lastInv) != outcome): # print c.rpc.getrawmempool(), c.cb.lastInv return False diff --git a/qa/rpc-tests/test_framework/coverage.py b/qa/rpc-tests/test_framework/coverage.py new file mode 100644 index 000000000..d21a001b6 --- /dev/null +++ b/qa/rpc-tests/test_framework/coverage.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +""" +This module contains utilities for doing coverage analysis on the RPC +interface. + +It provides a way to track which RPC commands are exercised during +testing. + +""" +import os + + +REFERENCE_FILENAME = 'rpc_interface.txt' + + +class AuthServiceProxyWrapper(object): + """ + An object that wraps AuthServiceProxy to record specific RPC calls. + + """ + def __init__(self, auth_service_proxy_instance, coverage_logfile=None): + """ + Kwargs: + auth_service_proxy_instance (AuthServiceProxy): the instance + being wrapped. + coverage_logfile (str): if specified, write each service_name + out to a file when called. + + """ + self.auth_service_proxy_instance = auth_service_proxy_instance + self.coverage_logfile = coverage_logfile + + def __getattr__(self, *args, **kwargs): + return_val = self.auth_service_proxy_instance.__getattr__( + *args, **kwargs) + + return AuthServiceProxyWrapper(return_val, self.coverage_logfile) + + def __call__(self, *args, **kwargs): + """ + Delegates to AuthServiceProxy, then writes the particular RPC method + called to a file. + + """ + return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs) + rpc_method = self.auth_service_proxy_instance._service_name + + if self.coverage_logfile: + with open(self.coverage_logfile, 'a+') as f: + f.write("%s\n" % rpc_method) + + return return_val + + @property + def url(self): + return self.auth_service_proxy_instance.url + + +def get_filename(dirname, n_node): + """ + Get a filename unique to the test process ID and node. + + This file will contain a list of RPC commands covered. + """ + pid = str(os.getpid()) + return os.path.join( + dirname, "coverage.pid%s.node%s.txt" % (pid, str(n_node))) + + +def write_all_rpc_commands(dirname, node): + """ + Write out a list of all RPC functions available in `bitcoin-cli` for + coverage comparison. This will only happen once per coverage + directory. + + Args: + dirname (str): temporary test dir + node (AuthServiceProxy): client + + Returns: + bool. if the RPC interface file was written. + + """ + filename = os.path.join(dirname, REFERENCE_FILENAME) + + if os.path.isfile(filename): + return False + + help_output = node.help().split('\n') + commands = set() + + for line in help_output: + line = line.strip() + + # Ignore blanks and headers + if line and not line.startswith('='): + commands.add("%s\n" % line.split()[0]) + + with open(filename, 'w') as f: + f.writelines(list(commands)) + + return True diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index b7d78e74f..5ee5b1327 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -20,11 +20,12 @@ import struct import socket import asyncore -import binascii import time import sys import random -import cStringIO +from binascii import hexlify, unhexlify +from io import BytesIO +from codecs import encode import hashlib from threading import RLock from threading import Thread @@ -33,9 +34,12 @@ import copy BIP0031_VERSION = 60000 MY_VERSION = 60001 # past bip-31 for ping/pong -MY_SUBVERSION = "/python-mininode-tester:0.0.1/" +MY_SUBVERSION = b"/python-mininode-tester:0.0.2/" MAX_INV_SZ = 50000 +MAX_BLOCK_SIZE = 1000000 + +COIN = 100000000L # 1 btc in satoshis # Keep our own socket map for asyncore, so that we can track disconnects # ourselves (to workaround an issue with closing an asyncore socket when @@ -72,12 +76,12 @@ def deser_string(f): def ser_string(s): if len(s) < 253: - return chr(len(s)) + s + return struct.pack("B", len(s)) + s elif len(s) < 0x10000: - return chr(253) + struct.pack("H", f.read(2))[0] def serialize(self): - r = "" + r = b"" r += struct.pack(" 21000000L * 100000000L: + if tout.nValue < 0 or tout.nValue > 21000000 * COIN: return False return True @@ -462,7 +474,7 @@ class CBlockHeader(object): self.hash = None def serialize(self): - r = "" + r = b"" r += struct.pack(" target: self.nNonce += 1 @@ -559,9 +571,9 @@ class CUnsignedAlert(object): self.nMaxVer = 0 self.setSubVer = [] self.nPriority = 0 - self.strComment = "" - self.strStatusBar = "" - self.strReserved = "" + self.strComment = b"" + self.strStatusBar = b"" + self.strReserved = b"" def deserialize(self, f): self.nVersion = struct.unpack(" class msg_headers(object): - command = "headers" + command = b"headers" def __init__(self): self.headers = [] @@ -956,11 +982,11 @@ class msg_headers(object): class msg_reject(object): - command = "reject" + command = b"reject" def __init__(self): - self.message = "" - self.code = "" + self.message = b"" + self.code = 0 self.reason = "" self.data = 0L @@ -983,39 +1009,74 @@ class msg_reject(object): return "msg_reject: %s %d %s [%064x]" \ % (self.message, self.code, self.reason, self.data) +# Helper function +def wait_until(predicate, attempts=float('inf'), timeout=float('inf')): + attempt = 0 + elapsed = 0 + + while attempt < attempts and elapsed < timeout: + with mininode_lock: + if predicate(): + return True + attempt += 1 + elapsed += 0.05 + time.sleep(0.05) + + return False + +class msg_feefilter(object): + command = b"feefilter" + + def __init__(self, feerate=0L): + self.feerate = feerate + + def deserialize(self, f): + self.feerate = struct.unpack("= 209: th = sha256(data) @@ -1220,11 +1313,11 @@ class NodeConn(asyncore.dispatcher): self.last_sent = time.time() def got_message(self, message): - if message.command == "version": + if message.command == b"version": if message.nVersion <= BIP0031_VERSION: - self.messagemap['ping'] = msg_ping_prebip31 + self.messagemap[b'ping'] = msg_ping_prebip31 if self.last_sent + 30 * 60 < time.time(): - self.send_message(self.messagemap['ping']()) + self.send_message(self.messagemap[b'ping']()) self.show_debug_msg("Recv %s" % repr(message)) self.cb.deliver(self, message) diff --git a/qa/rpc-tests/test_framework/netutil.py b/qa/rpc-tests/test_framework/netutil.py index b30a88a4f..52a7ab748 100644 --- a/qa/rpc-tests/test_framework/netutil.py +++ b/qa/rpc-tests/test_framework/netutil.py @@ -1,16 +1,17 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # Linux network utilities + import sys import socket import fcntl import struct import array import os -import binascii +from binascii import unhexlify, hexlify # Roughly based on http://voorloopnul.com/blog/a-python-netstat-in-less-than-100-lines-of-code/ by Ricardo Pascal STATE_ESTABLISHED = '01' @@ -43,9 +44,9 @@ def _remove_empty(array): def _convert_ip_port(array): host,port = array.split(':') # convert host from mangled-per-four-bytes form as used by kernel - host = binascii.unhexlify(host) + host = unhexlify(host) host_out = '' - for x in range(0, len(host)/4): + for x in range(0, len(host) // 4): (val,) = struct.unpack('=I', host[x*4:(x+1)*4]) host_out += '%08x' % val @@ -94,7 +95,7 @@ def all_interfaces(): max_possible = 8 # initial value while True: bytes = max_possible * struct_size - names = array.array('B', '\0' * bytes) + names = array.array('B', b'\0' * bytes) outbytes = struct.unpack('iL', fcntl.ioctl( s.fileno(), 0x8912, # SIOCGIFCONF @@ -105,7 +106,7 @@ def all_interfaces(): else: break namestr = names.tostring() - return [(namestr[i:i+16].split('\0', 1)[0], + return [(namestr[i:i+16].split(b'\0', 1)[0], socket.inet_ntoa(namestr[i+20:i+24])) for i in range(0, outbytes, struct_size)] @@ -136,4 +137,19 @@ def addr_to_hex(addr): addr = sub[0] + ([0] * nullbytes) + sub[1] else: raise ValueError('Could not parse address %s' % addr) - return binascii.hexlify(bytearray(addr)) + return hexlify(bytearray(addr)).decode('ascii') + +def test_ipv6_local(): + ''' + Check for (local) IPv6 support. + ''' + import socket + # By using SOCK_DGRAM this will not actually make a connection, but it will + # fail if there is no route to IPv6 localhost. + have_ipv6 = True + try: + s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + s.connect(('::1', 0)) + except socket.error: + have_ipv6 = False + return have_ipv6 diff --git a/qa/rpc-tests/test_framework/script.py b/qa/rpc-tests/test_framework/script.py index 0a78cf6fb..5fb5758f8 100644 --- a/qa/rpc-tests/test_framework/script.py +++ b/qa/rpc-tests/test_framework/script.py @@ -14,7 +14,8 @@ Functionality to build scripts, as well as SignatureHash(). from __future__ import absolute_import, division, print_function, unicode_literals -from test_framework.mininode import CTransaction, CTxOut, hash256 +from .mininode import CTransaction, CTxOut, hash256 +from binascii import hexlify import sys bchr = chr @@ -24,10 +25,9 @@ if sys.version > '3': bchr = lambda x: bytes([x]) bord = lambda x: x -import copy import struct -from test_framework.bignum import bn2vch +from .bignum import bn2vch MAX_SCRIPT_SIZE = 10000 MAX_SCRIPT_ELEMENT_SIZE = 520 @@ -226,7 +226,7 @@ OP_CHECKMULTISIGVERIFY = CScriptOp(0xaf) # expansion OP_NOP1 = CScriptOp(0xb0) -OP_NOP2 = CScriptOp(0xb1) +OP_CHECKLOCKTIMEVERIFY = CScriptOp(0xb1) OP_NOP3 = CScriptOp(0xb2) OP_NOP4 = CScriptOp(0xb3) OP_NOP5 = CScriptOp(0xb4) @@ -353,7 +353,7 @@ VALID_OPCODES = { OP_CHECKMULTISIGVERIFY, OP_NOP1, - OP_NOP2, + OP_CHECKLOCKTIMEVERIFY, OP_NOP3, OP_NOP4, OP_NOP5, @@ -472,7 +472,7 @@ OPCODE_NAMES.update({ OP_CHECKMULTISIG : 'OP_CHECKMULTISIG', OP_CHECKMULTISIGVERIFY : 'OP_CHECKMULTISIGVERIFY', OP_NOP1 : 'OP_NOP1', - OP_NOP2 : 'OP_NOP2', + OP_CHECKLOCKTIMEVERIFY : 'OP_CHECKLOCKTIMEVERIFY', OP_NOP3 : 'OP_NOP3', OP_NOP4 : 'OP_NOP4', OP_NOP5 : 'OP_NOP5', @@ -591,7 +591,7 @@ OPCODES_BY_NAME = { 'OP_CHECKMULTISIG' : OP_CHECKMULTISIG, 'OP_CHECKMULTISIGVERIFY' : OP_CHECKMULTISIGVERIFY, 'OP_NOP1' : OP_NOP1, - 'OP_NOP2' : OP_NOP2, + 'OP_CHECKLOCKTIMEVERIFY' : OP_CHECKLOCKTIMEVERIFY, 'OP_NOP3' : OP_NOP3, 'OP_NOP4' : OP_NOP4, 'OP_NOP5' : OP_NOP5, @@ -629,7 +629,7 @@ class CScriptNum(object): neg = obj.value < 0 absvalue = -obj.value if neg else obj.value while (absvalue): - r.append(chr(absvalue & 0xff)) + r.append(absvalue & 0xff) absvalue >>= 8 if r[-1] & 0x80: r.append(0x80 if neg else 0) @@ -777,7 +777,7 @@ class CScript(bytes): # need to change def _repr(o): if isinstance(o, bytes): - return "x('%s')" % binascii.hexlify(o).decode('utf8') + return b"x('%s')" % hexlify(o).decode('ascii') else: return repr(o) diff --git a/qa/rpc-tests/test_framework/socks5.py b/qa/rpc-tests/test_framework/socks5.py index 1dbfb98d5..f725d9770 100644 --- a/qa/rpc-tests/test_framework/socks5.py +++ b/qa/rpc-tests/test_framework/socks5.py @@ -102,7 +102,7 @@ class Socks5Connection(object): addr = recvall(self.conn, 4) elif atyp == AddressType.DOMAINNAME: n = recvall(self.conn, 1)[0] - addr = str(recvall(self.conn, n)) + addr = recvall(self.conn, n) elif atyp == AddressType.IPV6: addr = recvall(self.conn, 16) else: @@ -117,7 +117,7 @@ class Socks5Connection(object): self.serv.queue.put(cmdin) print('Proxy: ', cmdin) # Fall through to disconnect - except Exception,e: + except Exception as e: traceback.print_exc(file=sys.stderr) self.serv.queue.put(e) finally: diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py index 5671431f6..3b08cd138 100755 --- a/qa/rpc-tests/test_framework/test_framework.py +++ b/qa/rpc-tests/test_framework/test_framework.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,8 +13,20 @@ import shutil import tempfile import traceback -from authproxy import AuthServiceProxy, JSONRPCException -from util import * +from .util import ( + initialize_chain, + assert_equal, + start_nodes, + connect_nodes_bi, + sync_blocks, + sync_mempools, + stop_nodes, + wait_bitcoinds, + enable_coverage, + check_json_precision, + initialize_chain_clean, +) +from .authproxy import AuthServiceProxy, JSONRPCException class BitcoinTestFramework(object): @@ -96,6 +108,8 @@ class BitcoinTestFramework(object): help="Root directory for datadirs") parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true", help="Print out all RPC calls as they are made") + parser.add_option("--coveragedir", dest="coveragedir", + help="Write tested RPC commands into this directory") self.add_options(parser) (self.options, self.args) = parser.parse_args() @@ -103,7 +117,10 @@ class BitcoinTestFramework(object): import logging logging.basicConfig(level=logging.DEBUG) - os.environ['PATH'] = self.options.srcdir+":"+os.environ['PATH'] + if self.options.coveragedir: + enable_coverage(self.options.coveragedir) + + os.environ['PATH'] = self.options.srcdir+":"+self.options.srcdir+"/qt:"+os.environ['PATH'] check_json_precision() @@ -123,7 +140,10 @@ class BitcoinTestFramework(object): print("JSONRPC error: "+e.error['message']) traceback.print_tb(sys.exc_info()[2]) except AssertionError as e: - print("Assertion failed: "+e.message) + print("Assertion failed: "+ str(e)) + traceback.print_tb(sys.exc_info()[2]) + except KeyError as e: + print("key not found: "+ str(e)) traceback.print_tb(sys.exc_info()[2]) except Exception as e: print("Unexpected exception caught during testing: "+str(e)) @@ -173,7 +193,8 @@ class ComparisonTestFramework(BitcoinTestFramework): initialize_chain_clean(self.options.tmpdir, self.num_nodes) def setup_network(self): - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[['-debug', '-whitelist=127.0.0.1']] * self.num_nodes, - binary=[self.options.testbinary] + - [self.options.refbinary]*(self.num_nodes-1)) + self.nodes = start_nodes( + self.num_nodes, self.options.tmpdir, + extra_args=[['-debug', '-whitelist=127.0.0.1']] * self.num_nodes, + binary=[self.options.testbinary] + + [self.options.refbinary]*(self.num_nodes-1)) diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index c61260a14..977525746 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -1,6 +1,8 @@ -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. + + # # Helpful routines for regression testing # @@ -9,6 +11,8 @@ import os import sys +from binascii import hexlify, unhexlify +from base64 import b64encode from decimal import Decimal, ROUND_DOWN import json import random @@ -16,9 +20,65 @@ import shutil import subprocess import time import re +import errno + +from . import coverage +from .authproxy import AuthServiceProxy, JSONRPCException + +COVERAGE_DIR = None + +#Set Mocktime default to OFF. +#MOCKTIME is only needed for scripts that use the +#cached version of the blockchain. If the cached +#version of the blockchain is used without MOCKTIME +#then the mempools will not sync due to IBD. +MOCKTIME = 0 + +def enable_mocktime(): + #For backwared compatibility of the python scripts + #with previous versions of the cache, set MOCKTIME + #to Jan 1, 2014 + (201 * 10 * 60) + global MOCKTIME + MOCKTIME = 1388534400 + (201 * 10 * 60) + +def disable_mocktime(): + global MOCKTIME + MOCKTIME = 0 + +def get_mocktime(): + return MOCKTIME + +def enable_coverage(dirname): + """Maintain a log of which RPC calls are made during testing.""" + global COVERAGE_DIR + COVERAGE_DIR = dirname + + +def get_rpc_proxy(url, node_number, timeout=None): + """ + Args: + url (str): URL of the RPC server to call + node_number (int): the node number (or id) that this calls to + + Kwargs: + timeout (int): HTTP timeout in seconds + + Returns: + AuthServiceProxy. convenience object for making RPC calls. + + """ + proxy_kwargs = {} + if timeout is not None: + proxy_kwargs['timeout'] = timeout + + proxy = AuthServiceProxy(url, **proxy_kwargs) + proxy.url = url # store URL on proxy for info + + coverage_logfile = coverage.get_filename( + COVERAGE_DIR, node_number) if COVERAGE_DIR else None + + return coverage.AuthServiceProxyWrapper(proxy, coverage_logfile) -from authproxy import AuthServiceProxy, JSONRPCException -from util import * def p2p_port(n): return 11000 + n + os.getpid()%999 @@ -32,6 +92,18 @@ def check_json_precision(): if satoshis != 2000000000000003: raise RuntimeError("JSON encode/decode loses precision") +def count_bytes(hex_string): + return len(bytearray.fromhex(hex_string)) + +def bytes_to_hex_str(byte_str): + return hexlify(byte_str).decode('ascii') + +def hex_str_to_bytes(hex_str): + return unhexlify(hex_str.encode('ascii')) + +def str_to_b64str(string): + return b64encode(string.encode('utf-8')).decode('ascii') + def sync_blocks(rpc_connections, wait=1): """ Wait until everybody has the same block count @@ -69,54 +141,75 @@ def initialize_datadir(dirname, n): f.write("rpcpassword=rt\n"); f.write("port="+str(p2p_port(n))+"\n"); f.write("rpcport="+str(rpc_port(n))+"\n"); + f.write("listenonion=0\n") return datadir +def rpc_url(i, rpchost=None): + return "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i)) + +def wait_for_bitcoind_start(process, url, i): + ''' + Wait for bitcoind to start. This means that RPC is accessible and fully initialized. + Raise an exception if bitcoind exits during initialization. + ''' + while True: + if process.poll() is not None: + raise Exception('bitcoind exited with status %i during initialization' % process.returncode) + try: + rpc = get_rpc_proxy(url, i) + blocks = rpc.getblockcount() + break # break out of loop on success + except IOError as e: + if e.errno != errno.ECONNREFUSED: # Port not yet open? + raise # unknown IO error + except JSONRPCException as e: # Initialization phase + if e.error['code'] != -28: # RPC in warmup? + raise # unkown JSON RPC exception + time.sleep(0.25) + def initialize_chain(test_dir): """ Create (or copy from cache) a 200-block-long chain and 4 wallets. - bitcoind and bitcoin-cli must be in search path. """ if (not os.path.isdir(os.path.join("cache","node0")) - or not os.path.isdir(os.path.join("cache","node1")) - or not os.path.isdir(os.path.join("cache","node2")) + or not os.path.isdir(os.path.join("cache","node1")) + or not os.path.isdir(os.path.join("cache","node2")) or not os.path.isdir(os.path.join("cache","node3"))): #find and delete old cache directories if any exist for i in range(4): - if os.path.isdir(os.path.join("cache","node"+str(i))): + if os.path.isdir(os.path.join("cache","node"+str(i))): shutil.rmtree(os.path.join("cache","node"+str(i))) - devnull = open(os.devnull, "w") # Create cache directories, run bitcoinds: for i in range(4): datadir=initialize_datadir("cache", i) - args = [ os.getenv("BITCOIND", "bitcoind"), "-keypool=1", "-datadir="+datadir, "-discover=0" ] + args = [ os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir="+datadir, "-discover=0" ] if i > 0: args.append("-connect=127.0.0.1:"+str(p2p_port(0))) bitcoind_processes[i] = subprocess.Popen(args) if os.getenv("PYTHON_DEBUG", ""): - print "initialize_chain: bitcoind started, calling bitcoin-cli -rpcwait getblockcount" - subprocess.check_call([ os.getenv("BITCOINCLI", "bitcoin-cli"), "-datadir="+datadir, - "-rpcwait", "getblockcount"], stdout=devnull) + print "initialize_chain: bitcoind started, waiting for RPC to come up" + wait_for_bitcoind_start(bitcoind_processes[i], rpc_url(i), i) if os.getenv("PYTHON_DEBUG", ""): - print "initialize_chain: bitcoin-cli -rpcwait getblockcount completed" - devnull.close() + print "initialize_chain: RPC succesfully started" + rpcs = [] for i in range(4): try: - url = "http://rt:rt@127.0.0.1:%d"%(rpc_port(i),) - rpcs.append(AuthServiceProxy(url)) + rpcs.append(get_rpc_proxy(rpc_url(i), i)) except: sys.stderr.write("Error connecting to "+url+"\n") sys.exit(1) # Create a 200-block-long chain; each of the 4 nodes # gets 25 mature blocks and 25 immature. - # blocks are created with timestamps 10 minutes apart, starting - # at 1 Jan 2014 - block_time = 1388534400 + # blocks are created with timestamps 10 minutes apart + # starting from 2010 minutes in the past + enable_mocktime() + block_time = get_mocktime() - (201 * 10 * 60) for i in range(2): for peer in range(4): for j in range(25): @@ -129,6 +222,7 @@ def initialize_chain(test_dir): # Shut them down, and clean up cache directories: stop_nodes(rpcs) wait_bitcoinds() + disable_mocktime() for i in range(4): os.remove(log_filename("cache", i, "debug.log")) os.remove(log_filename("cache", i, "db.log")) @@ -177,24 +271,20 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary= datadir = os.path.join(dirname, "node"+str(i)) if binary is None: binary = os.getenv("BITCOIND", "bitcoind") - args = [ binary, "-datadir="+datadir, "-keypool=1", "-discover=0", "-rest" ] + args = [ binary, "-datadir="+datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-mocktime="+str(get_mocktime()) ] if extra_args is not None: args.extend(extra_args) bitcoind_processes[i] = subprocess.Popen(args) - devnull = open(os.devnull, "w") if os.getenv("PYTHON_DEBUG", ""): - print "start_node: bitcoind started, calling bitcoin-cli -rpcwait getblockcount" - subprocess.check_call([ os.getenv("BITCOINCLI", "bitcoin-cli"), "-datadir="+datadir] + - _rpchost_to_args(rpchost) + - ["-rpcwait", "getblockcount"], stdout=devnull) + print "start_node: bitcoind started, waiting for RPC to come up" + url = rpc_url(i, rpchost) + wait_for_bitcoind_start(bitcoind_processes[i], url, i) if os.getenv("PYTHON_DEBUG", ""): - print "start_node: calling bitcoin-cli -rpcwait getblockcount returned" - devnull.close() - url = "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i)) - if timewait is not None: - proxy = AuthServiceProxy(url, timeout=timewait) - else: - proxy = AuthServiceProxy(url) - proxy.url = url # store URL on proxy for info + print "start_node: RPC succesfully started" + proxy = get_rpc_proxy(url, i, timeout=timewait) + + if COVERAGE_DIR: + coverage.write_all_rpc_commands(COVERAGE_DIR, proxy) + return proxy def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None): @@ -203,7 +293,14 @@ def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None): """ if extra_args is None: extra_args = [ None for i in range(num_nodes) ] if binary is None: binary = [ None for i in range(num_nodes) ] - return [ start_node(i, dirname, extra_args[i], rpchost, binary=binary[i]) for i in range(num_nodes) ] + rpcs = [] + try: + for i in range(num_nodes): + rpcs.append(start_node(i, dirname, extra_args[i], rpchost, binary=binary[i])) + except: # If one node failed to start, stop the others + stop_nodes(rpcs) + raise + return rpcs def log_filename(dirname, n_node, logname): return os.path.join(dirname, "node"+str(n_node), "regtest", logname) @@ -363,3 +460,105 @@ def assert_raises(exc, fun, *args, **kwds): raise AssertionError("Unexpected exception raised: "+type(e).__name__) else: raise AssertionError("No exception raised") + +def assert_is_hex_string(string): + try: + int(string, 16) + except Exception as e: + raise AssertionError( + "Couldn't interpret %r as hexadecimal; raised: %s" % (string, e)) + +def assert_is_hash_string(string, length=64): + if not isinstance(string, basestring): + raise AssertionError("Expected a string, got type %r" % type(string)) + elif length and len(string) != length: + raise AssertionError( + "String of length %d expected; got %d" % (length, len(string))) + elif not re.match('[abcdef0-9]+$', string): + raise AssertionError( + "String %r contains invalid characters for a hash." % string) + +def satoshi_round(amount): + return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) + +# Helper to create at least "count" utxos +# Pass in a fee that is sufficient for relay and mining new transactions. +def create_confirmed_utxos(fee, node, count): + node.generate(int(0.5*count)+101) + utxos = node.listunspent() + iterations = count - len(utxos) + addr1 = node.getnewaddress() + addr2 = node.getnewaddress() + if iterations <= 0: + return utxos + for i in xrange(iterations): + t = utxos.pop() + inputs = [] + inputs.append({ "txid" : t["txid"], "vout" : t["vout"]}) + outputs = {} + send_value = t['amount'] - fee + outputs[addr1] = satoshi_round(send_value/2) + outputs[addr2] = satoshi_round(send_value/2) + raw_tx = node.createrawtransaction(inputs, outputs) + signed_tx = node.signrawtransaction(raw_tx)["hex"] + txid = node.sendrawtransaction(signed_tx) + + while (node.getmempoolinfo()['size'] > 0): + node.generate(1) + + utxos = node.listunspent() + assert(len(utxos) >= count) + return utxos + +# Create large OP_RETURN txouts that can be appended to a transaction +# to make it large (helper for constructing large transactions). +def gen_return_txouts(): + # Some pre-processing to create a bunch of OP_RETURN txouts to insert into transactions we create + # So we have big transactions (and therefore can't fit very many into each block) + # create one script_pubkey + script_pubkey = "6a4d0200" #OP_RETURN OP_PUSH2 512 bytes + for i in xrange (512): + script_pubkey = script_pubkey + "01" + # concatenate 128 txouts of above script_pubkey which we'll insert before the txout for change + txouts = "81" + for k in xrange(128): + # add txout value + txouts = txouts + "0000000000000000" + # add length of script_pubkey + txouts = txouts + "fd0402" + # add script_pubkey + txouts = txouts + script_pubkey + return txouts + +def create_tx(node, coinbase, to_address, amount): + inputs = [{ "txid" : coinbase, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + signresult = node.signrawtransaction(rawtx) + assert_equal(signresult["complete"], True) + return signresult["hex"] + +# Create a spend of each passed-in utxo, splicing in "txouts" to each raw +# transaction to make it large. See gen_return_txouts() above. +def create_lots_of_big_transactions(node, txouts, utxos, fee): + addr = node.getnewaddress() + txids = [] + for i in xrange(len(utxos)): + t = utxos.pop() + inputs = [] + inputs.append({ "txid" : t["txid"], "vout" : t["vout"]}) + outputs = {} + send_value = t['amount'] - fee + outputs[addr] = satoshi_round(send_value) + rawtx = node.createrawtransaction(inputs, outputs) + newtx = rawtx[0:92] + newtx = newtx + txouts + newtx = newtx + rawtx[94:] + signresult = node.signrawtransaction(newtx, None, None, "NONE") + txid = node.sendrawtransaction(signresult["hex"], True) + txids.append(txid) + return txids + +def get_bip9_status(node, key): + info = node.getblockchaininfo() + return info['bip9_softforks'][key] diff --git a/qa/rpc-tests/txn_clone.py b/qa/rpc-tests/txn_clone.py index e8ced0e5b..b132aec4b 100755 --- a/qa/rpc-tests/txn_clone.py +++ b/qa/rpc-tests/txn_clone.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,11 +8,7 @@ # from test_framework.test_framework import BitcoinTestFramework -from test_framework.authproxy import AuthServiceProxy, JSONRPCException -from decimal import Decimal from test_framework.util import * -import os -import shutil class TxnMallTest(BitcoinTestFramework): @@ -57,16 +53,10 @@ class TxnMallTest(BitcoinTestFramework): clone_inputs = [{"txid":rawtx1["vin"][0]["txid"],"vout":rawtx1["vin"][0]["vout"]}] clone_outputs = {rawtx1["vout"][0]["scriptPubKey"]["addresses"][0]:rawtx1["vout"][0]["value"], rawtx1["vout"][1]["scriptPubKey"]["addresses"][0]:rawtx1["vout"][1]["value"]} - clone_raw = self.nodes[0].createrawtransaction(clone_inputs, clone_outputs) + clone_locktime = rawtx1["locktime"] + clone_raw = self.nodes[0].createrawtransaction(clone_inputs, clone_outputs, clone_locktime) - # 3 hex manipulations on the clone are required - - # manipulation 1. sequence is at version+#inputs+input+sigstub - posseq = 2*(4+1+36+1) - seqbe = '%08x' % rawtx1["vin"][0]["sequence"] - clone_raw = clone_raw[:posseq] + seqbe[6:8] + seqbe[4:6] + seqbe[2:4] + seqbe[0:2] + clone_raw[posseq + 8:] - - # manipulation 2. createrawtransaction randomizes the order of its outputs, so swap them if necessary. + # createrawtransaction randomizes the order of its outputs, so swap them if necessary. # output 0 is at version+#inputs+input+sigstub+sequence+#outputs # 40 BTC serialized is 00286bee00000000 pos0 = 2*(4+1+36+1+4+1) @@ -78,11 +68,6 @@ class TxnMallTest(BitcoinTestFramework): output1 = clone_raw[pos0 + output_len : pos0 + 2 * output_len] clone_raw = clone_raw[:pos0] + output1 + output0 + clone_raw[pos0 + 2 * output_len:] - # manipulation 3. locktime is after outputs - poslt = pos0 + 2 * output_len - ltbe = '%08x' % rawtx1["locktime"] - clone_raw = clone_raw[:poslt] + ltbe[6:8] + ltbe[4:6] + ltbe[2:4] + ltbe[0:2] + clone_raw[poslt + 8:] - # Use a different signature hash type to sign. This creates an equivalent but malleated clone. # Don't send the clone anywhere yet tx1_clone = self.nodes[0].signrawtransaction(clone_raw, None, None, "ALL|ANYONECANPAY") @@ -136,7 +121,7 @@ class TxnMallTest(BitcoinTestFramework): tx2 = self.nodes[0].gettransaction(txid2) # Verify expected confirmations - assert_equal(tx1["confirmations"], -1) + assert_equal(tx1["confirmations"], -2) assert_equal(tx1_clone["confirmations"], 2) assert_equal(tx2["confirmations"], 1) diff --git a/qa/rpc-tests/txn_doublespend.py b/qa/rpc-tests/txn_doublespend.py index 36081127b..8d7f6e505 100755 --- a/qa/rpc-tests/txn_doublespend.py +++ b/qa/rpc-tests/txn_doublespend.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,9 +9,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -from decimal import Decimal -import os -import shutil class TxnMallTest(BitcoinTestFramework): @@ -99,7 +96,7 @@ class TxnMallTest(BitcoinTestFramework): # Now give doublespend and its parents to miner: self.nodes[2].sendrawtransaction(fund_foo_tx["hex"]) self.nodes[2].sendrawtransaction(fund_bar_tx["hex"]) - self.nodes[2].sendrawtransaction(doublespend["hex"]) + doublespend_txid = self.nodes[2].sendrawtransaction(doublespend["hex"]) # ... mine a block... self.nodes[2].generate(1) @@ -107,14 +104,15 @@ class TxnMallTest(BitcoinTestFramework): connect_nodes(self.nodes[1], 2) self.nodes[2].generate(1) # Mine another block to make sure we sync sync_blocks(self.nodes) + assert_equal(self.nodes[0].gettransaction(doublespend_txid)["confirmations"], 2) # Re-fetch transaction info: tx1 = self.nodes[0].gettransaction(txid1) tx2 = self.nodes[0].gettransaction(txid2) - + # Both transactions should be conflicted - assert_equal(tx1["confirmations"], -1) - assert_equal(tx2["confirmations"], -1) + assert_equal(tx1["confirmations"], -2) + assert_equal(tx2["confirmations"], -2) # Node0's total balance should be starting balance, plus 100BTC for # two more matured blocks, minus 1240 for the double-spend, plus fees (which are diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index f9ec6f429..8fdcea50b 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -1,29 +1,24 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -# -# Exercise the wallet. Ported from wallet.sh. -# Does the following: -# a) creates 3 nodes, with an empty chain (no blocks). -# b) node0 mines a block -# c) node1 mines 101 blocks, so now nodes 0 and 1 have 50btc, node2 has none. -# d) node0 sends 21 btc to node2, in two transactions (11 btc, then 10 btc). -# e) node0 mines a block, collects the fee on the second transaction -# f) node1 mines 100 blocks, to mature node0's just-mined block -# g) check that node0 has 100-21, node2 has 21 -# h) node0 should now have 2 unspent outputs; send these to node2 via raw tx broadcast by node1 -# i) have node1 mine a block -# j) check balances - node0 should have 0, node2 should have 100 -# k) test ResendWalletTransactions - create transactions, startup fourth node, make sure it syncs -# - from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class WalletTest (BitcoinTestFramework): + def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size): + """Return curr_balance after asserting the fee was in range""" + fee = balance_with_fee - curr_balance + target_fee = fee_per_byte * tx_size + if fee < target_fee: + raise AssertionError("Fee of %s BTC too low! (Should be %s BTC)"%(str(fee), str(target_fee))) + # allow the node's estimation to be at most 2 bytes off + if fee > fee_per_byte * (tx_size + 2): + raise AssertionError("Fee of %s BTC too high! (Should be %s BTC)"%(str(fee), str(target_fee))) + return curr_balance + def setup_chain(self): print("Initializing test directory "+self.options.tmpdir) initialize_chain_clean(self.options.tmpdir, 4) @@ -54,7 +49,6 @@ class WalletTest (BitcoinTestFramework): assert_equal(self.nodes[2].getbalance(), 0) # Send 21 BTC from 0 to 2 using sendtoaddress call. - # Second transaction will be child of first, and will require a fee self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) @@ -65,6 +59,15 @@ class WalletTest (BitcoinTestFramework): self.nodes[0].generate(1) self.sync_all() + # Exercise locking of unspent outputs + unspent_0 = self.nodes[2].listunspent()[0] + unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} + self.nodes[2].lockunspent(False, [unspent_0]) + assert_raises(JSONRPCException, self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) + assert_equal([unspent_0], self.nodes[2].listlockunspent()) + self.nodes[2].lockunspent(True, [unspent_0]) + assert_equal(len(self.nodes[2].listlockunspent()), 0) + # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) self.sync_all() @@ -86,7 +89,7 @@ class WalletTest (BitcoinTestFramework): inputs = [] outputs = {} inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]}) - outputs[self.nodes[2].getnewaddress("from1")] = utxo["amount"] + outputs[self.nodes[2].getnewaddress("from1")] = utxo["amount"] - 3 raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) txns_to_send.append(self.nodes[0].signrawtransaction(raw_tx)) @@ -99,38 +102,42 @@ class WalletTest (BitcoinTestFramework): self.sync_all() assert_equal(self.nodes[0].getbalance(), 0) - assert_equal(self.nodes[2].getbalance(), 100) - assert_equal(self.nodes[2].getbalance("from1"), 100-21) + assert_equal(self.nodes[2].getbalance(), 94) + assert_equal(self.nodes[2].getbalance("from1"), 94-21) # Send 10 BTC normal address = self.nodes[0].getnewaddress("test") - self.nodes[2].settxfee(Decimal('0.001')) + fee_per_byte = Decimal('0.001') / 1000 + self.nodes[2].settxfee(fee_per_byte * 1000) txid = self.nodes[2].sendtoaddress(address, 10, "", "", False) self.nodes[2].generate(1) self.sync_all() - assert_equal(self.nodes[2].getbalance(), Decimal('89.99900000')) - assert_equal(self.nodes[0].getbalance(), Decimal('10.00000000')) + node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) + assert_equal(self.nodes[0].getbalance(), Decimal('10')) # Send 10 BTC with subtract fee from amount txid = self.nodes[2].sendtoaddress(address, 10, "", "", True) self.nodes[2].generate(1) self.sync_all() - assert_equal(self.nodes[2].getbalance(), Decimal('79.99900000')) - assert_equal(self.nodes[0].getbalance(), Decimal('19.99900000')) + node_2_bal -= Decimal('10') + assert_equal(self.nodes[2].getbalance(), node_2_bal) + node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) # Sendmany 10 BTC txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", []) self.nodes[2].generate(1) self.sync_all() - assert_equal(self.nodes[2].getbalance(), Decimal('69.99800000')) - assert_equal(self.nodes[0].getbalance(), Decimal('29.99900000')) + node_0_bal += Decimal('10') + node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) + assert_equal(self.nodes[0].getbalance(), node_0_bal) # Sendmany 10 BTC with subtract fee from amount txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", [address]) self.nodes[2].generate(1) self.sync_all() - assert_equal(self.nodes[2].getbalance(), Decimal('59.99800000')) - assert_equal(self.nodes[0].getbalance(), Decimal('39.99800000')) + node_2_bal -= Decimal('10') + assert_equal(self.nodes[2].getbalance(), node_2_bal) + node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) # Test ResendWalletTransactions: # Create a couple of transactions, then start up a fourth @@ -145,11 +152,15 @@ class WalletTest (BitcoinTestFramework): sync_blocks(self.nodes) relayed = self.nodes[0].resendwallettransactions() - assert_equal(set(relayed), set([txid1, txid2])) + assert_equal(set(relayed), {txid1, txid2}) sync_mempools(self.nodes) assert(txid1 in self.nodes[3].getrawmempool()) + # Exercise balance rpcs + assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], 1) + assert_equal(self.nodes[0].getunconfirmedbalance(), 1) + #check if we can list zero value tx as available coins #1. create rawtx #2. hex-changed one output to 0.0 @@ -175,7 +186,7 @@ class WalletTest (BitcoinTestFramework): for uTx in unspentTxs: if uTx['txid'] == zeroValueTxid: found = True - assert_equal(uTx['amount'], Decimal('0.00000000')); + assert_equal(uTx['amount'], Decimal('0')) assert(found) #do some -walletbroadcast tests @@ -187,21 +198,22 @@ class WalletTest (BitcoinTestFramework): connect_nodes_bi(self.nodes,0,2) self.sync_all() - txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2); + txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) self.nodes[1].generate(1) #mine a block, tx should not be in there self.sync_all() - assert_equal(self.nodes[2].getbalance(), Decimal('59.99800000')); #should not be changed because tx was not broadcasted + assert_equal(self.nodes[2].getbalance(), node_2_bal) #should not be changed because tx was not broadcasted #now broadcast from another node, mine a block, sync, and check the balance self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex']) self.nodes[1].generate(1) self.sync_all() + node_2_bal += 2 txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) - assert_equal(self.nodes[2].getbalance(), Decimal('61.99800000')); #should not be + assert_equal(self.nodes[2].getbalance(), node_2_bal) #create another tx - txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2); + txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) #restart the nodes with -walletbroadcast=1 stop_nodes(self.nodes) @@ -214,41 +226,79 @@ class WalletTest (BitcoinTestFramework): self.nodes[0].generate(1) sync_blocks(self.nodes) + node_2_bal += 2 #tx should be added to balance because after restarting the nodes tx should be broadcastet - assert_equal(self.nodes[2].getbalance(), Decimal('63.99800000')); #should not be + assert_equal(self.nodes[2].getbalance(), node_2_bal) #send a tx with value in a string (PR#6380 +) txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2") txObj = self.nodes[0].gettransaction(txId) - assert_equal(txObj['amount'], Decimal('-2.00000000')) + assert_equal(txObj['amount'], Decimal('-2')) txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.0001") txObj = self.nodes[0].gettransaction(txId) - assert_equal(txObj['amount'], Decimal('-0.00010000')) + assert_equal(txObj['amount'], Decimal('-0.0001')) #check if JSON parser can handle scientific notation in strings txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1e-4") txObj = self.nodes[0].gettransaction(txId) - assert_equal(txObj['amount'], Decimal('-0.00010000')) + assert_equal(txObj['amount'], Decimal('-0.0001')) - #this should fail - errorString = "" try: txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1f-4") - except JSONRPCException,e: - errorString = e.error['message'] + except JSONRPCException as e: + assert("Invalid amount" in e.error['message']) + else: + raise AssertionError("Must not parse invalid amounts") - assert_equal("Invalid amount" in errorString, True); - errorString = "" try: - self.nodes[0].generate("2") #use a string to as block amount parameter must fail because it's not interpreted as amount - except JSONRPCException,e: - errorString = e.error['message'] + self.nodes[0].generate("2") + raise AssertionError("Must not accept strings as numeric") + except JSONRPCException as e: + assert("not an integer" in e.error['message']) - assert_equal("not an integer" in errorString, True); + # Mine a block from node0 to an address from node1 + cbAddr = self.nodes[1].getnewaddress() + blkHash = self.nodes[0].generatetoaddress(1, cbAddr)[0] + cbTxId = self.nodes[0].getblock(blkHash)['tx'][0] + self.sync_all() + + # Check that the txid and balance is found by node1 + self.nodes[1].gettransaction(cbTxId) + + #check if wallet or blochchain maintenance changes the balance + self.sync_all() + blocks = self.nodes[0].generate(2) + self.sync_all() + balance_nodes = [self.nodes[i].getbalance() for i in range(3)] + block_count = self.nodes[0].getblockcount() + + maintenance = [ + '-rescan', + '-reindex', + '-zapwallettxes=1', + '-zapwallettxes=2', + '-salvagewallet', + ] + for m in maintenance: + print "check " + m + stop_nodes(self.nodes) + wait_bitcoinds() + self.nodes = start_nodes(3, self.options.tmpdir, [[m]] * 3) + while m == '-reindex' and [block_count] * 3 != [self.nodes[i].getblockcount() for i in range(3)]: + # reindex will leave rpc warm up "early"; Wait for it to finish + time.sleep(0.1) + assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) + + # Exercise listsinceblock with the last two blocks + coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0]) + assert_equal(coinbase_tx_1["lastblock"], blocks[1]) + assert_equal(len(coinbase_tx_1["transactions"]), 1) + assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) + assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0) if __name__ == '__main__': WalletTest ().main () diff --git a/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py index da100d7fc..1221a0911 100755 --- a/qa/rpc-tests/walletbackup.py +++ b/qa/rpc-tests/walletbackup.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/qa/rpc-tests/zapwallettxes.py b/qa/rpc-tests/zapwallettxes.py index 0ec8ec536..1ba4ded24 100755 --- a/qa/rpc-tests/zapwallettxes.py +++ b/qa/rpc-tests/zapwallettxes.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2014 The Bitcoin Core developers +# Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -65,14 +65,8 @@ class ZapWalletTXesTest (BitcoinTestFramework): #restart bitcoind with zapwallettxes self.nodes[0] = start_node(0,self.options.tmpdir, ["-zapwallettxes=1"]) - aException = False - try: - tx3 = self.nodes[0].gettransaction(txid3) - except JSONRPCException,e: - print e - aException = True - - assert_equal(aException, True) #there must be a expection because the unconfirmed wallettx0 must be gone by now + assert_raises(JSONRPCException, self.nodes[0].gettransaction, [txid3]) + #there must be a expection because the unconfirmed wallettx0 must be gone by now tx0 = self.nodes[0].gettransaction(txid0) assert_equal(tx0['txid'], txid0) #tx0 (confirmed) must still be available because it was confirmed diff --git a/qa/rpc-tests/zmq_test.py b/qa/rpc-tests/zmq_test.py index bcb132321..3a8d62ef2 100755 --- a/qa/rpc-tests/zmq_test.py +++ b/qa/rpc-tests/zmq_test.py @@ -11,7 +11,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * import zmq import binascii -from test_framework.mininode import hash256 try: import http.client as httplib @@ -29,8 +28,8 @@ class ZMQTest (BitcoinTestFramework): def setup_nodes(self): self.zmqContext = zmq.Context() self.zmqSubSocket = self.zmqContext.socket(zmq.SUB) - self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "hashblock") - self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "hashtx") + self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock") + self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx") self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % self.port) return start_nodes(4, self.options.tmpdir, extra_args=[ ['-zmqpubhashtx=tcp://127.0.0.1:'+str(self.port), '-zmqpubhashblock=tcp://127.0.0.1:'+str(self.port)], @@ -42,32 +41,32 @@ class ZMQTest (BitcoinTestFramework): def run_test(self): self.sync_all() - genhashes = self.nodes[0].generate(1); + genhashes = self.nodes[0].generate(1) self.sync_all() print "listen..." msg = self.zmqSubSocket.recv_multipart() - topic = str(msg[0]) + topic = msg[0] body = msg[1] msg = self.zmqSubSocket.recv_multipart() - topic = str(msg[0]) + topic = msg[0] body = msg[1] - blkhash = binascii.hexlify(body) + blkhash = bytes_to_hex_str(body) assert_equal(genhashes[0], blkhash) #blockhash from generate must be equal to the hash received over zmq n = 10 - genhashes = self.nodes[1].generate(n); + genhashes = self.nodes[1].generate(n) self.sync_all() zmqHashes = [] for x in range(0,n*2): msg = self.zmqSubSocket.recv_multipart() - topic = str(msg[0]) + topic = msg[0] body = msg[1] - if topic == "hashblock": - zmqHashes.append(binascii.hexlify(body)) + if topic == b"hashblock": + zmqHashes.append(bytes_to_hex_str(body)) for x in range(0,n): assert_equal(genhashes[x], zmqHashes[x]) #blockhash from generate must be equal to the hash received over zmq @@ -76,13 +75,13 @@ class ZMQTest (BitcoinTestFramework): hashRPC = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.0) self.sync_all() - #now we should receive a zmq msg because the tx was broadcastet + # now we should receive a zmq msg because the tx was broadcast msg = self.zmqSubSocket.recv_multipart() - topic = str(msg[0]) + topic = msg[0] body = msg[1] hashZMQ = "" - if topic == "hashtx": - hashZMQ = binascii.hexlify(body) + if topic == b"hashtx": + hashZMQ = bytes_to_hex_str(body) assert_equal(hashRPC, hashZMQ) #blockhash from generate must be equal to the hash received over zmq diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in index a389332a5..6a34d64cd 100644 --- a/share/qt/Info.plist.in +++ b/share/qt/Info.plist.in @@ -17,7 +17,7 @@ APPL CFBundleGetInfoString - @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@, Copyright © 2009-@COPYRIGHT_YEAR@ The Bitcoin Core developers + @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@, Copyright © 2009-@COPYRIGHT_YEAR@ @COPYRIGHT_HOLDERS_FINAL@ CFBundleShortVersionString @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@ diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py index d4bd58513..7728a4377 100755 --- a/share/qt/extract_strings_qt.py +++ b/share/qt/extract_strings_qt.py @@ -1,8 +1,9 @@ #!/usr/bin/python ''' -Extract _("...") strings for translation and convert to Qt4 stringdefs so that +Extract _("...") strings for translation and convert to Qt stringdefs so that they can be picked up by Qt linguist. ''' +from __future__ import division,print_function,unicode_literals from subprocess import Popen, PIPE import glob import operator @@ -52,10 +53,14 @@ files = sys.argv[1:] # xgettext -n --keyword=_ $FILES XGETTEXT=os.getenv('XGETTEXT', 'xgettext') +if not XGETTEXT: + print('Cannot extract strings: xgettext utility is not installed or not configured.',file=sys.stderr) + print('Please install package "gettext" and re-run \'./configure\'.',file=sys.stderr) + exit(1) child = Popen([XGETTEXT,'--output=-','-n','--keyword=_'] + files, stdout=PIPE) (out, err) = child.communicate() -messages = parse_po(out) +messages = parse_po(out.decode('utf-8')) f = open(OUT_CPP, 'w') f.write(""" @@ -70,6 +75,10 @@ f.write(""" #endif """) f.write('static const char UNUSED *bitcoin_strings[] = {\n') +f.write('QT_TRANSLATE_NOOP("bitcoin-core", "%s"),\n' % (os.getenv('PACKAGE_NAME'),)) +f.write('QT_TRANSLATE_NOOP("bitcoin-core", "%s"),\n' % (os.getenv('COPYRIGHT_HOLDERS'),)) +if os.getenv('COPYRIGHT_HOLDERS_SUBSTITUTION') != os.getenv('PACKAGE_NAME'): + f.write('QT_TRANSLATE_NOOP("bitcoin-core", "%s"),\n' % (os.getenv('COPYRIGHT_HOLDERS_SUBSTITUTION'),)) messages.sort(key=operator.itemgetter(0)) for (msgid, msgstr) in messages: if msgid != EMPTY: diff --git a/share/rpcuser/README.md b/share/rpcuser/README.md new file mode 100644 index 000000000..12a8e6fb0 --- /dev/null +++ b/share/rpcuser/README.md @@ -0,0 +1,10 @@ +RPC Tools +--------------------- + +### [RPCUser](/share/rpcuser) ### + +Create an RPC user login credential. + +Usage: + + ./rpcuser.py diff --git a/share/rpcuser/rpcuser.py b/share/rpcuser/rpcuser.py new file mode 100755 index 000000000..9fd176908 --- /dev/null +++ b/share/rpcuser/rpcuser.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import hashlib +import sys +import os +from random import SystemRandom +import base64 +import hmac + +if len(sys.argv) < 2: + sys.stderr.write('Please include username as an argument.\n') + sys.exit(0) + +username = sys.argv[1] + +#This uses os.urandom() underneath +cryptogen = SystemRandom() + +#Create 16 byte hex salt +salt_sequence = [cryptogen.randrange(256) for i in range(16)] +hexseq = list(map(hex, salt_sequence)) +salt = "".join([x[2:] for x in hexseq]) + +#Create 32 byte b64 password +password = base64.urlsafe_b64encode(os.urandom(32)) + +digestmod = hashlib.sha256 + +if sys.version_info.major >= 3: + password = password.decode('utf-8') + digestmod = 'SHA256' + +m = hmac.new(bytearray(salt, 'utf-8'), bytearray(password, 'utf-8'), digestmod) +result = m.hexdigest() + +print("String to be appended to bitcoin.conf:") +print("rpcauth="+username+":"+salt+"$"+result) +print("Your password:\n"+password) diff --git a/share/setup.nsi.in b/share/setup.nsi.in index 6c0e895bb..c062f96a3 100644 --- a/share/setup.nsi.in +++ b/share/setup.nsi.in @@ -6,8 +6,8 @@ SetCompressor /SOLID lzma # General Symbol Definitions !define REGKEY "SOFTWARE\$(^Name)" !define VERSION @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@ -!define COMPANY "Bitcoin Core project" -!define URL http://www.bitcoin.org/ +!define COMPANY "@PACKAGE_NAME@ project" +!define URL @PACKAGE_URL@ # MUI Symbol Definitions !define MUI_ICON "@abs_top_srcdir@/share/pixmaps/bitcoin.ico" @@ -20,7 +20,7 @@ SetCompressor /SOLID lzma !define MUI_STARTMENUPAGE_REGISTRY_KEY ${REGKEY} !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME StartMenuGroup !define MUI_STARTMENUPAGE_DEFAULTFOLDER "@PACKAGE_NAME@" -!define MUI_FINISHPAGE_RUN $INSTDIR\bitcoin-qt.exe +!define MUI_FINISHPAGE_RUN $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico" !define MUI_UNWELCOMEFINISHPAGE_BITMAP "@abs_top_srcdir@/share/pixmaps/nsis-wizard.bmp" !define MUI_UNFINISHPAGE_NOAUTOCLOSE @@ -48,7 +48,7 @@ Var StartMenuGroup !insertmacro MUI_LANGUAGE English # Installer attributes -OutFile @abs_top_srcdir@/bitcoin-${VERSION}-win@WINDOWS_BITS@-setup.exe +OutFile @abs_top_srcdir@/@PACKAGE_TARNAME@-${VERSION}-win@WINDOWS_BITS@-setup.exe !if "@WINDOWS_BITS@" == "64" InstallDir $PROGRAMFILES64\Bitcoin !else @@ -59,7 +59,7 @@ XPStyle on BrandingText " " ShowInstDetails show VIProductVersion ${VERSION}.@CLIENT_VERSION_BUILD@ -VIAddVersionKey ProductName "Bitcoin Core" +VIAddVersionKey ProductName "@PACKAGE_NAME@" VIAddVersionKey ProductVersion "${VERSION}" VIAddVersionKey CompanyName "${COMPANY}" VIAddVersionKey CompanyWebsite "${URL}" @@ -73,20 +73,16 @@ ShowUninstDetails show Section -Main SEC0000 SetOutPath $INSTDIR SetOverwrite on - File @abs_top_srcdir@/release/bitcoin-qt.exe + File @abs_top_srcdir@/release/@BITCOIN_GUI_NAME@@EXEEXT@ File /oname=COPYING.txt @abs_top_srcdir@/COPYING File /oname=readme.txt @abs_top_srcdir@/doc/README_windows.txt SetOutPath $INSTDIR\daemon - File @abs_top_srcdir@/release/bitcoind.exe - File @abs_top_srcdir@/release/bitcoin-cli.exe + File @abs_top_srcdir@/release/@BITCOIN_DAEMON_NAME@@EXEEXT@ + File @abs_top_srcdir@/release/@BITCOIN_CLI_NAME@@EXEEXT@ SetOutPath $INSTDIR\doc File /r @abs_top_srcdir@/doc\*.* SetOutPath $INSTDIR WriteRegStr HKCU "${REGKEY}\Components" Main 1 - - # Remove old wxwidgets-based-bitcoin executable and locales: - Delete /REBOOTOK $INSTDIR\bitcoin.exe - RMDir /r /REBOOTOK $INSTDIR\locale SectionEnd Section -post SEC0001 @@ -95,7 +91,7 @@ Section -post SEC0001 WriteUninstaller $INSTDIR\uninstall.exe !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateDirectory $SMPROGRAMS\$StartMenuGroup - CreateShortcut "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" $INSTDIR\bitcoin-qt.exe + CreateShortcut "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" $INSTDIR\uninstall.exe !insertmacro MUI_STARTMENU_WRITE_END WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)" @@ -106,10 +102,10 @@ Section -post SEC0001 WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" UninstallString $INSTDIR\uninstall.exe WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoModify 1 WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoRepair 1 - WriteRegStr HKCR "bitcoin" "URL Protocol" "" - WriteRegStr HKCR "bitcoin" "" "URL:Bitcoin" - WriteRegStr HKCR "bitcoin\DefaultIcon" "" $INSTDIR\bitcoin-qt.exe - WriteRegStr HKCR "bitcoin\shell\open\command" "" '"$INSTDIR\bitcoin-qt.exe" "%1"' + WriteRegStr HKCR "@PACKAGE_TARNAME@" "URL Protocol" "" + WriteRegStr HKCR "@PACKAGE_TARNAME@" "" "URL:Bitcoin" + WriteRegStr HKCR "@PACKAGE_TARNAME@\DefaultIcon" "" $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ + WriteRegStr HKCR "@PACKAGE_TARNAME@\shell\open\command" "" '"$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" "%1"' SectionEnd # Macro for selecting uninstaller sections @@ -127,7 +123,7 @@ done${UNSECTION_ID}: # Uninstaller sections Section /o -un.Main UNSEC0000 - Delete /REBOOTOK $INSTDIR\bitcoin-qt.exe + Delete /REBOOTOK $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ Delete /REBOOTOK $INSTDIR\COPYING.txt Delete /REBOOTOK $INSTDIR\readme.txt RMDir /r /REBOOTOK $INSTDIR\daemon @@ -147,7 +143,7 @@ Section -un.post UNSEC0001 DeleteRegValue HKCU "${REGKEY}" Path DeleteRegKey /IfEmpty HKCU "${REGKEY}\Components" DeleteRegKey /IfEmpty HKCU "${REGKEY}" - DeleteRegKey HKCR "bitcoin" + DeleteRegKey HKCR "@PACKAGE_TARNAME@" RmDir /REBOOTOK $SMPROGRAMS\$StartMenuGroup RmDir /REBOOTOK $INSTDIR Push $R0 diff --git a/src/.clang-format b/src/.clang-format index 226a15d18..129f062ef 100644 --- a/src/.clang-format +++ b/src/.clang-format @@ -1,4 +1,6 @@ +Language: Cpp AccessModifierOffset: -4 +AlignAfterOpenBracket: false AlignEscapedNewlinesLeft: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: false @@ -26,7 +28,6 @@ IndentCaseLabels: false IndentFunctionDeclarationAfterType: false IndentWidth: 4 KeepEmptyLinesAtTheStartOfBlocks: false -Language: Cpp MaxEmptyLinesToKeep: 2 NamespaceIndentation: None ObjCSpaceAfterProperty: false diff --git a/src/Makefile.am b/src/Makefile.am index 355dec5fa..539657855 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,17 @@ DIST_SUBDIRS = secp256k1 univalue -AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) +AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) +AM_CXXFLAGS = $(HARDENED_CXXFLAGS) +AM_CPPFLAGS = $(HARDENED_CPPFLAGS) + +if EMBEDDED_UNIVALUE +LIBUNIVALUE = univalue/libunivalue.la + +$(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*) + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) +else +LIBUNIVALUE = $(UNIVALUE_LIBS) +endif if EMBEDDED_LEVELDB LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include @@ -14,30 +25,27 @@ $(LIBLEVELDB): $(LIBMEMENV) $(LIBLEVELDB) $(LIBMEMENV): @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ - OPT="$(CXXFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS" + OPT="$(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS" endif BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include -BITCOIN_INCLUDES += -I$(srcdir)/univalue/include +BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS) LIBBITCOIN_SERVER=libbitcoin_server.a LIBBITCOIN_WALLET=libbitcoin_wallet.a LIBBITCOIN_COMMON=libbitcoin_common.a +LIBBITCOIN_CONSENSUS=libbitcoin_consensus.a LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBBITCOINQT=qt/libbitcoinqt.a LIBSECP256K1=secp256k1/libsecp256k1.la -LIBUNIVALUE=univalue/libunivalue.la $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) - -$(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*) - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) # Make is not made aware of per-object dependencies to avoid limiting building parallelization # But to build the less dependent modules first, we manually select their order here: @@ -45,6 +53,7 @@ EXTRA_LIBRARIES = \ crypto/libbitcoin_crypto.a \ libbitcoin_util.a \ libbitcoin_common.a \ + libbitcoin_consensus.a \ libbitcoin_server.a \ libbitcoin_cli.a if ENABLE_WALLET @@ -57,9 +66,9 @@ endif if BUILD_BITCOIN_LIBS lib_LTLIBRARIES = libbitcoinconsensus.la -LIBBITCOIN_CONSENSUS=libbitcoinconsensus.la +LIBBITCOINCONSENSUS=libbitcoinconsensus.la else -LIBBITCOIN_CONSENSUS= +LIBBITCOINCONSENSUS= endif bin_PROGRAMS = @@ -74,13 +83,10 @@ if BUILD_BITCOIN_UTILS bin_PROGRAMS += lbrycrd-cli lbrycrd-tx endif -.PHONY: FORCE +.PHONY: FORCE check-symbols check-security # bitcoin core # BITCOIN_CORE_H = \ addrman.h \ - alert.h \ - amount.h \ - arith_uint256.h \ base58.h \ bloom.h \ chain.h \ @@ -98,25 +104,19 @@ BITCOIN_CORE_H = \ compat/sanity.h \ compressor.h \ consensus/consensus.h \ - consensus/params.h \ - consensus/validation.h \ core_io.h \ core_memusage.h \ - eccryptoverify.h \ - ecwrapper.h \ - hash.h \ httprpc.h \ httpserver.h \ init.h \ key.h \ keystore.h \ - leveldbwrapper.h \ + dbwrapper.h \ limitedmap.h \ main.h \ memusage.h \ merkleblock.h \ miner.h \ - mruset.h \ nameclaim.h \ claimtrie.h \ net.h \ @@ -124,24 +124,19 @@ BITCOIN_CORE_H = \ noui.h \ policy/fees.h \ policy/policy.h \ + policy/rbf.h \ pow.h \ - primitives/block.h \ - primitives/transaction.h \ protocol.h \ - pubkey.h \ random.h \ reverselock.h \ - rpcclient.h \ - rpcprotocol.h \ - rpcserver.h \ + rpc/client.h \ + rpc/protocol.h \ + rpc/server.h \ + rpc/register.h \ scheduler.h \ - script/interpreter.h \ - script/script.h \ - script/script_error.h \ script/sigcache.h \ script/sign.h \ script/standard.h \ - serialize.h \ streams.h \ support/allocators/secure.h \ support/allocators/zeroafterfree.h \ @@ -150,20 +145,19 @@ BITCOIN_CORE_H = \ sync.h \ threadsafety.h \ timedata.h \ - tinyformat.h \ + torcontrol.h \ txdb.h \ txmempool.h \ ui_interface.h \ - uint256.h \ undo.h \ util.h \ utilmoneystr.h \ - utilstrencodings.h \ utiltime.h \ validationinterface.h \ - version.h \ + versionbits.h \ wallet/crypter.h \ wallet/db.h \ + wallet/rpcwallet.h \ wallet/wallet.h \ wallet/wallet_ismine.h \ wallet/walletdb.h \ @@ -180,17 +174,17 @@ obj/build.h: FORCE libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h # server: shared between bitcoind and bitcoin-qt -libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_server_a_SOURCES = \ addrman.cpp \ - alert.cpp \ bloom.cpp \ chain.cpp \ checkpoints.cpp \ httprpc.cpp \ httpserver.cpp \ init.cpp \ - leveldbwrapper.cpp \ + dbwrapper.cpp \ main.cpp \ merkleblock.cpp \ miner.cpp \ @@ -201,24 +195,27 @@ libbitcoin_server_a_SOURCES = \ policy/policy.cpp \ pow.cpp \ rest.cpp \ - rpcblockchain.cpp \ - rpcmining.cpp \ - rpcmisc.cpp \ - rpcclaimtrie.cpp \ - rpcnet.cpp \ - rpcrawtransaction.cpp \ - rpcserver.cpp \ + rpc/blockchain.cpp \ + rpc/claimtrie.cpp \ + rpc/mining.cpp \ + rpc/misc.cpp \ + rpc/net.cpp \ + rpc/rawtransaction.cpp \ + rpc/server.cpp \ script/sigcache.cpp \ timedata.cpp \ + torcontrol.cpp \ txdb.cpp \ txmempool.cpp \ validationinterface.cpp \ + versionbits.cpp \ $(BITCOIN_CORE_H) if ENABLE_ZMQ LIBBITCOIN_ZMQ=libbitcoin_zmq.a libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS) +libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_zmq_a_SOURCES = \ zmq/zmqabstractnotifier.cpp \ zmq/zmqnotificationinterface.cpp \ @@ -228,7 +225,8 @@ endif # wallet: shared between bitcoind and bitcoin-qt, but only linked # when wallet enabled -libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_a_SOURCES = \ wallet/crypter.cpp \ wallet/db.cpp \ @@ -237,10 +235,12 @@ libbitcoin_wallet_a_SOURCES = \ wallet/wallet.cpp \ wallet/wallet_ismine.cpp \ wallet/walletdb.cpp \ + policy/rbf.cpp \ $(BITCOIN_CORE_H) # crypto primitives library -crypto_libbitcoin_crypto_a_CPPFLAGS = $(BITCOIN_CONFIG_INCLUDES) +crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES) +crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_a_SOURCES = \ crypto/common.h \ crypto/hmac_sha256.cpp \ @@ -256,32 +256,58 @@ crypto_libbitcoin_crypto_a_SOURCES = \ crypto/sha512.cpp \ crypto/sha512.h +# consensus: shared between all executables that validate any consensus rules. +libbitcoin_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_consensus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +libbitcoin_consensus_a_SOURCES = \ + amount.h \ + arith_uint256.cpp \ + arith_uint256.h \ + consensus/merkle.cpp \ + consensus/merkle.h \ + consensus/params.h \ + consensus/validation.h \ + hash.cpp \ + hash.h \ + prevector.h \ + primitives/block.cpp \ + primitives/block.h \ + primitives/transaction.cpp \ + primitives/transaction.h \ + pubkey.cpp \ + pubkey.h \ + script/bitcoinconsensus.cpp \ + script/interpreter.cpp \ + script/interpreter.h \ + script/script.cpp \ + script/script.h \ + script/script_error.cpp \ + script/script_error.h \ + serialize.h \ + tinyformat.h \ + uint256.cpp \ + uint256.h \ + utilstrencodings.cpp \ + utilstrencodings.h \ + version.h + # common: shared between bitcoind, and bitcoin-qt and non-server tools -libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_common_a_SOURCES = \ amount.cpp \ - arith_uint256.cpp \ base58.cpp \ chainparams.cpp \ coins.cpp \ compressor.cpp \ core_read.cpp \ core_write.cpp \ - eccryptoverify.cpp \ - ecwrapper.cpp \ - hash.cpp \ key.cpp \ keystore.cpp \ nameclaim.cpp \ netbase.cpp \ - primitives/block.cpp \ - primitives/transaction.cpp \ protocol.cpp \ - pubkey.cpp \ scheduler.cpp \ - script/interpreter.cpp \ - script/script.cpp \ - script/script_error.cpp \ script/sign.cpp \ script/standard.cpp \ $(BITCOIN_CORE_H) @@ -289,7 +315,8 @@ libbitcoin_common_a_SOURCES = \ # util: shared between all executables. # This library *must* be included to make sure that the glibc # backward-compatibility objects and their sanity checks are linked. -libbitcoin_util_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ support/pagelocker.cpp \ chainparamsbase.cpp \ @@ -298,10 +325,9 @@ libbitcoin_util_a_SOURCES = \ compat/glibcxx_sanity.cpp \ compat/strnlen.cpp \ random.cpp \ - rpcprotocol.cpp \ + rpc/protocol.cpp \ support/cleanse.cpp \ sync.cpp \ - uint256.cpp \ util.cpp \ utilmoneystr.cpp \ utilstrencodings.cpp \ @@ -313,9 +339,10 @@ libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp endif # cli: shared between bitcoin-cli and bitcoin-qt -libbitcoin_cli_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_cli_a_SOURCES = \ - rpcclient.cpp \ + rpc/client.cpp \ $(BITCOIN_CORE_H) nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h @@ -323,7 +350,8 @@ nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h # bitcoind binary # lbrycrdd_SOURCES = bitcoind.cpp -lbrycrdd_CPPFLAGS = $(BITCOIN_INCLUDES) +lbrycrdd_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +lbrycrdd_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) lbrycrdd_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS @@ -335,6 +363,7 @@ lbrycrdd_LDADD = \ $(LIBBITCOIN_COMMON) \ $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBLEVELDB) \ $(LIBMEMENV) \ @@ -352,7 +381,8 @@ lbrycrdd_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPN #lbrycrd-cli binary # lbrycrd_cli_SOURCES = bitcoin-cli.cpp -lbrycrd_cli_CPPFLAGS = $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) +lbrycrd_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) +lbrycrd_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) lbrycrd_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS @@ -369,7 +399,8 @@ lbrycrd_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS) # bitcoin-tx binary # lbrycrd_tx_SOURCES = bitcoin-tx.cpp -lbrycrd_tx_CPPFLAGS = $(BITCOIN_INCLUDES) +lbrycrd_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +lbrycrd_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) lbrycrd_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS @@ -380,6 +411,7 @@ lbrycrd_tx_LDADD = \ $(LIBUNIVALUE) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBSECP256K1) @@ -389,35 +421,34 @@ lbrycrd_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # bitcoinconsensus library # if BUILD_BITCOIN_LIBS include_HEADERS = script/bitcoinconsensus.h -libbitcoinconsensus_la_SOURCES = \ - crypto/hmac_sha512.cpp \ - crypto/ripemd160.cpp \ - crypto/sha1.cpp \ - crypto/sha256.cpp \ - crypto/sha512.cpp \ - eccryptoverify.cpp \ - ecwrapper.cpp \ - hash.cpp \ - primitives/transaction.cpp \ - pubkey.cpp \ - script/bitcoinconsensus.cpp \ - script/interpreter.cpp \ - script/script.cpp \ - uint256.cpp \ - utilstrencodings.cpp +libbitcoinconsensus_la_SOURCES = $(crypto_libbitcoin_crypto_a_SOURCES) $(libbitcoin_consensus_a_SOURCES) if GLIBC_BACK_COMPAT libbitcoinconsensus_la_SOURCES += compat/glibc_compat.cpp endif -libbitcoinconsensus_la_LDFLAGS = -no-undefined $(RELDFLAGS) -libbitcoinconsensus_la_LIBADD = $(CRYPTO_LIBS) -libbitcoinconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCOIN_INTERNAL +libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) +libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1) +libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL +libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) endif # -CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno +CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a +CLEANFILES += $(EXTRA_LIBRARIES) +CLEANFILES += *.gcda *.gcno +CLEANFILES += compat/*.gcda compat/*.gcno +CLEANFILES += consensus/*.gcda consensus/*.gcno +CLEANFILES += crypto/*.gcda crypto/*.gcno +CLEANFILES += policy/*.gcda policy/*.gcno +CLEANFILES += primitives/*.gcda primitives/*.gcno +CLEANFILES += script/*.gcda script/*.gcno +CLEANFILES += support/*.gcda support/*.gcno +CLEANFILES += univalue/*.gcda univalue/*.gcno +CLEANFILES += wallet/*.gcda wallet/*.gcno +CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno +CLEANFILES += zmq/*.gcda zmq/*.gcno DISTCLEANFILES = obj/build.h @@ -427,20 +458,33 @@ clean-local: -$(MAKE) -C leveldb clean -$(MAKE) -C secp256k1 clean -$(MAKE) -C univalue clean - rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno + -rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno -rm -f config.h .rc.o: @test -f $(WINDRES) - $(AM_V_GEN) $(WINDRES) -DWINDRES_PREPROC -i $< -o $@ + ## FIXME: How to get the appropriate modulename_CPPFLAGS in here? + $(AM_V_GEN) $(WINDRES) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) -DWINDRES_PREPROC -i $< -o $@ .mm.o: $(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(CXXFLAGS) -c -o $@ $< + $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) -c -o $@ $< + +check-symbols: $(bin_PROGRAMS) +if GLIBC_BACK_COMPAT + @echo "Checking glibc back compat..." + $(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py < $(bin_PROGRAMS) +endif + +check-security: $(bin_PROGRAMS) +if HARDEN + @echo "Checking binary security..." + $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS) +endif %.pb.cc %.pb.h: %.proto @test -f $(PROTOC) - $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $(nRefCount; n++) nFactor *= 2; - if (nFactor > 1 && (GetRandInt(nFactor) != 0)) + if (nFactor > 1 && (RandomInt(nFactor) != 0)) return false; } else { pinfo = Create(addr, source, &nId); @@ -339,12 +340,12 @@ CAddrInfo CAddrMan::Select_(bool newOnly) // Use a 50% chance for choosing between tried and new table entries. if (!newOnly && - (nTried > 0 && (nNew == 0 || GetRandInt(2) == 0))) { + (nTried > 0 && (nNew == 0 || RandomInt(2) == 0))) { // use a tried node double fChanceFactor = 1.0; while (1) { - int nKBucket = GetRandInt(ADDRMAN_TRIED_BUCKET_COUNT); - int nKBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE); + int nKBucket = RandomInt(ADDRMAN_TRIED_BUCKET_COUNT); + int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE); while (vvTried[nKBucket][nKBucketPos] == -1) { nKBucket = (nKBucket + insecure_rand()) % ADDRMAN_TRIED_BUCKET_COUNT; nKBucketPos = (nKBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE; @@ -352,7 +353,7 @@ CAddrInfo CAddrMan::Select_(bool newOnly) int nId = vvTried[nKBucket][nKBucketPos]; assert(mapInfo.count(nId) == 1); CAddrInfo& info = mapInfo[nId]; - if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) + if (RandomInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) return info; fChanceFactor *= 1.2; } @@ -360,8 +361,8 @@ CAddrInfo CAddrMan::Select_(bool newOnly) // use a new node double fChanceFactor = 1.0; while (1) { - int nUBucket = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT); - int nUBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE); + int nUBucket = RandomInt(ADDRMAN_NEW_BUCKET_COUNT); + int nUBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE); while (vvNew[nUBucket][nUBucketPos] == -1) { nUBucket = (nUBucket + insecure_rand()) % ADDRMAN_NEW_BUCKET_COUNT; nUBucketPos = (nUBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE; @@ -369,7 +370,7 @@ CAddrInfo CAddrMan::Select_(bool newOnly) int nId = vvNew[nUBucket][nUBucketPos]; assert(mapInfo.count(nId) == 1); CAddrInfo& info = mapInfo[nId]; - if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) + if (RandomInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) return info; fChanceFactor *= 1.2; } @@ -465,7 +466,7 @@ void CAddrMan::GetAddr_(std::vector& vAddr) if (vAddr.size() >= nNodes) break; - int nRndPos = GetRandInt(vRandom.size() - n) + n; + int nRndPos = RandomInt(vRandom.size() - n) + n; SwapRandom(n, nRndPos); assert(mapInfo.count(vRandom[n]) == 1); @@ -494,3 +495,7 @@ void CAddrMan::Connected_(const CService& addr, int64_t nTime) if (nTime - info.nTime > nUpdateInterval) info.nTime = nTime; } + +int CAddrMan::RandomInt(int nMax){ + return GetRandInt(nMax); +} diff --git a/src/addrman.h b/src/addrman.h index 1123caabf..4f3de8d7c 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -1,4 +1,5 @@ // Copyright (c) 2012 Pieter Wuille +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -175,9 +176,6 @@ private: //! critical section to protect the inner data structures mutable CCriticalSection cs; - //! secret key to randomize bucket select with - uint256 nKey; - //! last used nId int nIdCount; @@ -203,6 +201,8 @@ private: int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]; protected: + //! secret key to randomize bucket select with + uint256 nKey; //! Find an entry. CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL); @@ -235,6 +235,9 @@ protected: //! Select an address to connect to, if newOnly is set to true, only the new table is selected from. CAddrInfo Select_(bool newOnly); + //! Wraps GetRandInt to allow tests to override RandomInt and make it determinismistic. + virtual int RandomInt(int nMax); + #ifdef DEBUG_ADDRMAN //! Perform consistency check. Returns an error code or zero. int Check_(); @@ -569,11 +572,6 @@ public: Check(); } } - - //! Ensure that bucket placement is always the same for testing purposes. - void MakeDeterministic(){ - nKey.SetNull(); //Do not use outside of tests. - } }; diff --git a/src/alert.cpp b/src/alert.cpp deleted file mode 100644 index 91e54a917..000000000 --- a/src/alert.cpp +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "alert.h" - -#include "clientversion.h" -#include "net.h" -#include "pubkey.h" -#include "timedata.h" -#include "ui_interface.h" -#include "util.h" -#include "utilstrencodings.h" - -#include -#include -#include - -#include -#include -#include -#include - -using namespace std; - -map mapAlerts; -CCriticalSection cs_mapAlerts; - -void CUnsignedAlert::SetNull() -{ - nVersion = 1; - nRelayUntil = 0; - nExpiration = 0; - nID = 0; - nCancel = 0; - setCancel.clear(); - nMinVer = 0; - nMaxVer = 0; - setSubVer.clear(); - nPriority = 0; - - strComment.clear(); - strStatusBar.clear(); - strReserved.clear(); -} - -std::string CUnsignedAlert::ToString() const -{ - std::string strSetCancel; - BOOST_FOREACH(int n, setCancel) - strSetCancel += strprintf("%d ", n); - std::string strSetSubVer; - BOOST_FOREACH(const std::string& str, setSubVer) - strSetSubVer += "\"" + str + "\" "; - return strprintf( - "CAlert(\n" - " nVersion = %d\n" - " nRelayUntil = %d\n" - " nExpiration = %d\n" - " nID = %d\n" - " nCancel = %d\n" - " setCancel = %s\n" - " nMinVer = %d\n" - " nMaxVer = %d\n" - " setSubVer = %s\n" - " nPriority = %d\n" - " strComment = \"%s\"\n" - " strStatusBar = \"%s\"\n" - ")\n", - nVersion, - nRelayUntil, - nExpiration, - nID, - nCancel, - strSetCancel, - nMinVer, - nMaxVer, - strSetSubVer, - nPriority, - strComment, - strStatusBar); -} - -void CAlert::SetNull() -{ - CUnsignedAlert::SetNull(); - vchMsg.clear(); - vchSig.clear(); -} - -bool CAlert::IsNull() const -{ - return (nExpiration == 0); -} - -uint256 CAlert::GetHash() const -{ - return Hash(this->vchMsg.begin(), this->vchMsg.end()); -} - -bool CAlert::IsInEffect() const -{ - return (GetAdjustedTime() < nExpiration); -} - -bool CAlert::Cancels(const CAlert& alert) const -{ - if (!IsInEffect()) - return false; // this was a no-op before 31403 - return (alert.nID <= nCancel || setCancel.count(alert.nID)); -} - -bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const -{ - // TODO: rework for client-version-embedded-in-strSubVer ? - return (IsInEffect() && - nMinVer <= nVersion && nVersion <= nMaxVer && - (setSubVer.empty() || setSubVer.count(strSubVerIn))); -} - -bool CAlert::AppliesToMe() const -{ - return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector())); -} - -bool CAlert::RelayTo(CNode* pnode) const -{ - if (!IsInEffect()) - return false; - // don't relay to nodes which haven't sent their version message - if (pnode->nVersion == 0) - return false; - // returns true if wasn't already contained in the set - if (pnode->setKnown.insert(GetHash()).second) - { - if (AppliesTo(pnode->nVersion, pnode->strSubVer) || - AppliesToMe() || - GetAdjustedTime() < nRelayUntil) - { - pnode->PushMessage("alert", *this); - return true; - } - } - return false; -} - -bool CAlert::CheckSignature(const std::vector& alertKey) const -{ - CPubKey key(alertKey); - if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) - return error("CAlert::CheckSignature(): verify signature failed"); - - // Now unserialize the data - CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION); - sMsg >> *(CUnsignedAlert*)this; - return true; -} - -CAlert CAlert::getAlertByHash(const uint256 &hash) -{ - CAlert retval; - { - LOCK(cs_mapAlerts); - map::iterator mi = mapAlerts.find(hash); - if(mi != mapAlerts.end()) - retval = mi->second; - } - return retval; -} - -bool CAlert::ProcessAlert(const std::vector& alertKey, bool fThread) -{ - if (!CheckSignature(alertKey)) - return false; - if (!IsInEffect()) - return false; - - // alert.nID=max is reserved for if the alert key is - // compromised. It must have a pre-defined message, - // must never expire, must apply to all versions, - // and must cancel all previous - // alerts or it will be ignored (so an attacker can't - // send an "everything is OK, don't panic" version that - // cannot be overridden): - int maxInt = std::numeric_limits::max(); - if (nID == maxInt) - { - if (!( - nExpiration == maxInt && - nCancel == (maxInt-1) && - nMinVer == 0 && - nMaxVer == maxInt && - setSubVer.empty() && - nPriority == maxInt && - strStatusBar == "URGENT: Alert key compromised, upgrade required" - )) - return false; - } - - { - LOCK(cs_mapAlerts); - // Cancel previous alerts - for (map::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();) - { - const CAlert& alert = (*mi).second; - if (Cancels(alert)) - { - LogPrint("alert", "cancelling alert %d\n", alert.nID); - uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); - mapAlerts.erase(mi++); - } - else if (!alert.IsInEffect()) - { - LogPrint("alert", "expiring alert %d\n", alert.nID); - uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); - mapAlerts.erase(mi++); - } - else - mi++; - } - - // Check if this alert has been cancelled - BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) - { - const CAlert& alert = item.second; - if (alert.Cancels(*this)) - { - LogPrint("alert", "alert already cancelled by %d\n", alert.nID); - return false; - } - } - - // Add to mapAlerts - mapAlerts.insert(make_pair(GetHash(), *this)); - // Notify UI and -alertnotify if it applies to me - if(AppliesToMe()) - { - uiInterface.NotifyAlertChanged(GetHash(), CT_NEW); - Notify(strStatusBar, fThread); - } - } - - LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe()); - return true; -} - -void -CAlert::Notify(const std::string& strMessage, bool fThread) -{ - std::string strCmd = GetArg("-alertnotify", ""); - if (strCmd.empty()) return; - - // Alert text should be plain ascii coming from a trusted source, but to - // be safe we first strip anything not in safeChars, then add single quotes around - // the whole string before passing it to the shell: - std::string singleQuote("'"); - std::string safeStatus = SanitizeString(strMessage); - safeStatus = singleQuote+safeStatus+singleQuote; - boost::replace_all(strCmd, "%s", safeStatus); - - if (fThread) - boost::thread t(runCommand, strCmd); // thread runs free - else - runCommand(strCmd); -} diff --git a/src/alert.h b/src/alert.h deleted file mode 100644 index 4f9fff918..000000000 --- a/src/alert.h +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_ALERT_H -#define BITCOIN_ALERT_H - -#include "serialize.h" -#include "sync.h" - -#include -#include -#include -#include - -class CAlert; -class CNode; -class uint256; - -extern std::map mapAlerts; -extern CCriticalSection cs_mapAlerts; - -/** Alerts are for notifying old versions if they become too obsolete and - * need to upgrade. The message is displayed in the status bar. - * Alert messages are broadcast as a vector of signed data. Unserializing may - * not read the entire buffer if the alert is for a newer version, but older - * versions can still relay the original data. - */ -class CUnsignedAlert -{ -public: - int nVersion; - int64_t nRelayUntil; // when newer nodes stop relaying to newer nodes - int64_t nExpiration; - int nID; - int nCancel; - std::set setCancel; - int nMinVer; // lowest version inclusive - int nMaxVer; // highest version inclusive - std::set setSubVer; // empty matches all - int nPriority; - - // Actions - std::string strComment; - std::string strStatusBar; - std::string strReserved; - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(this->nVersion); - nVersion = this->nVersion; - READWRITE(nRelayUntil); - READWRITE(nExpiration); - READWRITE(nID); - READWRITE(nCancel); - READWRITE(setCancel); - READWRITE(nMinVer); - READWRITE(nMaxVer); - READWRITE(setSubVer); - READWRITE(nPriority); - - READWRITE(LIMITED_STRING(strComment, 65536)); - READWRITE(LIMITED_STRING(strStatusBar, 256)); - READWRITE(LIMITED_STRING(strReserved, 256)); - } - - void SetNull(); - - std::string ToString() const; -}; - -/** An alert is a combination of a serialized CUnsignedAlert and a signature. */ -class CAlert : public CUnsignedAlert -{ -public: - std::vector vchMsg; - std::vector vchSig; - - CAlert() - { - SetNull(); - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(vchMsg); - READWRITE(vchSig); - } - - void SetNull(); - bool IsNull() const; - uint256 GetHash() const; - bool IsInEffect() const; - bool Cancels(const CAlert& alert) const; - bool AppliesTo(int nVersion, const std::string& strSubVerIn) const; - bool AppliesToMe() const; - bool RelayTo(CNode* pnode) const; - bool CheckSignature(const std::vector& alertKey) const; - bool ProcessAlert(const std::vector& alertKey, bool fThread = true); // fThread means run -alertnotify in a free-running thread - static void Notify(const std::string& strMessage, bool fThread); - - /* - * Get copy of (active) alert object by hash. Returns a null alert if it is not found. - */ - static CAlert getAlertByHash(const uint256 &hash); -}; - -#endif // BITCOIN_ALERT_H diff --git a/src/amount.cpp b/src/amount.cpp index b46918198..7b8618de3 100644 --- a/src/amount.cpp +++ b/src/amount.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,20 +9,30 @@ const std::string CURRENCY_UNIT = "BTC"; -CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nSize) +CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nBytes_) { + assert(nBytes_ <= uint64_t(std::numeric_limits::max())); + int64_t nSize = int64_t(nBytes_); + if (nSize > 0) - nSatoshisPerK = nFeePaid*1000/nSize; + nSatoshisPerK = nFeePaid * 1000 / nSize; else nSatoshisPerK = 0; } -CAmount CFeeRate::GetFee(size_t nSize) const +CAmount CFeeRate::GetFee(size_t nBytes_) const { - CAmount nFee = nSatoshisPerK*nSize / 1000; + assert(nBytes_ <= uint64_t(std::numeric_limits::max())); + int64_t nSize = int64_t(nBytes_); - if (nFee == 0 && nSatoshisPerK > 0) - nFee = nSatoshisPerK; + CAmount nFee = nSatoshisPerK * nSize / 1000; + + if (nFee == 0 && nSize != 0) { + if (nSatoshisPerK > 0) + nFee = CAmount(1); + if (nSatoshisPerK < 0) + nFee = CAmount(-1); + } return nFee; } diff --git a/src/amount.h b/src/amount.h index b224c2c7d..3c2be2c48 100644 --- a/src/amount.h +++ b/src/amount.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,6 +11,7 @@ #include #include +/** Amount in satoshis (Can be negative) */ typedef int64_t CAmount; static const CAmount COIN = 100000000; @@ -30,27 +31,34 @@ extern const std::string CURRENCY_UNIT; static const CAmount MAX_MONEY = 21000000000 * COIN; inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } -/** Type-safe wrapper class to for fee rates - * (how much to pay based on transaction size) +/** + * Fee rate in satoshis per kilobyte: CAmount / kB */ class CFeeRate { private: CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes public: + /** Fee rate of 0 satoshis per kB */ CFeeRate() : nSatoshisPerK(0) { } explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { } - CFeeRate(const CAmount& nFeePaid, size_t nSize); + /** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/ + CFeeRate(const CAmount& nFeePaid, size_t nBytes); CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; } - - CAmount GetFee(size_t size) const; // unit returned is satoshis - CAmount GetFeePerK() const { return GetFee(1000); } // satoshis-per-1000-bytes - + /** + * Return the fee in satoshis for the given size in bytes. + */ + CAmount GetFee(size_t nBytes) const; + /** + * Return the fee in satoshis for a size of 1000 bytes + */ + CAmount GetFeePerK() const { return GetFee(1000); } friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; } friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; } friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; } friend bool operator<=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK <= b.nSatoshisPerK; } friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; } + CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; } std::string ToString() const; ADD_SERIALIZE_METHODS; diff --git a/src/arith_uint256.h b/src/arith_uint256.h index 103c78bb8..ba3d62015 100644 --- a/src/arith_uint256.h +++ b/src/arith_uint256.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2015 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/base58.cpp b/src/base58.cpp index c80918505..d81c26092 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014 The Bitcoin Core developers +// Copyright (c) 2014-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -68,26 +68,31 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) { // Skip & count leading zeroes. int zeroes = 0; + int length = 0; while (pbegin != pend && *pbegin == 0) { pbegin++; zeroes++; } // Allocate enough space in big-endian base58 representation. - std::vector b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up. + int size = (pend - pbegin) * 138 / 100 + 1; // log(256) / log(58), rounded up. + std::vector b58(size); // Process the bytes. while (pbegin != pend) { int carry = *pbegin; + int i = 0; // Apply "b58 = b58 * 256 + ch". - for (std::vector::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) { + for (std::vector::reverse_iterator it = b58.rbegin(); (carry != 0 || i < length) && (it != b58.rend()); it++, i++) { carry += 256 * (*it); *it = carry % 58; carry /= 58; } + assert(carry == 0); + length = i; pbegin++; } // Skip leading zeroes in base58 result. - std::vector::iterator it = b58.begin(); + std::vector::iterator it = b58.begin() + (size - length); while (it != b58.end() && *it == 0) it++; // Translate the result into a string. diff --git a/src/base58.h b/src/base58.h index 90014b949..cccebc9e0 100644 --- a/src/base58.h +++ b/src/base58.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -164,7 +164,7 @@ public: CBitcoinExtKeyBase() {} }; -typedef CBitcoinExtKeyBase CBitcoinExtKey; -typedef CBitcoinExtKeyBase CBitcoinExtPubKey; +typedef CBitcoinExtKeyBase CBitcoinExtKey; +typedef CBitcoinExtKeyBase CBitcoinExtPubKey; #endif // BITCOIN_BASE58_H diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index 89c3b0cc2..6ee3cdc27 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -1,7 +1,9 @@ // Copyright (c) 2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "bench.h" + #include #include diff --git a/src/bench/bench.h b/src/bench/bench.h index bf591a2be..5ce13c642 100644 --- a/src/bench/bench.h +++ b/src/bench/bench.h @@ -1,8 +1,16 @@ // Copyright (c) 2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_BENCH_H -#define BITCOIN_BENCH_H + +#ifndef BITCOIN_BENCH_BENCH_H +#define BITCOIN_BENCH_BENCH_H + +#include +#include + +#include +#include +#include // Simple micro-benchmarking framework; API mostly matches a subset of the Google Benchmark // framework (see https://github.com/google/benchmark) @@ -25,14 +33,7 @@ static void CODE_TO_TIME(benchmark::State& state) BENCHMARK(CODE_TO_TIME); */ - - -#include -#include -#include -#include -#include - + namespace benchmark { class State { @@ -68,4 +69,4 @@ namespace benchmark { #define BENCHMARK(n) \ benchmark::BenchRunner BOOST_PP_CAT(bench_, BOOST_PP_CAT(__LINE__, n))(BOOST_PP_STRINGIZE(n), n); -#endif // BITCOIN_BENCH_H +#endif // BITCOIN_BENCH_BENCH_H diff --git a/src/bitcoin-cli-res.rc b/src/bitcoin-cli-res.rc index 8ff4925fe..0a94d2710 100644 --- a/src/bitcoin-cli-res.rc +++ b/src/bitcoin-cli-res.rc @@ -17,7 +17,7 @@ BEGIN BLOCK "040904E4" // U.S. English - multilingual (hex) BEGIN VALUE "CompanyName", "LBRY, Inc" - VALUE "FileDescription", "lbrycrd-cli (JSON-RPC client for LBRYcrd Core)" + VALUE "FileDescription", "lbrycrd-cli (JSON-RPC client for " PACKAGE_NAME ")" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "lbrycrd-cli" VALUE "LegalCopyright", COPYRIGHT_STR diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 0f00a5d7d..c3dfe26fc 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -1,12 +1,16 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + #include "chainparamsbase.h" #include "clientversion.h" -#include "rpcclient.h" -#include "rpcprotocol.h" +#include "rpc/client.h" +#include "rpc/protocol.h" #include "util.h" #include "utilstrencodings.h" @@ -22,6 +26,7 @@ using namespace std; +static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; std::string HelpMessageCli() @@ -29,15 +34,16 @@ std::string HelpMessageCli() string strUsage; strUsage += HelpMessageGroup(_("Options:")); strUsage += HelpMessageOpt("-?", _("This help message")); - strUsage += HelpMessageOpt("-conf=", strprintf(_("Specify configuration file (default: %s)"), "lbrycrd.conf")); + strUsage += HelpMessageOpt("-conf=", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME)); strUsage += HelpMessageOpt("-datadir=", _("Specify data directory")); AppendParamsHelpMessages(strUsage); - strUsage += HelpMessageOpt("-rpcconnect=", strprintf(_("Send commands to node running on (default: %s)"), "127.0.0.1")); - strUsage += HelpMessageOpt("-rpcport=", strprintf(_("Connect to JSON-RPC on (default: %u or testnet: %u)"), 9245, 19245)); + strUsage += HelpMessageOpt("-rpcconnect=", strprintf(_("Send commands to node running on (default: %s)"), DEFAULT_RPCCONNECT)); + strUsage += HelpMessageOpt("-rpcport=", strprintf(_("Connect to JSON-RPC on (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort())); strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start")); strUsage += HelpMessageOpt("-rpcuser=", _("Username for JSON-RPC connections")); strUsage += HelpMessageOpt("-rpcpassword=", _("Password for JSON-RPC connections")); strUsage += HelpMessageOpt("-rpcclienttimeout=", strprintf(_("Timeout during HTTP requests (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT)); + strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases)")); return strUsage; } @@ -67,11 +73,11 @@ static bool AppInitRPC(int argc, char* argv[]) // Parameters // ParseParameters(argc, argv); - if (argc<2 || mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) { - std::string strUsage = _("LBRYcrd Core RPC client version") + " " + FormatFullVersion() + "\n"; + if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) { + std::string strUsage = strprintf(_("%s RPC client version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n"; if (!mapArgs.count("-version")) { strUsage += "\n" + _("Usage:") + "\n" + - " lbrycrd-cli [options] [params] " + _("Send command to LBRYcrd Core") + "\n" + + " lbrycrd-cli [options] [params] " + strprintf(_("Send command to %s"), _(PACKAGE_NAME)) + "\n" + " lbrycrd-cli [options] help " + _("List commands") + "\n" + " lbrycrd-cli [options] help " + _("Get help for a command") + "\n"; @@ -94,7 +100,7 @@ static bool AppInitRPC(int argc, char* argv[]) // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause) try { SelectBaseParams(ChainNameFromCommandLine()); - } catch(std::exception &e) { + } catch (const std::exception& e) { fprintf(stderr, "Error: %s\n", e.what()); return false; } @@ -141,7 +147,7 @@ static void http_request_done(struct evhttp_request *req, void *ctx) UniValue CallRPC(const string& strMethod, const UniValue& params) { - std::string host = GetArg("-rpcconnect", "127.0.0.1"); + std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT); int port = GetArg("-rpcport", BaseParams().RPCPort()); // Create event base @@ -227,15 +233,17 @@ int CommandLineRPC(int argc, char *argv[]) argc--; argv++; } - - // Method - if (argc < 2) - throw runtime_error("too few parameters"); - string strMethod = argv[1]; - - // Parameters default to strings - std::vector strParams(&argv[2], &argv[argc]); - UniValue params = RPCConvertValues(strMethod, strParams); + std::vector args = std::vector(&argv[1], &argv[argc]); + if (GetBoolArg("-stdin", false)) { + // Read one arg per line from stdin and append + std::string line; + while (std::getline(std::cin,line)) + args.push_back(line); + } + if (args.size() < 1) + throw runtime_error("too few parameters (need at least command)"); + std::string strMethod = args[0]; + UniValue params = RPCConvertValues(strMethod, std::vector(args.begin()+1, args.end())); // Execute and handle connection failures with -rpcwait const bool fWait = GetBoolArg("-rpcwait", false); diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index a96396330..1dffb1398 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -1,7 +1,11 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + #include "base58.h" #include "clientversion.h" #include "coins.h" @@ -37,17 +41,17 @@ static bool AppInitRawTx(int argc, char* argv[]) // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) try { SelectParams(ChainNameFromCommandLine()); - } catch(std::exception &e) { + } catch (const std::exception& e) { fprintf(stderr, "Error: %s\n", e.what()); return false; } fCreateBlank = GetBoolArg("-create", false); - if (argc<2 || mapArgs.count("-?") || mapArgs.count("-help")) + if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help")) { // First part of help message is specific to this utility - std::string strUsage = _("LBRYcrd Core lbrycrd-tx utility version") + " " + FormatFullVersion() + "\n\n" + + std::string strUsage = strprintf(_("%s lbrycrd-tx utility version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n\n" + _("Usage:") + "\n" + " lbrycrd-tx [options] [commands] " + _("Update hex-encoded lbrycrd transaction") + "\n" + " lbrycrd-tx [options] -create [commands] " + _("Create hex-encoded lbrycrd transaction") + "\n" + @@ -477,9 +481,15 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) class Secp256k1Init { + ECCVerifyHandle globalVerifyHandle; + public: - Secp256k1Init() { ECC_Start(); } - ~Secp256k1Init() { ECC_Stop(); } + Secp256k1Init() { + ECC_Start(); + } + ~Secp256k1Init() { + ECC_Stop(); + } }; static void MutateTx(CMutableTransaction& tx, const string& command, diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index b521b7724..9ef12cc73 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -1,18 +1,22 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + #include "chainparams.h" #include "clientversion.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "init.h" #include "noui.h" #include "scheduler.h" #include "util.h" #include "httpserver.h" #include "httprpc.h" -#include "rpcserver.h" +#include "utilstrencodings.h" #include #include @@ -72,18 +76,18 @@ bool AppInit(int argc, char* argv[]) ParseParameters(argc, argv); // Process help and version before taking care about datadir - if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) + if (mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) { - std::string strUsage = _("Bitcoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n"; + std::string strUsage = strprintf(_("%s Daemon"), _(PACKAGE_NAME)) + " " + _("version") + " " + FormatFullVersion() + "\n"; if (mapArgs.count("-version")) { - strUsage += LicenseInfo(); + strUsage += FormatParagraph(LicenseInfo()); } else { strUsage += "\n" + _("Usage:") + "\n" + - " lbrycrdd [options] " + _("Start Bitcoin Core Daemon") + "\n"; + " lbrycrdd [options] " + strprintf(_("Start %s Daemon"), _(PACKAGE_NAME)) + "\n"; strUsage += "\n" + HelpMessage(HMM_BITCOIND); } @@ -109,7 +113,7 @@ bool AppInit(int argc, char* argv[]) // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) try { SelectParams(ChainNameFromCommandLine()); - } catch(std::exception &e) { + } catch (const std::exception& e) { fprintf(stderr, "Error: %s\n", e.what()); return false; } @@ -151,6 +155,9 @@ bool AppInit(int argc, char* argv[]) #endif SoftSetBoolArg("-server", true); + // Set this early so that parameter interactions go to console + InitLogging(); + InitParameterInteraction(); fRet = AppInit2(threadGroup, scheduler); } catch (const std::exception& e) { diff --git a/src/bloom.cpp b/src/bloom.cpp index de8720659..4e6f0e5d2 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2014 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -216,30 +216,54 @@ void CBloomFilter::UpdateEmptyFull() isEmpty = empty; } -CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate) : - b1(nElements * 2, fpRate, 0), b2(nElements * 2, fpRate, 0) +CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate) { - // Implemented using two bloom filters of 2 * nElements each. - // We fill them up, and clear them, staggered, every nElements - // inserted, so at least one always contains the last nElements - // inserted. - nInsertions = 0; - nBloomSize = nElements * 2; - + double logFpRate = log(fpRate); + /* The optimal number of hash functions is log(fpRate) / log(0.5), but + * restrict it to the range 1-50. */ + nHashFuncs = std::max(1, std::min((int)round(logFpRate / log(0.5)), 50)); + /* In this rolling bloom filter, we'll store between 2 and 3 generations of nElements / 2 entries. */ + nEntriesPerGeneration = (nElements + 1) / 2; + uint32_t nMaxElements = nEntriesPerGeneration * 3; + /* The maximum fpRate = pow(1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits), nHashFuncs) + * => pow(fpRate, 1.0 / nHashFuncs) = 1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits) + * => 1.0 - pow(fpRate, 1.0 / nHashFuncs) = exp(-nHashFuncs * nMaxElements / nFilterBits) + * => log(1.0 - pow(fpRate, 1.0 / nHashFuncs)) = -nHashFuncs * nMaxElements / nFilterBits + * => nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - pow(fpRate, 1.0 / nHashFuncs)) + * => nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs)) + */ + uint32_t nFilterBits = (uint32_t)ceil(-1.0 * nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs))); + data.clear(); + /* We store up to 16 'bits' per data element. */ + data.resize((nFilterBits + 15) / 16); reset(); } +/* Similar to CBloomFilter::Hash */ +inline unsigned int CRollingBloomFilter::Hash(unsigned int nHashNum, const std::vector& vDataToHash) const { + return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (data.size() * 16); +} + void CRollingBloomFilter::insert(const std::vector& vKey) { - if (nInsertions == 0) { - b1.clear(); - } else if (nInsertions == nBloomSize / 2) { - b2.clear(); + if (nEntriesThisGeneration == nEntriesPerGeneration) { + nEntriesThisGeneration = 0; + nGeneration++; + if (nGeneration == 4) { + nGeneration = 1; + } + /* Wipe old entries that used this generation number. */ + for (uint32_t p = 0; p < data.size() * 16; p++) { + if (get(p) == nGeneration) { + put(p, 0); + } + } } - b1.insert(vKey); - b2.insert(vKey); - if (++nInsertions == nBloomSize) { - nInsertions = 0; + nEntriesThisGeneration++; + + for (int n = 0; n < nHashFuncs; n++) { + uint32_t h = Hash(n, vKey); + put(h, nGeneration); } } @@ -251,10 +275,13 @@ void CRollingBloomFilter::insert(const uint256& hash) bool CRollingBloomFilter::contains(const std::vector& vKey) const { - if (nInsertions < nBloomSize / 2) { - return b2.contains(vKey); + for (int n = 0; n < nHashFuncs; n++) { + uint32_t h = Hash(n, vKey); + if (get(h) == 0) { + return false; + } } - return b1.contains(vKey); + return true; } bool CRollingBloomFilter::contains(const uint256& hash) const @@ -265,8 +292,10 @@ bool CRollingBloomFilter::contains(const uint256& hash) const void CRollingBloomFilter::reset() { - unsigned int nNewTweak = GetRand(std::numeric_limits::max()); - b1.reset(nNewTweak); - b2.reset(nNewTweak); - nInsertions = 0; + nTweak = GetRand(std::numeric_limits::max()); + nEntriesThisGeneration = 0; + nGeneration = 1; + for (std::vector::iterator it = data.begin(); it != data.end(); it++) { + *it = 0; + } } diff --git a/src/bloom.h b/src/bloom.h index a4dba8cb4..b0ad8b875 100644 --- a/src/bloom.h +++ b/src/bloom.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2014 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -110,8 +110,11 @@ public: * reset() is provided, which also changes nTweak to decrease the impact of * false-positives. * - * contains(item) will always return true if item was one of the last N things + * contains(item) will always return true if item was one of the last N to 1.5*N * insert()'ed ... but may also return true for items that were not inserted. + * + * It needs around 1.8 bytes per element per factor 0.1 of false positive rate. + * (More accurately: 3/(log(256)*log(2)) * log(1/fpRate) * nElements bytes) */ class CRollingBloomFilter { @@ -129,10 +132,23 @@ public: void reset(); private: - unsigned int nBloomSize; - unsigned int nInsertions; - CBloomFilter b1, b2; + int nEntriesPerGeneration; + int nEntriesThisGeneration; + int nGeneration; + std::vector data; + unsigned int nTweak; + int nHashFuncs; + + unsigned int Hash(unsigned int nHashNum, const std::vector& vDataToHash) const; + + inline int get(uint32_t position) const { + return (data[(position >> 4) % data.size()] >> (2 * (position & 0xF))) & 0x3; + } + + inline void put(uint32_t position, uint32_t val) { + uint32_t& cell = data[(position >> 4) % data.size()]; + cell = (cell & ~(((uint32_t)3) << (2 * (position & 0xF)))) | (val << (2 * (position & 0xF))); + } }; - #endif // BITCOIN_BLOOM_H diff --git a/src/chain.cpp b/src/chain.cpp index 5b8ce076c..32f6480f8 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -51,6 +51,9 @@ CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const { } const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const { + if (pindex == NULL) { + return NULL; + } if (pindex->nHeight > Height()) pindex = pindex->GetAncestor(Height()); while (pindex && !Contains(pindex)) @@ -107,3 +110,35 @@ void CBlockIndex::BuildSkip() if (pprev) pskip = pprev->GetAncestor(GetSkipHeight(nHeight)); } + +arith_uint256 GetBlockProof(const CBlockIndex& block) +{ + arith_uint256 bnTarget; + bool fNegative; + bool fOverflow; + bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); + if (fNegative || fOverflow || bnTarget == 0) + return 0; + // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 + // as it's too large for a arith_uint256. However, as 2**256 is at least as large + // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, + // or ~bnTarget / (nTarget+1) + 1. + return (~bnTarget / (bnTarget + 1)) + 1; +} + +int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params) +{ + arith_uint256 r; + int sign = 1; + if (to.nChainWork > from.nChainWork) { + r = to.nChainWork - from.nChainWork; + } else { + r = from.nChainWork - to.nChainWork; + sign = -1; + } + r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip); + if (r.bits() > 63) { + return sign * std::numeric_limits::max(); + } + return sign * r.GetLow64(); +} diff --git a/src/chain.h b/src/chain.h index 3b800934c..3761bb087 100644 --- a/src/chain.h +++ b/src/chain.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,8 +14,6 @@ #include -#include - struct CDiskBlockPos { int nFile; @@ -292,6 +290,10 @@ public: const CBlockIndex* GetAncestor(int height) const; }; +arith_uint256 GetBlockProof(const CBlockIndex& block); +/** 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. */ +int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&); + /** Used to marshal pointers into hashes for db storage. */ class CDiskBlockIndex : public CBlockIndex { diff --git a/src/chainparams.cpp b/src/chainparams.cpp index a433d7d0e..15beb38bf 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -1,9 +1,10 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "chainparams.h" +#include "consensus/merkle.h" #include "tinyformat.h" #include "util.h" @@ -56,7 +57,7 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi genesis.nVersion = nVersion; genesis.vtx.push_back(txNew); genesis.hashPrevBlock.SetNull(); - genesis.hashMerkleRoot = genesis.ComputeMerkleRoot(); + genesis.hashMerkleRoot = BlockMerkleRoot(genesis); genesis.hashClaimTrie = uint256S("0x0000000000000000000000000000000000000000000000000000000000000001"); /*while (true) @@ -110,12 +111,25 @@ public: consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; + consensus.BIP34Height = 227931; + consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"); consensus.powLimit = uint256S("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 150 * 24 * 2; // 2 hours consensus.nPowTargetSpacing = 150; consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; - /** + consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 + consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 + + // Deployment of BIP68, BIP112, and BIP113. + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1462060800; // May 1st, 2016 + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017 + + /** * The message start string is designed to be unlikely to occur in normal data. * The characters are rarely used upper ASCII, not valid as UTF-8, and produce * a large 32-bit integer with any alignment. @@ -124,9 +138,7 @@ public: pchMessageStart[1] = 0xe4; pchMessageStart[2] = 0xaa; pchMessageStart[3] = 0xf1; - vAlertPubKey = ParseHex("04a887418f021a52e33c345367ba4265890f4e295426894f4e1aece407f6441b14a036efa702d6abeb2c61883e11dd00ddc193f669c23a896981c632a73f1314ae"); nDefaultPort = 9246; - nMaxTipAge = 24 * 60 * 60; nPruneAfterHeight = 100000; genesis = CreateGenesisBlock(1446058291, 71748, 0x1f00ffff, 1, 400000000 * COIN, consensus); @@ -174,24 +186,33 @@ class CTestNetParams : public CChainParams { public: CTestNetParams() { strNetworkID = "test"; - - consensus.nSubsidyLevelInterval = 1 << 5; - consensus.nMajorityEnforceBlockUpgrade = 750; - consensus.nMajorityRejectBlockOutdated = 950; - consensus.nMajorityWindow = 1000; + consensus.nMajorityEnforceBlockUpgrade = 51; + consensus.nMajorityRejectBlockOutdated = 75; + consensus.nMajorityWindow = 100; + consensus.BIP34Height = 21111; + consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8"); consensus.powLimit = uint256S("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 30 * 60 * 12;//14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 30; - consensus.fPowAllowMinDifficultyBlocks = false; + consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = false; + consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains + consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 + + // Deployment of BIP68, BIP112, and BIP113. + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1456790400; // March 1st, 2016 + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017 + pchMessageStart[0] = 0x1d; pchMessageStart[1] = 0x0c; pchMessageStart[2] = 0xaa; pchMessageStart[3] = 0xd1; - vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"); nDefaultPort = 19246; - nMaxTipAge = 0x7fffffff; nPruneAfterHeight = 1000; genesis = CreateGenesisBlock(1446058291, 71748, 0x1f00ffff, 1, 400000000 * COIN, consensus); @@ -203,7 +224,6 @@ public: vFixedSeeds.clear(); vSeeds.clear(); - //vSeeds.push_back(CDNSSeedData("alexykot.me", "testnet-seed.alexykot.me")); //vSeeds.push_back(CDNSSeedData("bitcoin.petertodd.org", "testnet-seed.bitcoin.petertodd.org")); //vSeeds.push_back(CDNSSeedData("bluematt.me", "testnet-seed.bluematt.me")); //vSeeds.push_back(CDNSSeedData("bitcoin.schildbach.de", "testnet-seed.bitcoin.schildbach.de")); @@ -245,17 +265,26 @@ public: consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; + consensus.BIP34Height = -1; // BIP34 has not necessarily activated on regtest + consensus.BIP34Hash = uint256(); consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 30 * 60 * 12;//14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 30; consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; + consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains + consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016) + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL; + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL; pchMessageStart[0] = 0xfb; pchMessageStart[1] = 0xbe; pchMessageStart[2] = 0xbf; pchMessageStart[3] = 0xd9; - nMaxTipAge = 24 * 60 * 60; nDefaultPort = 29246; nPruneAfterHeight = 1000; @@ -266,8 +295,8 @@ public: assert(consensus.hashGenesisBlock == uint256S("0x6e3fcf1299d4ec5d79c3a4c91d624a4acf9e2e173d95a1a0504f677669687556")); assert(genesis.hashMerkleRoot == uint256S("0xb8211c82c3d15bcd78bba57005b86fed515149a53a425eb592c07af99fe559cc")); - vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds. - vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds. + vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds. + vSeeds.clear(); //!< Regtest mode doesn't have any DNS seeds. fMiningRequiresPeers = false; fDefaultConsistencyChecks = true; diff --git a/src/chainparams.h b/src/chainparams.h index cb061d596..59202f548 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -54,7 +54,6 @@ public: const Consensus::Params& GetConsensus() const { return consensus; } const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } - const std::vector& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } const CBlock& GenesisBlock() const { return genesis; } @@ -64,8 +63,7 @@ public: bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; } /** Policy: Filter transactions that do not match well-defined patterns */ bool RequireStandard() const { return fRequireStandard; } - int64_t MaxTipAge() const { return nMaxTipAge; } - int64_t PruneAfterHeight() const { return nPruneAfterHeight; } + uint64_t PruneAfterHeight() const { return nPruneAfterHeight; } /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */ bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } /** In the future use NetworkIDString() for RPC fields */ @@ -81,10 +79,7 @@ protected: Consensus::Params consensus; CMessageHeader::MessageStartChars pchMessageStart; - //! Raw pub key bytes for the broadcast alert signing key. - std::vector vAlertPubKey; int nDefaultPort; - long nMaxTipAge; uint64_t nPruneAfterHeight; std::vector vSeeds; std::vector base58Prefixes[MAX_BASE58_TYPES]; diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 4872122b3..f7f521cc8 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -65,19 +65,6 @@ public: }; static CBaseRegTestParams regTestParams; -/* - * Unit test - */ -class CBaseUnitTestParams : public CBaseMainParams -{ -public: - CBaseUnitTestParams() - { - strDataDir = "unittest"; - } -}; -static CBaseUnitTestParams unitTestParams; - static CBaseChainParams* pCurrentBaseParams = 0; const CBaseChainParams& BaseParams() @@ -86,18 +73,23 @@ const CBaseChainParams& BaseParams() return *pCurrentBaseParams; } -void SelectBaseParams(const std::string& chain) +CBaseChainParams& BaseParams(const std::string& chain) { if (chain == CBaseChainParams::MAIN) - pCurrentBaseParams = &mainParams; + return mainParams; else if (chain == CBaseChainParams::TESTNET) - pCurrentBaseParams = &testNetParams; + return testNetParams; else if (chain == CBaseChainParams::REGTEST) - pCurrentBaseParams = ®TestParams; + return regTestParams; else throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); } +void SelectBaseParams(const std::string& chain) +{ + pCurrentBaseParams = &BaseParams(chain); +} + std::string ChainNameFromCommandLine() { bool fRegTest = GetBoolArg("-regtest", false); diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h index 095c4cbdc..59493afb9 100644 --- a/src/chainparamsbase.h +++ b/src/chainparamsbase.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014 The Bitcoin Core developers +// Copyright (c) 2014-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -42,6 +42,8 @@ void AppendParamsHelpMessages(std::string& strUsage, bool debugHelp=true); */ const CBaseChainParams& BaseParams(); +CBaseChainParams& BaseParams(const std::string& chain); + /** Sets the params returned by Params() to those for the given network. */ void SelectBaseParams(const std::string& chain); diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index a9822eed8..aefddce46 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/checkpoints.h b/src/checkpoints.h index 5fce6fa81..cd25ea537 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/checkqueue.h b/src/checkqueue.h index 20ba25bb4..32e25d5c8 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2014 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/claimtrie.cpp b/src/claimtrie.cpp index 561f15b5f..1473ef59c 100644 --- a/src/claimtrie.cpp +++ b/src/claimtrie.cpp @@ -149,7 +149,7 @@ bool CClaimTrie::empty() const template bool CClaimTrie::keyTypeEmpty(char keyType, K& dummy) const { - boost::scoped_ptr pcursor(const_cast(&db)->NewIterator()); + boost::scoped_ptr pcursor(const_cast(&db)->NewIterator()); pcursor->SeekToFirst(); while (pcursor->Valid()) @@ -824,7 +824,7 @@ bool CClaimTrie::updateTakeoverHeight(const std::string& name, int nTakeoverHeig return true; } -void CClaimTrie::BatchWriteNode(CLevelDBBatch& batch, const std::string& name, const CClaimTrieNode* pNode) const +void CClaimTrie::BatchWriteNode(CDBBatch& batch, const std::string& name, const CClaimTrieNode* pNode) const { uint32_t num_claims = 0; if (pNode) @@ -836,7 +836,7 @@ void CClaimTrie::BatchWriteNode(CLevelDBBatch& batch, const std::string& name, c batch.Erase(std::make_pair(TRIE_NODE, name)); } -void CClaimTrie::BatchWriteQueueRows(CLevelDBBatch& batch) +void CClaimTrie::BatchWriteQueueRows(CDBBatch& batch) { for (claimQueueType::iterator itQueue = dirtyQueueRows.begin(); itQueue != dirtyQueueRows.end(); ++itQueue) { @@ -851,7 +851,7 @@ void CClaimTrie::BatchWriteQueueRows(CLevelDBBatch& batch) } } -void CClaimTrie::BatchWriteQueueNameRows(CLevelDBBatch& batch) +void CClaimTrie::BatchWriteQueueNameRows(CDBBatch& batch) { for (queueNameType::iterator itQueue = dirtyQueueNameRows.begin(); itQueue != dirtyQueueNameRows.end(); ++itQueue) { @@ -866,7 +866,7 @@ void CClaimTrie::BatchWriteQueueNameRows(CLevelDBBatch& batch) } } -void CClaimTrie::BatchWriteExpirationQueueRows(CLevelDBBatch& batch) +void CClaimTrie::BatchWriteExpirationQueueRows(CDBBatch& batch) { for (expirationQueueType::iterator itQueue = dirtyExpirationQueueRows.begin(); itQueue != dirtyExpirationQueueRows.end(); ++itQueue) { @@ -881,7 +881,7 @@ void CClaimTrie::BatchWriteExpirationQueueRows(CLevelDBBatch& batch) } } -void CClaimTrie::BatchWriteSupportNodes(CLevelDBBatch& batch) +void CClaimTrie::BatchWriteSupportNodes(CDBBatch& batch) { for (supportMapType::iterator itSupport = dirtySupportNodes.begin(); itSupport != dirtySupportNodes.end(); ++itSupport) { @@ -896,7 +896,7 @@ void CClaimTrie::BatchWriteSupportNodes(CLevelDBBatch& batch) } } -void CClaimTrie::BatchWriteSupportQueueRows(CLevelDBBatch& batch) +void CClaimTrie::BatchWriteSupportQueueRows(CDBBatch& batch) { for (supportQueueType::iterator itQueue = dirtySupportQueueRows.begin(); itQueue != dirtySupportQueueRows.end(); ++itQueue) { @@ -911,7 +911,7 @@ void CClaimTrie::BatchWriteSupportQueueRows(CLevelDBBatch& batch) } } -void CClaimTrie::BatchWriteSupportQueueNameRows(CLevelDBBatch& batch) +void CClaimTrie::BatchWriteSupportQueueNameRows(CDBBatch& batch) { for (queueNameType::iterator itQueue = dirtySupportQueueNameRows.begin(); itQueue != dirtySupportQueueNameRows.end(); ++itQueue) { @@ -926,7 +926,7 @@ void CClaimTrie::BatchWriteSupportQueueNameRows(CLevelDBBatch& batch) } } -void CClaimTrie::BatchWriteSupportExpirationQueueRows(CLevelDBBatch& batch) +void CClaimTrie::BatchWriteSupportExpirationQueueRows(CDBBatch& batch) { for (expirationQueueType::iterator itQueue = dirtySupportExpirationQueueRows.begin(); itQueue != dirtySupportExpirationQueueRows.end(); ++itQueue) { @@ -943,7 +943,7 @@ void CClaimTrie::BatchWriteSupportExpirationQueueRows(CLevelDBBatch& batch) bool CClaimTrie::WriteToDisk() { - CLevelDBBatch batch(&db.GetObfuscateKey()); + CDBBatch batch(&db.GetObfuscateKey()); for (nodeCacheType::iterator itcache = dirtyNodes.begin(); itcache != dirtyNodes.end(); ++itcache) BatchWriteNode(batch, itcache->first, itcache->second); dirtyNodes.clear(); @@ -991,7 +991,7 @@ bool CClaimTrie::ReadFromDisk(bool check) LogPrintf("%s: Couldn't read the best block's hash\n", __func__); if (!db.Read(CURRENT_HEIGHT, nCurrentHeight)) LogPrintf("%s: Couldn't read the current height\n", __func__); - boost::scoped_ptr pcursor(const_cast(&db)->NewIterator()); + boost::scoped_ptr pcursor(const_cast(&db)->NewIterator()); pcursor->SeekToFirst(); while (pcursor->Valid()) diff --git a/src/claimtrie.h b/src/claimtrie.h index b7275538a..6cd28b7b2 100644 --- a/src/claimtrie.h +++ b/src/claimtrie.h @@ -5,7 +5,7 @@ #include "serialize.h" #include "uint256.h" #include "util.h" -#include "leveldbwrapper.h" +#include "dbwrapper.h" #include "primitives/transaction.h" #include @@ -321,7 +321,7 @@ public: friend class CClaimTrieCache; - CLevelDBWrapper db; + CDBWrapper db; int nCurrentHeight; int nExpirationTime; int nProportionalDelayFactor; @@ -367,16 +367,16 @@ private: queueNameRowType& row); void updateSupportExpirationQueue(int nHeight, expirationQueueRowType& row); - void BatchWriteNode(CLevelDBBatch& batch, const std::string& name, + void BatchWriteNode(CDBBatch& batch, const std::string& name, const CClaimTrieNode* pNode) const; - void BatchEraseNode(CLevelDBBatch& batch, const std::string& nome) const; - void BatchWriteQueueRows(CLevelDBBatch& batch); - void BatchWriteQueueNameRows(CLevelDBBatch& batch); - void BatchWriteExpirationQueueRows(CLevelDBBatch& batch); - void BatchWriteSupportNodes(CLevelDBBatch& batch); - void BatchWriteSupportQueueRows(CLevelDBBatch& batch); - void BatchWriteSupportQueueNameRows(CLevelDBBatch& batch); - void BatchWriteSupportExpirationQueueRows(CLevelDBBatch& batch); + void BatchEraseNode(CDBBatch& batch, const std::string& nome) const; + void BatchWriteQueueRows(CDBBatch& batch); + void BatchWriteQueueNameRows(CDBBatch& batch); + void BatchWriteExpirationQueueRows(CDBBatch& batch); + void BatchWriteSupportNodes(CDBBatch& batch); + void BatchWriteSupportQueueRows(CDBBatch& batch); + void BatchWriteSupportQueueNameRows(CDBBatch& batch); + void BatchWriteSupportExpirationQueueRows(CDBBatch& batch); template bool keyTypeEmpty(char key, K& dummy) const; CClaimTrieNode root; diff --git a/src/clientversion.h b/src/clientversion.h index 5a06b310a..6f255d69c 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,7 +15,7 @@ //! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 0 -#define CLIENT_VERSION_MINOR 11 +#define CLIENT_VERSION_MINOR 12 #define CLIENT_VERSION_REVISION 99 #define CLIENT_VERSION_BUILD 0 @@ -26,7 +26,7 @@ * Copyright year (2009-this) * Todo: update this when changing our copyright comments in the source */ -#define COPYRIGHT_YEAR 2015 +#define COPYRIGHT_YEAR 2016 #endif //HAVE_CONFIG_H @@ -38,7 +38,7 @@ #define DO_STRINGIZE(X) #X //! Copyright string used in Windows .rc files -#define COPYRIGHT_STR "2009-" STRINGIZE(COPYRIGHT_YEAR) " The Bitcoin Core Developers" +#define COPYRIGHT_STR "2009-" STRINGIZE(COPYRIGHT_YEAR) " " COPYRIGHT_HOLDERS_FINAL /** * bitcoind-res.rc includes this file, but it cannot cope with real c++ code. diff --git a/src/coincontrol.h b/src/coincontrol.h index bc965f9e1..12fe9ce21 100644 --- a/src/coincontrol.h +++ b/src/coincontrol.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,6 +16,8 @@ public: bool fAllowOtherInputs; //! Includes watch only addresses which match the ISMINE_WATCH_SOLVABLE criteria bool fAllowWatchOnly; + //! Minimum absolute fee (not per kilobyte) + CAmount nMinimumTotalFee; CCoinControl() { @@ -28,6 +30,7 @@ public: fAllowOtherInputs = false; fAllowWatchOnly = false; setSelected.clear(); + nMinimumTotalFee = 0; } bool HasSelected() const @@ -35,10 +38,9 @@ public: return (setSelected.size() > 0); } - bool IsSelected(const uint256& hash, unsigned int n) const + bool IsSelected(const COutPoint& output) const { - COutPoint outpt(hash, n); - return (setSelected.count(outpt) > 0); + return (setSelected.count(output) > 0); } void Select(const COutPoint& output) diff --git a/src/coins.cpp b/src/coins.cpp index f02949de5..1c329740b 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2014 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -45,7 +45,7 @@ bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return fal bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; } uint256 CCoinsView::GetBestBlock() const { return uint256(); } bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; } -bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; } +CCoinsViewCursor *CCoinsView::Cursor() const { return 0; } CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { } @@ -54,7 +54,7 @@ bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveC uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } -bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); } +CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); } CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {} @@ -117,6 +117,21 @@ CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) { return CCoinsModifier(*this, ret.first, cachedCoinUsage); } +// ModifyNewCoins has to know whether the new outputs its creating are for a +// coinbase or not. If they are for a coinbase, it can not mark them as fresh. +// This is to ensure that the historical duplicate coinbases before BIP30 was +// in effect will still be properly overwritten when spent. +CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid, bool coinbase) { + assert(!hasModifier); + std::pair ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); + ret.first->second.coins.Clear(); + if (!coinbase) { + ret.first->second.flags = CCoinsCacheEntry::FRESH; + } + ret.first->second.flags |= CCoinsCacheEntry::DIRTY; + return CCoinsModifier(*this, ret.first, 0); +} + const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const { CCoinsMap::const_iterator it = FetchCoins(txid); if (it == cacheCoins.end()) { @@ -135,6 +150,11 @@ bool CCoinsViewCache::HaveCoins(const uint256 &txid) const { return (it != cacheCoins.end() && !it->second.coins.vout.empty()); } +bool CCoinsViewCache::HaveCoinsInCache(const uint256 &txid) const { + CCoinsMap::const_iterator it = cacheCoins.find(txid); + return it != cacheCoins.end(); +} + uint256 CCoinsViewCache::GetBestBlock() const { if (hashBlock.IsNull()) hashBlock = base->GetBestBlock(); @@ -151,18 +171,23 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization). CCoinsMap::iterator itUs = cacheCoins.find(it->first); if (itUs == cacheCoins.end()) { - if (!it->second.coins.IsPruned()) { - // The parent cache does not have an entry, while the child - // cache does have (a non-pruned) one. Move the data up, and - // mark it as fresh (if the grandparent did have it, we - // would have pulled it in at first GetCoins). - assert(it->second.flags & CCoinsCacheEntry::FRESH); + // The parent cache does not have an entry, while the child does + // We can ignore it if it's both FRESH and pruned in the child + if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coins.IsPruned())) { + // Otherwise we will need to create it in the parent + // and move the data up and mark it as dirty CCoinsCacheEntry& entry = cacheCoins[it->first]; entry.coins.swap(it->second.coins); cachedCoinsUsage += entry.coins.DynamicMemoryUsage(); - entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH; + entry.flags = CCoinsCacheEntry::DIRTY; + // We can mark it FRESH in the parent if it was FRESH in the child + // Otherwise it might have just been flushed from the parent's cache + // and already exist in the grandparent + if (it->second.flags & CCoinsCacheEntry::FRESH) + entry.flags |= CCoinsCacheEntry::FRESH; } } else { + // Found the entry in the parent cache if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) { // The grandparent does not have an entry, and the child is // modified and being pruned. This means we can just delete @@ -192,6 +217,15 @@ bool CCoinsViewCache::Flush() { return fOk; } +void CCoinsViewCache::Uncache(const uint256& hash) +{ + CCoinsMap::iterator it = cacheCoins.find(hash); + if (it != cacheCoins.end() && it->second.flags == 0) { + cachedCoinsUsage -= it->second.coins.DynamicMemoryUsage(); + cacheCoins.erase(it); + } +} + unsigned int CCoinsViewCache::GetCacheSize() const { return cacheCoins.size(); } @@ -229,8 +263,9 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const return true; } -double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const +double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const { + inChainInputValue = 0; if (tx.IsCoinBase()) return 0.0; double dResult = 0.0; @@ -239,8 +274,9 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const const CCoins* coins = AccessCoins(txin.prevout.hash); assert(coins); if (!coins->IsAvailable(txin.prevout.n)) continue; - if (coins->nHeight < nHeight) { + if (coins->nHeight <= nHeight) { dResult += coins->vout[txin.prevout.n].nValue * (nHeight-coins->nHeight); + inChainInputValue += coins->vout[txin.prevout.n].nValue; } } return tx.ComputePriority(dResult); @@ -264,3 +300,7 @@ CCoinsModifier::~CCoinsModifier() cache.cachedCoinsUsage += it->second.coins.DynamicMemoryUsage(); } } + +CCoinsViewCursor::~CCoinsViewCursor() +{ +} diff --git a/src/coins.h b/src/coins.h index bf4a777b8..d72f88547 100644 --- a/src/coins.h +++ b/src/coins.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -29,11 +29,11 @@ * - VARINT(nHeight) * * The nCode value consists of: - * - bit 1: IsCoinBase() - * - bit 2: vout[0] is not spent - * - bit 4: vout[1] is not spent + * - bit 0: IsCoinBase() + * - bit 1: vout[0] is not spent + * - bit 2: vout[1] is not spent * - The higher bits encode N, the number of non-zero bytes in the following bitvector. - * - In case both bit 2 and bit 4 are unset, they encode N-1, as there must be at + * - In case both bit 1 and bit 2 are unset, they encode N-1, as there must be at * least one non-spent output). * * Example: 0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e @@ -58,7 +58,7 @@ * * - version = 1 * - code = 9 (coinbase, neither vout[0] or vout[1] are unspent, - * 2 (1, +1 because both bit 2 and bit 4 are unset) non-zero bitvector bytes follow) + * 2 (1, +1 because both bit 1 and bit 2 are unset) non-zero bitvector bytes follow) * - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent * - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee * * 86ef97d579: compact amount representation for 234925952 (2.35 BTC) @@ -297,20 +297,27 @@ struct CCoinsCacheEntry typedef boost::unordered_map CCoinsMap; -struct CCoinsStats +/** Cursor for iterating over CoinsView state */ +class CCoinsViewCursor { - int nHeight; +public: + CCoinsViewCursor(const uint256 &hashBlockIn): hashBlock(hashBlockIn) {} + virtual ~CCoinsViewCursor(); + + virtual bool GetKey(uint256 &key) const = 0; + virtual bool GetValue(CCoins &coins) const = 0; + /* Don't care about GetKeySize here */ + virtual unsigned int GetValueSize() const = 0; + + virtual bool Valid() const = 0; + virtual void Next() = 0; + + //! Get best block at the time this cursor was created + const uint256 &GetBestBlock() const { return hashBlock; } +private: uint256 hashBlock; - uint64_t nTransactions; - uint64_t nTransactionOutputs; - uint64_t nSerializedSize; - uint256 hashSerialized; - CAmount nTotalAmount; - - CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), nTotalAmount(0) {} }; - /** Abstract view on the open txout dataset. */ class CCoinsView { @@ -329,8 +336,8 @@ public: //! The passed mapCoins can be modified. virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); - //! Calculate statistics about the unspent transaction output set - virtual bool GetStats(CCoinsStats &stats) const; + //! Get a cursor to iterate over the whole state + virtual CCoinsViewCursor *Cursor() const; //! As we use CCoinsViews polymorphically, have a virtual destructor virtual ~CCoinsView() {} @@ -350,7 +357,7 @@ public: uint256 GetBestBlock() const; void SetBackend(CCoinsView &viewIn); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); - bool GetStats(CCoinsStats &stats) const; + CCoinsViewCursor *Cursor() const; }; @@ -405,6 +412,13 @@ public: void SetBestBlock(const uint256 &hashBlock); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); + /** + * Check if we have the given tx already loaded in this cache. + * The semantics are the same as HaveCoins(), but no calls to + * the backing CCoinsView are made. + */ + bool HaveCoinsInCache(const uint256 &txid) const; + /** * Return a pointer to CCoins in the cache, or NULL if not found. This is * more efficient than GetCoins. Modifications to other cache entries are @@ -419,6 +433,17 @@ public: */ CCoinsModifier ModifyCoins(const uint256 &txid); + /** + * Return a modifiable reference to a CCoins. Assumes that no entry with the given + * txid exists and creates a new one. This saves a database access in the case where + * the coins were to be wiped out by FromTx anyway. This should not be called with + * the 2 historical coinbase duplicate pairs because the new coins are marked fresh, and + * in the event the duplicate coinbase was spent before a flush, the now pruned coins + * would not properly overwrite the first coinbase of the pair. Simultaneous modifications + * are not allowed. + */ + CCoinsModifier ModifyNewCoins(const uint256 &txid, bool coinbase); + /** * Push the modifications applied to this cache to its base. * Failure to call this method before destruction will cause the changes to be forgotten. @@ -426,6 +451,12 @@ public: */ bool Flush(); + /** + * Removes the transaction with the given hash from the cache, if it is + * not modified. + */ + void Uncache(const uint256 &txid); + //! Calculate the size of the cache (in number of transactions) unsigned int GetCacheSize() const; @@ -445,8 +476,12 @@ public: //! Check whether all prevouts of the transaction are present in the UTXO set represented by this view bool HaveInputs(const CTransaction& tx) const; - //! Return priority of tx at height nHeight - double GetPriority(const CTransaction &tx, int nHeight) const; + /** + * Return priority of tx at height nHeight. Also calculate the sum of the values of the inputs + * that are already in the chain. These are the inputs that will age and increase priority as + * new blocks are added to the chain. + */ + double GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const; const CTxOut &GetOutputFor(const CTxIn& input) const; diff --git a/src/compat.h b/src/compat.h index 5378c2c76..1225ea18e 100644 --- a/src/compat.h +++ b/src/compat.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include diff --git a/src/compat/endian.h b/src/compat/endian.h index 9fec2a07f..6bfae42c7 100644 --- a/src/compat/endian.h +++ b/src/compat/endian.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014 The Bitcoin developers +// Copyright (c) 2014-2015 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 9e7dd468e..de58c2bf3 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,4 +13,13 @@ static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ static const int COINBASE_MATURITY = 100; +/** Flags for nSequence and nLockTime locks */ +enum { + /* Interpret sequence numbers as relative lock-time constraints. */ + LOCKTIME_VERIFY_SEQUENCE = (1 << 0), + + /* Use GetMedianTimePast() instead of nTime for end point timestamp. */ + LOCKTIME_MEDIAN_TIME_PAST = (1 << 1), +}; + #endif // BITCOIN_CONSENSUS_CONSENSUS_H diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp new file mode 100644 index 000000000..22eb7159a --- /dev/null +++ b/src/consensus/merkle.cpp @@ -0,0 +1,176 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "merkle.h" +#include "hash.h" +#include "utilstrencodings.h" + +/* WARNING! If you're reading this because you're learning about crypto + and/or designing a new system that will use merkle trees, keep in mind + that the following merkle tree algorithm has a serious flaw related to + duplicate txids, resulting in a vulnerability (CVE-2012-2459). + + The reason is that if the number of hashes in the list at a given time + is odd, the last one is duplicated before computing the next level (which + is unusual in Merkle trees). This results in certain sequences of + transactions leading to the same merkle root. For example, these two + trees: + + A A + / \ / \ + B C B C + / \ | / \ / \ + D E F D E F F + / \ / \ / \ / \ / \ / \ / \ + 1 2 3 4 5 6 1 2 3 4 5 6 5 6 + + for transaction lists [1,2,3,4,5,6] and [1,2,3,4,5,6,5,6] (where 5 and + 6 are repeated) result in the same root hash A (because the hash of both + of (F) and (F,F) is C). + + The vulnerability results from being able to send a block with such a + transaction list, with the same merkle root, and the same block hash as + the original without duplication, resulting in failed validation. If the + receiving node proceeds to mark that block as permanently invalid + however, it will fail to accept further unmodified (and thus potentially + valid) versions of the same block. We defend against this by detecting + the case where we would hash two identical hashes at the end of the list + together, and treating that identically to the block having an invalid + merkle root. Assuming no double-SHA256 collisions, this will detect all + known ways of changing the transactions without affecting the merkle + root. +*/ + +/* This implements a constant-space merkle root/path calculator, limited to 2^32 leaves. */ +static void MerkleComputation(const std::vector& leaves, uint256* proot, bool* pmutated, uint32_t branchpos, std::vector* pbranch) { + if (pbranch) pbranch->clear(); + if (leaves.size() == 0) { + if (pmutated) *pmutated = false; + if (proot) *proot = uint256(); + return; + } + bool mutated = false; + // count is the number of leaves processed so far. + uint32_t count = 0; + // inner is an array of eagerly computed subtree hashes, indexed by tree + // level (0 being the leaves). + // For example, when count is 25 (11001 in binary), inner[4] is the hash of + // the first 16 leaves, inner[3] of the next 8 leaves, and inner[0] equal to + // the last leaf. The other inner entries are undefined. + uint256 inner[32]; + // Which position in inner is a hash that depends on the matching leaf. + int matchlevel = -1; + // First process all leaves into 'inner' values. + while (count < leaves.size()) { + uint256 h = leaves[count]; + bool matchh = count == branchpos; + count++; + int level; + // For each of the lower bits in count that are 0, do 1 step. Each + // corresponds to an inner value that existed before processing the + // current leaf, and each needs a hash to combine it. + for (level = 0; !(count & (((uint32_t)1) << level)); level++) { + if (pbranch) { + if (matchh) { + pbranch->push_back(inner[level]); + } else if (matchlevel == level) { + pbranch->push_back(h); + matchh = true; + } + } + mutated |= (inner[level] == h); + CHash256().Write(inner[level].begin(), 32).Write(h.begin(), 32).Finalize(h.begin()); + } + // Store the resulting hash at inner position level. + inner[level] = h; + if (matchh) { + matchlevel = level; + } + } + // Do a final 'sweep' over the rightmost branch of the tree to process + // odd levels, and reduce everything to a single top value. + // Level is the level (counted from the bottom) up to which we've sweeped. + int level = 0; + // As long as bit number level in count is zero, skip it. It means there + // is nothing left at this level. + while (!(count & (((uint32_t)1) << level))) { + level++; + } + uint256 h = inner[level]; + bool matchh = matchlevel == level; + while (count != (((uint32_t)1) << level)) { + // If we reach this point, h is an inner value that is not the top. + // We combine it with itself (Bitcoin's special rule for odd levels in + // the tree) to produce a higher level one. + if (pbranch && matchh) { + pbranch->push_back(h); + } + CHash256().Write(h.begin(), 32).Write(h.begin(), 32).Finalize(h.begin()); + // Increment count to the value it would have if two entries at this + // level had existed. + count += (((uint32_t)1) << level); + level++; + // And propagate the result upwards accordingly. + while (!(count & (((uint32_t)1) << level))) { + if (pbranch) { + if (matchh) { + pbranch->push_back(inner[level]); + } else if (matchlevel == level) { + pbranch->push_back(h); + matchh = true; + } + } + CHash256().Write(inner[level].begin(), 32).Write(h.begin(), 32).Finalize(h.begin()); + level++; + } + } + // Return result. + if (pmutated) *pmutated = mutated; + if (proot) *proot = h; +} + +uint256 ComputeMerkleRoot(const std::vector& leaves, bool* mutated) { + uint256 hash; + MerkleComputation(leaves, &hash, mutated, -1, NULL); + return hash; +} + +std::vector ComputeMerkleBranch(const std::vector& leaves, uint32_t position) { + std::vector ret; + MerkleComputation(leaves, NULL, NULL, position, &ret); + return ret; +} + +uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector& vMerkleBranch, uint32_t nIndex) { + uint256 hash = leaf; + for (std::vector::const_iterator it = vMerkleBranch.begin(); it != vMerkleBranch.end(); ++it) { + if (nIndex & 1) { + hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash)); + } else { + hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it)); + } + nIndex >>= 1; + } + return hash; +} + +uint256 BlockMerkleRoot(const CBlock& block, bool* mutated) +{ + std::vector leaves; + leaves.resize(block.vtx.size()); + for (size_t s = 0; s < block.vtx.size(); s++) { + leaves[s] = block.vtx[s].GetHash(); + } + return ComputeMerkleRoot(leaves, mutated); +} + +std::vector BlockMerkleBranch(const CBlock& block, uint32_t position) +{ + std::vector leaves; + leaves.resize(block.vtx.size()); + for (size_t s = 0; s < block.vtx.size(); s++) { + leaves[s] = block.vtx[s].GetHash(); + } + return ComputeMerkleBranch(leaves, position); +} diff --git a/src/consensus/merkle.h b/src/consensus/merkle.h new file mode 100644 index 000000000..6ef59745a --- /dev/null +++ b/src/consensus/merkle.h @@ -0,0 +1,32 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_MERKLE +#define BITCOIN_MERKLE + +#include +#include + +#include "primitives/transaction.h" +#include "primitives/block.h" +#include "uint256.h" + +uint256 ComputeMerkleRoot(const std::vector& leaves, bool* mutated = NULL); +std::vector ComputeMerkleBranch(const std::vector& leaves, uint32_t position); +uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector& branch, uint32_t position); + +/* + * Compute the Merkle root of the transactions in a block. + * *mutated is set to true if a duplicated subtree was found. + */ +uint256 BlockMerkleRoot(const CBlock& block, bool* mutated = NULL); + +/* + * Compute the Merkle branch for the tree of transactions in a block, for a + * given position. + * This can be verified using ComputeMerkleRootFromBranch. + */ +std::vector BlockMerkleBranch(const CBlock& block, uint32_t position); + +#endif diff --git a/src/consensus/params.h b/src/consensus/params.h index 58e18c420..f1be85e9c 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,8 +7,30 @@ #define BITCOIN_CONSENSUS_PARAMS_H #include "uint256.h" +#include +#include namespace Consensus { + +enum DeploymentPos +{ + DEPLOYMENT_TESTDUMMY, + DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113. + MAX_VERSION_BITS_DEPLOYMENTS +}; + +/** + * Struct for each individual consensus rule change using BIP9. + */ +struct BIP9Deployment { + /** Bit position to select the particular bit in nVersion. */ + int bit; + /** Start MedianTime for version bits miner confirmation. Can be a date in the past */ + int64_t nStartTime; + /** Timeout/expiry MedianTime for the deployment attempt. */ + int64_t nTimeout; +}; + /** * Parameters that influence chain consensus. */ @@ -19,6 +41,17 @@ struct Params { int nMajorityEnforceBlockUpgrade; int nMajorityRejectBlockOutdated; int nMajorityWindow; + /** Block height and hash at which BIP34 becomes active */ + int BIP34Height; + uint256 BIP34Hash; + /** + * Minimum blocks including miner confirmation of the total of 2016 blocks in a retargetting period, + * (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments. + * Examples: 1916 for 95%, 1512 for testchains. + */ + uint32_t nRuleChangeActivationThreshold; + uint32_t nMinerConfirmationWindow; + BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS]; /** Proof of work parameters */ uint256 powLimit; bool fPowAllowMinDifficultyBlocks; diff --git a/src/consensus/validation.h b/src/consensus/validation.h index d6051edc3..d7e57f5b5 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/core_io.h b/src/core_io.h index ba5b4e648..e8c0c49e8 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/core_memusage.h b/src/core_memusage.h index a05f59ee0..450537d05 100644 --- a/src/core_memusage.h +++ b/src/core_memusage.h @@ -10,7 +10,7 @@ #include "memusage.h" static inline size_t RecursiveDynamicUsage(const CScript& script) { - return memusage::DynamicUsage(*static_cast*>(&script)); + return memusage::DynamicUsage(*static_cast(&script)); } static inline size_t RecursiveDynamicUsage(const COutPoint& out) { diff --git a/src/core_read.cpp b/src/core_read.cpp index 4be24f8e0..444a4c7eb 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/core_write.cpp b/src/core_write.cpp index 533fedfe7..6f9e2266a 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -35,7 +35,7 @@ string FormatScript(const CScript& script) } else if ((op >= OP_1 && op <= OP_16) || op == OP_1NEGATE) { ret += strprintf("%i ", op - OP_1NEGATE - 1); continue; - } else if (op >= OP_NOP && op <= OP_CHECKMULTISIGVERIFY) { + } else if (op >= OP_NOP && op <= OP_NOP10) { string str(GetOpName(op)); if (str.substr(0, 3) == string("OP_")) { ret += str.substr(3, string::npos) + " "; @@ -45,7 +45,7 @@ string FormatScript(const CScript& script) if (vch.size() > 0) { ret += strprintf("0x%x 0x%x ", HexStr(it2, it - vch.size()), HexStr(it - vch.size(), it)); } else { - ret += strprintf("0x%x", HexStr(it2, it)); + ret += strprintf("0x%x ", HexStr(it2, it)); } continue; } diff --git a/src/crypto/ripemd160.h b/src/crypto/ripemd160.h index 687204fda..bd41f0250 100644 --- a/src/crypto/ripemd160.h +++ b/src/crypto/ripemd160.h @@ -14,7 +14,7 @@ class CRIPEMD160 private: uint32_t s[5]; unsigned char buf[64]; - size_t bytes; + uint64_t bytes; public: static const size_t OUTPUT_SIZE = 20; diff --git a/src/crypto/sha1.h b/src/crypto/sha1.h index 7b2a21bc6..8fb20810b 100644 --- a/src/crypto/sha1.h +++ b/src/crypto/sha1.h @@ -14,7 +14,7 @@ class CSHA1 private: uint32_t s[5]; unsigned char buf[64]; - size_t bytes; + uint64_t bytes; public: static const size_t OUTPUT_SIZE = 20; diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h index 85cf33739..5b15b6a23 100644 --- a/src/crypto/sha256.h +++ b/src/crypto/sha256.h @@ -14,7 +14,7 @@ class CSHA256 private: uint32_t s[8]; unsigned char buf[64]; - size_t bytes; + uint64_t bytes; public: static const size_t OUTPUT_SIZE = 32; diff --git a/src/crypto/sha512.h b/src/crypto/sha512.h index f1f17caf9..614681fae 100644 --- a/src/crypto/sha512.h +++ b/src/crypto/sha512.h @@ -14,7 +14,7 @@ class CSHA512 private: uint64_t s[8]; unsigned char buf[128]; - size_t bytes; + uint64_t bytes; public: static const size_t OUTPUT_SIZE = 64; diff --git a/src/leveldbwrapper.cpp b/src/dbwrapper.cpp similarity index 71% rename from src/leveldbwrapper.cpp rename to src/dbwrapper.cpp index 32c9345be..1907e2fa7 100644 --- a/src/leveldbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -1,8 +1,8 @@ -// Copyright (c) 2012-2014 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "leveldbwrapper.h" +#include "dbwrapper.h" #include "util.h" #include "random.h" @@ -15,18 +15,18 @@ #include #include -void HandleError(const leveldb::Status& status) throw(leveldb_error) +void HandleError(const leveldb::Status& status) throw(dbwrapper_error) { if (status.ok()) return; LogPrintf("%s\n", status.ToString()); if (status.IsCorruption()) - throw leveldb_error("Database corrupted"); + throw dbwrapper_error("Database corrupted"); if (status.IsIOError()) - throw leveldb_error("Database I/O error"); + throw dbwrapper_error("Database I/O error"); if (status.IsNotFound()) - throw leveldb_error("Database entry missing"); - throw leveldb_error("Unknown database error"); + throw dbwrapper_error("Database entry missing"); + throw dbwrapper_error("Unknown database error"); } static leveldb::Options GetOptions(size_t nCacheSize) @@ -45,7 +45,7 @@ static leveldb::Options GetOptions(size_t nCacheSize) return options; } -CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) +CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) { penv = NULL; readoptions.verify_checksums = true; @@ -76,7 +76,7 @@ CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCa bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key); if (!key_exists && obfuscate && IsEmpty()) { - // Initialize non-degenerate obfuscation if it won't upset + // Initialize non-degenerate obfuscation if it won't upset // existing, non-obfuscated data. std::vector new_key = CreateObfuscateKey(); @@ -90,7 +90,7 @@ CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCa LogPrintf("Using obfuscation key for %s: %s\n", path.string(), GetObfuscateKeyHex()); } -CLevelDBWrapper::~CLevelDBWrapper() +CDBWrapper::~CDBWrapper() { delete pdb; pdb = NULL; @@ -102,7 +102,7 @@ CLevelDBWrapper::~CLevelDBWrapper() options.env = NULL; } -bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) throw(leveldb_error) +bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) throw(dbwrapper_error) { leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch); HandleError(status); @@ -113,15 +113,15 @@ bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) throw(leveldb // // We must use a string constructor which specifies length so that we copy // past the null-terminator. -const std::string CLevelDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14); +const std::string CDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14); -const unsigned int CLevelDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8; +const unsigned int CDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8; /** - * Returns a string (consisting of 8 random bytes) suitable for use as an - * obfuscating XOR key. + * Returns a string (consisting of 8 random bytes) suitable for use as an + * obfuscating XOR key. */ -std::vector CLevelDBWrapper::CreateObfuscateKey() const +std::vector CDBWrapper::CreateObfuscateKey() const { unsigned char buff[OBFUSCATE_KEY_NUM_BYTES]; GetRandBytes(buff, OBFUSCATE_KEY_NUM_BYTES); @@ -129,26 +129,24 @@ std::vector CLevelDBWrapper::CreateObfuscateKey() const } -bool CLevelDBWrapper::IsEmpty() +bool CDBWrapper::IsEmpty() { - boost::scoped_ptr it(NewIterator()); + boost::scoped_ptr it(NewIterator()); it->SeekToFirst(); return !(it->Valid()); } -const std::vector& CLevelDBWrapper::GetObfuscateKey() const -{ - return obfuscate_key; +const std::vector& CDBWrapper::GetObfuscateKey() const +{ + return obfuscate_key; } -std::string CLevelDBWrapper::GetObfuscateKeyHex() const -{ - return HexStr(obfuscate_key); +std::string CDBWrapper::GetObfuscateKeyHex() const +{ + return HexStr(obfuscate_key); } -CLevelDBIterator::~CLevelDBIterator() { delete piter; } -bool CLevelDBIterator::Valid() { return piter->Valid(); } -void CLevelDBIterator::SeekToFirst() { piter->SeekToFirst(); } -void CLevelDBIterator::SeekToLast() { piter->SeekToLast(); } -void CLevelDBIterator::Next() { piter->Next(); } -void CLevelDBIterator::Prev() { piter->Prev(); } +CDBIterator::~CDBIterator() { delete piter; } +bool CDBIterator::Valid() { return piter->Valid(); } +void CDBIterator::SeekToFirst() { piter->SeekToFirst(); } +void CDBIterator::Next() { piter->Next(); } diff --git a/src/leveldbwrapper.h b/src/dbwrapper.h similarity index 80% rename from src/leveldbwrapper.h rename to src/dbwrapper.h index 60101e18c..5e7313f7e 100644 --- a/src/leveldbwrapper.h +++ b/src/dbwrapper.h @@ -1,9 +1,9 @@ -// Copyright (c) 2012-2014 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_LEVELDBWRAPPER_H -#define BITCOIN_LEVELDBWRAPPER_H +#ifndef BITCOIN_DBWRAPPER_H +#define BITCOIN_DBWRAPPER_H #include "clientversion.h" #include "serialize.h" @@ -17,18 +17,18 @@ #include #include -class leveldb_error : public std::runtime_error +class dbwrapper_error : public std::runtime_error { public: - leveldb_error(const std::string& msg) : std::runtime_error(msg) {} + dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {} }; -void HandleError(const leveldb::Status& status) throw(leveldb_error); +void HandleError(const leveldb::Status& status) throw(dbwrapper_error); -/** Batch of changes queued to be written to a CLevelDBWrapper */ -class CLevelDBBatch +/** Batch of changes queued to be written to a CDBWrapper */ +class CDBBatch { - friend class CLevelDBWrapper; + friend class CDBWrapper; private: leveldb::WriteBatch batch; @@ -38,7 +38,7 @@ public: /** * @param[in] obfuscate_key If passed, XOR data with this key. */ - CLevelDBBatch(const std::vector *obfuscate_key) : obfuscate_key(obfuscate_key) { }; + CDBBatch(const std::vector *obfuscate_key) : obfuscate_key(obfuscate_key) { }; template void Write(const K& key, const V& value) @@ -68,8 +68,8 @@ public: batch.Delete(slKey); } }; - -class CLevelDBIterator + +class CDBIterator { private: leveldb::Iterator *piter; @@ -81,14 +81,13 @@ public: * @param[in] piterIn The original leveldb iterator. * @param[in] obfuscate_key If passed, XOR data with this key. */ - CLevelDBIterator(leveldb::Iterator *piterIn, const std::vector* obfuscate_key) : + CDBIterator(leveldb::Iterator *piterIn, const std::vector* obfuscate_key) : piter(piterIn), obfuscate_key(obfuscate_key) { }; - ~CLevelDBIterator(); + ~CDBIterator(); bool Valid(); void SeekToFirst(); - void SeekToLast(); template void Seek(const K& key) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); @@ -99,14 +98,13 @@ public: } void Next(); - void Prev(); template bool GetKey(K& key) { leveldb::Slice slKey = piter->key(); try { CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION); ssKey >> key; - } catch(std::exception &e) { + } catch (const std::exception&) { return false; } return true; @@ -122,7 +120,7 @@ public: CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); ssValue.Xor(*obfuscate_key); ssValue >> value; - } catch(std::exception &e) { + } catch (const std::exception&) { return false; } return true; @@ -133,8 +131,8 @@ public: } }; - -class CLevelDBWrapper + +class CDBWrapper { private: //! custom environment this database is using (may be NULL in case of default environment) @@ -163,10 +161,10 @@ private: //! the key under which the obfuscation key is stored static const std::string OBFUSCATE_KEY_KEY; - + //! the length of the obfuscate key in number of bytes static const unsigned int OBFUSCATE_KEY_NUM_BYTES; - + std::vector CreateObfuscateKey() const; public: @@ -178,11 +176,11 @@ public: * @param[in] obfuscate If true, store data obfuscated via simple XOR. If false, XOR * with a zero'd byte array. */ - CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false); - ~CLevelDBWrapper(); + CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false); + ~CDBWrapper(); template - bool Read(const K& key, V& value) const throw(leveldb_error) + bool Read(const K& key, V& value) const throw(dbwrapper_error) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(ssKey.GetSerializeSize(key)); @@ -208,15 +206,15 @@ public: } template - bool Write(const K& key, const V& value, bool fSync = false) throw(leveldb_error) + bool Write(const K& key, const V& value, bool fSync = false) throw(dbwrapper_error) { - CLevelDBBatch batch(&obfuscate_key); + CDBBatch batch(&obfuscate_key); batch.Write(key, value); return WriteBatch(batch, fSync); } template - bool Exists(const K& key) const throw(leveldb_error) + bool Exists(const K& key) const throw(dbwrapper_error) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(ssKey.GetSerializeSize(key)); @@ -235,14 +233,14 @@ public: } template - bool Erase(const K& key, bool fSync = false) throw(leveldb_error) + bool Erase(const K& key, bool fSync = false) throw(dbwrapper_error) { - CLevelDBBatch batch(&obfuscate_key); + CDBBatch batch(&obfuscate_key); batch.Erase(key); return WriteBatch(batch, fSync); } - bool WriteBatch(CLevelDBBatch& batch, bool fSync = false) throw(leveldb_error); + bool WriteBatch(CDBBatch& batch, bool fSync = false) throw(dbwrapper_error); // not available for LevelDB; provide for compatibility with BDB bool Flush() @@ -250,15 +248,15 @@ public: return true; } - bool Sync() throw(leveldb_error) + bool Sync() throw(dbwrapper_error) { - CLevelDBBatch batch(&obfuscate_key); + CDBBatch batch(&obfuscate_key); return WriteBatch(batch, true); } - CLevelDBIterator *NewIterator() + CDBIterator *NewIterator() { - return new CLevelDBIterator(pdb->NewIterator(iteroptions), &obfuscate_key); + return new CDBIterator(pdb->NewIterator(iteroptions), &obfuscate_key); } /** @@ -278,5 +276,5 @@ public: }; -#endif // BITCOIN_LEVELDBWRAPPER_H +#endif // BITCOIN_DBWRAPPER_H diff --git a/src/eccryptoverify.cpp b/src/eccryptoverify.cpp deleted file mode 100644 index e894e1122..000000000 --- a/src/eccryptoverify.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "eccryptoverify.h" - -namespace { - -int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char *c2, size_t c2len) { - while (c1len > c2len) { - if (*c1) - return 1; - c1++; - c1len--; - } - while (c2len > c1len) { - if (*c2) - return -1; - c2++; - c2len--; - } - while (c1len > 0) { - if (*c1 > *c2) - return 1; - if (*c2 > *c1) - return -1; - c1++; - c2++; - c1len--; - } - return 0; -} - -/** Order of secp256k1's generator minus 1. */ -const unsigned char vchMaxModOrder[32] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, - 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, - 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40 -}; - -/** Half of the order of secp256k1's generator minus 1. */ -const unsigned char vchMaxModHalfOrder[32] = { - 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0x5D,0x57,0x6E,0x73,0x57,0xA4,0x50,0x1D, - 0xDF,0xE9,0x2F,0x46,0x68,0x1B,0x20,0xA0 -}; - -const unsigned char vchZero[1] = {0}; -} // anon namespace - -namespace eccrypto { - -bool Check(const unsigned char *vch) { - return vch && - CompareBigEndian(vch, 32, vchZero, 0) > 0 && - CompareBigEndian(vch, 32, vchMaxModOrder, 32) <= 0; -} - -bool CheckSignatureElement(const unsigned char *vch, int len, bool half) { - return vch && - CompareBigEndian(vch, len, vchZero, 0) > 0 && - CompareBigEndian(vch, len, half ? vchMaxModHalfOrder : vchMaxModOrder, 32) <= 0; -} - -} // namespace eccrypto diff --git a/src/eccryptoverify.h b/src/eccryptoverify.h deleted file mode 100644 index c67c1e44f..000000000 --- a/src/eccryptoverify.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_ECCRYPTOVERIFY_H -#define BITCOIN_ECCRYPTOVERIFY_H - -#include -#include - -class uint256; - -namespace eccrypto { - -bool Check(const unsigned char *vch); -bool CheckSignatureElement(const unsigned char *vch, int len, bool half); - -} // eccrypto namespace - -#endif // BITCOIN_ECCRYPTOVERIFY_H diff --git a/src/ecwrapper.cpp b/src/ecwrapper.cpp deleted file mode 100644 index f94bc954f..000000000 --- a/src/ecwrapper.cpp +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "ecwrapper.h" - -#include "serialize.h" -#include "uint256.h" - -#include -#include -#include - -namespace { - -class ecgroup_order -{ -public: - static const EC_GROUP* get() - { - static const ecgroup_order wrapper; - return wrapper.pgroup; - } - -private: - ecgroup_order() - : pgroup(EC_GROUP_new_by_curve_name(NID_secp256k1)) - { - } - - ~ecgroup_order() - { - EC_GROUP_free(pgroup); - } - - EC_GROUP* pgroup; -}; - -/** - * Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields - * recid selects which key is recovered - * if check is non-zero, additional checks are performed - */ -int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) -{ - if (!eckey) return 0; - - int ret = 0; - BN_CTX *ctx = NULL; - - BIGNUM *x = NULL; - BIGNUM *e = NULL; - BIGNUM *order = NULL; - BIGNUM *sor = NULL; - BIGNUM *eor = NULL; - BIGNUM *field = NULL; - EC_POINT *R = NULL; - EC_POINT *O = NULL; - EC_POINT *Q = NULL; - BIGNUM *rr = NULL; - BIGNUM *zero = NULL; - int n = 0; - int i = recid / 2; - - const EC_GROUP *group = EC_KEY_get0_group(eckey); - if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; } - BN_CTX_start(ctx); - order = BN_CTX_get(ctx); - if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; } - x = BN_CTX_get(ctx); - if (!BN_copy(x, order)) { ret=-1; goto err; } - if (!BN_mul_word(x, i)) { ret=-1; goto err; } - if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; } - field = BN_CTX_get(ctx); - if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; } - if (BN_cmp(x, field) >= 0) { ret=0; goto err; } - if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; } - if (check) - { - if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; } - if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; } - } - if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - n = EC_GROUP_get_degree(group); - e = BN_CTX_get(ctx); - if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; } - if (8*msglen > n) BN_rshift(e, e, 8-(n & 7)); - zero = BN_CTX_get(ctx); - if (!BN_zero(zero)) { ret=-1; goto err; } - if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; } - rr = BN_CTX_get(ctx); - if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; } - sor = BN_CTX_get(ctx); - if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; } - eor = BN_CTX_get(ctx); - if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; } - if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; } - if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; } - - ret = 1; - -err: - if (ctx) { - BN_CTX_end(ctx); - BN_CTX_free(ctx); - } - if (R != NULL) EC_POINT_free(R); - if (O != NULL) EC_POINT_free(O); - if (Q != NULL) EC_POINT_free(Q); - return ret; -} - -} // anon namespace - -CECKey::CECKey() { - pkey = EC_KEY_new(); - assert(pkey != NULL); - int result = EC_KEY_set_group(pkey, ecgroup_order::get()); - assert(result); -} - -CECKey::~CECKey() { - EC_KEY_free(pkey); -} - -void CECKey::GetPubKey(std::vector &pubkey, bool fCompressed) { - EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED); - int nSize = i2o_ECPublicKey(pkey, NULL); - assert(nSize); - assert(nSize <= 65); - pubkey.clear(); - pubkey.resize(nSize); - unsigned char *pbegin(begin_ptr(pubkey)); - int nSize2 = i2o_ECPublicKey(pkey, &pbegin); - assert(nSize == nSize2); -} - -bool CECKey::SetPubKey(const unsigned char* pubkey, size_t size) { - return o2i_ECPublicKey(&pkey, &pubkey, size) != NULL; -} - -bool CECKey::Verify(const uint256 &hash, const std::vector& vchSig) { - if (vchSig.empty()) - return false; - - // New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first. - unsigned char *norm_der = NULL; - ECDSA_SIG *norm_sig = ECDSA_SIG_new(); - const unsigned char* sigptr = &vchSig[0]; - assert(norm_sig); - if (d2i_ECDSA_SIG(&norm_sig, &sigptr, vchSig.size()) == NULL) - { - /* As of OpenSSL 1.0.0p d2i_ECDSA_SIG frees and nulls the pointer on - * error. But OpenSSL's own use of this function redundantly frees the - * result. As ECDSA_SIG_free(NULL) is a no-op, and in the absence of a - * clear contract for the function behaving the same way is more - * conservative. - */ - ECDSA_SIG_free(norm_sig); - return false; - } - int derlen = i2d_ECDSA_SIG(norm_sig, &norm_der); - ECDSA_SIG_free(norm_sig); - if (derlen <= 0) - return false; - - // -1 = error, 0 = bad sig, 1 = good - bool ret = ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), norm_der, derlen, pkey) == 1; - OPENSSL_free(norm_der); - return ret; -} - -bool CECKey::Recover(const uint256 &hash, const unsigned char *p64, int rec) -{ - if (rec<0 || rec>=3) - return false; - ECDSA_SIG *sig = ECDSA_SIG_new(); - BN_bin2bn(&p64[0], 32, sig->r); - BN_bin2bn(&p64[32], 32, sig->s); - bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1; - ECDSA_SIG_free(sig); - return ret; -} - -bool CECKey::TweakPublic(const unsigned char vchTweak[32]) { - bool ret = true; - BN_CTX *ctx = BN_CTX_new(); - BN_CTX_start(ctx); - BIGNUM *bnTweak = BN_CTX_get(ctx); - BIGNUM *bnOrder = BN_CTX_get(ctx); - BIGNUM *bnOne = BN_CTX_get(ctx); - const EC_GROUP *group = EC_KEY_get0_group(pkey); - EC_GROUP_get_order(group, bnOrder, ctx); // what a grossly inefficient way to get the (constant) group order... - BN_bin2bn(vchTweak, 32, bnTweak); - if (BN_cmp(bnTweak, bnOrder) >= 0) - ret = false; // extremely unlikely - EC_POINT *point = EC_POINT_dup(EC_KEY_get0_public_key(pkey), group); - BN_one(bnOne); - EC_POINT_mul(group, point, bnTweak, point, bnOne, ctx); - if (EC_POINT_is_at_infinity(group, point)) - ret = false; // ridiculously unlikely - EC_KEY_set_public_key(pkey, point); - EC_POINT_free(point); - BN_CTX_end(ctx); - BN_CTX_free(ctx); - return ret; -} - -bool CECKey::SanityCheck() -{ - const EC_GROUP *pgroup = ecgroup_order::get(); - if(pgroup == NULL) - return false; - // TODO Is there more EC functionality that could be missing? - return true; -} diff --git a/src/ecwrapper.h b/src/ecwrapper.h deleted file mode 100644 index efb6cd18a..000000000 --- a/src/ecwrapper.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_ECWRAPPER_H -#define BITCOIN_ECWRAPPER_H - -#include -#include - -#include - -class uint256; - -/** RAII Wrapper around OpenSSL's EC_KEY */ -class CECKey { -private: - EC_KEY *pkey; - -public: - CECKey(); - ~CECKey(); - - void GetPubKey(std::vector& pubkey, bool fCompressed); - bool SetPubKey(const unsigned char* pubkey, size_t size); - bool Verify(const uint256 &hash, const std::vector& vchSig); - - /** - * reconstruct public key from a compact signature - * This is only slightly more CPU intensive than just verifying it. - * If this function succeeds, the recovered public key is guaranteed to be valid - * (the signature is a valid signature of the given data for that key) - */ - bool Recover(const uint256 &hash, const unsigned char *p64, int rec); - - bool TweakPublic(const unsigned char vchTweak[32]); - static bool SanityCheck(); -}; - -#endif // BITCOIN_ECWRAPPER_H diff --git a/src/hash.cpp b/src/hash.cpp index 58999d108..58b63934b 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2014 The Bitcoin Core developers +// Copyright (c) 2013-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/hash.h b/src/hash.h index ac24b9444..50dc4b430 100644 --- a/src/hash.h +++ b/src/hash.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,6 +8,7 @@ #include "crypto/ripemd160.h" #include "crypto/sha256.h" +#include "prevector.h" #include "serialize.h" #include "uint256.h" #include "version.h" @@ -118,6 +119,13 @@ inline uint160 Hash160(const std::vector& vch) return Hash160(vch.begin(), vch.end()); } +/** Compute the 160-bit hash of a vector. */ +template +inline uint160 Hash160(const prevector& vch) +{ + return Hash160(vch.begin(), vch.end()); +} + /** A writer stream (for serialization) that computes a 256-bit hash. */ class CHashWriter { diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 98ac750bb..04d3386e9 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -1,17 +1,28 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "httprpc.h" #include "base58.h" #include "chainparams.h" #include "httpserver.h" -#include "rpcprotocol.h" -#include "rpcserver.h" +#include "rpc/protocol.h" +#include "rpc/server.h" #include "random.h" #include "sync.h" #include "util.h" #include "utilstrencodings.h" #include "ui_interface.h" +#include "crypto/hmac_sha256.h" +#include +#include "utilstrencodings.h" #include // boost::trim +#include //BOOST_FOREACH + +/** WWW-Authenticate to present with 401 Unauthorized response */ +static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\""; /** Simple one-shot callback timer to be used by the RPC mechanism to e.g. * re-lock the wellet. @@ -72,6 +83,50 @@ static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const Uni req->WriteReply(nStatus, strReply); } +//This function checks username and password against -rpcauth +//entries from config file. +static bool multiUserAuthorized(std::string strUserPass) +{ + if (strUserPass.find(":") == std::string::npos) { + return false; + } + std::string strUser = strUserPass.substr(0, strUserPass.find(":")); + std::string strPass = strUserPass.substr(strUserPass.find(":") + 1); + + if (mapMultiArgs.count("-rpcauth") > 0) { + //Search for multi-user login/pass "rpcauth" from config + BOOST_FOREACH(std::string strRPCAuth, mapMultiArgs["-rpcauth"]) + { + std::vector vFields; + boost::split(vFields, strRPCAuth, boost::is_any_of(":$")); + if (vFields.size() != 3) { + //Incorrect formatting in config file + continue; + } + + std::string strName = vFields[0]; + if (!TimingResistantEqual(strName, strUser)) { + continue; + } + + std::string strSalt = vFields[1]; + std::string strHash = vFields[2]; + + unsigned int KEY_SIZE = 32; + unsigned char *out = new unsigned char[KEY_SIZE]; + + CHMAC_SHA256(reinterpret_cast(strSalt.c_str()), strSalt.size()).Write(reinterpret_cast(strPass.c_str()), strPass.size()).Finalize(out); + std::vector hexvec(out, out+KEY_SIZE); + std::string strHashFromPass = HexStr(hexvec); + + if (TimingResistantEqual(strHashFromPass, strHash)) { + return true; + } + } + } + return false; +} + static bool RPCAuthorized(const std::string& strAuth) { if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called @@ -81,7 +136,12 @@ static bool RPCAuthorized(const std::string& strAuth) std::string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64); std::string strUserPass = DecodeBase64(strUserPass64); - return TimingResistantEqual(strUserPass, strRPCUserColonPass); + + //Check if authorized under single-user field + if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) { + return true; + } + return multiUserAuthorized(strUserPass); } static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &) @@ -94,6 +154,7 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &) // Check authorization std::pair authHeader = req->GetHeader("authorization"); if (!authHeader.first) { + req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA); req->WriteReply(HTTP_UNAUTHORIZED); return false; } @@ -106,6 +167,7 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &) shouldn't have their RPC port exposed. */ MilliSleep(250); + req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA); req->WriteReply(HTTP_UNAUTHORIZED); return false; } @@ -157,6 +219,7 @@ static bool InitRPCAuthentication() return false; } } else { + 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"); strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; } return true; @@ -172,7 +235,7 @@ bool StartHTTPRPC() assert(EventBase()); httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase()); - RPCRegisterTimerInterface(httpRPCTimerInterface); + RPCSetTimerInterface(httpRPCTimerInterface); return true; } @@ -186,7 +249,7 @@ void StopHTTPRPC() LogPrint("rpc", "Stopping HTTP RPC server\n"); UnregisterHTTPHandler("/", true); if (httpRPCTimerInterface) { - RPCUnregisterTimerInterface(httpRPCTimerInterface); + RPCUnsetTimerInterface(httpRPCTimerInterface); delete httpRPCTimerInterface; httpRPCTimerInterface = 0; } diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 0a7f903e9..ce1accb04 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -8,7 +8,7 @@ #include "compat.h" #include "util.h" #include "netbase.h" -#include "rpcprotocol.h" // For HTTP status codes +#include "rpc/protocol.h" // For HTTP status codes #include "sync.h" #include "ui_interface.h" @@ -38,6 +38,9 @@ #include #include +/** Maximum size of http request (request line + headers) */ +static const size_t MAX_HEADERS_SIZE = 8192; + /** HTTP request work item */ class HTTPWorkItem : public HTTPClosure { @@ -362,6 +365,10 @@ static void HTTPWorkQueueRun(WorkQueue* queue) /** libevent event log callback */ static void libevent_log_cb(int severity, const char *msg) { +#ifndef EVENT_LOG_WARN +// EVENT_LOG_WARN was added in 2.0.19; but before then _EVENT_LOG_WARN existed. +# define EVENT_LOG_WARN _EVENT_LOG_WARN +#endif if (severity >= EVENT_LOG_WARN) // Log warn messages and higher without debug category LogPrintf("libevent: %s\n", msg); else @@ -414,6 +421,7 @@ bool InitHTTPServer() } evhttp_set_timeout(http, GetArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT)); + evhttp_set_max_headers_size(http, MAX_HEADERS_SIZE); evhttp_set_max_body_size(http, MAX_SIZE); evhttp_set_gencb(http, http_request_cb, NULL); @@ -434,15 +442,17 @@ bool InitHTTPServer() return true; } -bool StartHTTPServer(boost::thread_group& threadGroup) +boost::thread threadHTTP; + +bool StartHTTPServer() { LogPrint("http", "Starting HTTP server\n"); int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L); LogPrintf("HTTP: starting %d worker threads\n", rpcThreads); - threadGroup.create_thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP)); + threadHTTP = boost::thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP)); for (int i = 0; i < rpcThreads; i++) - threadGroup.create_thread(boost::bind(&HTTPWorkQueueRun, workQueue)); + boost::thread(boost::bind(&HTTPWorkQueueRun, workQueue)); return true; } @@ -457,13 +467,6 @@ void InterruptHTTPServer() // Reject requests on current connections evhttp_set_gencb(eventHTTP, http_reject_request_cb, NULL); } - if (eventBase) { - // Force-exit event loop after predefined time - struct timeval tv; - tv.tv_sec = 10; - tv.tv_usec = 0; - event_base_loopexit(eventBase, &tv); - } if (workQueue) workQueue->Interrupt(); } @@ -476,6 +479,24 @@ void StopHTTPServer() workQueue->WaitExit(); delete workQueue; } + if (eventBase) { + LogPrint("http", "Waiting for HTTP event thread to exit\n"); + // Give event loop a few seconds to exit (to send back last RPC responses), then break it + // Before this was solved with event_base_loopexit, but that didn't work as expected in + // at least libevent 2.0.21 and always introduced a delay. In libevent + // master that appears to be solved, so in the future that solution + // could be used again (if desirable). + // (see discussion in https://github.com/bitcoin/bitcoin/pull/6990) +#if BOOST_VERSION >= 105000 + if (!threadHTTP.try_join_for(boost::chrono::milliseconds(2000))) { +#else + if (!threadHTTP.timed_join(boost::posix_time::milliseconds(2000))) { +#endif + LogPrintf("HTTP event loop did not exit within allotted time, sending loopbreak\n"); + event_base_loopbreak(eventBase); + threadHTTP.join(); + } + } if (eventHTTP) { evhttp_free(eventHTTP); eventHTTP = 0; @@ -484,6 +505,7 @@ void StopHTTPServer() event_base_free(eventBase); eventBase = 0; } + LogPrint("http", "Stopped HTTP server\n"); } struct event_base* EventBase() diff --git a/src/httpserver.h b/src/httpserver.h index b377dc19f..20a119cc5 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -28,7 +28,7 @@ bool InitHTTPServer(); * This is separate from InitHTTPServer to give users race-condition-free time * to register their handlers between InitHTTPServer and StartHTTPServer. */ -bool StartHTTPServer(boost::thread_group& threadGroup); +bool StartHTTPServer(); /** Interrupt HTTP server threads */ void InterruptHTTPServer(); /** Stop HTTP server */ diff --git a/src/init.cpp b/src/init.cpp index 1d9a59508..c064dd334 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -23,15 +23,18 @@ #include "miner.h" #include "net.h" #include "policy/policy.h" -#include "rpcserver.h" +#include "rpc/server.h" +#include "rpc/register.h" #include "script/standard.h" +#include "script/sigcache.h" #include "scheduler.h" +#include "timedata.h" #include "txdb.h" #include "txmempool.h" +#include "torcontrol.h" #include "ui_interface.h" #include "util.h" #include "utilmoneystr.h" -#include "utilstrencodings.h" #include "validationinterface.h" #ifdef ENABLE_WALLET #include "wallet/db.h" @@ -45,8 +48,10 @@ #include #endif +#include #include #include +#include #include #include #include @@ -60,10 +65,12 @@ using namespace std; -#ifdef ENABLE_WALLET -CWallet* pwalletMain = NULL; -#endif bool fFeeEstimatesInitialized = false; +static const bool DEFAULT_PROXYRANDOMIZE = true; +static const bool DEFAULT_REST_ENABLE = false; +static const bool DEFAULT_DISABLE_SAFEMODE = false; +static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; + #if ENABLE_ZMQ static CZMQNotificationInterface* pzmqNotificationInterface = NULL; @@ -152,6 +159,7 @@ public: static CCoinsViewDB *pcoinsdbview = NULL; static CCoinsViewErrorCatcher *pcoinscatcher = NULL; +static boost::scoped_ptr globalVerifyHandle; void Interrupt(boost::thread_group& threadGroup) { @@ -159,6 +167,7 @@ void Interrupt(boost::thread_group& threadGroup) InterruptHTTPRPC(); InterruptRPC(); InterruptREST(); + InterruptTorControl(); threadGroup.interrupt_all(); } @@ -187,6 +196,7 @@ void Shutdown() #endif GenerateBitcoins(false, 0, Params()); StopNode(); + StopTorControl(); UnregisterNodeSignals(GetNodeSignals()); if (fFeeEstimatesInitialized) @@ -224,7 +234,6 @@ void Shutdown() #if ENABLE_ZMQ if (pzmqNotificationInterface) { UnregisterValidationInterface(pzmqNotificationInterface); - pzmqNotificationInterface->Shutdown(); delete pzmqNotificationInterface; pzmqNotificationInterface = NULL; } @@ -242,6 +251,7 @@ void Shutdown() delete pwalletMain; pwalletMain = NULL; #endif + globalVerifyHandle.reset(); ECC_Stop(); LogPrintf("%s: done\n", __func__); } @@ -293,7 +303,7 @@ void OnRPCPreCommand(const CRPCCommand& cmd) { // Observe safe mode string strWarning = GetWarnings("rpc"); - if (strWarning != "" && !GetBoolArg("-disablesafemode", false) && + if (strWarning != "" && !GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE) && !cmd.okSafeMode) throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning); } @@ -305,13 +315,15 @@ std::string HelpMessage(HelpMessageMode mode) // When adding new options to the categories, please keep and ensure alphabetical ordering. // Do not translate _(...) -help-debug options, Many technical terms, and only a very small audience, so is unnecessary stress to translators. string strUsage = HelpMessageGroup(_("Options:")); - strUsage += HelpMessageOpt("-?", _("This help message")); - strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS)); + strUsage += HelpMessageOpt("-?", _("Print this help message and exit")); + strUsage += HelpMessageOpt("-version", _("Print version and exit")); strUsage += HelpMessageOpt("-alertnotify=", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)")); strUsage += HelpMessageOpt("-blocknotify=", _("Execute command when the best block changes (%s in cmd is replaced by block hash)")); - strUsage += HelpMessageOpt("-checkblocks=", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), 288)); - strUsage += HelpMessageOpt("-checklevel=", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), 3)); - strUsage += HelpMessageOpt("-conf=", strprintf(_("Specify configuration file (default: %s)"), "lbrycrd.conf")); + if (showDebug) + strUsage += HelpMessageOpt("-blocksonly", strprintf(_("Whether to operate in a blocks only mode (default: %u)"), DEFAULT_BLOCKSONLY)); + strUsage += HelpMessageOpt("-checkblocks=", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), DEFAULT_CHECKBLOCKS)); + strUsage += HelpMessageOpt("-checklevel=", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), DEFAULT_CHECKLEVEL)); + strUsage += HelpMessageOpt("-conf=", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME)); if (mode == HMM_BITCOIND) { #ifndef WIN32 @@ -320,12 +332,15 @@ std::string HelpMessage(HelpMessageMode mode) } strUsage += HelpMessageOpt("-datadir=", _("Specify data directory")); strUsage += HelpMessageOpt("-dbcache=", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache)); - strUsage += HelpMessageOpt("-loadblock=", _("Imports blocks from external blk000??.dat file") + " " + _("on startup")); + strUsage += HelpMessageOpt("-feefilter", strprintf(_("Tell other nodes to filter invs to us by our mempool min fee (default: %u)"), DEFAULT_FEEFILTER)); + strUsage += HelpMessageOpt("-loadblock=", _("Imports blocks from external blk000??.dat file on startup")); strUsage += HelpMessageOpt("-maxorphantx=", strprintf(_("Keep at most unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS)); + strUsage += HelpMessageOpt("-maxmempool=", strprintf(_("Keep the transaction memory pool below megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE)); + strUsage += HelpMessageOpt("-mempoolexpiry=", strprintf(_("Do not keep transactions in the mempool longer than hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY)); strUsage += HelpMessageOpt("-par=", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS)); #ifndef WIN32 - strUsage += HelpMessageOpt("-pid=", strprintf(_("Specify pid file (default: %s)"), "lbrycrdd.pid")); + strUsage += HelpMessageOpt("-pid=", strprintf(_("Specify pid file (default: %s)"), BITCOIN_PID_FILENAME)); #endif strUsage += HelpMessageOpt("-prune=", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. " "Warning: Reverting this setting requires re-downloading the entire blockchain. " @@ -334,31 +349,36 @@ std::string HelpMessage(HelpMessageMode mode) #ifndef WIN32 strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)")); #endif - strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), 0)); + strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), DEFAULT_TXINDEX)); strUsage += HelpMessageGroup(_("Connection options:")); strUsage += HelpMessageOpt("-addnode=", _("Add a node to connect to and attempt to keep the connection open")); - strUsage += HelpMessageOpt("-banscore=", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), 100)); - strUsage += HelpMessageOpt("-bantime=", strprintf(_("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), 86400)); + strUsage += HelpMessageOpt("-banscore=", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), DEFAULT_BANSCORE_THRESHOLD)); + strUsage += HelpMessageOpt("-bantime=", strprintf(_("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), DEFAULT_MISBEHAVING_BANTIME)); strUsage += HelpMessageOpt("-bind=", _("Bind to given address and always listen on it. Use [host]:port notation for IPv6")); strUsage += HelpMessageOpt("-connect=", _("Connect only to the specified node(s)")); strUsage += HelpMessageOpt("-discover", _("Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)")); - strUsage += HelpMessageOpt("-dns", _("Allow DNS lookups for -addnode, -seednode and -connect") + " " + _("(default: 1)")); + strUsage += HelpMessageOpt("-dns", _("Allow DNS lookups for -addnode, -seednode and -connect") + " " + strprintf(_("(default: %u)"), DEFAULT_NAME_LOOKUP)); strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)")); strUsage += HelpMessageOpt("-externalip=", _("Specify your own public address")); - strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), 0)); + strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), DEFAULT_FORCEDNSSEED)); strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect)")); + strUsage += HelpMessageOpt("-listenonion", strprintf(_("Automatically create Tor hidden service (default: %d)"), DEFAULT_LISTEN_ONION)); strUsage += HelpMessageOpt("-maxconnections=", strprintf(_("Maintain at most connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS)); - strUsage += HelpMessageOpt("-maxreceivebuffer=", strprintf(_("Maximum per-connection receive buffer, *1000 bytes (default: %u)"), 5000)); - strUsage += HelpMessageOpt("-maxsendbuffer=", strprintf(_("Maximum per-connection send buffer, *1000 bytes (default: %u)"), 1000)); + strUsage += HelpMessageOpt("-maxreceivebuffer=", strprintf(_("Maximum per-connection receive buffer, *1000 bytes (default: %u)"), DEFAULT_MAXRECEIVEBUFFER)); + strUsage += HelpMessageOpt("-maxsendbuffer=", strprintf(_("Maximum per-connection send buffer, *1000 bytes (default: %u)"), DEFAULT_MAXSENDBUFFER)); + strUsage += HelpMessageOpt("-maxtimeadjustment", strprintf(_("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)); strUsage += HelpMessageOpt("-onion=", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy")); strUsage += HelpMessageOpt("-onlynet=", _("Only connect to nodes in network (ipv4, ipv6 or onion)")); - strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), 1)); - strUsage += HelpMessageOpt("-port=", strprintf(_("Listen for connections on (default: %u or testnet: %u)"), 8333, 18333)); + strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), DEFAULT_PERMIT_BAREMULTISIG)); + strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with bloom filters (default: %u)"), DEFAULT_PEERBLOOMFILTERS)); + strUsage += HelpMessageOpt("-port=", strprintf(_("Listen for connections on (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort())); strUsage += HelpMessageOpt("-proxy=", _("Connect through SOCKS5 proxy")); - strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), 1)); + strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE)); strUsage += HelpMessageOpt("-seednode=", _("Connect to a node to retrieve peer addresses, and disconnect")); strUsage += HelpMessageOpt("-timeout=", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT)); + strUsage += HelpMessageOpt("-torcontrol=:", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL)); + strUsage += HelpMessageOpt("-torpassword=", _("Tor control port password (default: empty)")); #ifdef USE_UPNP #if USE_UPNP strUsage += HelpMessageOpt("-upnp", _("Use UPnP to map the listening port (default: 1 when listening and no -proxy)")); @@ -369,78 +389,68 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-whitebind=", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6")); strUsage += HelpMessageOpt("-whitelist=", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") + " " + _("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")); + strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY)); + strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY)); + strUsage += HelpMessageOpt("-maxuploadtarget=", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET)); #ifdef ENABLE_WALLET - strUsage += HelpMessageGroup(_("Wallet options:")); - strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); - strUsage += HelpMessageOpt("-keypool=", strprintf(_("Set key pool size to (default: %u)"), 100)); - if (showDebug) - strUsage += HelpMessageOpt("-mintxfee=", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)", - CURRENCY_UNIT, FormatMoney(CWallet::minTxFee.GetFeePerK()))); - strUsage += HelpMessageOpt("-paytxfee=", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), - CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); - strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions") + " " + _("on startup")); - strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup")); - strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0)); - strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), 1)); - strUsage += HelpMessageOpt("-txconfirmtarget=", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET)); - strUsage += HelpMessageOpt("-maxtxfee=", strprintf(_("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)"), - CURRENCY_UNIT, FormatMoney(maxTxFee))); - strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format") + " " + _("on startup")); - strUsage += HelpMessageOpt("-wallet=", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat")); - strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), true)); - strUsage += HelpMessageOpt("-walletnotify=", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)")); - strUsage += HelpMessageOpt("-zapwallettxes=", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") + - " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)")); + strUsage += CWallet::GetWalletHelpString(showDebug); #endif #if ENABLE_ZMQ strUsage += HelpMessageGroup(_("ZeroMQ notification options:")); strUsage += HelpMessageOpt("-zmqpubhashblock=
", _("Enable publish hash block in
")); - strUsage += HelpMessageOpt("-zmqpubhashtransaction=
", _("Enable publish hash transaction in
")); + strUsage += HelpMessageOpt("-zmqpubhashtx=
", _("Enable publish hash transaction in
")); strUsage += HelpMessageOpt("-zmqpubrawblock=
", _("Enable publish raw block in
")); - strUsage += HelpMessageOpt("-zmqpubrawtransaction=
", _("Enable publish raw transaction in
")); + strUsage += HelpMessageOpt("-zmqpubrawtx=
", _("Enable publish raw transaction in
")); #endif strUsage += HelpMessageGroup(_("Debugging/Testing options:")); + strUsage += HelpMessageOpt("-uacomment=", _("Append comment to the user agent string")); if (showDebug) { - strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", 1)); - strUsage += HelpMessageOpt("-dblogsize=", strprintf("Flush database activity from memory pool to disk log every megabytes (default: %u)", 100)); - strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", 0)); - strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", 0)); + strUsage += HelpMessageOpt("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); + strUsage += HelpMessageOpt("-checkmempool=", strprintf("Run checks every transactions (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); + strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED)); + strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", DEFAULT_DISABLE_SAFEMODE)); + strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", DEFAULT_TESTSAFEMODE)); strUsage += HelpMessageOpt("-dropmessagestest=", "Randomly drop 1 of every network messages"); strUsage += HelpMessageOpt("-fuzzmessagestest=", "Randomly fuzz 1 of every network messages"); - strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", 1)); - strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0)); + strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT)); strUsage += HelpMessageOpt("-limitancestorcount=", strprintf("Do not accept transactions if number of in-mempool ancestors is or more (default: %u)", DEFAULT_ANCESTOR_LIMIT)); strUsage += HelpMessageOpt("-limitancestorsize=", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT)); strUsage += HelpMessageOpt("-limitdescendantcount=", strprintf("Do not accept transactions if any ancestor would have or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT)); strUsage += HelpMessageOpt("-limitdescendantsize=", strprintf("Do not accept transactions if any ancestor would have more than kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT)); } - string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, mempoolrej, net, proxy, prune, http, libevent"; // Don't translate these and qt below + string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, mempoolrej, net, proxy, prune, http, libevent, tor, zmq"; // Don't translate these and qt below if (mode == HMM_BITCOIN_QT) debugCategories += ", qt"; strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + _("If is not supplied or if = 1, output all debugging information.") + _(" can be:") + " " + debugCategories + "."); strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0)); strUsage += HelpMessageOpt("-genproclimit=", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 1)); + if (showDebug) + strUsage += HelpMessageOpt("-nodebug", "Turn off debugging messages, same as -debug=0"); strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)")); - strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), 0)); - strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), 1)); + strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), DEFAULT_LOGIPS)); + strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), DEFAULT_LOGTIMESTAMPS)); if (showDebug) { - strUsage += HelpMessageOpt("-limitfreerelay=", strprintf("Continuously rate-limit free transactions to *1000 bytes per minute (default: %u)", 15)); - strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 1)); - strUsage += HelpMessageOpt("-maxsigcachesize=", strprintf("Limit size of signature cache to entries (default: %u)", 50000)); + strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS)); + strUsage += HelpMessageOpt("-mocktime=", "Replace actual time with seconds since epoch (default: 0)"); + strUsage += HelpMessageOpt("-limitfreerelay=", strprintf("Continuously rate-limit free transactions to *1000 bytes per minute (default: %u)", DEFAULT_LIMITFREERELAY)); + strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", DEFAULT_RELAYPRIORITY)); + strUsage += HelpMessageOpt("-maxsigcachesize=", strprintf("Limit size of signature cache to MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE)); + strUsage += HelpMessageOpt("-maxtipage=", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE)); } - strUsage += HelpMessageOpt("-minrelaytxfee=", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s)"), - CURRENCY_UNIT, FormatMoney(::minRelayTxFee.GetFeePerK()))); + strUsage += HelpMessageOpt("-minrelaytxfee=", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)"), + CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE))); + strUsage += HelpMessageOpt("-maxtxfee=", strprintf(_("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)"), + CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE))); strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of debug.log file")); if (showDebug) { - strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", 0)); - strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", 1)); + strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY)); } strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)")); @@ -449,23 +459,27 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Node relay options:")); if (showDebug) strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard())); - strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), 1)); + strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Minimum bytes per sigop in transactions we relay and mine (default: %u)"), DEFAULT_BYTES_PER_SIGOP)); + strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER)); strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY)); + strUsage += HelpMessageOpt("-mempoolreplacement", strprintf(_("Enable transaction replacement in the memory pool (default: %u)"), DEFAULT_ENABLE_REPLACEMENT)); strUsage += HelpMessageGroup(_("Block creation options:")); - strUsage += HelpMessageOpt("-blockminsize=", strprintf(_("Set minimum block size in bytes (default: %u)"), 0)); + strUsage += HelpMessageOpt("-blockminsize=", strprintf(_("Set minimum block size in bytes (default: %u)"), DEFAULT_BLOCK_MIN_SIZE)); strUsage += HelpMessageOpt("-blockmaxsize=", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE)); strUsage += HelpMessageOpt("-blockprioritysize=", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE)); if (showDebug) - strUsage += HelpMessageOpt("-blockversion=", strprintf("Override block version to test forking scenarios (default: %d)", (int)CBlock::CURRENT_VERSION)); + strUsage += HelpMessageOpt("-blockversion=", "Override block version to test forking scenarios"); strUsage += HelpMessageGroup(_("RPC server options:")); strUsage += HelpMessageOpt("-server", _("Accept command line and JSON-RPC commands")); - strUsage += HelpMessageOpt("-rest", strprintf(_("Accept public REST requests (default: %u)"), 0)); + strUsage += HelpMessageOpt("-rest", strprintf(_("Accept public REST requests (default: %u)"), DEFAULT_REST_ENABLE)); strUsage += HelpMessageOpt("-rpcbind=", _("Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces)")); + strUsage += HelpMessageOpt("-rpccookiefile=", _("Location of the auth cookie (default: data dir)")); strUsage += HelpMessageOpt("-rpcuser=", _("Username for JSON-RPC connections")); strUsage += HelpMessageOpt("-rpcpassword=", _("Password for JSON-RPC connections")); - strUsage += HelpMessageOpt("-rpcport=", strprintf(_("Listen for JSON-RPC connections on (default: %u or testnet: %u)"), 9245, 19245)); + strUsage += HelpMessageOpt("-rpcauth=", _("Username and hashed password for JSON-RPC connections. The field comes in the format: :$. A canonical python script is included in share/rpcuser. This option can be specified multiple times")); + strUsage += HelpMessageOpt("-rpcport=", strprintf(_("Listen for JSON-RPC connections on (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort())); strUsage += HelpMessageOpt("-rpcallowip=", _("Allow JSON-RPC connections from specified source. Valid for 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")); strUsage += HelpMessageOpt("-rpcthreads=", strprintf(_("Set the number of threads to service RPC calls (default: %d)"), DEFAULT_HTTP_THREADS)); if (showDebug) { @@ -473,42 +487,30 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-rpcservertimeout=", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT)); } - if (mode == HMM_BITCOIN_QT) - { - strUsage += HelpMessageGroup(_("UI Options:")); - if (showDebug) { - strUsage += HelpMessageOpt("-allowselfsignedrootcertificates", "Allow self signed root certificates (default: 0)"); - } - strUsage += HelpMessageOpt("-choosedatadir", _("Choose data directory on startup (default: 0)")); - strUsage += HelpMessageOpt("-lang=", _("Set language, for example \"de_DE\" (default: system locale)")); - strUsage += HelpMessageOpt("-min", _("Start minimized")); - strUsage += HelpMessageOpt("-rootcertificates=", _("Set SSL root certificates for payment request (default: -system-)")); - strUsage += HelpMessageOpt("-splash", _("Show splash screen on startup (default: 1)")); - if (showDebug) { - strUsage += HelpMessageOpt("-uiplatform", "Select platform to customize UI for (one of windows, macosx, other; default: platform compiled on)"); - } - } - return strUsage; } std::string LicenseInfo() { - return FormatParagraph(strprintf(_("Copyright (C) 2009-%i The Bitcoin Core Developers"), COPYRIGHT_YEAR)) + "\n" + + // todo: remove urls from translations on next change + return CopyrightHolders(strprintf(_("Copyright (C) %i-%i"), 2009, COPYRIGHT_YEAR) + " ") + "\n" + "\n" + - FormatParagraph(_("This is experimental software.")) + "\n" + + _("This is experimental software.") + "\n" + "\n" + - FormatParagraph(_("Distributed under the MIT software license, see the accompanying file COPYING or .")) + "\n" + + _("Distributed under the MIT software license, see the accompanying file COPYING or .") + "\n" + "\n" + - FormatParagraph(_("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.")) + + _("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.") + "\n"; } -static void BlockNotifyCallback(const uint256& hashNewTip) +static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex) { + if (initialSync || !pBlockIndex) + return; + std::string strCmd = GetArg("-blocknotify", ""); - boost::replace_all(strCmd, "%s", hashNewTip.GetHex()); + boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex()); boost::thread t(runCommand, strCmd); // thread runs free } @@ -570,6 +572,7 @@ void CleanupBlockRevFiles() void ThreadImport(std::vector vImportFiles) { + const CChainParams& chainparams = Params(); RenameThread("bitcoin-loadblk"); // -reindex if (fReindex) { @@ -583,14 +586,14 @@ void ThreadImport(std::vector vImportFiles) if (!file) break; // This error is logged in OpenBlockFile LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile); - LoadExternalBlockFile(file, &pos); + LoadExternalBlockFile(chainparams, file, &pos); nFile++; } pblocktree->WriteReindexing(false); fReindex = false; LogPrintf("Reindexing finished\n"); // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked): - InitBlockIndex(); + InitBlockIndex(chainparams); } // hardcoded $DATADIR/bootstrap.dat @@ -601,7 +604,7 @@ void ThreadImport(std::vector vImportFiles) CImportingNow imp; boost::filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; LogPrintf("Importing bootstrap.dat...\n"); - LoadExternalBlockFile(file); + LoadExternalBlockFile(chainparams, file); RenameOver(pathBootstrap, pathBootstrapOld); } else { LogPrintf("Warning: Could not open bootstrap file %s\n", pathBootstrap.string()); @@ -614,13 +617,13 @@ void ThreadImport(std::vector vImportFiles) if (file) { CImportingNow imp; LogPrintf("Importing blocks file %s...\n", path.string()); - LoadExternalBlockFile(file); + LoadExternalBlockFile(chainparams, file); } else { LogPrintf("Warning: Could not open blocks file %s\n", path.string()); } } - if (GetBoolArg("-stopafterblockimport", false)) { + if (GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { LogPrintf("Stopping after block import\n"); StartShutdown(); } @@ -633,8 +636,7 @@ void ThreadImport(std::vector vImportFiles) bool InitSanityCheck(void) { if(!ECC_InitSanityCheck()) { - InitError("OpenSSL appears to lack support for elliptic curve cryptography. For more " - "information, visit https://en.bitcoin.it/wiki/OpenSSL_and_EC_Libraries"); + InitError("Elliptic curve cryptography sanity check failure. Aborting."); return false; } if (!glibc_sanity_test() || !glibcxx_sanity_test()) @@ -653,85 +655,16 @@ bool AppInitServers(boost::thread_group& threadGroup) return false; if (!StartHTTPRPC()) return false; - if (GetBoolArg("-rest", false) && !StartREST()) + if (GetBoolArg("-rest", DEFAULT_REST_ENABLE) && !StartREST()) return false; - if (!StartHTTPServer(threadGroup)) + if (!StartHTTPServer()) return false; return true; } -/** Initialize bitcoin. - * @pre Parameters should be parsed and config file should be read. - */ -bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) +// Parameter interaction based on rules +void InitParameterInteraction() { - // ********************************************************* Step 1: setup -#ifdef _MSC_VER - // Turn off Microsoft heap dump noise - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)); -#endif -#if _MSC_VER >= 1400 - // Disable confusing "helpful" text message on abort, Ctrl-C - _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); -#endif -#ifdef WIN32 - // Enable Data Execution Prevention (DEP) - // Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008 - // A failure is non-critical and needs no further attention! -#ifndef PROCESS_DEP_ENABLE - // We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7), - // which is not correct. Can be removed, when GCCs winbase.h is fixed! -#define PROCESS_DEP_ENABLE 0x00000001 -#endif - typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD); - PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy"); - if (setProcDEPPol != NULL) setProcDEPPol(PROCESS_DEP_ENABLE); -#endif - - if (!SetupNetworking()) - return InitError("Error: Initializing networking failed"); - -#ifndef WIN32 - if (GetBoolArg("-sysperms", false)) { -#ifdef ENABLE_WALLET - if (!GetBoolArg("-disablewallet", false)) - return InitError("Error: -sysperms is not allowed in combination with enabled wallet functionality"); -#endif - } else { - umask(077); - } - - // Clean shutdown on SIGTERM - struct sigaction sa; - sa.sa_handler = HandleSIGTERM; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - - // Reopen debug.log on SIGHUP - struct sigaction sa_hup; - sa_hup.sa_handler = HandleSIGHUP; - sigemptyset(&sa_hup.sa_mask); - sa_hup.sa_flags = 0; - sigaction(SIGHUP, &sa_hup, NULL); - - // Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly - signal(SIGPIPE, SIG_IGN); -#endif - - // ********************************************************* Step 2: parameter interactions - const CChainParams& chainparams = Params(); - - // Set this early so that parameter interactions go to console - fPrintToConsole = GetBoolArg("-printtoconsole", false); - fLogTimestamps = GetBoolArg("-logtimestamps", true); - fLogIPs = GetBoolArg("-logips", false); - - LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - LogPrintf("LBRYcrd version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); - // when specifying an explicit binding address, you want to listen on it // even when -connect or -proxy is specified if (mapArgs.count("-bind")) { @@ -770,6 +703,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__); if (SoftSetBoolArg("-discover", false)) LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__); + if (SoftSetBoolArg("-listenonion", false)) + LogPrintf("%s: parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__); } if (mapArgs.count("-externalip")) { @@ -790,9 +725,113 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("%s: parameter interaction: -zapwallettxes= -> setting -rescan=1\n", __func__); } + // disable walletbroadcast and whitelistrelay in blocksonly mode + if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) { + if (SoftSetBoolArg("-whitelistrelay", false)) + LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n", __func__); +#ifdef ENABLE_WALLET + if (SoftSetBoolArg("-walletbroadcast", false)) + LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__); +#endif + } + + // Forcing relay from whitelisted hosts implies we will accept relays from them in the first place. + if (GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) { + if (SoftSetBoolArg("-whitelistrelay", true)) + LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__); + } +} + +static std::string ResolveErrMsg(const char * const optname, const std::string& strBind) +{ + return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind); +} + +static std::string AmountErrMsg(const char * const optname, const std::string& strValue) +{ + return strprintf(_("Invalid amount for -%s=: '%s'"), optname, strValue); +} + +void InitLogging() +{ + fPrintToConsole = GetBoolArg("-printtoconsole", false); + fLogTimestamps = GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); + fLogTimeMicros = GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); + fLogIPs = GetBoolArg("-logips", DEFAULT_LOGIPS); + + LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + LogPrintf("Bitcoin version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); +} + +/** Initialize bitcoin. + * @pre Parameters should be parsed and config file should be read. + */ +bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) +{ + // ********************************************************* Step 1: setup +#ifdef _MSC_VER + // Turn off Microsoft heap dump noise + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)); +#endif +#if _MSC_VER >= 1400 + // Disable confusing "helpful" text message on abort, Ctrl-C + _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); +#endif +#ifdef WIN32 + // Enable Data Execution Prevention (DEP) + // Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008 + // A failure is non-critical and needs no further attention! +#ifndef PROCESS_DEP_ENABLE + // We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7), + // which is not correct. Can be removed, when GCCs winbase.h is fixed! +#define PROCESS_DEP_ENABLE 0x00000001 +#endif + typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD); + PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy"); + if (setProcDEPPol != NULL) setProcDEPPol(PROCESS_DEP_ENABLE); +#endif + + if (!SetupNetworking()) + return InitError("Initializing networking failed"); + +#ifndef WIN32 + if (GetBoolArg("-sysperms", false)) { +#ifdef ENABLE_WALLET + if (!GetBoolArg("-disablewallet", false)) + return InitError("-sysperms is not allowed in combination with enabled wallet functionality"); +#endif + } else { + umask(077); + } + + // Clean shutdown on SIGTERM + struct sigaction sa; + sa.sa_handler = HandleSIGTERM; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + // Reopen debug.log on SIGHUP + struct sigaction sa_hup; + sa_hup.sa_handler = HandleSIGHUP; + sigemptyset(&sa_hup.sa_mask); + sa_hup.sa_flags = 0; + sigaction(SIGHUP, &sa_hup, NULL); + + // Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly + signal(SIGPIPE, SIG_IGN); +#endif + + // ********************************************************* Step 2: parameter interactions + const CChainParams& chainparams = Params(); + + // also see: InitParameterInteraction() + // if using block pruning, then disable txindex if (GetArg("-prune", 0)) { - if (GetBoolArg("-txindex", false)) + if (GetBoolArg("-txindex", DEFAULT_TXINDEX)) return InitError(_("Prune mode is incompatible with -txindex.")); #ifdef ENABLE_WALLET if (GetBoolArg("-rescan", false)) { @@ -800,7 +839,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } #endif } - + // Make sure enough file descriptors are available int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1); int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); @@ -826,21 +865,33 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // Check for -debugnet if (GetBoolArg("-debugnet", false)) - InitWarning(_("Warning: Unsupported argument -debugnet ignored, use -debug=net.")); + InitWarning(_("Unsupported argument -debugnet ignored, use -debug=net.")); // Check for -socks - as this is a privacy risk to continue, exit here if (mapArgs.count("-socks")) - return InitError(_("Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.")); + return InitError(_("Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.")); // Check for -tor - as this is a privacy risk to continue, exit here if (GetBoolArg("-tor", false)) - return InitError(_("Error: Unsupported argument -tor found, use -onion.")); + return InitError(_("Unsupported argument -tor found, use -onion.")); if (GetBoolArg("-benchmark", false)) - InitWarning(_("Warning: Unsupported argument -benchmark ignored, use -debug=bench.")); + InitWarning(_("Unsupported argument -benchmark ignored, use -debug=bench.")); + + if (GetBoolArg("-whitelistalwaysrelay", false)) + InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.")); // Checkmempool and checkblockindex default to true in regtest mode - mempool.setSanityCheck(GetBoolArg("-checkmempool", chainparams.DefaultConsistencyChecks())); + int ratio = std::min(std::max(GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); + if (ratio != 0) { + mempool.setSanityCheck(1.0 / ratio); + } fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); - fCheckpointsEnabled = GetBoolArg("-checkpoints", true); + fCheckpointsEnabled = GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED); + + // mempool limits + int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; + int64_t nMempoolSizeMin = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; + if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin) + return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0))); // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); @@ -867,8 +918,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fPruneMode = true; } + RegisterAllCoreRPCCommands(tableRPC); #ifdef ENABLE_WALLET bool fDisableWallet = GetBoolArg("-disablewallet", false); + if (!fDisableWallet) + RegisterWalletRPCCommands(tableRPC); #endif nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT); @@ -887,83 +941,52 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0) ::minRelayTxFee = CFeeRate(n); else - return InitError(strprintf(_("Invalid amount for -minrelaytxfee=: '%s'"), mapArgs["-minrelaytxfee"])); + return InitError(AmountErrMsg("minrelaytxfee", mapArgs["-minrelaytxfee"])); } fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !Params().RequireStandard()); if (Params().RequireStandard() && !fRequireStandard) return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString())); + nBytesPerSigOp = GetArg("-bytespersigop", nBytesPerSigOp); #ifdef ENABLE_WALLET - if (mapArgs.count("-mintxfee")) - { - CAmount n = 0; - if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0) - CWallet::minTxFee = CFeeRate(n); - else - return InitError(strprintf(_("Invalid amount for -mintxfee=: '%s'"), mapArgs["-mintxfee"])); - } - if (mapArgs.count("-paytxfee")) - { - CAmount nFeePerK = 0; - if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK)) - return InitError(strprintf(_("Invalid amount for -paytxfee=: '%s'"), mapArgs["-paytxfee"])); - if (nFeePerK > nHighTransactionFeeWarning) - InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); - payTxFee = CFeeRate(nFeePerK, 1000); - if (payTxFee < ::minRelayTxFee) - { - return InitError(strprintf(_("Invalid amount for -paytxfee=: '%s' (must be at least %s)"), - mapArgs["-paytxfee"], ::minRelayTxFee.ToString())); - } - } - if (mapArgs.count("-maxtxfee")) - { - CAmount nMaxFee = 0; - if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee)) - return InitError(strprintf(_("Invalid amount for -maxtxfee=: '%s'"), mapArgs["-maptxfee"])); - if (nMaxFee > nHighTransactionMaxFeeWarning) - InitWarning(_("Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction.")); - maxTxFee = nMaxFee; - if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) - { - return InitError(strprintf(_("Invalid amount for -maxtxfee=: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), - mapArgs["-maxtxfee"], ::minRelayTxFee.ToString())); - } - } - nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); - bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", true); - fSendFreeTransactions = GetBoolArg("-sendfreetransactions", false); - - std::string strWalletFile = GetArg("-wallet", "wallet.dat"); + if (!CWallet::ParameterInteraction()) + return false; #endif // ENABLE_WALLET - fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", true); + fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); + fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER); nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes); - fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS); - // Option to startup with mocktime set (used for regression testing): SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op - if (GetBoolArg("-peerbloomfilters", true)) + if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) nLocalServices |= NODE_BLOOM; + nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); + + fEnableReplacement = GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT); + if ((!fEnableReplacement) && mapArgs.count("-mempoolreplacement")) { + // Minimal effort at forwards compatibility + std::string strReplacementModeList = GetArg("-mempoolreplacement", ""); // default is impossible + std::vector vstrReplacementModes; + boost::split(vstrReplacementModes, strReplacementModeList, boost::is_any_of(",")); + fEnableReplacement = (std::find(vstrReplacementModes.begin(), vstrReplacementModes.end(), "fee") != vstrReplacementModes.end()); + } + // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log // Initialize elliptic curve code ECC_Start(); + globalVerifyHandle.reset(new ECCVerifyHandle()); // Sanity check if (!InitSanityCheck()) - return InitError(_("Initialization sanity check failed. LBRYcrd Core is shutting down.")); + return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME))); std::string strDataDir = GetDataDir().string(); -#ifdef ENABLE_WALLET - // Wallet file must be a plain filename without a directory - if (strWalletFile != boost::filesystem::basename(strWalletFile) + boost::filesystem::extension(strWalletFile)) - return InitError(strprintf(_("Wallet %s resides outside data directory %s"), strWalletFile, strDataDir)); -#endif + // Make sure only a single Bitcoin process is using the data directory. boost::filesystem::path pathLockFile = GetDataDir() / ".lock"; FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist. @@ -972,9 +995,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) try { static boost::interprocess::file_lock lock(pathLockFile.string().c_str()); if (!lock.try_lock()) - return InitError(strprintf(_("Cannot obtain a lock on data directory %s. LBRYcrd Core is probably already running."), strDataDir)); + return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), strDataDir, _(PACKAGE_NAME))); } catch(const boost::interprocess::interprocess_exception& e) { - return InitError(strprintf(_("Cannot obtain a lock on data directory %s. LBRYcrd Core is probably already running.") + " %s.", strDataDir, e.what())); + return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running.") + " %s.", strDataDir, _(PACKAGE_NAME), e.what())); } #ifndef WIN32 @@ -986,7 +1009,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (fPrintToDebugLog) OpenDebugLog(); - LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION)); #ifdef ENABLE_WALLET LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); #endif @@ -1025,20 +1047,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 5: verify wallet database integrity #ifdef ENABLE_WALLET if (!fDisableWallet) { - LogPrintf("Using wallet %s\n", strWalletFile); - uiInterface.InitMessage(_("Verifying wallet...")); - - std::string warningString; - std::string errorString; - - if (!CWallet::Verify(strWalletFile, warningString, errorString)) + if (!CWallet::Verify()) return false; - - if (!warningString.empty()) - InitWarning(warningString); - if (!errorString.empty()) - return InitError(errorString); - } // (!fDisableWallet) #endif // ENABLE_WALLET // ********************************************************* Step 6: network initialization @@ -1050,12 +1060,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) BOOST_FOREACH(string cmt, mapMultiArgs["-uacomment"]) { if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) - return InitError(strprintf("User Agent comment (%s) contains unsafe characters.", cmt)); + return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt)); uacomments.push_back(SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)); } strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments); if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) { - return InitError(strprintf("Total length of network version string %i exceeds maximum of %i characters. Reduce the number and/or size of uacomments.", + return InitError(strprintf(_("Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments."), strSubVersion.size(), MAX_SUBVERSION_LENGTH)); } @@ -1083,10 +1093,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } - bool proxyRandomize = GetBoolArg("-proxyrandomize", true); + bool proxyRandomize = GetBoolArg("-proxyrandomize", DEFAULT_PROXYRANDOMIZE); // -proxy sets a proxy for all outgoing network traffic // -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default std::string proxyArg = GetArg("-proxy", ""); + SetLimited(NET_TOR); if (proxyArg != "" && proxyArg != "0") { proxyType addrProxy = proxyType(CService(proxyArg, 9050), proxyRandomize); if (!addrProxy.IsValid()) @@ -1096,7 +1107,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) SetProxy(NET_IPV6, addrProxy); SetProxy(NET_TOR, addrProxy); SetNameProxy(addrProxy); - SetReachable(NET_TOR); // by default, -proxy sets onion as reachable, unless -noonion later + SetLimited(NET_TOR, false); // by default, -proxy sets onion as reachable, unless -noonion later } // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses @@ -1105,20 +1116,20 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) std::string onionArg = GetArg("-onion", ""); if (onionArg != "") { if (onionArg == "0") { // Handle -noonion/-onion=0 - SetReachable(NET_TOR, false); // set onions as unreachable + SetLimited(NET_TOR); // set onions as unreachable } else { proxyType addrOnion = proxyType(CService(onionArg, 9050), proxyRandomize); if (!addrOnion.IsValid()) return InitError(strprintf(_("Invalid -onion address: '%s'"), onionArg)); SetProxy(NET_TOR, addrOnion); - SetReachable(NET_TOR); + SetLimited(NET_TOR, false); } } // see Step 2: parameter interactions for more information about these fListen = GetBoolArg("-listen", DEFAULT_LISTEN); fDiscover = GetBoolArg("-discover", true); - fNameLookup = GetBoolArg("-dns", true); + fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP); bool fBound = false; if (fListen) { @@ -1126,13 +1137,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-bind"]) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) - return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind)); + return InitError(ResolveErrMsg("bind", strBind)); fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); } BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, 0, false)) - return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind)); + return InitError(ResolveErrMsg("whitebind", strBind)); if (addrBind.GetPort() == 0) return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind)); fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST)); @@ -1152,7 +1163,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-externalip"]) { CService addrLocal(strAddr, GetListenPort(), fNameLookup); if (!addrLocal.IsValid()) - return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr)); + return InitError(ResolveErrMsg("externalip", strAddr)); AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL); } } @@ -1164,10 +1175,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) pzmqNotificationInterface = CZMQNotificationInterface::CreateWithArguments(mapArgs); if (pzmqNotificationInterface) { - pzmqNotificationInterface->Initialize(); RegisterValidationInterface(pzmqNotificationInterface); } #endif + if (mapArgs.count("-maxuploadtarget")) { + CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024); + } // ********************************************************* Step 7: load block chain @@ -1205,7 +1218,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache int64_t nBlockTreeDBCache = nTotalCache / 8; - if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", false)) + if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", DEFAULT_TXINDEX)) nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB nTotalCache -= nBlockTreeDBCache; int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache @@ -1257,13 +1270,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); // Initialize the block index (no-op if non-empty database was already loaded) - if (!InitBlockIndex()) { + if (!InitBlockIndex(chainparams)) { strLoadError = _("Error initializing block database"); break; } // Check for changed -txindex state - if (fTxIndex != GetBoolArg("-txindex", false)) { + if (fTxIndex != GetBoolArg("-txindex", DEFAULT_TXINDEX)) { strLoadError = _("You need to rebuild the database using -reindex to change -txindex"); break; } @@ -1282,9 +1295,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } uiInterface.InitMessage(_("Verifying blocks...")); - if (fHavePruned && GetArg("-checkblocks", 288) > MIN_BLOCKS_TO_KEEP) { + if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) { LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n", - MIN_BLOCKS_TO_KEEP, GetArg("-checkblocks", 288)); + MIN_BLOCKS_TO_KEEP, GetArg("-checkblocks", DEFAULT_CHECKBLOCKS)); } { @@ -1298,8 +1311,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } - if (!CVerifyDB().VerifyDB(pcoinsdbview, GetArg("-checklevel", 3), - GetArg("-checkblocks", 288))) { + if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, GetArg("-checklevel", DEFAULT_CHECKLEVEL), + GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) { strLoadError = _("Corrupted block database detected"); break; } @@ -1354,150 +1367,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) pwalletMain = NULL; LogPrintf("Wallet disabled!\n"); } else { - - // needed to restore wallet transaction meta data after -zapwallettxes - std::vector vWtx; - - if (GetBoolArg("-zapwallettxes", false)) { - uiInterface.InitMessage(_("Zapping all transactions from wallet...")); - - pwalletMain = new CWallet(strWalletFile); - DBErrors nZapWalletRet = pwalletMain->ZapWalletTx(vWtx); - if (nZapWalletRet != DB_LOAD_OK) { - uiInterface.InitMessage(_("Error loading wallet.dat: Wallet corrupted")); - return false; - } - - delete pwalletMain; - pwalletMain = NULL; - } - - uiInterface.InitMessage(_("Loading wallet...")); - - nStart = GetTimeMillis(); - bool fFirstRun = true; - pwalletMain = new CWallet(strWalletFile); - DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun); - if (nLoadWalletRet != DB_LOAD_OK) - { - if (nLoadWalletRet == DB_CORRUPT) - strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n"; - else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) - { - string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data" - " or address book entries might be missing or incorrect.")); - InitWarning(msg); - } - else if (nLoadWalletRet == DB_TOO_NEW) - strErrors << _("Error loading wallet.dat: Wallet requires newer version of LBRYcrd Core") << "\n"; - else if (nLoadWalletRet == DB_NEED_REWRITE) - { - strErrors << _("Wallet needed to be rewritten: restart LBRYcrd Core to complete") << "\n"; - LogPrintf("%s", strErrors.str()); - return InitError(strErrors.str()); - } - else - strErrors << _("Error loading wallet.dat") << "\n"; - } - - if (GetBoolArg("-upgradewallet", fFirstRun)) - { - int nMaxVersion = GetArg("-upgradewallet", 0); - if (nMaxVersion == 0) // the -upgradewallet without argument case - { - LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST); - nMaxVersion = CLIENT_VERSION; - pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately - } - else - LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion); - if (nMaxVersion < pwalletMain->GetVersion()) - strErrors << _("Cannot downgrade wallet") << "\n"; - pwalletMain->SetMaxVersion(nMaxVersion); - } - - if (fFirstRun) - { - // Create new keyUser and set as default key - RandAddSeedPerfmon(); - - CPubKey newDefaultKey; - if (pwalletMain->GetKeyFromPool(newDefaultKey)) { - pwalletMain->SetDefaultKey(newDefaultKey); - if (!pwalletMain->SetAddressBook(pwalletMain->vchDefaultKey.GetID(), "", "receive")) - strErrors << _("Cannot write default address") << "\n"; - } - - pwalletMain->SetBestChain(chainActive.GetLocator()); - } - - LogPrintf("%s", strErrors.str()); - LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart); - - RegisterValidationInterface(pwalletMain); - - CBlockIndex *pindexRescan = chainActive.Tip(); - if (GetBoolArg("-rescan", false)) - pindexRescan = chainActive.Genesis(); - else - { - CWalletDB walletdb(strWalletFile); - CBlockLocator locator; - if (walletdb.ReadBestBlock(locator)) - pindexRescan = FindForkInGlobalIndex(chainActive, locator); - else - pindexRescan = chainActive.Genesis(); - } - if (chainActive.Tip() && chainActive.Tip() != pindexRescan) - { - //We can't rescan beyond non-pruned blocks, stop and throw an error - //this might happen if a user uses a old wallet within a pruned node - // or if he ran -disablewallet for a longer time, then decided to re-enable - if (fPruneMode) - { - CBlockIndex *block = chainActive.Tip(); - while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block) - block = block->pprev; - - if (pindexRescan != block) - return InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)")); - } - - uiInterface.InitMessage(_("Rescanning...")); - LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight); - nStart = GetTimeMillis(); - pwalletMain->ScanForWalletTransactions(pindexRescan, true); - LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); - pwalletMain->SetBestChain(chainActive.GetLocator()); - nWalletDBUpdated++; - - // Restore wallet transaction metadata after -zapwallettxes=1 - if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") - { - CWalletDB walletdb(strWalletFile); - - BOOST_FOREACH(const CWalletTx& wtxOld, vWtx) - { - uint256 hash = wtxOld.GetHash(); - std::map::iterator mi = pwalletMain->mapWallet.find(hash); - if (mi != pwalletMain->mapWallet.end()) - { - const CWalletTx* copyFrom = &wtxOld; - CWalletTx* copyTo = &mi->second; - copyTo->mapValue = copyFrom->mapValue; - copyTo->vOrderForm = copyFrom->vOrderForm; - copyTo->nTimeReceived = copyFrom->nTimeReceived; - copyTo->nTimeSmart = copyFrom->nTimeSmart; - copyTo->fFromMe = copyFrom->fFromMe; - copyTo->strFromAccount = copyFrom->strFromAccount; - copyTo->nOrderPos = copyFrom->nOrderPos; - copyTo->WriteToDisk(&walletdb); - } - } - } - } - pwalletMain->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", true)); - } // (!fDisableWallet) + CWallet::InitLoadWallet(); + if (!pwalletMain) + return false; + } #else // ENABLE_WALLET LogPrintf("No wallet support compiled in!\n"); #endif // !ENABLE_WALLET @@ -1507,10 +1380,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // if pruning, unset the service bit and perform the initial blockstore prune // after any wallet rescanning has taken place. if (fPruneMode) { - uiInterface.InitMessage(_("Pruning blockstore...")); LogPrintf("Unsetting NODE_NETWORK on prune mode\n"); nLocalServices &= ~NODE_NETWORK; if (!fReindex) { + uiInterface.InitMessage(_("Pruning blockstore...")); PruneAndFlush(); } } @@ -1523,7 +1396,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) uiInterface.InitMessage(_("Activating best chain...")); // scan for better chains in the block chain database, that are not yet connected in the active best chain CValidationState state; - if (!ActivateBestChain(state)) + if (!ActivateBestChain(state, chainparams)) strErrors << "Failed to connect best block"; std::vector vImportFiles; @@ -1558,6 +1431,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0); #endif + if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) + StartTorControl(threadGroup, scheduler); + StartNode(threadGroup, scheduler); // Monitor the chain, and alert if we get blocks much quicker or slower than expected diff --git a/src/init.h b/src/init.h index 8cd51b028..63e07ccb3 100644 --- a/src/init.h +++ b/src/init.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,13 +16,15 @@ namespace boost class thread_group; } // namespace boost -extern CWallet* pwalletMain; - void StartShutdown(); bool ShutdownRequested(); /** Interrupt threads */ void Interrupt(boost::thread_group& threadGroup); void Shutdown(); +//!Initialize the logging infrastructure +void InitLogging(); +//!Parameter interaction: change current parameters depending on various rules +void InitParameterInteraction(); bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler); /** The help message mode determines what help message to show */ diff --git a/src/key.cpp b/src/key.cpp index b772dff33..6a3d9aa14 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,17 +7,120 @@ #include "arith_uint256.h" #include "crypto/common.h" #include "crypto/hmac_sha512.h" -#include "eccryptoverify.h" #include "pubkey.h" #include "random.h" #include -#include "ecwrapper.h" +#include -static secp256k1_context_t* secp256k1_context = NULL; +static secp256k1_context* secp256k1_context_sign = NULL; + +/** These functions are taken from the libsecp256k1 distribution and are very ugly. */ +static int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) { + const unsigned char *end = privkey + privkeylen; + int lenb = 0; + int len = 0; + memset(out32, 0, 32); + /* sequence header */ + if (end < privkey+1 || *privkey != 0x30) { + return 0; + } + privkey++; + /* sequence length constructor */ + if (end < privkey+1 || !(*privkey & 0x80)) { + return 0; + } + lenb = *privkey & ~0x80; privkey++; + if (lenb < 1 || lenb > 2) { + return 0; + } + if (end < privkey+lenb) { + return 0; + } + /* sequence length */ + len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); + privkey += lenb; + if (end < privkey+len) { + return 0; + } + /* sequence element 0: version number (=1) */ + if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { + return 0; + } + privkey += 3; + /* sequence element 1: octet string, up to 32 bytes */ + if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { + return 0; + } + memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); + if (!secp256k1_ec_seckey_verify(ctx, out32)) { + memset(out32, 0, 32); + return 0; + } + return 1; +} + +static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { + secp256k1_pubkey pubkey; + size_t pubkeylen = 0; + if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { + *privkeylen = 0; + return 0; + } + if (compressed) { + static const unsigned char begin[] = { + 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,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,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 33; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } else { + static const unsigned char begin[] = { + 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,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,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, + 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, + 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 65; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } + return 1; +} bool CKey::Check(const unsigned char *vch) { - return eccrypto::Check(vch); + return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch); } void CKey::MakeNewKey(bool fCompressedIn) { @@ -30,7 +133,7 @@ void CKey::MakeNewKey(bool fCompressedIn) { } bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) { - if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size())) + if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size())) return false; fCompressed = fCompressedIn; fValid = true; @@ -40,10 +143,11 @@ bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) { CPrivKey CKey::GetPrivKey() const { assert(fValid); CPrivKey privkey; - int privkeylen, ret; + int ret; + size_t privkeylen; privkey.resize(279); privkeylen = 279; - ret = secp256k1_ec_privkey_export(secp256k1_context, begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed); + ret = ec_privkey_export_der(secp256k1_context_sign, (unsigned char*)&privkey[0], &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); assert(ret); privkey.resize(privkeylen); return privkey; @@ -51,11 +155,13 @@ CPrivKey CKey::GetPrivKey() const { CPubKey CKey::GetPubKey() const { assert(fValid); + secp256k1_pubkey pubkey; + size_t clen = 65; CPubKey result; - int clen = 65; - int ret = secp256k1_ec_pubkey_create(secp256k1_context, (unsigned char*)result.begin(), &clen, begin(), fCompressed); - assert((int)result.size() == clen); + int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin()); assert(ret); + secp256k1_ec_pubkey_serialize(secp256k1_context_sign, (unsigned char*)result.begin(), &clen, &pubkey, fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); + assert(result.size() == clen); assert(result.IsValid()); return result; } @@ -64,11 +170,13 @@ bool CKey::Sign(const uint256 &hash, std::vector& vchSig, uint32_ if (!fValid) return false; vchSig.resize(72); - int nSigLen = 72; + size_t nSigLen = 72; unsigned char extra_entropy[32] = {0}; WriteLE32(extra_entropy, test_case); - int ret = secp256k1_ecdsa_sign(secp256k1_context, hash.begin(), (unsigned char*)&vchSig[0], &nSigLen, begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL); + secp256k1_ecdsa_signature sig; + int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL); assert(ret); + secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, (unsigned char*)&vchSig[0], &nSigLen, &sig); vchSig.resize(nSigLen); return true; } @@ -92,7 +200,10 @@ bool CKey::SignCompact(const uint256 &hash, std::vector& vchSig) return false; vchSig.resize(65); int rec = -1; - int ret = secp256k1_ecdsa_sign_compact(secp256k1_context, hash.begin(), &vchSig[1], begin(), secp256k1_nonce_function_rfc6979, NULL, &rec); + secp256k1_ecdsa_recoverable_signature sig; + int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, NULL); + assert(ret); + secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, (unsigned char*)&vchSig[1], &rec, &sig); assert(ret); assert(rec != -1); vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); @@ -100,7 +211,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector& vchSig) } bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) { - if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size())) + if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size())) return false; fCompressed = vchPubKey.IsCompressed(); fValid = true; @@ -126,7 +237,7 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const } memcpy(ccChild.begin(), out+32, 32); memcpy((unsigned char*)keyChild.begin(), begin(), 32); - bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context, (unsigned char*)keyChild.begin(), out); + bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), out); UnlockObject(out); keyChild.fCompressed = true; keyChild.fValid = ret; @@ -164,7 +275,7 @@ CExtPubKey CExtKey::Neuter() const { return ret; } -void CExtKey::Encode(unsigned char code[74]) const { +void CExtKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const { code[0] = nDepth; memcpy(code+1, vchFingerprint, 4); code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF; @@ -175,29 +286,25 @@ void CExtKey::Encode(unsigned char code[74]) const { memcpy(code+42, key.begin(), 32); } -void CExtKey::Decode(const unsigned char code[74]) { +void CExtKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) { nDepth = code[0]; memcpy(vchFingerprint, code+1, 4); nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8]; memcpy(chaincode.begin(), code+9, 32); - key.Set(code+42, code+74, true); + key.Set(code+42, code+BIP32_EXTKEY_SIZE, true); } bool ECC_InitSanityCheck() { - if (!CECKey::SanityCheck()) { - return false; - } CKey key; key.MakeNewKey(true); CPubKey pubkey = key.GetPubKey(); return key.VerifyPubKey(pubkey); } - void ECC_Start() { - assert(secp256k1_context == NULL); + assert(secp256k1_context_sign == NULL); - secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); assert(ctx != NULL); { @@ -210,12 +317,12 @@ void ECC_Start() { UnlockObject(seed); } - secp256k1_context = ctx; + secp256k1_context_sign = ctx; } void ECC_Stop() { - secp256k1_context_t *ctx = secp256k1_context; - secp256k1_context = NULL; + secp256k1_context *ctx = secp256k1_context_sign; + secp256k1_context_sign = NULL; if (ctx) { secp256k1_context_destroy(ctx); diff --git a/src/key.h b/src/key.h index 021eac2a8..b4f48d59f 100644 --- a/src/key.h +++ b/src/key.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -164,11 +164,28 @@ struct CExtKey { a.chaincode == b.chaincode && a.key == b.key; } - void Encode(unsigned char code[74]) const; - void Decode(const unsigned char code[74]); + void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; + void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); bool Derive(CExtKey& out, unsigned int nChild) const; CExtPubKey Neuter() const; void SetMaster(const unsigned char* seed, unsigned int nSeedLen); + template + void Serialize(Stream& s, int nType, int nVersion) const + { + unsigned int len = BIP32_EXTKEY_SIZE; + ::WriteCompactSize(s, len); + unsigned char code[BIP32_EXTKEY_SIZE]; + Encode(code); + s.write((const char *)&code[0], len); + } + template + void Unserialize(Stream& s, int nType, int nVersion) + { + unsigned int len = ::ReadCompactSize(s); + unsigned char code[BIP32_EXTKEY_SIZE]; + s.read((char *)&code[0], len); + Decode(code); + } }; /** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */ diff --git a/src/keystore.cpp b/src/keystore.cpp index cf49ba83a..cc8a57336 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/keystore.h b/src/keystore.h index b917bf20b..d9290722e 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc index ef2ecae83..e11a96b79 100644 --- a/src/leveldb/util/env_win.cc +++ b/src/leveldb/util/env_win.cc @@ -103,39 +103,20 @@ private: DISALLOW_COPY_AND_ASSIGN(Win32RandomAccessFile); }; -class Win32MapFile : public WritableFile +class Win32WritableFile : public WritableFile { public: - Win32MapFile(const std::string& fname); + Win32WritableFile(const std::string& fname); + ~Win32WritableFile(); - ~Win32MapFile(); virtual Status Append(const Slice& data); virtual Status Close(); virtual Status Flush(); virtual Status Sync(); BOOL isEnable(); private: - std::string _filename; - HANDLE _hFile; - size_t _page_size; - size_t _map_size; // How much extra memory to map at a time - char* _base; // The mapped region - HANDLE _base_handle; - char* _limit; // Limit of the mapped region - char* _dst; // Where to write next (in range [base_,limit_]) - char* _last_sync; // Where have we synced up to - uint64_t _file_offset; // Offset of base_ in file - //LARGE_INTEGER file_offset_; - // Have we done an munmap of unsynced data? - bool _pending_sync; - - // Roundup x to a multiple of y - static size_t _Roundup(size_t x, size_t y); - size_t _TruncateToPageBoundary(size_t s); - bool _UnmapCurrentRegion(); - bool _MapNewRegion(); - DISALLOW_COPY_AND_ASSIGN(Win32MapFile); - BOOL _Init(LPCWSTR Path); + std::string filename_; + ::HANDLE _hFile; }; class Win32FileLock : public FileLock @@ -442,202 +423,63 @@ void Win32RandomAccessFile::_CleanUp() } } -size_t Win32MapFile::_Roundup( size_t x, size_t y ) +Win32WritableFile::Win32WritableFile(const std::string& fname) + : filename_(fname) { - return ((x + y - 1) / y) * y; -} - -size_t Win32MapFile::_TruncateToPageBoundary( size_t s ) -{ - s -= (s & (_page_size - 1)); - assert((s % _page_size) == 0); - return s; -} - -bool Win32MapFile::_UnmapCurrentRegion() -{ - bool result = true; - if (_base != NULL) { - if (_last_sync < _limit) { - // Defer syncing this data until next Sync() call, if any - _pending_sync = true; - } - if (!UnmapViewOfFile(_base) || !CloseHandle(_base_handle)) - result = false; - _file_offset += _limit - _base; - _base = NULL; - _base_handle = NULL; - _limit = NULL; - _last_sync = NULL; - _dst = NULL; - // Increase the amount we map the next time, but capped at 1MB - if (_map_size < (1<<20)) { - _map_size *= 2; - } - } - return result; -} - -bool Win32MapFile::_MapNewRegion() -{ - assert(_base == NULL); - //LONG newSizeHigh = (LONG)((file_offset_ + map_size_) >> 32); - //LONG newSizeLow = (LONG)((file_offset_ + map_size_) & 0xFFFFFFFF); - DWORD off_hi = (DWORD)(_file_offset >> 32); - DWORD off_lo = (DWORD)(_file_offset & 0xFFFFFFFF); - LARGE_INTEGER newSize; - newSize.QuadPart = _file_offset + _map_size; - SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN); - SetEndOfFile(_hFile); - - _base_handle = CreateFileMappingA( - _hFile, - NULL, - PAGE_READWRITE, - 0, - 0, - 0); - if (_base_handle != NULL) { - _base = (char*) MapViewOfFile(_base_handle, - FILE_MAP_ALL_ACCESS, - off_hi, - off_lo, - _map_size); - if (_base != NULL) { - _limit = _base + _map_size; - _dst = _base; - _last_sync = _base; - return true; - } - } - return false; -} - -Win32MapFile::Win32MapFile( const std::string& fname) : - _filename(fname), - _hFile(NULL), - _page_size(Win32::g_PageSize), - _map_size(_Roundup(65536, Win32::g_PageSize)), - _base(NULL), - _base_handle(NULL), - _limit(NULL), - _dst(NULL), - _last_sync(NULL), - _file_offset(0), - _pending_sync(false) -{ - std::wstring path; - ToWidePath(fname, path); - _Init(path.c_str()); - assert((Win32::g_PageSize & (Win32::g_PageSize - 1)) == 0); -} - -Status Win32MapFile::Append( const Slice& data ) -{ - const char* src = data.data(); - size_t left = data.size(); - Status s; - while (left > 0) { - assert(_base <= _dst); - assert(_dst <= _limit); - size_t avail = _limit - _dst; - if (avail == 0) { - if (!_UnmapCurrentRegion() || - !_MapNewRegion()) { - return Status::IOError("WinMmapFile.Append::UnmapCurrentRegion or MapNewRegion: ", Win32::GetLastErrSz()); - } - } - size_t n = (left <= avail) ? left : avail; - memcpy(_dst, src, n); - _dst += n; - src += n; - left -= n; - } - return s; -} - -Status Win32MapFile::Close() -{ - Status s; - size_t unused = _limit - _dst; - if (!_UnmapCurrentRegion()) { - s = Status::IOError("WinMmapFile.Close::UnmapCurrentRegion: ",Win32::GetLastErrSz()); - } else if (unused > 0) { - // Trim the extra space at the end of the file - LARGE_INTEGER newSize; - newSize.QuadPart = _file_offset - unused; - if (!SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN)) { - s = Status::IOError("WinMmapFile.Close::SetFilePointer: ",Win32::GetLastErrSz()); - } else - SetEndOfFile(_hFile); - } - if (!CloseHandle(_hFile)) { - if (s.ok()) { - s = Status::IOError("WinMmapFile.Close::CloseHandle: ", Win32::GetLastErrSz()); - } - } - _hFile = INVALID_HANDLE_VALUE; - _base = NULL; - _base_handle = NULL; - _limit = NULL; - - return s; -} - -Status Win32MapFile::Sync() -{ - Status s; - if (_pending_sync) { - // Some unmapped data was not synced - _pending_sync = false; - if (!FlushFileBuffers(_hFile)) { - s = Status::IOError("WinMmapFile.Sync::FlushFileBuffers: ",Win32::GetLastErrSz()); - } - } - if (_dst > _last_sync) { - // Find the beginnings of the pages that contain the first and last - // bytes to be synced. - size_t p1 = _TruncateToPageBoundary(_last_sync - _base); - size_t p2 = _TruncateToPageBoundary(_dst - _base - 1); - _last_sync = _dst; - if (!FlushViewOfFile(_base + p1, p2 - p1 + _page_size)) { - s = Status::IOError("WinMmapFile.Sync::FlushViewOfFile: ",Win32::GetLastErrSz()); - } - } - return s; -} - -Status Win32MapFile::Flush() -{ - return Status::OK(); -} - -Win32MapFile::~Win32MapFile() -{ - if (_hFile != INVALID_HANDLE_VALUE) { - Win32MapFile::Close(); - } -} - -BOOL Win32MapFile::_Init( LPCWSTR Path ) -{ - DWORD Flag = PathFileExistsW(Path) ? OPEN_EXISTING : CREATE_ALWAYS; - _hFile = CreateFileW(Path, + std::wstring path; + ToWidePath(fname, path); + DWORD Flag = PathFileExistsW(path.c_str()) ? OPEN_EXISTING : CREATE_ALWAYS; + _hFile = CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, NULL, Flag, FILE_ATTRIBUTE_NORMAL, NULL); - if(!_hFile || _hFile == INVALID_HANDLE_VALUE) - return FALSE; - else - return TRUE; + // CreateFileW returns INVALID_HANDLE_VALUE in case of error, always check isEnable() before use } -BOOL Win32MapFile::isEnable() +Win32WritableFile::~Win32WritableFile() { - return _hFile ? TRUE : FALSE; + if (_hFile != INVALID_HANDLE_VALUE) + Close(); +} + +Status Win32WritableFile::Append(const Slice& data) +{ + DWORD r = 0; + if (!WriteFile(_hFile, data.data(), data.size(), &r, NULL) || r != data.size()) { + return Status::IOError("Win32WritableFile.Append::WriteFile: "+filename_, Win32::GetLastErrSz()); + } + return Status::OK(); +} + +Status Win32WritableFile::Close() +{ + if (!CloseHandle(_hFile)) { + return Status::IOError("Win32WritableFile.Close::CloseHandle: "+filename_, Win32::GetLastErrSz()); + } + _hFile = INVALID_HANDLE_VALUE; + return Status::OK(); +} + +Status Win32WritableFile::Flush() +{ + // Nothing to do here, there are no application-side buffers + return Status::OK(); +} + +Status Win32WritableFile::Sync() +{ + if (!FlushFileBuffers(_hFile)) { + return Status::IOError("Win32WritableFile.Sync::FlushFileBuffers "+filename_, Win32::GetLastErrSz()); + } + return Status::OK(); +} + +BOOL Win32WritableFile::isEnable() +{ + return _hFile != INVALID_HANDLE_VALUE; } Win32FileLock::Win32FileLock( const std::string& fname ) : @@ -981,7 +823,7 @@ Status Win32Env::NewLogger( const std::string& fname, Logger** result ) { Status sRet; std::string path = fname; - Win32MapFile* pMapFile = new Win32MapFile(ModifyPath(path)); + Win32WritableFile* pMapFile = new Win32WritableFile(ModifyPath(path)); if(!pMapFile->isEnable()){ delete pMapFile; *result = NULL; @@ -995,7 +837,7 @@ Status Win32Env::NewWritableFile( const std::string& fname, WritableFile** resul { Status sRet; std::string path = fname; - Win32MapFile* pFile = new Win32MapFile(ModifyPath(path)); + Win32WritableFile* pFile = new Win32WritableFile(ModifyPath(path)); if(!pFile->isEnable()){ *result = NULL; sRet = Status::IOError(fname,Win32::GetLastErrSz()); diff --git a/src/limitedmap.h b/src/limitedmap.h index 5456dfc7c..4d9bb4fa2 100644 --- a/src/limitedmap.h +++ b/src/limitedmap.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2014 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/main.cpp b/src/main.cpp index 84efbcd61..22d0c3237 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,27 +1,29 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "main.h" #include "addrman.h" -#include "alert.h" #include "arith_uint256.h" #include "chainparams.h" #include "checkpoints.h" #include "checkqueue.h" #include "consensus/consensus.h" +#include "consensus/merkle.h" #include "consensus/validation.h" #include "hash.h" #include "init.h" #include "merkleblock.h" #include "nameclaim.h" #include "net.h" +#include "policy/fees.h" #include "policy/policy.h" #include "pow.h" #include "primitives/block.h" #include "primitives/transaction.h" +#include "random.h" #include "script/script.h" #include "script/sigcache.h" #include "script/standard.h" @@ -34,6 +36,7 @@ #include "utilmoneystr.h" #include "utilstrencodings.h" #include "validationinterface.h" +#include "versionbits.h" #include @@ -67,25 +70,28 @@ bool fReindex = false; bool fTxIndex = false; bool fHavePruned = false; bool fPruneMode = false; -bool fIsBareMultisigStd = true; +bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG; bool fRequireStandard = true; +unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP; bool fCheckBlockIndex = false; -bool fCheckpointsEnabled = true; +bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED; size_t nCoinCacheUsage = 5000 * 300; uint64_t nPruneTarget = 0; -bool fAlerts = DEFAULT_ALERTS; +int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; +bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT; -/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */ -CFeeRate minRelayTxFee = CFeeRate(5000); +CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); +CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; CTxMemPool mempool(::minRelayTxFee); +FeeFilterRounder filterRounder(::minRelayTxFee); struct COrphanTx { CTransaction tx; NodeId fromPeer; }; -map mapOrphanTransactions GUARDED_BY(cs_main);; -map > mapOrphanTransactionsByPrev GUARDED_BY(cs_main);; +map mapOrphanTransactions GUARDED_BY(cs_main); +map > mapOrphanTransactionsByPrev GUARDED_BY(cs_main); void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** @@ -93,7 +99,7 @@ void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); * in the last Consensus::Params::nMajorityWindow blocks, starting at pstart and going backwards. */ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams); -static void CheckBlockIndex(); +static void CheckBlockIndex(const Consensus::Params& consensusParams); /** Constant stuff for coinbase transactions we create: */ CScript COINBASE_FLAGS; @@ -134,9 +140,9 @@ namespace { set setBlockIndexCandidates; /** Number of nodes with fSyncStarted. */ int nSyncStarted = 0; - /** All pairs A->B, where A (or one if its ancestors) misses transactions, but B has transactions. - * Pruned nodes may have entries where B is missing data. - */ + /** All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions. + * Pruned nodes may have entries where B is missing data. + */ multimap mapBlocksUnlinked; CCriticalSection cs_LastBlockFile; @@ -181,7 +187,7 @@ namespace { * million to make it highly unlikely for users to have issues with this * filter. * - * Memory used: 1.7MB + * Memory used: 1.3 MB */ boost::scoped_ptr recentRejects; uint256 hashRecentRejectsChainTip; @@ -189,16 +195,11 @@ namespace { /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */ struct QueuedBlock { uint256 hash; - CBlockIndex *pindex; //! Optional. - int64_t nTime; //! Time of "getdata" request in microseconds. - bool fValidatedHeaders; //! Whether this block has validated headers at the time of request. - int64_t nTimeDisconnect; //! The timeout for this block request (for disconnecting a slow peer) + CBlockIndex* pindex; //!< Optional. + bool fValidatedHeaders; //!< Whether this block has validated headers at the time of request. }; map::iterator> > mapBlocksInFlight; - /** Number of blocks in flight with validated headers. */ - int nQueuedValidatedHeaders = 0; - /** Number of preferable block download peers. */ int nPreferredDownload = 0; @@ -207,6 +208,9 @@ namespace { /** Dirty block file entries. */ set setDirtyFileInfo; + + /** Number of peers from which we're downloading blocks. */ + int nPeersWithValidatedDownloads = 0; } // anon namespace ////////////////////////////////////////////////////////////////////////////// @@ -247,15 +251,21 @@ struct CNodeState { uint256 hashLastUnknownBlock; //! The last full block we both have. CBlockIndex *pindexLastCommonBlock; + //! The best header we have sent our peer. + CBlockIndex *pindexBestHeaderSent; //! Whether we've started headers synchronization with this peer. bool fSyncStarted; //! Since when we're stalling block download progress (in microseconds), or 0. int64_t nStallingSince; list vBlocksInFlight; + //! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty. + int64_t nDownloadingSince; int nBlocksInFlight; int nBlocksInFlightValidHeaders; //! Whether we consider this a preferred download peer. bool fPreferredDownload; + //! Whether this peer wants invs or headers (when possible) for block announcements. + bool fPreferHeaders; CNodeState() { fCurrentlyConnected = false; @@ -264,11 +274,14 @@ struct CNodeState { pindexBestKnownBlock = NULL; hashLastUnknownBlock.SetNull(); pindexLastCommonBlock = NULL; + pindexBestHeaderSent = NULL; fSyncStarted = false; nStallingSince = 0; + nDownloadingSince = 0; nBlocksInFlight = 0; nBlocksInFlightValidHeaders = 0; fPreferredDownload = false; + fPreferHeaders = false; } }; @@ -299,12 +312,6 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state) nPreferredDownload += state->fPreferredDownload; } -// Returns time at which to timeout block request (nTime in microseconds) -int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consensus::Params &consensusParams) -{ - return nTime + 500000 * consensusParams.nPowTargetSpacing * (4 + nValidatedQueuedBefore); -} - void InitializeNode(NodeId nodeid, const CNode *pnode) { LOCK(cs_main); CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second; @@ -323,12 +330,22 @@ void FinalizeNode(NodeId nodeid) { AddressCurrentlyConnected(state->address); } - BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) + BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) { mapBlocksInFlight.erase(entry.hash); + } EraseOrphansFor(nodeid); nPreferredDownload -= state->fPreferredDownload; + nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0); + assert(nPeersWithValidatedDownloads >= 0); mapNodeState.erase(nodeid); + + if (mapNodeState.empty()) { + // Do a consistency check after the last peer is removed. + assert(mapBlocksInFlight.empty()); + assert(nPreferredDownload == 0); + assert(nPeersWithValidatedDownloads == 0); + } } // Requires cs_main. @@ -337,8 +354,15 @@ bool MarkBlockAsReceived(const uint256& hash) { map::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); if (itInFlight != mapBlocksInFlight.end()) { CNodeState *state = State(itInFlight->second.first); - nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders; state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders; + if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) { + // Last validated block on the queue was received. + nPeersWithValidatedDownloads--; + } + if (state->vBlocksInFlight.begin() == itInFlight->second.second) { + // First block on the queue was received, update the start download time for the next one + state->nDownloadingSince = std::max(state->nDownloadingSince, GetTimeMicros()); + } state->vBlocksInFlight.erase(itInFlight->second.second); state->nBlocksInFlight--; state->nStallingSince = 0; @@ -356,16 +380,21 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Pa // Make sure it's not listed somewhere already. MarkBlockAsReceived(hash); - int64_t nNow = GetTimeMicros(); - QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL, GetBlockTimeout(nNow, nQueuedValidatedHeaders, consensusParams)}; - nQueuedValidatedHeaders += newentry.fValidatedHeaders; + QueuedBlock newentry = {hash, pindex, pindex != NULL}; list::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry); state->nBlocksInFlight++; state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders; + if (state->nBlocksInFlight == 1) { + // We're starting a block download (batch) from this peer. + state->nDownloadingSince = GetTimeMicros(); + } + if (state->nBlocksInFlightValidHeaders == 1 && pindex != NULL) { + nPeersWithValidatedDownloads++; + } mapBlocksInFlight[hash] = std::make_pair(nodeid, it); } -/** Check whether the last unknown block a peer advertized is not yet known. */ +/** Check whether the last unknown block a peer advertised is not yet known. */ void ProcessBlockAvailability(NodeId nodeid) { CNodeState *state = State(nodeid); assert(state != NULL); @@ -398,6 +427,22 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { } } +// Requires cs_main +bool CanDirectFetch(const Consensus::Params &consensusParams) +{ + return chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20; +} + +// Requires cs_main +bool PeerHasHeader(CNodeState *state, CBlockIndex *pindex) +{ + if (state->pindexBestKnownBlock && pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight)) + return true; + if (state->pindexBestHeaderSent && pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight)) + return true; + return false; +} + /** Find the last common ancestor two blocks have. * Both pa and pb must be non-NULL. */ CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) { @@ -646,18 +691,217 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) return true; if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime)) return true; - BOOST_FOREACH(const CTxIn& txin, tx.vin) - if (!txin.IsFinal()) + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL)) return false; + } return true; } -bool CheckFinalTx(const CTransaction &tx) +bool CheckFinalTx(const CTransaction &tx, int flags) { AssertLockHeld(cs_main); - return IsFinalTx(tx, chainActive.Height() + 1, GetAdjustedTime()); + + // By convention a negative value for flags indicates that the + // current network-enforced consensus rules should be used. In + // a future soft-fork scenario that would mean checking which + // rules would be enforced for the next block and setting the + // appropriate flags. At the present time no soft-forks are + // scheduled, so no flags are set. + flags = std::max(flags, 0); + + // CheckFinalTx() uses chainActive.Height()+1 to evaluate + // nLockTime because when IsFinalTx() is called within + // CBlock::AcceptBlock(), the height of the block *being* + // evaluated is what is used. Thus if we want to know if a + // transaction can be part of the *next* block, we need to call + // IsFinalTx() with one more than chainActive.Height(). + const int nBlockHeight = chainActive.Height() + 1; + + // BIP113 will require that time-locked transactions have nLockTime set to + // less than the median time of the previous block they're contained in. + // When the next block is created its previous block will be the current + // chain tip, so we use that to calculate the median time passed to + // IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set. + const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) + ? chainActive.Tip()->GetMedianTimePast() + : GetAdjustedTime(); + + return IsFinalTx(tx, nBlockHeight, nBlockTime); } +/** + * Calculates the block height and previous block's median time past at + * which the transaction will be considered final in the context of BIP 68. + * Also removes from the vector of input heights any entries which did not + * correspond to sequence locked inputs as they do not affect the calculation. + */ +static std::pair CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector* prevHeights, const CBlockIndex& block) +{ + assert(prevHeights->size() == tx.vin.size()); + + // Will be set to the equivalent height- and time-based nLockTime + // values that would be necessary to satisfy all relative lock- + // time constraints given our view of block chain history. + // The semantics of nLockTime are the last invalid height/time, so + // use -1 to have the effect of any height or time being valid. + int nMinHeight = -1; + int64_t nMinTime = -1; + + // tx.nVersion is signed integer so requires cast to unsigned otherwise + // we would be doing a signed comparison and half the range of nVersion + // wouldn't support BIP 68. + bool fEnforceBIP68 = static_cast(tx.nVersion) >= 2 + && flags & LOCKTIME_VERIFY_SEQUENCE; + + // Do not enforce sequence numbers as a relative lock time + // unless we have been instructed to + if (!fEnforceBIP68) { + return std::make_pair(nMinHeight, nMinTime); + } + + for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { + const CTxIn& txin = tx.vin[txinIndex]; + + // Sequence numbers with the most significant bit set are not + // treated as relative lock-times, nor are they given any + // consensus-enforced meaning at this point. + if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) { + // The height of this input is not relevant for sequence locks + (*prevHeights)[txinIndex] = 0; + continue; + } + + int nCoinHeight = (*prevHeights)[txinIndex]; + + if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) { + int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight-1, 0))->GetMedianTimePast(); + // NOTE: Subtract 1 to maintain nLockTime semantics + // BIP 68 relative lock times have the semantics of calculating + // the first block or time at which the transaction would be + // valid. When calculating the effective block time or height + // for the entire transaction, we switch to using the + // semantics of nLockTime which is the last invalid block + // time or height. Thus we subtract 1 from the calculated + // time or height. + + // Time-based relative lock-times are measured from the + // smallest allowed timestamp of the block containing the + // txout being spent, which is the median time past of the + // block prior. + nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1); + } else { + nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1); + } + } + + return std::make_pair(nMinHeight, nMinTime); +} + +static bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair lockPair) +{ + assert(block.pprev); + int64_t nBlockTime = block.pprev->GetMedianTimePast(); + if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime) + return false; + + return true; +} + +bool SequenceLocks(const CTransaction &tx, int flags, std::vector* prevHeights, const CBlockIndex& block) +{ + return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block)); +} + +bool TestLockPointValidity(const LockPoints* lp) +{ + AssertLockHeld(cs_main); + assert(lp); + // If there are relative lock times then the maxInputBlock will be set + // If there are no relative lock times, the LockPoints don't depend on the chain + if (lp->maxInputBlock) { + // Check whether chainActive is an extension of the block at which the LockPoints + // calculation was valid. If not LockPoints are no longer valid + if (!chainActive.Contains(lp->maxInputBlock)) { + return false; + } + } + + // LockPoints still valid + return true; +} + +bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool useExistingLockPoints) +{ + AssertLockHeld(cs_main); + AssertLockHeld(mempool.cs); + + CBlockIndex* tip = chainActive.Tip(); + CBlockIndex index; + index.pprev = tip; + // CheckSequenceLocks() uses chainActive.Height()+1 to evaluate + // height based locks because when SequenceLocks() is called within + // ConnectBlock(), the height of the block *being* + // evaluated is what is used. + // Thus if we want to know if a transaction can be part of the + // *next* block, we need to use one more than chainActive.Height() + index.nHeight = tip->nHeight + 1; + + std::pair lockPair; + if (useExistingLockPoints) { + assert(lp); + lockPair.first = lp->height; + lockPair.second = lp->time; + } + else { + // pcoinsTip contains the UTXO set for chainActive.Tip() + CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); + std::vector prevheights; + prevheights.resize(tx.vin.size()); + for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { + const CTxIn& txin = tx.vin[txinIndex]; + CCoins coins; + if (!viewMemPool.GetCoins(txin.prevout.hash, coins)) { + return error("%s: Missing input", __func__); + } + if (coins.nHeight == MEMPOOL_HEIGHT) { + // Assume all mempool transaction confirm in the next block + prevheights[txinIndex] = tip->nHeight + 1; + } else { + prevheights[txinIndex] = coins.nHeight; + } + } + lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index); + if (lp) { + lp->height = lockPair.first; + lp->time = lockPair.second; + // Also store the hash of the block with the highest height of + // all the blocks which have sequence locked prevouts. + // This hash needs to still be on the chain + // for these LockPoint calculations to be valid + // Note: It is impossible to correctly calculate a maxInputBlock + // if any of the sequence locked inputs depend on unconfirmed txs, + // except in the special case where the relative lock time/height + // is 0, which is equivalent to no sequence lock. Since we assume + // input height of tip+1 for mempool txs and test the resulting + // lockPair from CalculateSequenceLocks against tip+1. We know + // EvaluateSequenceLocks will fail if there was a non-zero sequence + // lock on a mempool input, so we can use the return value of + // CheckSequenceLocks to indicate the LockPoints validity + int maxInputHeight = 0; + BOOST_FOREACH(int height, prevheights) { + // Can ignore mempool inputs since we'll fail if they had non-zero locks + if (height != tip->nHeight+1) { + maxInputHeight = std::max(maxInputHeight, height); + } + } + lp->maxInputBlock = tip->GetAncestor(maxInputHeight); + } + } + return EvaluateSequenceLocks(index, lockPair); +} + + unsigned int GetLegacySigOpCount(const CTransaction& tx) { unsigned int nSigOps = 0; @@ -718,7 +962,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) if (!MoneyRange(nValueOut)) return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge"); if (ClaimScriptSize(txout.scriptPubKey) > MAX_CLAIM_SCRIPT_SIZE) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-claimscriptsize-toolarg"); + return state.DoS(100, false, REJECT_INVALID, "bad-txns-claimscriptsize-toolarge"); } // Check for duplicate inputs @@ -745,37 +989,19 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) return true; } -CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree) -{ - { - LOCK(mempool.cs); - uint256 hash = tx.GetHash(); - double dPriorityDelta = 0; - CAmount nFeeDelta = 0; - mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta); - if (dPriorityDelta > 0 || nFeeDelta > 0) - return 0; - } +void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) { + int expired = pool.Expire(GetTime() - age); + if (expired != 0) + LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired); - CAmount nMinFee = ::minRelayTxFee.GetFee(nBytes); - - if (fAllowFree) - { - // There is a free transaction area in blocks created by most miners, - // * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000 - // to be considered to fall into this category. We don't want to encourage sending - // multiple transactions instead of one big transaction to avoid fees. - if (nBytes < (DEFAULT_BLOCK_PRIORITY_SIZE - 1000)) - nMinFee = 0; - } - - if (!MoneyRange(nMinFee)) - nMinFee = MAX_MONEY; - return nMinFee; + std::vector vNoSpendsRemaining; + pool.TrimToSize(limit, &vNoSpendsRemaining); + BOOST_FOREACH(const uint256& removed, vNoSpendsRemaining) + pcoinsTip->Uncache(removed); } /** Convert CValidationState to a human-readable message for logging */ -static std::string FormatStateMessage(const CValidationState &state) +std::string FormatStateMessage(const CValidationState &state) { return strprintf("%s%s (code %i)", state.GetRejectReason(), @@ -783,15 +1009,17 @@ static std::string FormatStateMessage(const CValidationState &state) state.GetRejectCode()); } -bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, - bool* pfMissingInputs, bool fRejectAbsurdFee) +bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree, + bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee, + std::vector& vHashTxnToUncache) { + const uint256 hash = tx.GetHash(); AssertLockHeld(cs_main); if (pfMissingInputs) *pfMissingInputs = false; if (!CheckTransaction(tx, state)) - return false; + return false; // state filled in by CheckTransaction // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) @@ -802,27 +1030,64 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa if (fRequireStandard && !IsStandardTx(tx, reason)) return state.DoS(0, false, REJECT_NONSTANDARD, reason); + // Don't relay version 2 transactions until CSV is active, and we can be + // sure that such transactions will be mined (unless we're on + // -testnet/-regtest). + const CChainParams& chainparams = Params(); + if (fRequireStandard && tx.nVersion >= 2 && VersionBitsTipState(chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV) != THRESHOLD_ACTIVE) { + return state.DoS(0, false, REJECT_NONSTANDARD, "premature-version2-tx"); + } + // Only accept nLockTime-using transactions that can be mined in the next // block; we don't want our mempool filled up with transactions that can't // be mined yet. - if (!CheckFinalTx(tx)) + if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) return state.DoS(0, false, REJECT_NONSTANDARD, "non-final"); // is it already in the memory pool? - uint256 hash = tx.GetHash(); if (pool.exists(hash)) return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-in-mempool"); // Check for conflicts with in-memory transactions + set setConflicts; { LOCK(pool.cs); // protect pool.mapNextTx - for (unsigned int i = 0; i < tx.vin.size(); i++) + BOOST_FOREACH(const CTxIn &txin, tx.vin) { - COutPoint outpoint = tx.vin[i].prevout; - if (pool.mapNextTx.count(outpoint)) + if (pool.mapNextTx.count(txin.prevout)) { - // Disable replacement feature for now - return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict"); + const CTransaction *ptxConflicting = pool.mapNextTx[txin.prevout].ptx; + if (!setConflicts.count(ptxConflicting->GetHash())) + { + // Allow opt-out of transaction replacement by setting + // nSequence >= maxint-1 on all inputs. + // + // maxint-1 is picked to still allow use of nLockTime by + // non-replacable transactions. All inputs rather than just one + // is for the sake of multi-party protocols, where we don't + // want a single party to be able to disable replacement. + // + // The opt-out ignores descendants as anyone relying on + // first-seen mempool behavior should be checking all + // unconfirmed ancestors anyway; doing otherwise is hopelessly + // insecure. + bool fReplacementOptOut = true; + if (fEnableReplacement) + { + BOOST_FOREACH(const CTxIn &txin, ptxConflicting->vin) + { + if (txin.nSequence < std::numeric_limits::max()-1) + { + fReplacementOptOut = false; + break; + } + } + } + if (fReplacementOptOut) + return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict"); + + setConflicts.insert(ptxConflicting->GetHash()); + } } } } @@ -832,19 +1097,26 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa CCoinsViewCache view(&dummy); CAmount nValueIn = 0; + LockPoints lp; { LOCK(pool.cs); CCoinsViewMemPool viewMemPool(pcoinsTip, pool); view.SetBackend(viewMemPool); // do we already have it? - if (view.HaveCoins(hash)) + bool fHadTxInCache = pcoinsTip->HaveCoinsInCache(hash); + if (view.HaveCoins(hash)) { + if (!fHadTxInCache) + vHashTxnToUncache.push_back(hash); return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-known"); + } // do all inputs exist? // Note that this does not check for the presence of actual outputs (see the next check for that), // and only helps with filling in pfMissingInputs (to determine missing vs spent). BOOST_FOREACH(const CTxIn txin, tx.vin) { + if (!pcoinsTip->HaveCoinsInCache(txin.prevout.hash)) + vHashTxnToUncache.push_back(txin.prevout.hash); if (!view.HaveCoins(txin.prevout.hash)) { if (pfMissingInputs) *pfMissingInputs = true; @@ -863,45 +1135,71 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool view.SetBackend(dummy); + + // Only accept BIP68 sequence locked transactions that can be mined in the next + // block; we don't want our mempool filled up with transactions that can't + // be mined yet. + // Must keep pool.cs for this unless we change CheckSequenceLocks to take a + // CoinsViewCache instead of create its own + if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) + return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final"); } // Check for non-standard pay-to-script-hash in inputs if (fRequireStandard && !AreInputsStandard(tx, view)) return state.Invalid(false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs"); + unsigned int nSigOps = GetLegacySigOpCount(tx); + nSigOps += GetP2SHSigOpCount(tx, view); + + CAmount nValueOut = tx.GetValueOut(); + CAmount nFees = nValueIn-nValueOut; + // nModifiedFees includes any fee deltas from PrioritiseTransaction + CAmount nModifiedFees = nFees; + double nPriorityDummy = 0; + pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees); + + CAmount inChainInputValue; + double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue); + + // Keep track of transactions that spend a coinbase, which we re-scan + // during reorgs to ensure COINBASE_MATURITY is still met. + bool fSpendsCoinbase = false; + BOOST_FOREACH(const CTxIn &txin, tx.vin) { + const CCoins *coins = view.AccessCoins(txin.prevout.hash); + if (coins->IsCoinBase()) { + fSpendsCoinbase = true; + break; + } + } + + CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp); + unsigned int nSize = entry.GetTxSize(); + if (txFeeRate) { + *txFeeRate = CFeeRate(nFees, nSize); + } + // Check that the transaction doesn't have an excessive number of // sigops, making it impossible to mine. Since the coinbase transaction // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than // merely non-standard transaction. - unsigned int nSigOps = GetLegacySigOpCount(tx); - nSigOps += GetP2SHSigOpCount(tx, view); - if (nSigOps > MAX_STANDARD_TX_SIGOPS) + if ((nSigOps > MAX_STANDARD_TX_SIGOPS) || (nBytesPerSigOp && nSigOps > nSize / nBytesPerSigOp)) return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false, - strprintf("%d > %d", nSigOps, MAX_STANDARD_TX_SIGOPS)); + strprintf("%d", nSigOps)); - CAmount nValueOut = tx.GetValueOut(); - CAmount nFees = nValueIn-nValueOut; - double dPriority = view.GetPriority(tx, chainActive.Height()); - - CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx)); - unsigned int nSize = entry.GetTxSize(); - - // Don't accept it if it can't get into a block - CAmount txMinFee = GetMinRelayFee(tx, nSize, true); - if (fLimitFree && nFees < txMinFee) - return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient fee", false, - strprintf("%d < %d", nFees, txMinFee)); - - // Require that free transactions have sufficient priority to be mined in the next block. - if (GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) { + CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize); + if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) { + return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee)); + } else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) { + // Require that free transactions have sufficient priority to be mined in the next block. return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority"); } // Continuously rate-limit free (really, very-low-fee) transactions // This mitigates 'penny-flooding' -- sending thousands of free transactions just to // be annoying or make others' transactions take longer to confirm. - if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize)) + if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) { static CCriticalSection csFreeLimiter; static double dFreeCount; @@ -915,16 +1213,16 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa nLastTime = nNow; // -limitfreerelay unit is thousand-bytes-per-minute // At default rate it would take over a month to fill 1GB - if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000) + if (dFreeCount + nSize >= GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * 1000) return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "rate limited free transaction"); LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); dFreeCount += nSize; } - if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000) + if (nAbsurdFee && nFees > nAbsurdFee) return state.Invalid(false, REJECT_HIGHFEE, "absurdly-high-fee", - strprintf("%d > %d", nFees, ::minRelayTxFee.GetFee(nSize) * 10000)); + strprintf("%d > %d", nFees, nAbsurdFee)); // Calculate in-mempool ancestors, up to a limit. CTxMemPool::setEntries setAncestors; @@ -937,10 +1235,153 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa return state.DoS(0, false, REJECT_NONSTANDARD, "too-long-mempool-chain", false, errString); } + // A transaction that spends outputs that would be replaced by it is invalid. Now + // that we have the set of all ancestors we can detect this + // pathological case by making sure setConflicts and setAncestors don't + // intersect. + BOOST_FOREACH(CTxMemPool::txiter ancestorIt, setAncestors) + { + const uint256 &hashAncestor = ancestorIt->GetTx().GetHash(); + if (setConflicts.count(hashAncestor)) + { + return state.DoS(10, false, + REJECT_INVALID, "bad-txns-spends-conflicting-tx", false, + strprintf("%s spends conflicting transaction %s", + hash.ToString(), + hashAncestor.ToString())); + } + } + + // Check if it's economically rational to mine this transaction rather + // than the ones it replaces. + CAmount nConflictingFees = 0; + size_t nConflictingSize = 0; + uint64_t nConflictingCount = 0; + CTxMemPool::setEntries allConflicting; + + // If we don't hold the lock allConflicting might be incomplete; the + // subsequent RemoveStaged() and addUnchecked() calls don't guarantee + // mempool consistency for us. + LOCK(pool.cs); + if (setConflicts.size()) + { + CFeeRate newFeeRate(nModifiedFees, nSize); + set setConflictsParents; + const int maxDescendantsToVisit = 100; + CTxMemPool::setEntries setIterConflicting; + BOOST_FOREACH(const uint256 &hashConflicting, setConflicts) + { + CTxMemPool::txiter mi = pool.mapTx.find(hashConflicting); + if (mi == pool.mapTx.end()) + continue; + + // Save these to avoid repeated lookups + setIterConflicting.insert(mi); + + // Don't allow the replacement to reduce the feerate of the + // mempool. + // + // We usually don't want to accept replacements with lower + // feerates than what they replaced as that would lower the + // feerate of the next block. Requiring that the feerate always + // be increased is also an easy-to-reason about way to prevent + // DoS attacks via replacements. + // + // The mining code doesn't (currently) take children into + // account (CPFP) so we only consider the feerates of + // transactions being directly replaced, not their indirect + // descendants. While that does mean high feerate children are + // ignored when deciding whether or not to replace, we do + // require the replacement to pay more overall fees too, + // mitigating most cases. + CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize()); + if (newFeeRate <= oldFeeRate) + { + return state.DoS(0, false, + REJECT_INSUFFICIENTFEE, "insufficient fee", false, + strprintf("rejecting replacement %s; new feerate %s <= old feerate %s", + hash.ToString(), + newFeeRate.ToString(), + oldFeeRate.ToString())); + } + + BOOST_FOREACH(const CTxIn &txin, mi->GetTx().vin) + { + setConflictsParents.insert(txin.prevout.hash); + } + + nConflictingCount += mi->GetCountWithDescendants(); + } + // This potentially overestimates the number of actual descendants + // but we just want to be conservative to avoid doing too much + // work. + if (nConflictingCount <= maxDescendantsToVisit) { + // If not too many to replace, then calculate the set of + // transactions that would have to be evicted + BOOST_FOREACH(CTxMemPool::txiter it, setIterConflicting) { + pool.CalculateDescendants(it, allConflicting); + } + BOOST_FOREACH(CTxMemPool::txiter it, allConflicting) { + nConflictingFees += it->GetModifiedFee(); + nConflictingSize += it->GetTxSize(); + } + } else { + return state.DoS(0, false, + REJECT_NONSTANDARD, "too many potential replacements", false, + strprintf("rejecting replacement %s; too many potential replacements (%d > %d)\n", + hash.ToString(), + nConflictingCount, + maxDescendantsToVisit)); + } + + for (unsigned int j = 0; j < tx.vin.size(); j++) + { + // We don't want to accept replacements that require low + // feerate junk to be mined first. Ideally we'd keep track of + // the ancestor feerates and make the decision based on that, + // but for now requiring all new inputs to be confirmed works. + if (!setConflictsParents.count(tx.vin[j].prevout.hash)) + { + // Rather than check the UTXO set - potentially expensive - + // it's cheaper to just check if the new input refers to a + // tx that's in the mempool. + if (pool.mapTx.find(tx.vin[j].prevout.hash) != pool.mapTx.end()) + return state.DoS(0, false, + REJECT_NONSTANDARD, "replacement-adds-unconfirmed", false, + strprintf("replacement %s adds unconfirmed input, idx %d", + hash.ToString(), j)); + } + } + + // The replacement must pay greater fees than the transactions it + // replaces - if we did the bandwidth used by those conflicting + // transactions would not be paid for. + if (nModifiedFees < nConflictingFees) + { + return state.DoS(0, false, + REJECT_INSUFFICIENTFEE, "insufficient fee", false, + strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s", + hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees))); + } + + // Finally in addition to paying more fees than the conflicts the + // new transaction must pay for its own bandwidth. + CAmount nDeltaFees = nModifiedFees - nConflictingFees; + if (nDeltaFees < ::minRelayTxFee.GetFee(nSize)) + { + return state.DoS(0, false, + REJECT_INSUFFICIENTFEE, "insufficient fee", false, + strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s", + hash.ToString(), + FormatMoney(nDeltaFees), + FormatMoney(::minRelayTxFee.GetFee(nSize)))); + } + } + // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true)) - return false; + return false; // state filled in by CheckInputs // Check again against just the consensus-critical mandatory script // verification flags, in case of bugs in the standard flags that cause @@ -957,17 +1398,47 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa __func__, hash.ToString(), FormatStateMessage(state)); } + // Remove conflicting transactions from the mempool + BOOST_FOREACH(const CTxMemPool::txiter it, allConflicting) + { + LogPrint("mempool", "replacing tx %s with %s for %s BTC additional fees, %d delta bytes\n", + it->GetTx().GetHash().ToString(), + hash.ToString(), + FormatMoney(nModifiedFees - nConflictingFees), + (int)nSize - (int)nConflictingSize); + } + pool.RemoveStaged(allConflicting, false); + // Store transaction in memory pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload()); + + // trim mempool and check if tx was trimmed + if (!fOverrideMempoolLimit) { + LimitMempoolSize(pool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); + if (!pool.exists(hash)) + return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool full"); + } } - SyncWithWallets(tx, NULL); + SyncWithWallets(tx, NULL, NULL); return true; } +bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, + bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount nAbsurdFee) +{ + std::vector vHashTxToUncache; + bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, txFeeRate, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache); + if (!res) { + BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache) + pcoinsTip->Uncache(hashTx); + } + return res; +} + /** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */ -bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) +bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow) { CBlockIndex *pindexSlow = NULL; @@ -1013,7 +1484,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock if (pindexSlow) { CBlock block; - if (ReadBlockFromDisk(block, pindexSlow)) { + if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) { BOOST_FOREACH(const CTransaction &tx, block.vtx) { if (tx.GetHash() == hash) { txOut = tx; @@ -1058,7 +1529,7 @@ bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHea return true; } -bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams) { block.SetNull(); @@ -1076,15 +1547,15 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) } // Check the header - if (!CheckProofOfWork(block.GetPoWHash(), block.nBits, Params().GetConsensus())) + if (!CheckProofOfWork(block.GetPoWHash(), block.nBits, consensusParams)) return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); return true; } -bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex) +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams) { - if (!ReadBlockFromDisk(block, pindex->GetBlockPos())) + if (!ReadBlockFromDisk(block, pindex->GetBlockPos(), consensusParams)) return false; if (block.GetHash() != pindex->GetBlockHash()) return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s", @@ -1154,7 +1625,7 @@ bool IsInitialBlockDownload() if (lockIBDState) return false; bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6);// || - //pindexBestHeader->GetBlockTime() < GetTime() - chainParams.MaxTipAge()); + //pindexBestHeader->GetBlockTime() < GetTime() - nMaxTipAge); if (!state) lockIBDState = true; return state; @@ -1164,6 +1635,26 @@ bool fLargeWorkForkFound = false; bool fLargeWorkInvalidChainFound = false; CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL; +static void AlertNotify(const std::string& strMessage, bool fThread) +{ + uiInterface.NotifyAlertChanged(); + std::string strCmd = GetArg("-alertnotify", ""); + if (strCmd.empty()) return; + + // Alert text should be plain ascii coming from a trusted source, but to + // be safe we first strip anything not in safeChars, then add single quotes around + // the whole string before passing it to the shell: + std::string singleQuote("'"); + std::string safeStatus = SanitizeString(strMessage); + safeStatus = singleQuote+safeStatus+singleQuote; + boost::replace_all(strCmd, "%s", safeStatus); + + if (fThread) + boost::thread t(runCommand, strCmd); // thread runs free + else + runCommand(strCmd); +} + void CheckForkWarningConditions() { AssertLockHeld(cs_main); @@ -1183,7 +1674,7 @@ void CheckForkWarningConditions() { std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + pindexBestForkBase->phashBlock->ToString() + std::string("'"); - CAlert::Notify(warning, true); + AlertNotify(warning, true); } if (pindexBestForkTip && pindexBestForkBase) { @@ -1249,7 +1740,7 @@ void Misbehaving(NodeId pnode, int howmuch) return; state->nMisbehavior += howmuch; - int banscore = GetArg("-banscore", 100); + int banscore = GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD); if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore) { LogPrintf("%s: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior); @@ -1318,9 +1809,8 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach } } } - // add outputs - inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); + inputs.ModifyNewCoins(tx.GetHash(), tx.IsCoinBase())->FromTx(tx, nHeight); } void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight) @@ -1404,9 +1894,12 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // Only if ALL inputs pass do we perform expensive ECDSA signature checks. // Helps prevent CPU exhaustion attacks. - // Skip ECDSA signature verification when connecting blocks - // before the last block chain checkpoint. This is safe because block merkle hashes are - // still computed and checked, and any change will be caught at the next checkpoint. + // Skip ECDSA signature verification when connecting blocks before the + // last block chain checkpoint. Assuming the checkpoints are valid this + // is safe because block merkle hashes are still computed and checked, + // and any change will be caught at the next checkpoint. Of course, if + // the checkpoint is for a chain that's invalid due to false scriptSigs + // this optimisation would allow an invalid chain to be accepted. if (fScriptChecks) { for (unsigned int i = 0; i < tx.vin.size(); i++) { const COutPoint &prevout = tx.vin[i].prevout; @@ -1426,9 +1919,9 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // arguments; if so, don't trigger DoS protection to // avoid splitting the network between upgraded and // non-upgraded nodes. - CScriptCheck check(*coins, tx, i, + CScriptCheck check2(*coins, tx, i, flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore); - if (check()) + if (check2()) return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); } // Failures of other flags indicate a transaction that is @@ -1789,8 +2282,8 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const // How likely is it to find that many by chance? double p = boost::math::pdf(poisson, nBlocks); - LogPrint("partitioncheck", "%s : Found %d blocks in the last %d hours\n", __func__, nBlocks, SPAN_HOURS); - LogPrint("partitioncheck", "%s : likelihood: %g\n", __func__, p); + LogPrint("partitioncheck", "%s: Found %d blocks in the last %d hours\n", __func__, nBlocks, SPAN_HOURS); + LogPrint("partitioncheck", "%s: likelihood: %g\n", __func__, p); // Aim for one false-positive about every fifty years of normal running: const int FIFTY_YEARS = 50*365*24*60*60; @@ -1811,11 +2304,58 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const if (!strWarning.empty()) { strMiscWarning = strWarning; - CAlert::Notify(strWarning, true); + AlertNotify(strWarning, true); lastAlertTime = now; } } +// Protected by cs_main +static VersionBitsCache versionbitscache; + +int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) +{ + LOCK(cs_main); + int32_t nVersion = VERSIONBITS_TOP_BITS; + + for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { + ThresholdState state = VersionBitsState(pindexPrev, params, (Consensus::DeploymentPos)i, versionbitscache); + if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) { + nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i); + } + } + + return nVersion; +} + +/** + * Threshold condition checker that triggers when unknown versionbits are seen on the network. + */ +class WarningBitsConditionChecker : public AbstractThresholdConditionChecker +{ +private: + int bit; + +public: + WarningBitsConditionChecker(int bitIn) : bit(bitIn) {} + + int64_t BeginTime(const Consensus::Params& params) const { return 0; } + int64_t EndTime(const Consensus::Params& params) const { return std::numeric_limits::max(); } + int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; } + int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; } + + bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const + { + return ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && + ((pindex->nVersion >> bit) & 1) != 0 && + ((ComputeBlockVersion(pindex->pprev, params) >> bit) & 1) == 0; + } +}; + +// Protected by cs_main +static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS]; + +static int64_t nTimeCheck = 0; +static int64_t nTimeForks = 0; static int64_t nTimeVerify = 0; static int64_t nTimeConnect = 0; static int64_t nTimeIndex = 0; @@ -1826,9 +2366,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin { const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); + + int64_t nTimeStart = GetTimeMicros(); + // Check it again in case a previous version let a bad block in if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) - return false; + return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); // verify that the view's current state corresponds to the previous block uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); @@ -1857,6 +2400,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } } + int64_t nTime1 = GetTimeMicros(); nTimeCheck += nTime1 - nTimeStart; + LogPrint("bench", " - Sanity checks: %.2fms [%.2fs]\n", 0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001); + // Do not allow blocks that contain transactions which 'overwrite' older transactions, // unless those are already completely spent. // If such overwrites are allowed, coinbases and transactions depending upon those @@ -1872,6 +2418,21 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin bool fEnforceBIP30 = (!pindex->phashBlock) || // Enforce on CreateNewBlock invocations which don't have a hash. !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); + + // Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting + // with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs. But by the + // time BIP34 activated, in each of the existing pairs the duplicate coinbase had overwritten the first + // before the first had been spent. Since those coinbases are sufficiently buried its no longer possible to create further + // duplicate transactions descending from the known pairs either. + // 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. + CBlockIndex *pindexBIP34height = NULL; + if (pindex->pprev) + { + pindexBIP34height = pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height); + } + //Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond. + fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == chainparams.GetConsensus().BIP34Hash)); + if (fEnforceBIP30) { BOOST_FOREACH(const CTransaction& tx, block.vtx) { const CCoins* coins = view.AccessCoins(tx.GetHash()); @@ -1887,16 +2448,33 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE; - // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, when 75% of the network has upgraded: + // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, + // when 75% of the network has upgraded: if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { flags |= SCRIPT_VERIFY_DERSIG; } + // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4 + // blocks, when 75% of the network has upgraded: + if (block.nVersion >= 4 && IsSuperMajority(4, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { + flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; + } + + // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic. + int nLockTimeFlags = 0; + if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) { + flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; + nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE; + } + + int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1; + LogPrint("bench", " - Fork checks: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001); + CBlockUndo blockundo; CCheckQueueControl control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); - int64_t nTimeStart = GetTimeMicros(); + std::vector prevheights; CAmount nFees = 0; int nInputs = 0; unsigned int nSigOps = 0; @@ -1922,6 +2500,19 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), REJECT_INVALID, "bad-txns-inputs-missingorspent"); + // Check that transaction is BIP68 final + // BIP68 lock checks (as opposed to nLockTime checks) must + // be in ConnectBlock because they require the UTXO set + prevheights.resize(tx.vin.size()); + for (size_t j = 0; j < tx.vin.size(); j++) { + prevheights[j] = view.AccessCoins(tx.vin[j].prevout.hash)->nHeight; + } + + if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) { + return state.DoS(100, error("%s: contains a non-BIP68-final transaction", __func__), + REJECT_INVALID, "bad-txns-nonfinal"); + } + if (fStrictPayToScriptHash) { // Add in sigops done by pay-to-script-hash inputs; @@ -1936,7 +2527,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin nFees += view.GetValueIn(tx)-tx.GetValueOut(); std::vector vChecks; - if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL)) + bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ + if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL)) return error("ConnectBlock(): CheckInputs on %s failed with %s", tx.GetHash().ToString(), FormatStateMessage(state)); control.Add(vChecks); @@ -2092,20 +2684,22 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin "(actual=%s vs block=%s)", trieCache.getMerkleHash().GetHex(), block.hashClaimTrie.GetHex()), REJECT_INVALID, "bad-claim-merkle-hash"); - int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart; - LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001); + int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2; + LogPrint("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); CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); if (block.vtx[0].GetValueOut() > blockReward) + { return state.DoS(100, error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", block.vtx[0].GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount"); + } if (!control.Wait()) return state.DoS(100, false); - int64_t nTime2 = GetTimeMicros(); nTimeVerify += nTime2 - nTimeStart; - LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime2 - nTimeStart), nInputs <= 1 ? 0 : 0.001 * (nTime2 - nTimeStart) / (nInputs-1), nTimeVerify * 0.000001); + int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2; + LogPrint("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); if (fJustCheck) return true; @@ -2137,16 +2731,16 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin view.SetBestBlock(pindex->GetBlockHash()); trieCache.setBestBlock(pindex->GetBlockHash()); - int64_t nTime3 = GetTimeMicros(); nTimeIndex += nTime3 - nTime2; - LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeIndex * 0.000001); + int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4; + LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001); // Watch for changes to the previous coinbase transaction. static uint256 hashPrevBestCoinBase; GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); hashPrevBestCoinBase = block.vtx[0].GetHash(); - int64_t nTime4 = GetTimeMicros(); nTimeCallbacks += nTime4 - nTime3; - LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeCallbacks * 0.000001); + int64_t nTime6 = GetTimeMicros(); nTimeCallbacks += nTime6 - nTime5; + LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001); return true; } @@ -2165,6 +2759,7 @@ enum FlushStateMode { * or always and in all cases if we're in prune mode and are deleting files. */ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { + const CChainParams& chainparams = Params(); LOCK2(cs_main, cs_LastBlockFile); static int64_t nLastWrite = 0; static int64_t nLastFlush = 0; @@ -2172,8 +2767,8 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { std::set setFilesToPrune; bool fFlushForPrune = false; try { - if (fPruneMode && fCheckForPruning) { - FindFilesToPrune(setFilesToPrune); + if (fPruneMode && fCheckForPruning && !fReindex) { + FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight()); fCheckForPruning = false; if (!setFilesToPrune.empty()) { fFlushForPrune = true; @@ -2251,7 +2846,7 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { return AbortNode(state, "Failed to write to coin database"); nLastFlush = nNow; } - if ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000) { + if (fDoFullFlush || ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) { // Update best block in wallet (so we can detect restored wallets). GetMainSignals().SetBestChain(chainActive.GetLocator()); nLastSetChain = nNow; @@ -2282,8 +2877,9 @@ void static UpdateTip(CBlockIndex *pindexNew) { nTimeBestReceived = GetTime(); mempool.AddTransactionsUpdated(1); - LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__, - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, + LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utx)\n", __func__, + chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion, + log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); @@ -2291,36 +2887,54 @@ void static UpdateTip(CBlockIndex *pindexNew) { // Check the version of the last 100 blocks to see if we need to upgrade: static bool fWarned = false; - if (!IsInitialBlockDownload() && !fWarned) + if (!IsInitialBlockDownload()) { int nUpgraded = 0; const CBlockIndex* pindex = chainActive.Tip(); + for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) { + WarningBitsConditionChecker checker(bit); + ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]); + if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) { + if (state == THRESHOLD_ACTIVE) { + strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit); + if (!fWarned) { + AlertNotify(strMiscWarning, true); + fWarned = true; + } + } else { + LogPrintf("%s: unknown new rules are about to activate (versionbit %i)\n", __func__, bit); + } + } + } for (int i = 0; i < 100 && pindex != NULL; i++) { - if (pindex->nVersion > CBlock::CURRENT_VERSION) + int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus()); + if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0) ++nUpgraded; pindex = pindex->pprev; } if (nUpgraded > 0) - LogPrintf("%s: %d of last 100 blocks above version %d\n", __func__, nUpgraded, (int)CBlock::CURRENT_VERSION); + LogPrintf("%s: %d of last 100 blocks have unexpected version\n", __func__, nUpgraded); if (nUpgraded > 100/2) { // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: - strMiscWarning = _("Warning: This version is obsolete; upgrade required!"); - CAlert::Notify(strMiscWarning, true); - fWarned = true; + strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect"); + if (!fWarned) { + AlertNotify(strMiscWarning, true); + fWarned = true; + } } } } -/** Disconnect chainActive's tip. */ -bool static DisconnectTip(CValidationState &state) { +/** Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and manually re-limit mempool size after this, with cs_main held. */ +bool static DisconnectTip(CValidationState& state, const Consensus::Params& consensusParams) +{ CBlockIndex *pindexDelete = chainActive.Tip(); assert(pindexDelete); - mempool.check(pcoinsTip); // Read block from disk. CBlock block; - if (!ReadBlockFromDisk(block, pindexDelete)) + if (!ReadBlockFromDisk(block, pindexDelete, consensusParams)) return AbortNode(state, "Failed to read block"); // Apply the block atomically to the chain state. int64_t nStart = GetTimeMicros(); @@ -2343,8 +2957,8 @@ bool static DisconnectTip(CValidationState &state) { // ignore validation errors in resurrected transactions list removed; CValidationState stateDummy; - if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) { - mempool.remove(tx, removed, true); + if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, NULL, true)) { + mempool.removeRecursive(tx, removed); } else if (mempool.exists(tx.GetHash())) { vHashUpdate.push_back(tx.GetHash()); } @@ -2355,14 +2969,12 @@ bool static DisconnectTip(CValidationState &state) { // UpdateTransactionsFromBlock finds descendants of any transactions in this // block that were added back and cleans up the mempool state. mempool.UpdateTransactionsFromBlock(vHashUpdate); - mempool.removeCoinbaseSpends(pcoinsTip, pindexDelete->nHeight); - mempool.check(pcoinsTip); // Update chainActive and related variables. UpdateTip(pindexDelete->pprev); // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: BOOST_FOREACH(const CTransaction &tx, block.vtx) { - SyncWithWallets(tx, NULL); + SyncWithWallets(tx, pindexDelete->pprev, NULL); } return true; } @@ -2377,14 +2989,14 @@ static int64_t nTimePostConnect = 0; * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock * corresponding to pindexNew, to bypass loading it again from disk. */ -bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, const CBlock *pblock) { +bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock) +{ assert(pindexNew->pprev == chainActive.Tip()); - mempool.check(pcoinsTip); // Read block from disk. int64_t nTime1 = GetTimeMicros(); CBlock block; if (!pblock) { - if (!ReadBlockFromDisk(block, pindexNew)) + if (!ReadBlockFromDisk(block, pindexNew, chainparams.GetConsensus())) return AbortNode(state, "Failed to read block"); pblock = █ } @@ -2418,17 +3030,16 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, const CB // Remove conflicting transactions from the mempool. list txConflicted; mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !IsInitialBlockDownload()); - mempool.check(pcoinsTip); // Update chainActive & related variables. UpdateTip(pindexNew); // Tell wallet about transactions that went from mempool // to conflicted: BOOST_FOREACH(const CTransaction &tx, txConflicted) { - SyncWithWallets(tx, NULL); + SyncWithWallets(tx, pindexNew, NULL); } // ... and about transactions that got confirmed: BOOST_FOREACH(const CTransaction &tx, pblock->vtx) { - SyncWithWallets(tx, pblock); + SyncWithWallets(tx, pindexNew, pblock); } int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; @@ -2511,16 +3122,19 @@ static void PruneBlockIndexCandidates() { * Try to make some progress towards making pindexMostWork the active block. * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. */ -static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, const CBlock *pblock) { +static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock) +{ AssertLockHeld(cs_main); bool fInvalidFound = false; const CBlockIndex *pindexOldTip = chainActive.Tip(); const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); // Disconnect active blocks which are no longer in the best chain. + bool fBlocksDisconnected = false; while (chainActive.Tip() && chainActive.Tip() != pindexFork) { - if (!DisconnectTip(state)) + if (!DisconnectTip(state, chainparams.GetConsensus())) return false; + fBlocksDisconnected = true; } // Build list of new blocks to connect. @@ -2528,43 +3142,49 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo bool fContinue = true; int nHeight = pindexFork ? pindexFork->nHeight : -1; while (fContinue && nHeight != pindexMostWork->nHeight) { - // Don't iterate the entire list of potential improvements toward the best tip, as we likely only need - // a few blocks along the way. - int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight); - vpindexToConnect.clear(); - vpindexToConnect.reserve(nTargetHeight - nHeight); - CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight); - while (pindexIter && pindexIter->nHeight != nHeight) { - vpindexToConnect.push_back(pindexIter); - pindexIter = pindexIter->pprev; - } - nHeight = nTargetHeight; + // Don't iterate the entire list of potential improvements toward the best tip, as we likely only need + // a few blocks along the way. + int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight); + vpindexToConnect.clear(); + vpindexToConnect.reserve(nTargetHeight - nHeight); + CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight); + while (pindexIter && pindexIter->nHeight != nHeight) { + vpindexToConnect.push_back(pindexIter); + pindexIter = pindexIter->pprev; + } + nHeight = nTargetHeight; - // Connect new blocks. - BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { - if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { - if (state.IsInvalid()) { - // The block violates a consensus rule. - if (!state.CorruptionPossible()) - InvalidChainFound(vpindexToConnect.back()); - state = CValidationState(); - fInvalidFound = true; - fContinue = false; - break; + // Connect new blocks. + BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { + if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { + if (state.IsInvalid()) { + // The block violates a consensus rule. + if (!state.CorruptionPossible()) + InvalidChainFound(vpindexToConnect.back()); + state = CValidationState(); + fInvalidFound = true; + fContinue = false; + break; + } else { + // A system error occurred (disk space, database error, ...). + return false; + } } else { - // A system error occurred (disk space, database error, ...). - return false; - } - } else { - PruneBlockIndexCandidates(); - if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) { - // We're in a better position than we were. Return temporarily to release the lock. - fContinue = false; - break; + PruneBlockIndexCandidates(); + if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) { + // We're in a better position than we were. Return temporarily to release the lock. + fContinue = false; + break; + } } } } + + if (fBlocksDisconnected) { + mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); + LimitMempoolSize(mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); } + mempool.check(pcoinsTip); // Callbacks/notifications for a new best chain. if (fInvalidFound) @@ -2580,49 +3200,74 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo * or an activated best chain. pblock is either NULL or a pointer to a block * that is already loaded (to avoid loading it again from disk). */ -bool ActivateBestChain(CValidationState &state, const CBlock *pblock) { - CBlockIndex *pindexNewTip = NULL; +bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) { CBlockIndex *pindexMostWork = NULL; - const CChainParams& chainParams = Params(); do { boost::this_thread::interruption_point(); + if (ShutdownRequested()) + break; + CBlockIndex *pindexNewTip = NULL; + const CBlockIndex *pindexFork; bool fInitialDownload; { LOCK(cs_main); + CBlockIndex *pindexOldTip = chainActive.Tip(); pindexMostWork = FindMostWorkChain(); // Whether we have anything to do at all. if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) return true; - if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL)) + if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL)) return false; pindexNewTip = chainActive.Tip(); + pindexFork = chainActive.FindFork(pindexOldTip); fInitialDownload = IsInitialBlockDownload(); } // When we reach this point, we switched to a new tip (stored in pindexNewTip). // Notifications/callbacks that can run without cs_main - if (!fInitialDownload) { - uint256 hashNewTip = pindexNewTip->GetBlockHash(); - // Relay inventory, but don't relay old inventory during initial block download. - int nBlockEstimate = 0; - if (fCheckpointsEnabled) - nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints()); - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) - pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); + // Always notify the UI if a new block tip was connected + if (pindexFork != pindexNewTip) { + uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip); + + if (!fInitialDownload) { + // Find the hashes of all blocks that weren't previously in the best chain. + std::vector vHashes; + CBlockIndex *pindexToAnnounce = pindexNewTip; + while (pindexToAnnounce != pindexFork) { + vHashes.push_back(pindexToAnnounce->GetBlockHash()); + pindexToAnnounce = pindexToAnnounce->pprev; + if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE) { + // Limit announcements in case of a huge reorganization. + // Rely on the peer's synchronization mechanism in that case. + break; + } + } + // Relay inventory, but don't relay old inventory during initial block download. + int nBlockEstimate = 0; + if (fCheckpointsEnabled) + nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()); + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) { + if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) { + BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) { + pnode->PushBlockHash(hash); + } + } + } + } + // Notify external listeners about the new tip. + if (!vHashes.empty()) { + GetMainSignals().UpdatedBlockTip(pindexNewTip); + } } - // Notify external listeners about the new tip. - GetMainSignals().UpdatedBlockTip(pindexNewTip); - uiInterface.NotifyBlockTip(hashNewTip); } } while(pindexMostWork != chainActive.Tip()); - CheckBlockIndex(); + CheckBlockIndex(chainparams.GetConsensus()); // Write changes periodically to disk, after relay. if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC)) { @@ -2632,7 +3277,8 @@ bool ActivateBestChain(CValidationState &state, const CBlock *pblock) { return true; } -bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { +bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex *pindex) +{ AssertLockHeld(cs_main); // Mark the block itself as invalid. @@ -2647,11 +3293,14 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { setBlockIndexCandidates.erase(pindexWalk); // ActivateBestChain considers blocks already in chainActive // unconditionally valid already, so force disconnect away from it. - if (!DisconnectTip(state)) { + if (!DisconnectTip(state, consensusParams)) { + mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); return false; } } + LimitMempoolSize(mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); + // The resulting new best tip may not be in setBlockIndexCandidates anymore, so // add it again. BlockMap::iterator it = mapBlockIndex.begin(); @@ -2663,6 +3312,7 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { } InvalidChainFound(pindex); + mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); return true; } @@ -2790,8 +3440,6 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd if (!fKnown) { while (vinfoBlockFile[nFile].nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { - LogPrintf("Leaving block file %i: %s\n", nFile, vinfoBlockFile[nFile].ToString()); - FlushBlockFile(true); nFile++; if (vinfoBlockFile.size() <= nFile) { vinfoBlockFile.resize(nFile + 1); @@ -2801,7 +3449,14 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd pos.nPos = vinfoBlockFile[nFile].nSize; } - nLastBlockFile = nFile; + if ((int)nFile != nLastBlockFile) { + if (!fKnown) { + LogPrintf("Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString()); + } + FlushBlockFile(!fKnown); + nLastBlockFile = nFile; + } + vinfoBlockFile[nFile].AddBlock(nHeight, nTime); if (fKnown) vinfoBlockFile[nFile].nSize = std::max(pos.nPos + nAddSize, vinfoBlockFile[nFile].nSize); @@ -2866,13 +3521,11 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f { // Check proof of work matches claimed amount if (fCheckPOW && !CheckProofOfWork(block.GetPoWHash(), block.nBits, Params().GetConsensus())) - return state.DoS(50, error("CheckBlockHeader(): proof of work failed"), - REJECT_INVALID, "high-hash"); + return state.DoS(50, false, REJECT_INVALID, "high-hash", false, "proof of work failed"); // Check timestamp if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) - return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"), - REJECT_INVALID, "time-too-new"); + return state.Invalid(false, REJECT_INVALID, "time-too-new", "block timestamp too far in the future"); return true; } @@ -2892,17 +3545,15 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo // Check the merkle root. if (fCheckMerkleRoot) { bool mutated; - uint256 hashMerkleRoot2 = block.ComputeMerkleRoot(&mutated); + uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated); if (block.hashMerkleRoot != hashMerkleRoot2) - return state.DoS(100, error("CheckBlock(): hashMerkleRoot mismatch"), - REJECT_INVALID, "bad-txnmrklroot", true); + return state.DoS(100, false, REJECT_INVALID, "bad-txnmrklroot", true, "hashMerkleRoot mismatch"); // Check for merkle tree malleability (CVE-2012-2459): repeating sequences // of transactions in a block without affecting the merkle root of a block, // while still invalidating it. if (mutated) - return state.DoS(100, error("CheckBlock(): duplicate transaction"), - REJECT_INVALID, "bad-txns-duplicate", true); + return state.DoS(100, false, REJECT_INVALID, "bad-txns-duplicate", true, "duplicate transaction"); } // All potential-corruption validation must be done before we do any @@ -2911,24 +3562,20 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo // Size limits if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) - return state.DoS(100, error("CheckBlock(): size limits failed"), - REJECT_INVALID, "bad-blk-length"); + return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed"); // First transaction must be coinbase, the rest must not be if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) - return state.DoS(100, error("CheckBlock(): first tx is not coinbase"), - REJECT_INVALID, "bad-cb-missing"); + return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false, "first tx is not coinbase"); for (unsigned int i = 1; i < block.vtx.size(); i++) if (block.vtx[i].IsCoinBase()) - return state.DoS(100, error("CheckBlock(): more than one coinbase"), - REJECT_INVALID, "bad-cb-multiple"); + return state.DoS(100, false, REJECT_INVALID, "bad-cb-multiple", false, "more than one coinbase"); // Check transactions BOOST_FOREACH(const CTransaction& tx, block.vtx) if (!CheckTransaction(tx, state)) - return error("CheckBlock(): CheckTransaction of %s failed with %s", - tx.GetHash().ToString(), - FormatStateMessage(state)); + return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), + strprintf("Transaction check failed (tx hash %s) %s", tx.GetHash().ToString(), state.GetDebugMessage())); unsigned int nSigOps = 0; BOOST_FOREACH(const CTransaction& tx, block.vtx) @@ -2936,8 +3583,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo nSigOps += GetLegacySigOpCount(tx); } if (nSigOps > MAX_BLOCK_SIGOPS) - return state.DoS(100, error("CheckBlock(): out-of-bounds SigOpCount"), - REJECT_INVALID, "bad-blk-sigops", true); + return state.DoS(100, false, REJECT_INVALID, "bad-blk-sigops", false, "out-of-bounds SigOpCount"); if (fCheckPOW && fCheckMerkleRoot) block.fChecked = true; @@ -2964,23 +3610,17 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta const Consensus::Params& consensusParams = Params().GetConsensus(); // Check proof of work if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) - return state.DoS(100, error("%s: incorrect proof of work", __func__), - REJECT_INVALID, "bad-diffbits"); + return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false, "incorrect proof of work"); // Check timestamp against prev if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) - return state.Invalid(error("%s: block's timestamp is too early", __func__), - REJECT_INVALID, "time-too-old"); + return state.Invalid(false, REJECT_INVALID, "time-too-old", "block's timestamp is too early"); - // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: - if (block.nVersion < 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams)) - return state.Invalid(error("%s: rejected nVersion=1 block", __func__), - REJECT_OBSOLETE, "bad-version"); - - // Reject block.nVersion=2 blocks when 95% (75% on testnet) of the network has upgraded: - if (block.nVersion < 3 && IsSuperMajority(3, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams)) - return state.Invalid(error("%s : rejected nVersion=2 block", __func__), - REJECT_OBSOLETE, "bad-version"); + // Reject outdated version blocks when 95% (75% on testnet) of the network has upgraded: + for (int32_t version = 2; version < 5; ++version) // check for version 2, 3 and 4 upgrades + if (block.nVersion < version && IsSuperMajority(version, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams)) + return state.Invalid(false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", version - 1), + strprintf("rejected nVersion=0x%08x block", version - 1)); return true; } @@ -2990,11 +3630,22 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; const Consensus::Params& consensusParams = Params().GetConsensus(); + // Start enforcing BIP113 (Median Time Past) using versionbits logic. + int nLockTimeFlags = 0; + if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) { + nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST; + } + + int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST) + ? pindexPrev->GetMedianTimePast() + : block.GetBlockTime(); + // Check that all transactions are finalized - BOOST_FOREACH(const CTransaction& tx, block.vtx) - if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) { - return state.DoS(10, error("%s: contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); + BOOST_FOREACH(const CTransaction& tx, block.vtx) { + if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { + return state.DoS(10, false, REJECT_INVALID, "bad-txns-nonfinal", false, "non-final transaction"); } + } // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): @@ -3003,16 +3654,15 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn CScript expect = CScript() << nHeight; if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { - return state.DoS(100, error("%s: block height mismatch in coinbase", __func__), REJECT_INVALID, "bad-cb-height"); + return state.DoS(100, false, REJECT_INVALID, "bad-cb-height", false, "block height mismatch in coinbase"); } } return true; } -bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex) +static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex=NULL) { - const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); // Check for duplicate uint256 hash = block.GetHash(); @@ -3031,7 +3681,7 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc } if (!CheckBlockHeader(block, state)) - return false; + return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); // Get prev block index CBlockIndex* pindexPrev = NULL; @@ -3047,7 +3697,7 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str()); if (!ContextualCheckBlockHeader(block, state, pindexPrev)) - return false; + return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); } if (pindex == NULL) pindex = AddToBlockIndex(block); @@ -3058,14 +3708,14 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc return true; } -bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) +/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */ +static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) { - const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); CBlockIndex *&pindex = *ppindex; - if (!AcceptBlockHeader(block, state, &pindex)) + if (!AcceptBlockHeader(block, state, chainparams, &pindex)) return false; // Try to process all requested blocks that we don't have, but only @@ -3094,7 +3744,7 @@ bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex** ppi pindex->nStatus |= BLOCK_FAILED_VALID; setDirtyBlockIndex.insert(pindex); } - return false; + return error("%s: %s", __func__, FormatStateMessage(state)); } int nHeight = pindex->nHeight; @@ -3135,39 +3785,32 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned } -bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp) +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp) { - // Preliminary checks - bool checked = CheckBlock(*pblock, state); - { LOCK(cs_main); bool fRequested = MarkBlockAsReceived(pblock->GetHash()); fRequested |= fForceProcessing; - if (!checked) { - return error("%s: CheckBlock FAILED", __func__); - } // Store to disk CBlockIndex *pindex = NULL; - bool ret = AcceptBlock(*pblock, state, &pindex, fRequested, dbp); + bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fRequested, dbp); if (pindex && pfrom) { mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); } - CheckBlockIndex(); + CheckBlockIndex(chainparams.GetConsensus()); if (!ret) return error("%s: AcceptBlock FAILED", __func__); } - if (!ActivateBestChain(state, pblock)) + if (!ActivateBestChain(state, chainparams, pblock)) return error("%s: ActivateBestChain failed", __func__); return true; } -bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * const pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) +bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) { - const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); assert(pindexPrev && pindexPrev == chainActive.Tip()); if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, block.GetHash())) @@ -3181,11 +3824,11 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex // NOTE: CheckBlockHeader is called by CheckBlock if (!ContextualCheckBlockHeader(block, state, pindexPrev)) - return false; + return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, FormatStateMessage(state)); if (!CheckBlock(block, state, fCheckPOW, fCheckMerkleRoot)) - return false; + return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); if (!ContextualCheckBlock(block, state, pindexPrev)) - return false; + return error("%s: Consensus::ContextualCheckBlock: %s", __func__, FormatStateMessage(state)); if (!ConnectBlock(block, state, &indexDummy, viewNew, trieCache, true)) return false; assert(state.IsValid()); @@ -3251,13 +3894,13 @@ void UnlinkPrunedFiles(std::set& setFilesToPrune) } /* Calculate the block/rev files that should be deleted to remain under target*/ -void FindFilesToPrune(std::set& setFilesToPrune) +void FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPruneAfterHeight) { LOCK2(cs_main, cs_LastBlockFile); if (chainActive.Tip() == NULL || nPruneTarget == 0) { return; } - if (chainActive.Tip()->nHeight <= Params().PruneAfterHeight()) { + if ((uint64_t)chainActive.Tip()->nHeight <= nPruneAfterHeight) { return; } @@ -3485,7 +4128,7 @@ CVerifyDB::~CVerifyDB() uiInterface.ShowProgress("", 100); } -bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) +bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) { LOCK(cs_main); if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL) @@ -3512,11 +4155,12 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth break; CBlock block; // check level 0: read from disk - if (!ReadBlockFromDisk(block, pindex)) + if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); // check level 1: verify block validity if (nCheckLevel >= 1 && !CheckBlock(block, state)) - return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); + return error("%s: *** found bad block at %d, hash=%s (%s)\n", __func__, + pindex->nHeight, pindex->GetBlockHash().ToString(), FormatStateMessage(state)); // check level 2: verify undo validity if (nCheckLevel >= 2 && pindex) { CBlockUndo undo; @@ -3552,7 +4196,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)))); pindex = chainActive.Next(pindex); CBlock block; - if (!ReadBlockFromDisk(block, pindex)) + if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); if (!ConnectBlock(block, state, pindex, coins, trieCache)) return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); @@ -3579,7 +4223,7 @@ bool GetProofForName(const CBlockIndex* pindexProof, const std::string& name, CC { boost::this_thread::interruption_point(); CBlock block; - if (!ReadBlockFromDisk(block, pindex)) + if (!ReadBlockFromDisk(block, pindex, Params().GetConsensus())) { return false; } @@ -3617,12 +4261,15 @@ void UnloadBlockIndex() nBlockSequenceId = 1; mapBlockSource.clear(); mapBlocksInFlight.clear(); - nQueuedValidatedHeaders = 0; nPreferredDownload = 0; setDirtyBlockIndex.clear(); setDirtyFileInfo.clear(); mapNodeState.clear(); recentRejects.reset(NULL); + versionbitscache.Clear(); + for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) { + warningcache[b].clear(); + } BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) { delete entry.second; @@ -3639,9 +4286,8 @@ bool LoadBlockIndex() return true; } - -bool InitBlockIndex() { - const CChainParams& chainparams = Params(); +bool InitBlockIndex(const CChainParams& chainparams) +{ LOCK(cs_main); // Initialize global variables that cannot be constructed at startup. @@ -3652,14 +4298,14 @@ bool InitBlockIndex() { return true; // Use the provided setting for -txindex in the new database - fTxIndex = GetBoolArg("-txindex", false); + fTxIndex = GetBoolArg("-txindex", DEFAULT_TXINDEX); pblocktree->WriteFlag("txindex", fTxIndex); LogPrintf("Initializing databases...\n"); // Only add the genesis block if not reindexing (in which case we reuse the one already on disk) if (!fReindex) { try { - CBlock &block = const_cast(Params().GenesisBlock()); + CBlock &block = const_cast(chainparams.GenesisBlock()); // Start new block file unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); CDiskBlockPos blockPos; @@ -3671,7 +4317,7 @@ bool InitBlockIndex() { CBlockIndex *pindex = AddToBlockIndex(block); if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("LoadBlockIndex(): genesis block not accepted"); - if (!ActivateBestChain(state, &block)) + if (!ActivateBestChain(state, chainparams, &block)) return error("LoadBlockIndex(): genesis block cannot be activated"); // Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data return FlushStateToDisk(state, FLUSH_STATE_ALWAYS); @@ -3683,11 +4329,8 @@ bool InitBlockIndex() { return true; } - - -bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) +bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp) { - const CChainParams& chainparams = Params(); // Map of disk positions for blocks with unknown parent (only used for reindex) static std::multimap mapBlocksUnknownParent; int64_t nStart = GetTimeMillis(); @@ -3707,10 +4350,10 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) try { // locate a header unsigned char buf[MESSAGE_START_SIZE]; - blkdat.FindByte(Params().MessageStart()[0]); + blkdat.FindByte(chainparams.MessageStart()[0]); nRewind = blkdat.GetPos()+1; blkdat >> FLATDATA(buf); - if (memcmp(buf, Params().MessageStart(), MESSAGE_START_SIZE)) + if (memcmp(buf, chainparams.MessageStart(), MESSAGE_START_SIZE)) continue; // read size blkdat >> nSize; @@ -3744,7 +4387,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) // process in case the block isn't known yet if (hash != chainparams.GetConsensus().hashGenesisBlock && (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0)) { CValidationState state; - if (ProcessNewBlock(state, NULL, &block, true, dbp)) + if (ProcessNewBlock(state, chainparams, NULL, &block, true, dbp)) nLoaded++; if (state.IsError()) break; @@ -3761,12 +4404,12 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) std::pair::iterator, std::multimap::iterator> range = mapBlocksUnknownParent.equal_range(head); while (range.first != range.second) { std::multimap::iterator it = range.first; - if (ReadBlockFromDisk(block, it->second)) + if (ReadBlockFromDisk(block, it->second, chainparams.GetConsensus())) { LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), head.ToString()); CValidationState dummy; - if (ProcessNewBlock(dummy, NULL, &block, true, &it->second)) + if (ProcessNewBlock(dummy, chainparams, NULL, &block, true, &it->second)) { nLoaded++; queue.push_back(block.GetHash()); @@ -3788,9 +4431,8 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) return nLoaded > 0; } -void static CheckBlockIndex() +void static CheckBlockIndex(const Consensus::Params& consensusParams) { - const Consensus::Params& consensusParams = Params().GetConsensus(); if (!fCheckBlockIndex) { return; } @@ -3973,56 +4615,40 @@ void static CheckBlockIndex() assert(nNodes == forward.size()); } -////////////////////////////////////////////////////////////////////////////// -// -// CAlert -// - std::string GetWarnings(const std::string& strFor) { - int nPriority = 0; string strStatusBar; string strRPC; + string strGUI; - if (!CLIENT_VERSION_IS_RELEASE) - strStatusBar = _("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"); + if (!CLIENT_VERSION_IS_RELEASE) { + strStatusBar = "This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"; + strGUI = _("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"); + } - if (GetBoolArg("-testsafemode", false)) - strStatusBar = strRPC = "testsafemode enabled"; + if (GetBoolArg("-testsafemode", DEFAULT_TESTSAFEMODE)) + strStatusBar = strRPC = strGUI = "testsafemode enabled"; // Misc warnings like out of disk space and clock is wrong if (strMiscWarning != "") { - nPriority = 1000; - strStatusBar = strMiscWarning; + strStatusBar = strGUI = strMiscWarning; } if (fLargeWorkForkFound) { - nPriority = 2000; - strStatusBar = strRPC = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."); + strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."; + strGUI = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."); } else if (fLargeWorkInvalidChainFound) { - nPriority = 2000; - 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."); + 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."; + strGUI = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."); } - // Alerts - { - LOCK(cs_mapAlerts); - BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) - { - const CAlert& alert = item.second; - if (alert.AppliesToMe() && alert.nPriority > nPriority) - { - nPriority = alert.nPriority; - strStatusBar = alert.strStatusBar; - } - } - } - - if (strFor == "statusbar") + if (strFor == "gui") + return strGUI; + else if (strFor == "statusbar") return strStatusBar; else if (strFor == "rpc") return strRPC; @@ -4060,10 +4686,12 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) recentRejects->reset(); } + // Use pcoinsTip->HaveCoinsInCache as a quick approximation to exclude + // requesting or processing some txs which have already been included in a block return recentRejects->contains(inv.hash) || mempool.exists(inv.hash) || mapOrphanTransactions.count(inv.hash) || - pcoinsTip->HaveCoins(inv.hash); + pcoinsTip->HaveCoinsInCache(inv.hash); } case MSG_BLOCK: return mapBlockIndex.count(inv.hash); @@ -4072,7 +4700,7 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) return true; } -void static ProcessGetData(CNode* pfrom) +void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams) { std::deque::iterator it = pfrom->vRecvGetData.begin(); @@ -4105,29 +4733,40 @@ void static ProcessGetData(CNode* pfrom) // best equivalent proof of work) than the best header chain we know about. send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) && - (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, Params().GetConsensus()) < nOneMonth); + (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, consensusParams) < nOneMonth); if (!send) { LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId()); } } } + // disconnect node in case we have reached the outbound limit for serving historical blocks + // never disconnect whitelisted nodes + static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical + if (send && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) + { + LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId()); + + //disconnect node + pfrom->fDisconnect = true; + send = false; + } // Pruned nodes may have deleted the block, so check whether // it's available before trying to send. if (send && (mi->second->nStatus & BLOCK_HAVE_DATA)) { // Send block from disk CBlock block; - if (!ReadBlockFromDisk(block, (*mi).second)) + if (!ReadBlockFromDisk(block, (*mi).second, consensusParams)) assert(!"cannot load block from disk"); if (inv.type == MSG_BLOCK) - pfrom->PushMessage("block", block); + pfrom->PushMessage(NetMsgType::BLOCK, block); else // MSG_FILTERED_BLOCK) { LOCK(pfrom->cs_filter); if (pfrom->pfilter) { CMerkleBlock merkleBlock(block, *pfrom->pfilter); - pfrom->PushMessage("merkleblock", merkleBlock); + pfrom->PushMessage(NetMsgType::MERKLEBLOCK, merkleBlock); // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see // This avoids hurting performance by pointlessly requiring a round-trip // Note that there is currently no way for a node to request any single transactions we didn't send here - @@ -4136,8 +4775,7 @@ void static ProcessGetData(CNode* pfrom) // however we MUST always provide at least what the remote peer needs typedef std::pair PairType; BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn) - if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second))) - pfrom->PushMessage("tx", block.vtx[pair.first]); + pfrom->PushMessage(NetMsgType::TX, block.vtx[pair.first]); } // else // no response @@ -4151,7 +4789,7 @@ void static ProcessGetData(CNode* pfrom) // wait for other stuff first. vector vInv; vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash())); - pfrom->PushMessage("inv", vInv); + pfrom->PushMessage(NetMsgType::INV, vInv); pfrom->hashContinue.SetNull(); } } @@ -4162,7 +4800,7 @@ void static ProcessGetData(CNode* pfrom) bool pushed = false; { LOCK(cs_mapRelay); - map::iterator mi = mapRelay.find(inv); + map::iterator mi = mapRelay.find(inv.hash); if (mi != mapRelay.end()) { pfrom->PushMessage(inv.GetCommand(), (*mi).second); pushed = true; @@ -4171,10 +4809,7 @@ void static ProcessGetData(CNode* pfrom) if (!pushed && inv.type == MSG_TX) { CTransaction tx; if (mempool.lookup(inv.hash, tx)) { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss.reserve(1000); - ss << tx; - pfrom->PushMessage("tx", ss); + pfrom->PushMessage(NetMsgType::TX, tx); pushed = true; } } @@ -4201,13 +4836,12 @@ void static ProcessGetData(CNode* pfrom) // do that because they want to know about (and store and rebroadcast and // risk analyze) the dependencies of transactions relevant to them, without // having to download the entire memory pool. - pfrom->PushMessage("notfound", vNotFound); + pfrom->PushMessage(NetMsgType::NOTFOUND, vNotFound); } } -bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) +bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams) { - const CChainParams& chainparams = Params(); RandAddSeedPerfmon(); LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) @@ -4217,14 +4851,27 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } + if (!(nLocalServices & NODE_BLOOM) && + (strCommand == NetMsgType::FILTERLOAD || + strCommand == NetMsgType::FILTERADD || + strCommand == NetMsgType::FILTERCLEAR)) + { + if (pfrom->nVersion >= NO_BLOOM_VERSION) { + Misbehaving(pfrom->GetId(), 100); + return false; + } else { + pfrom->fDisconnect = true; + return false; + } + } - if (strCommand == "version") + if (strCommand == NetMsgType::VERSION) { // Each connection can only send one version message if (pfrom->nVersion != 0) { - pfrom->PushMessage("reject", strCommand, REJECT_DUPLICATE, string("Duplicate version message")); + pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message")); Misbehaving(pfrom->GetId(), 1); return false; } @@ -4238,7 +4885,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, { // disconnect from peers older than this proto version LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); - pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE, + pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)); pfrom->fDisconnect = true; return false; @@ -4283,7 +4930,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, UpdatePreferredDownload(pfrom, State(pfrom->GetId())); // Change version - pfrom->PushMessage("verack"); + pfrom->PushMessage(NetMsgType::VERACK); pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); if (!pfrom->fInbound) @@ -4294,9 +4941,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, CAddress addr = GetLocalAddress(&pfrom->addr); if (addr.IsRoutable()) { + LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString()); pfrom->PushAddress(addr); } else if (IsPeerAddrLocalGood(pfrom)) { addr.SetIP(pfrom->addrLocal); + LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString()); pfrom->PushAddress(addr); } } @@ -4304,7 +4953,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Get recent addresses if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000) { - pfrom->PushMessage("getaddr"); + pfrom->PushMessage(NetMsgType::GETADDR); pfrom->fGetAddr = true; } addrman.Good(pfrom->addr); @@ -4316,13 +4965,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } - // Relay alerts - { - LOCK(cs_mapAlerts); - BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) - item.second.RelayTo(pfrom); - } - pfrom->fSuccessfullyConnected = true; string remoteAddr; @@ -4348,7 +4990,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - else if (strCommand == "verack") + else if (strCommand == NetMsgType::VERACK) { pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); @@ -4357,10 +4999,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LOCK(cs_main); State(pfrom->GetId())->fCurrentlyConnected = true; } + + if (pfrom->nVersion >= SENDHEADERS_VERSION) { + // Tell our peer we prefer to receive headers rather than inv's + // We send this to non-NODE NETWORK peers as well, because even + // non-NODE NETWORK peers can announce blocks (such as pruning + // nodes) + pfrom->PushMessage(NetMsgType::SENDHEADERS); + } } - else if (strCommand == "addr") + else if (strCommand == NetMsgType::ADDR) { vector vAddr; vRecv >> vAddr; @@ -4426,8 +5076,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->fDisconnect = true; } + else if (strCommand == NetMsgType::SENDHEADERS) + { + LOCK(cs_main); + State(pfrom->GetId())->fPreferHeaders = true; + } - else if (strCommand == "inv") + + else if (strCommand == NetMsgType::INV) { vector vInv; vRecv >> vInv; @@ -4437,6 +5093,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return error("message inv size() = %u", vInv.size()); } + bool fBlocksOnly = GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); + + // Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true + if (pfrom->fWhitelisted && GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) + fBlocksOnly = false; + LOCK(cs_main); std::vector vToFetch; @@ -4451,9 +5113,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, bool fAlreadyHave = AlreadyHave(inv); LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->id); - if (!fAlreadyHave && !fImporting && !fReindex && inv.type != MSG_BLOCK) - pfrom->AskFor(inv); - if (inv.type == MSG_BLOCK) { UpdateBlockAvailability(pfrom->GetId(), inv.hash); if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) { @@ -4465,9 +5124,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // time the block arrives, the header chain leading up to it is already validated. Not // doing this will result in the received block being rejected as an orphan in case it is // not a direct successor. - pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexBestHeader), inv.hash); + pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash); CNodeState *nodestate = State(pfrom->GetId()); - if (chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - chainparams.GetConsensus().nPowTargetSpacing * 20 && + if (CanDirectFetch(chainparams.GetConsensus()) && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { vToFetch.push_back(inv); // Mark block as in flight already, even though the actual "getdata" message only goes out @@ -4477,6 +5136,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); } } + else + { + if (fBlocksOnly) + LogPrint("net", "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->id); + else if (!fAlreadyHave && !fImporting && !fReindex && !IsInitialBlockDownload()) + pfrom->AskFor(inv); + } // Track requests for our stuff GetMainSignals().Inventory(inv.hash); @@ -4488,11 +5154,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } if (!vToFetch.empty()) - pfrom->PushMessage("getdata", vToFetch); + pfrom->PushMessage(NetMsgType::GETDATA, vToFetch); } - else if (strCommand == "getdata") + else if (strCommand == NetMsgType::GETDATA) { vector vInv; vRecv >> vInv; @@ -4509,11 +5175,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id); pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); - ProcessGetData(pfrom); + ProcessGetData(pfrom, chainparams.GetConsensus()); } - else if (strCommand == "getblocks") + else if (strCommand == NetMsgType::GETBLOCKS) { CBlockLocator locator; uint256 hashStop; @@ -4557,17 +5223,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - else if (strCommand == "getheaders") + else if (strCommand == NetMsgType::GETHEADERS) { CBlockLocator locator; uint256 hashStop; vRecv >> locator >> hashStop; LOCK(cs_main); - - if (IsInitialBlockDownload()) + if (IsInitialBlockDownload() && !pfrom->fWhitelisted) { + LogPrint("net", "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->id); return true; + } + CNodeState *nodestate = State(pfrom->GetId()); CBlockIndex* pindex = NULL; if (locator.IsNull()) { @@ -4595,12 +5263,25 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) break; } - pfrom->PushMessage("headers", vHeaders); + // pindex can be NULL either if we sent chainActive.Tip() OR + // if our peer has chainActive.Tip() (and thus we are sending an empty + // headers message). In both cases it's safe to update + // pindexBestHeaderSent to be our tip. + nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip(); + pfrom->PushMessage(NetMsgType::HEADERS, vHeaders); } - else if (strCommand == "tx") + else if (strCommand == NetMsgType::TX) { + // Stop processing the transaction early if + // We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off + if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && (!pfrom->fWhitelisted || !GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))) + { + LogPrint("net", "transaction sent in violation of protocol peer=%d\n", pfrom->id); + return true; + } + vector vWorkQueue; vector vEraseQueue; CTransaction tx; @@ -4614,22 +5295,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, bool fMissingInputs = false; CValidationState state; - mapAlreadyAskedFor.erase(inv); + pfrom->setAskFor.erase(inv.hash); + mapAlreadyAskedFor.erase(inv.hash); - // Check for recently rejected (and do other quick existence checks) - if (AlreadyHave(inv)) - return true; - - if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) - { + CFeeRate txFeeRate = CFeeRate(0); + if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, &txFeeRate)) { mempool.check(pcoinsTip); - RelayTransaction(tx); + RelayTransaction(tx, txFeeRate); vWorkQueue.push_back(inv.hash); - LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u)\n", + LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n", pfrom->id, tx.GetHash().ToString(), - mempool.size()); + mempool.size(), mempool.DynamicMemoryUsage() / 1000); // Recursively process any orphan transactions that depended on this one set setMisbehaving; @@ -4654,10 +5332,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (setMisbehaving.count(fromPeer)) continue; - if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) - { + CFeeRate orphanFeeRate = CFeeRate(0); + if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2, &orphanFeeRate)) { LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); - RelayTransaction(orphanTx); + RelayTransaction(orphanTx, orphanFeeRate); vWorkQueue.push_back(orphanHash); vEraseQueue.push_back(orphanHash); } @@ -4698,15 +5376,22 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, assert(recentRejects); recentRejects->insert(tx.GetHash()); - if (pfrom->fWhitelisted) { + if (pfrom->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) { // Always relay transactions received from whitelisted peers, even - // if they were rejected from the mempool, allowing the node to - // function as a gateway for nodes hidden behind it. + // if they were already in the mempool or rejected from it due + // to policy, allowing the node to function as a gateway for + // nodes hidden behind it. // - // FIXME: This includes invalid transactions, which means a - // whitelisted peer could get us banned! We may want to change - // that. - RelayTransaction(tx); + // Never relay transactions that we would assign a non-zero DoS + // score for, as we expect peers to do the same with us in that + // case. + int nDoS = 0; + if (!state.IsInvalid(nDoS) || nDoS == 0) { + LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id); + RelayTransaction(tx, txFeeRate); + } else { + LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state)); + } } } int nDoS = 0; @@ -4716,15 +5401,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->id, FormatStateMessage(state)); if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P - pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), + pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); if (nDoS > 0) Misbehaving(pfrom->GetId(), nDoS); } + FlushStateToDisk(state, FLUSH_STATE_PERIODIC); } - else if (strCommand == "headers" && !fImporting && !fReindex) // Ignore headers received while importing + else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing { std::vector headers; @@ -4754,7 +5440,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), 20); return error("non-continuous headers sequence"); } - if (!AcceptBlockHeader(header, state, &pindexLast)) { + if (!AcceptBlockHeader(header, state, chainparams, &pindexLast)) { int nDoS; if (state.IsInvalid(nDoS)) { if (nDoS > 0) @@ -4772,13 +5458,60 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue // from there instead. LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight); - pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexLast), uint256()); + pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()); } - CheckBlockIndex(); + bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); + CNodeState *nodestate = State(pfrom->GetId()); + // If this set of headers is valid and ends in a block with at least as + // much work as our tip, download as much as possible. + if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) { + vector vToFetch; + CBlockIndex *pindexWalk = pindexLast; + // Calculate all the blocks we'd need to switch to pindexLast, up to a limit. + while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) && + !mapBlocksInFlight.count(pindexWalk->GetBlockHash())) { + // We don't have this block, and it's not yet in flight. + vToFetch.push_back(pindexWalk); + } + pindexWalk = pindexWalk->pprev; + } + // If pindexWalk still isn't on our main chain, we're looking at a + // very large reorg at a time we think we're close to caught up to + // the main chain -- this shouldn't really happen. Bail out on the + // direct fetch and rely on parallel download instead. + if (!chainActive.Contains(pindexWalk)) { + LogPrint("net", "Large reorg, won't direct fetch to %s (%d)\n", + pindexLast->GetBlockHash().ToString(), + pindexLast->nHeight); + } else { + vector vGetData; + // Download as much as possible, from earliest to latest. + BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vToFetch) { + if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + // Can't download any more from this peer + break; + } + vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); + MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), chainparams.GetConsensus(), pindex); + LogPrint("net", "Requesting block %s from peer=%d\n", + pindex->GetBlockHash().ToString(), pfrom->id); + } + if (vGetData.size() > 1) { + LogPrint("net", "Downloading blocks toward %s (%d) via headers direct fetch\n", + pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); + } + if (vGetData.size() > 0) { + pfrom->PushMessage(NetMsgType::GETDATA, vGetData); + } + } + } + + CheckBlockIndex(chainparams.GetConsensus()); } - else if (strCommand == "block" && !fImporting && !fReindex) // Ignore blocks received while importing + else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing { CBlock block; vRecv >> block; @@ -4794,11 +5527,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Such an unrequested block may still be processed, subject to the // conditions in AcceptBlock(). bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); - ProcessNewBlock(state, pfrom, &block, forceProcessing, NULL); + ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL); int nDoS; if (state.IsInvalid(nDoS)) { assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes - pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), + pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); if (nDoS > 0) { LOCK(cs_main); @@ -4809,13 +5542,26 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - // This asymmetric behavior for inbound and outbound connections was introduced - // to prevent a fingerprinting attack: an attacker can send specific fake addresses - // to users' AddrMan and later request them by sending getaddr messages. - // Making nodes which are behind NAT and can only make outgoing connections ignore - // the getaddr message mitigates the attack. - else if ((strCommand == "getaddr") && (pfrom->fInbound)) + else if (strCommand == NetMsgType::GETADDR) { + // This asymmetric behavior for inbound and outbound connections was introduced + // to prevent a fingerprinting attack: an attacker can send specific fake addresses + // to users' AddrMan and later request them by sending getaddr messages. + // Making nodes which are behind NAT and can only make outgoing connections ignore + // the getaddr message mitigates the attack. + if (!pfrom->fInbound) { + LogPrint("net", "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom->id); + return true; + } + + // Only send one GetAddr response per connection to reduce resource waste + // and discourage addr stamping of INV announcements. + if (pfrom->fSentAddr) { + LogPrint("net", "Ignoring repeated \"getaddr\". peer=%d\n", pfrom->id); + return true; + } + pfrom->fSentAddr = true; + pfrom->vAddrToSend.clear(); vector vAddr = addrman.GetAddr(); BOOST_FOREACH(const CAddress &addr, vAddr) @@ -4823,8 +5569,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - else if (strCommand == "mempool") + else if (strCommand == NetMsgType::MEMPOOL) { + if (CNode::OutboundTargetReached(false) && !pfrom->fWhitelisted) + { + LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId()); + pfrom->fDisconnect = true; + return true; + } LOCK2(cs_main, pfrom->cs_filter); std::vector vtxid; @@ -4832,23 +5584,31 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vector vInv; BOOST_FOREACH(uint256& hash, vtxid) { CInv inv(MSG_TX, hash); - CTransaction tx; - bool fInMemPool = mempool.lookup(hash, tx); - if (!fInMemPool) continue; // another thread removed since queryHashes, maybe... - if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(tx)) || - (!pfrom->pfilter)) - vInv.push_back(inv); + if (pfrom->pfilter) { + CTransaction tx; + bool fInMemPool = mempool.lookup(hash, tx); + if (!fInMemPool) continue; // another thread removed since queryHashes, maybe... + if (!pfrom->pfilter->IsRelevantAndUpdate(tx)) continue; + } + if (pfrom->minFeeFilter) { + CFeeRate feeRate; + mempool.lookupFeeRate(hash, feeRate); + LOCK(pfrom->cs_feeFilter); + if (feeRate.GetFeePerK() < pfrom->minFeeFilter) + continue; + } + vInv.push_back(inv); if (vInv.size() == MAX_INV_SZ) { - pfrom->PushMessage("inv", vInv); + pfrom->PushMessage(NetMsgType::INV, vInv); vInv.clear(); } } if (vInv.size() > 0) - pfrom->PushMessage("inv", vInv); + pfrom->PushMessage(NetMsgType::INV, vInv); } - else if (strCommand == "ping") + else if (strCommand == NetMsgType::PING) { if (pfrom->nVersion > BIP0031_VERSION) { @@ -4865,12 +5625,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // it, if the remote node sends a ping once per second and this node takes 5 // seconds to respond to each, the 5th ping the remote sends would appear to // return very quickly. - pfrom->PushMessage("pong", nonce); + pfrom->PushMessage(NetMsgType::PONG, nonce); } } - else if (strCommand == "pong") + else if (strCommand == NetMsgType::PONG) { int64_t pingUsecEnd = nTimeReceived; uint64_t nonce = 0; @@ -4927,53 +5687,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - else if (fAlerts && strCommand == "alert") - { - CAlert alert; - vRecv >> alert; - - uint256 alertHash = alert.GetHash(); - if (pfrom->setKnown.count(alertHash) == 0) - { - if (alert.ProcessAlert(Params().AlertKey())) - { - // Relay - pfrom->setKnown.insert(alertHash); - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - alert.RelayTo(pnode); - } - } - else { - // Small DoS penalty so peers that send us lots of - // duplicate/expired/invalid-signature/whatever alerts - // eventually get banned. - // This isn't a Misbehaving(100) (immediate ban) because the - // peer might be an older or different implementation with - // a different signature key, etc. - Misbehaving(pfrom->GetId(), 10); - } - } - } - - - else if (!(nLocalServices & NODE_BLOOM) && - (strCommand == "filterload" || - strCommand == "filteradd" || - strCommand == "filterclear") && - //TODO: Remove this line after reasonable network upgrade - pfrom->nVersion >= NO_BLOOM_VERSION) - { - if (pfrom->nVersion >= NO_BLOOM_VERSION) - Misbehaving(pfrom->GetId(), 100); - //TODO: Enable this after reasonable network upgrade - //else - // pfrom->fDisconnect = true; - } - - - else if (strCommand == "filterload") + else if (strCommand == NetMsgType::FILTERLOAD) { CBloomFilter filter; vRecv >> filter; @@ -4992,7 +5706,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - else if (strCommand == "filteradd") + else if (strCommand == NetMsgType::FILTERADD) { vector vData; vRecv >> vData; @@ -5012,7 +5726,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - else if (strCommand == "filterclear") + else if (strCommand == NetMsgType::FILTERCLEAR) { LOCK(pfrom->cs_filter); delete pfrom->pfilter; @@ -5021,7 +5735,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - else if (strCommand == "reject") + else if (strCommand == NetMsgType::REJECT) { if (fDebug) { try { @@ -5031,7 +5745,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, ostringstream ss; ss << strMsg << " code " << itostr(ccode) << ": " << strReason; - if (strMsg == "block" || strMsg == "tx") + if (strMsg == NetMsgType::BLOCK || strMsg == NetMsgType::TX) { uint256 hash; vRecv >> hash; @@ -5045,8 +5759,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } - else - { + else if (strCommand == NetMsgType::FEEFILTER) { + CAmount newFeeFilter = 0; + vRecv >> newFeeFilter; + if (MoneyRange(newFeeFilter)) { + { + LOCK(pfrom->cs_feeFilter); + pfrom->minFeeFilter = newFeeFilter; + } + LogPrint("net", "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->id); + } + } + + else { // Ignore unknown commands for extensibility LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id); } @@ -5059,6 +5784,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // requires LOCK(cs_vRecvMsg) bool ProcessMessages(CNode* pfrom) { + const CChainParams& chainparams = Params(); //if (fDebug) // LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size()); @@ -5073,7 +5799,7 @@ bool ProcessMessages(CNode* pfrom) bool fOk = true; if (!pfrom->vRecvGetData.empty()) - ProcessGetData(pfrom); + ProcessGetData(pfrom, chainparams.GetConsensus()); // this maintains the order of responses if (!pfrom->vRecvGetData.empty()) return fOk; @@ -5100,7 +5826,7 @@ bool ProcessMessages(CNode* pfrom) it++; // Scan for message start - if (memcmp(msg.hdr.pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0) { + if (memcmp(msg.hdr.pchMessageStart, chainparams.MessageStart(), MESSAGE_START_SIZE) != 0) { LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->id); fOk = false; break; @@ -5108,7 +5834,7 @@ bool ProcessMessages(CNode* pfrom) // Read header CMessageHeader& hdr = msg.hdr; - if (!hdr.IsValid(Params().MessageStart())) + if (!hdr.IsValid(chainparams.MessageStart())) { LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->id); continue; @@ -5133,12 +5859,12 @@ bool ProcessMessages(CNode* pfrom) bool fRet = false; try { - fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime); + fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams); boost::this_thread::interruption_point(); } catch (const std::ios_base::failure& e) { - pfrom->PushMessage("reject", strCommand, REJECT_MALFORMED, string("error parsing message")); + pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message")); if (strstr(e.what(), "end of data")) { // Allow exceptions from under-length message on vRecv @@ -5177,7 +5903,7 @@ bool ProcessMessages(CNode* pfrom) } -bool SendMessages(CNode* pto, bool fSendTrickle) +bool SendMessages(CNode* pto) { const Consensus::Params& consensusParams = Params().GetConsensus(); { @@ -5206,11 +5932,11 @@ bool SendMessages(CNode* pto, bool fSendTrickle) pto->nPingUsecStart = GetTimeMicros(); if (pto->nVersion > BIP0031_VERSION) { pto->nPingNonceSent = nonce; - pto->PushMessage("ping", nonce); + pto->PushMessage(NetMsgType::PING, nonce); } else { // Peer is too old to support ping command with nonce, pong will never arrive. pto->nPingNonceSent = 0; - pto->PushMessage("ping"); + pto->PushMessage(NetMsgType::PING); } } @@ -5219,28 +5945,17 @@ bool SendMessages(CNode* pto, bool fSendTrickle) return true; // Address refresh broadcast - static int64_t nLastRebroadcast; - if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - { - // Periodically clear addrKnown to allow refresh broadcasts - if (nLastRebroadcast) - pnode->addrKnown.reset(); - - // Rebroadcast our address - AdvertizeLocal(pnode); - } - if (!vNodes.empty()) - nLastRebroadcast = GetTime(); + int64_t nNow = GetTimeMicros(); + if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) { + AdvertiseLocal(pto); + pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); } // // Message: addr // - if (fSendTrickle) - { + if (pto->nNextAddrSend < nNow) { + pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL); vector vAddr; vAddr.reserve(pto->vAddrToSend.size()); BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend) @@ -5252,14 +5967,14 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // receiver rejects addr messages larger than 1000 if (vAddr.size() >= 1000) { - pto->PushMessage("addr", vAddr); + pto->PushMessage(NetMsgType::ADDR, vAddr); vAddr.clear(); } } } pto->vAddrToSend.clear(); if (!vAddr.empty()) - pto->PushMessage("addr", vAddr); + pto->PushMessage(NetMsgType::ADDR, vAddr); } CNodeState &state = *State(pto->GetId()); @@ -5279,7 +5994,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) } BOOST_FOREACH(const CBlockReject& reject, state.rejects) - pto->PushMessage("reject", (string)"block", reject.chRejectCode, reject.strRejectReason, reject.hashBlock); + pto->PushMessage(NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock); state.rejects.clear(); // Start block sync @@ -5302,7 +6017,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) if (pindexStart->pprev) pindexStart = pindexStart->pprev; LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight); - pto->PushMessage("getheaders", chainActive.GetLocator(pindexStart), uint256()); + pto->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()); } } @@ -5314,18 +6029,117 @@ bool SendMessages(CNode* pto, bool fSendTrickle) GetMainSignals().Broadcast(nTimeBestReceived); } + // + // Try sending block announcements via headers + // + { + // If we have less than MAX_BLOCKS_TO_ANNOUNCE in our + // list of block hashes we're relaying, and our peer wants + // headers announcements, then find the first header + // not yet known to our peer but would connect, and send. + // If no header would connect, or if we have too many + // blocks, or if the peer doesn't want headers, just + // add all to the inv queue. + LOCK(pto->cs_inventory); + vector vHeaders; + bool fRevertToInv = (!state.fPreferHeaders || pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE); + CBlockIndex *pBestIndex = NULL; // last header queued for delivery + ProcessBlockAvailability(pto->id); // ensure pindexBestKnownBlock is up-to-date + + if (!fRevertToInv) { + bool fFoundStartingHeader = false; + // Try to find first header that our peer doesn't have, and + // then send all headers past that one. If we come across any + // headers that aren't on chainActive, give up. + BOOST_FOREACH(const uint256 &hash, pto->vBlockHashesToAnnounce) { + BlockMap::iterator mi = mapBlockIndex.find(hash); + assert(mi != mapBlockIndex.end()); + CBlockIndex *pindex = mi->second; + if (chainActive[pindex->nHeight] != pindex) { + // Bail out if we reorged away from this block + fRevertToInv = true; + break; + } + assert(pBestIndex == NULL || pindex->pprev == pBestIndex); + pBestIndex = pindex; + if (fFoundStartingHeader) { + // add this to the headers message + vHeaders.push_back(pindex->GetBlockHeader()); + } else if (PeerHasHeader(&state, pindex)) { + continue; // keep looking for the first new block + } else if (pindex->pprev == NULL || PeerHasHeader(&state, pindex->pprev)) { + // Peer doesn't have this header but they do have the prior one. + // Start sending headers. + fFoundStartingHeader = true; + vHeaders.push_back(pindex->GetBlockHeader()); + } else { + // Peer doesn't have this header or the prior one -- nothing will + // connect, so bail out. + fRevertToInv = true; + break; + } + } + } + if (fRevertToInv) { + // If falling back to using an inv, just try to inv the tip. + // The last entry in vBlockHashesToAnnounce was our tip at some point + // in the past. + if (!pto->vBlockHashesToAnnounce.empty()) { + const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back(); + BlockMap::iterator mi = mapBlockIndex.find(hashToAnnounce); + assert(mi != mapBlockIndex.end()); + CBlockIndex *pindex = mi->second; + + // Warn if we're announcing a block that is not on the main chain. + // This should be very rare and could be optimized out. + // Just log for now. + if (chainActive[pindex->nHeight] != pindex) { + LogPrint("net", "Announcing block %s not on main chain (tip=%s)\n", + hashToAnnounce.ToString(), chainActive.Tip()->GetBlockHash().ToString()); + } + + // If the peer announced this block to us, don't inv it back. + // (Since block announcements may not be via inv's, we can't solely rely on + // setInventoryKnown to track this.) + if (!PeerHasHeader(&state, pindex)) { + pto->PushInventory(CInv(MSG_BLOCK, hashToAnnounce)); + LogPrint("net", "%s: sending inv peer=%d hash=%s\n", __func__, + pto->id, hashToAnnounce.ToString()); + } + } + } else if (!vHeaders.empty()) { + if (vHeaders.size() > 1) { + LogPrint("net", "%s: %u headers, range (%s, %s), to peer=%d\n", __func__, + vHeaders.size(), + vHeaders.front().GetHash().ToString(), + vHeaders.back().GetHash().ToString(), pto->id); + } else { + LogPrint("net", "%s: sending header %s to peer=%d\n", __func__, + vHeaders.front().GetHash().ToString(), pto->id); + } + pto->PushMessage(NetMsgType::HEADERS, vHeaders); + state.pindexBestHeaderSent = pBestIndex; + } + pto->vBlockHashesToAnnounce.clear(); + } + // // Message: inventory // vector vInv; vector vInvWait; { + bool fSendTrickle = pto->fWhitelisted; + if (pto->nNextInvSend < nNow) { + fSendTrickle = true; + pto->nNextInvSend = PoissonNextSend(nNow, AVG_INVENTORY_BROADCAST_INTERVAL); + } LOCK(pto->cs_inventory); - vInv.reserve(pto->vInventoryToSend.size()); + vInv.reserve(std::min(1000, pto->vInventoryToSend.size())); vInvWait.reserve(pto->vInventoryToSend.size()); BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend) { - if (pto->setInventoryKnown.count(inv)) + if (inv.type == MSG_TX && pto->filterInventoryKnown.contains(inv.hash)) continue; // trickle out tx inv to protect privacy @@ -5346,24 +6160,22 @@ bool SendMessages(CNode* pto, bool fSendTrickle) } } - // returns true if wasn't already contained in the set - if (pto->setInventoryKnown.insert(inv).second) + pto->filterInventoryKnown.insert(inv.hash); + + vInv.push_back(inv); + if (vInv.size() >= 1000) { - vInv.push_back(inv); - if (vInv.size() >= 1000) - { - pto->PushMessage("inv", vInv); - vInv.clear(); - } + pto->PushMessage(NetMsgType::INV, vInv); + vInv.clear(); } } pto->vInventoryToSend = vInvWait; } if (!vInv.empty()) - pto->PushMessage("inv", vInv); + pto->PushMessage(NetMsgType::INV, vInv); // Detect whether we're stalling - int64_t nNow = GetTimeMicros(); + nNow = GetTimeMicros(); if (!pto->fDisconnect && state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) { // Stalling only triggers when the block download window cannot move. During normal steady state, // the download window should be much larger than the to-be-downloaded set of blocks, so disconnection @@ -5371,24 +6183,15 @@ bool SendMessages(CNode* pto, bool fSendTrickle) LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id); pto->fDisconnect = true; } - // In case there is a block that has been in flight from this peer for (2 + 0.5 * N) times the block interval - // (with N the number of validated blocks that were in flight at the time it was requested), disconnect due to - // timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link + // In case there is a block that has been in flight from this peer for 2 + 0.5 * N times the block interval + // (with N the number of peers from which we're downloading validated blocks), disconnect due to timeout. + // We compensate for other peers to prevent killing off peers due to our own downstream link // being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes // to unreasonably increase our timeout. - // We also compare the block download timeout originally calculated against the time at which we'd disconnect - // if we assumed the block were being requested now (ignoring blocks we've requested from this peer, since we're - // only looking at this peer's oldest request). This way a large queue in the past doesn't result in a - // permanently large window for this block to be delivered (ie if the number of blocks in flight is decreasing - // more quickly than once every 5 minutes, then we'll shorten the download window for this block). if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) { QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); - int64_t nTimeoutIfRequestedNow = GetBlockTimeout(nNow, nQueuedValidatedHeaders - state.nBlocksInFlightValidHeaders, consensusParams); - if (queuedBlock.nTimeDisconnect > nTimeoutIfRequestedNow) { - LogPrint("net", "Reducing block download timeout for peer=%d block=%s, orig=%d new=%d\n", pto->id, queuedBlock.hash.ToString(), queuedBlock.nTimeDisconnect, nTimeoutIfRequestedNow); - queuedBlock.nTimeDisconnect = nTimeoutIfRequestedNow; - } - if (queuedBlock.nTimeDisconnect < nNow) { + int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0); + if (nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) { LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id); pto->fDisconnect = true; } @@ -5429,15 +6232,41 @@ bool SendMessages(CNode* pto, bool fSendTrickle) vGetData.push_back(inv); if (vGetData.size() >= 1000) { - pto->PushMessage("getdata", vGetData); + pto->PushMessage(NetMsgType::GETDATA, vGetData); vGetData.clear(); } + } else { + //If we're not going to ask, don't expect a response. + pto->setAskFor.erase(inv.hash); } pto->mapAskFor.erase(pto->mapAskFor.begin()); } if (!vGetData.empty()) - pto->PushMessage("getdata", vGetData); + pto->PushMessage(NetMsgType::GETDATA, vGetData); + // + // Message: feefilter + // + // We don't want white listed peers to filter txs to us if we have -whitelistforcerelay + if (pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && + !(pto->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) { + CAmount currentFilter = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(); + int64_t timeNow = GetTimeMicros(); + if (timeNow > pto->nextSendTimeFeeFilter) { + CAmount filterToSend = filterRounder.round(currentFilter); + if (filterToSend != pto->lastSentFeeFilter) { + pto->PushMessage(NetMsgType::FEEFILTER, filterToSend); + pto->lastSentFeeFilter = filterToSend; + } + pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL); + } + // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY + // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY. + else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter && + (currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3)) { + pto->nextSendTimeFeeFilter = timeNow + (insecure_rand() % MAX_FEEFILTER_CHANGE_DELAY) * 1000000; + } + } } return true; } @@ -5446,7 +6275,11 @@ bool SendMessages(CNode* pto, bool fSendTrickle) return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast)); } - +ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos) +{ + LOCK(cs_main); + return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache); +} class CMainCleanup { diff --git a/src/main.h b/src/main.h index 8b21535b9..4ba6ee59f 100644 --- a/src/main.h +++ b/src/main.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -17,6 +17,7 @@ #include "claimtrie.h" #include "script/script_error.h" #include "sync.h" +#include "versionbits.h" #include #include @@ -32,6 +33,7 @@ class CBlockIndex; class CBlockTreeDB; class CBloomFilter; +class CChainParams; class CInv; class CScriptCheck; class CTxMemPool; @@ -39,25 +41,39 @@ class CValidationInterface; class CValidationState; struct CNodeStateStats; +struct LockPoints; -/** Default for accepting alerts from the P2P network. */ -static const bool DEFAULT_ALERTS = true; +/** Default for DEFAULT_WHITELISTRELAY. */ +static const bool DEFAULT_WHITELISTRELAY = true; +/** Default for DEFAULT_WHITELISTFORCERELAY. */ +static const bool DEFAULT_WHITELISTFORCERELAY = true; +/** Default for -minrelaytxfee, minimum relay fee for transactions */ +static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000; +//! -maxtxfee default +static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN; +//! Discourage users to set fees higher than this amount (in satoshis) per kB +static const CAmount HIGH_TX_FEE_PER_KB = 0.01 * COIN; +//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis) +static const CAmount HIGH_MAX_TX_FEE = 100 * HIGH_TX_FEE_PER_KB; /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; /** Default for -limitancestorcount, max number of in-mempool ancestors */ -static const unsigned int DEFAULT_ANCESTOR_LIMIT = 100; +static const unsigned int DEFAULT_ANCESTOR_LIMIT = 25; /** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */ -static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 900; +static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 101; /** Default for -limitdescendantcount, max number of in-mempool descendants */ -static const unsigned int DEFAULT_DESCENDANT_LIMIT = 1000; +static const unsigned int DEFAULT_DESCENDANT_LIMIT = 25; /** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */ -static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 2500; +static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 101; +/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */ +static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 72; /** The maximum size of a blk?????.dat file (since 0.8) */ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB /** The pre-allocation chunk size for blk?????.dat files (since 0.8) */ static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB /** The pre-allocation chunk size for rev?????.dat files (since 0.8) */ static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB + /** Maximum number of script-checking threads allowed */ static const int MAX_SCRIPTCHECK_THREADS = 16; /** -par default (number of script-checking threads, 0 = auto) */ @@ -80,6 +96,43 @@ static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60; static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60; /** Maximum length of reject messages. */ static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111; +/** Average delay between local address broadcasts in seconds. */ +static const unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 24 * 60; +/** Average delay between peer address broadcasts in seconds. */ +static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30; +/** Average delay between trickled inventory broadcasts in seconds. + * Blocks, whitelisted receivers, and a random 25% of transactions bypass this. */ +static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5; +/** Average delay between feefilter broadcasts in seconds. */ +static const unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60; +/** Maximum feefilter broadcast delay after significant change. */ +static const unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60; +/** Block download timeout base, expressed in millionths of the block interval (i.e. 10 min) */ +static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1000000; +/** Additional block download timeout per parallel downloading peer (i.e. 5 min) */ +static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000; + +static const unsigned int DEFAULT_LIMITFREERELAY = 15; +static const bool DEFAULT_RELAYPRIORITY = true; +static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60; + +/** Default for -permitbaremultisig */ +static const bool DEFAULT_PERMIT_BAREMULTISIG = true; +static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20; +static const bool DEFAULT_CHECKPOINTS_ENABLED = true; +static const bool DEFAULT_TXINDEX = false; +static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100; + +static const bool DEFAULT_TESTSAFEMODE = false; +/** Default for -mempoolreplacement */ +static const bool DEFAULT_ENABLE_REPLACEMENT = true; +/** Default for using fee filter */ +static const bool DEFAULT_FEEFILTER = true; + +/** Maximum number of headers to announce when relaying blocks with headers message.*/ +static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8; + +static const bool DEFAULT_PEERBLOOMFILTERS = true; struct BlockHasher { @@ -102,11 +155,17 @@ extern int nScriptCheckThreads; extern bool fTxIndex; extern bool fIsBareMultisigStd; extern bool fRequireStandard; +extern unsigned int nBytesPerSigOp; extern bool fCheckBlockIndex; extern bool fCheckpointsEnabled; extern size_t nCoinCacheUsage; +/** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */ extern CFeeRate minRelayTxFee; -extern bool fAlerts; +/** Absolute maximum transaction fee (in satoshis) used by wallet and mempool (rejects high fee in sendrawtransaction) */ +extern CAmount maxTxFee; +/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */ +extern int64_t nMaxTipAge; +extern bool fEnableReplacement; /** Best header we've seen so far (used for getheaders queries' starting points). */ extern CBlockIndex *pindexBestHeader; @@ -124,6 +183,9 @@ extern uint64_t nPruneTarget; /** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */ static const unsigned int MIN_BLOCKS_TO_KEEP = 288; +static const signed int DEFAULT_CHECKBLOCKS = MIN_BLOCKS_TO_KEEP; +static const unsigned int DEFAULT_CHECKLEVEL = 3; + // Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat) // At 1MB per block, 288 blocks = 288MB. // Add 15% for Undo data = 331MB @@ -151,7 +213,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals); * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location. * @return True if state.IsValid() */ -bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp); +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ @@ -163,9 +225,9 @@ boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char /** Get a cryptographic proof that a name maps to a value **/ bool GetProofForName(const CBlockIndex* pindexProof, const std::string& name, CClaimTrieProof& proof); /** Import blocks from an external file */ -bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp = NULL); +bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp = NULL); /** Initialize a new block tree database + block data on disk */ -bool InitBlockIndex(); +bool InitBlockIndex(const CChainParams& chainparams); /** Load the block tree and coins database from disk */ bool LoadBlockIndex(); /** Unload database information */ @@ -176,21 +238,26 @@ bool ProcessMessages(CNode* pfrom); * Send queued protocol messages to be sent to a give node. * * @param[in] pto The node which we are sending messages to. - * @param[in] fSendTrickle When true send the trickled data, otherwise trickle the data until true. */ -bool SendMessages(CNode* pto, bool fSendTrickle); +bool SendMessages(CNode* pto); /** Run an instance of the script checking thread */ void ThreadScriptCheck(); /** Try to detect Partition (network isolation) attacks against us */ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing); /** Check whether we are doing an initial block download (synchronizing from disk or network) */ bool IsInitialBlockDownload(); -/** Format a string that describes several potential problems detected by the core */ +/** Format a string that describes several potential problems detected by the core. + * strFor can have three values: + * - "rpc": get critical warnings, which should put the client in safe mode if non-empty + * - "statusbar": get all warnings + * - "gui": get all warnings, translated (where possible) for GUI + * This function only returns the highest priority warning of the set selected by strFor. + */ std::string GetWarnings(const std::string& strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ -bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false); +bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false); /** Find the best known block, and make it the tip of the block chain */ -bool ActivateBestChain(CValidationState &state, const CBlock *pblock = NULL); +bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL); CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); /** @@ -201,14 +268,14 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); * * Pruning functions are called from FlushStateToDisk when the global fCheckForPruning flag has been set. * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.) - * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 10 on regtest). + * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 1000 on regtest). * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip. * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files. * A db flag records the fact that at least some block files have been pruned. * * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned */ -void FindFilesToPrune(std::set& setFilesToPrune); +void FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPruneAfterHeight); /** * Actually unlink the specified files @@ -228,8 +295,13 @@ void PruneAndFlush(); /** (try to) add transaction to memory pool **/ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, - bool* pfMissingInputs, bool fRejectAbsurdFee=false); + bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0); +/** Convert CValidationState to a human-readable message for logging */ +std::string FormatStateMessage(const CValidationState &state); + +/** Get the BIP9 state for a given deployment at the current tip. */ +ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos); struct CNodeStateStats { int nMisbehavior; @@ -264,8 +336,6 @@ struct CDiskTxPos : public CDiskBlockPos }; -CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree); - /** * Count ECDSA signature operations the old-fashioned (pre-0.6) way * @return number of sigops this transaction's outputs will produce when spent @@ -307,11 +377,36 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime); * Check if transaction will be final in the next block to be created. * * Calls IsFinalTx() with current block height and appropriate block time. + * + * See consensus/consensus.h for flag definitions. */ -bool CheckFinalTx(const CTransaction &tx); +bool CheckFinalTx(const CTransaction &tx, int flags = -1); +/** + * Test whether the LockPoints height and time are still valid on the current chain + */ +bool TestLockPointValidity(const LockPoints* lp); -/** +/** + * Check if transaction is final per BIP 68 sequence numbers and can be included in a block. + * Consensus critical. Takes as input a list of heights at which tx's inputs (in order) confirmed. + */ +bool SequenceLocks(const CTransaction &tx, int flags, std::vector* prevHeights, const CBlockIndex& block); + +/** + * Check if transaction will be BIP 68 final in the next block to be created. + * + * Simulates calling SequenceLocks() with data from the tip of the current active chain. + * Optionally stores in LockPoints the resulting height and time calculated and the hash + * of the block needed for calculation or skips the calculation and uses the LockPoints + * passed in for evaluation. + * The LockPoints should not be considered valid if CheckSequenceLocks returns false. + * + * See consensus/consensus.h for flag definitions. + */ +bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = NULL, bool useExistingLockPoints = false); + +/** * Closure representing one script verification * Note that this stores references to the spending transaction */ @@ -348,48 +443,46 @@ public: /** Functions for disk access for blocks */ bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart); -bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos); -bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); - +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams); +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams); /** Functions for validating blocks and updating the block tree */ +/** Context-independent validity checks */ +bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); +bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true); + +/** Context-dependent validity checks. + * By "context", we mean only the previous block headers, but not the UTXO + * set; UTXO-related validity checks are done in ConnectBlock(). */ +bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev); +bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); + +/** Apply the effects of this block (with given index) on the UTXO set represented by coins. + * Validity checks that depend on the UTXO set are also done; ConnectBlock() + * can fail if those validity checks fail (among other reasons). */ +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, CClaimTrieCache& trieCache, bool fJustCheck = false); + /** Undo the effects of this block (with given index) on the UTXO set represented by coins. * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean * will be true if no problems were found. Otherwise, the return value will be false in case * of problems. Note that in any case, coins may be modified. */ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& coins, CClaimTrieCache& trieCache, bool* pfClean = NULL); -/** Apply the effects of this block (with given index) on the UTXO set represented by coins */ -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, CClaimTrieCache& trieCache, bool fJustCheck = false); - -/** Context-independent validity checks */ -bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); -bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true); - -/** Context-dependent validity checks */ -bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev); -bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); - /** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */ -bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); - -/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */ -bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp); -bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL); - +bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); class CBlockFileInfo { public: - unsigned int nBlocks; //! number of blocks stored in file - unsigned int nSize; //! number of used bytes of block file - unsigned int nUndoSize; //! number of used bytes in the undo file - unsigned int nHeightFirst; //! lowest height of block in file - unsigned int nHeightLast; //! highest height of block in file - uint64_t nTimeFirst; //! earliest time of block in file - uint64_t nTimeLast; //! latest time of block in file + unsigned int nBlocks; //!< number of blocks stored in file + unsigned int nSize; //!< number of used bytes of block file + unsigned int nUndoSize; //!< number of used bytes in the undo file + unsigned int nHeightFirst; //!< lowest height of block in file + unsigned int nHeightLast; //!< highest height of block in file + uint64_t nTimeFirst; //!< earliest time of block in file + uint64_t nTimeLast; //!< latest time of block in file ADD_SERIALIZE_METHODS; @@ -439,19 +532,19 @@ class CVerifyDB { public: CVerifyDB(); ~CVerifyDB(); - bool VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth); + bool VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth); }; /** Find the last common block between the parameter chain and a locator. */ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator); /** Mark a block as invalid. */ -bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex); +bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex *pindex); /** Remove invalidity status from a block and its descendants. */ bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex); -/** The currently-connected chain of blocks. */ +/** The currently-connected chain of blocks (protected by cs_main). */ extern CChain chainActive; /** Global variable that points to the active CCoinsView (protected by cs_main) */ @@ -470,6 +563,11 @@ extern CBlockTreeDB *pblocktree; */ int GetSpendHeight(const CCoinsViewCache& inputs); +/** + * Determine what nVersion a new block should use. + */ +int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params); + /** Reject codes greater or equal to this can be returned by AcceptToMemPool * for transactions, to signal internal conditions. They cannot and should not * be sent over the P2P network. diff --git a/src/memusage.h b/src/memusage.h index b475c3313..49760e64c 100644 --- a/src/memusage.h +++ b/src/memusage.h @@ -46,7 +46,9 @@ template static inline size_t DynamicUsage(const X * const &v) { ret static inline size_t MallocUsage(size_t alloc) { // Measured on libc6 2.19 on Linux. - if (sizeof(void*) == 8) { + if (alloc == 0) { + return 0; + } else if (sizeof(void*) == 8) { return ((alloc + 31) >> 4) << 4; } else if (sizeof(void*) == 4) { return ((alloc + 15) >> 3) << 3; @@ -74,6 +76,12 @@ static inline size_t DynamicUsage(const std::vector& v) return MallocUsage(v.capacity() * sizeof(X)); } +template +static inline size_t DynamicUsage(const prevector& v) +{ + return MallocUsage(v.allocated_memory()); +} + template static inline size_t DynamicUsage(const std::set& s) { @@ -121,4 +129,4 @@ static inline size_t DynamicUsage(const boost::unordered_map& m) } -#endif +#endif // BITCOIN_MEMUSAGE_H diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index f8e877df2..dca4973cc 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -95,7 +95,7 @@ void CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, const st } } -uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector &vMatch) { +uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector &vMatch, std::vector &vnIndex) { if (nBitsUsed >= vBits.size()) { // overflowed the bits array - failure fBad = true; @@ -110,14 +110,16 @@ uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, uns return uint256(); } const uint256 &hash = vHash[nHashUsed++]; - if (height==0 && fParentOfMatch) // in case of height 0, we have a matched txid + if (height==0 && fParentOfMatch) { // in case of height 0, we have a matched txid vMatch.push_back(hash); + vnIndex.push_back(pos); + } return hash; } else { // otherwise, descend into the subtrees to extract matched txids and hashes - uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch), right; + uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch, vnIndex), right; if (pos*2+1 < CalcTreeWidth(height-1)) { - right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch); + right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch, vnIndex); if (right == left) { // The left and right branches should never be identical, as the transaction // hashes covered by them must each be unique. @@ -147,7 +149,7 @@ CPartialMerkleTree::CPartialMerkleTree(const std::vector &vTxid, const CPartialMerkleTree::CPartialMerkleTree() : nTransactions(0), fBad(true) {} -uint256 CPartialMerkleTree::ExtractMatches(std::vector &vMatch) { +uint256 CPartialMerkleTree::ExtractMatches(std::vector &vMatch, std::vector &vnIndex) { vMatch.clear(); // An empty set will not work if (nTransactions == 0) @@ -167,7 +169,7 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector &vMatch) { nHeight++; // traverse the partial tree unsigned int nBitsUsed = 0, nHashUsed = 0; - uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch); + uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch, vnIndex); // verify that no problems occurred during the tree traversal if (fBad) return uint256(); diff --git a/src/merkleblock.h b/src/merkleblock.h index 904c22abc..835cbcce5 100644 --- a/src/merkleblock.h +++ b/src/merkleblock.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -75,9 +75,9 @@ protected: /** * recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild. - * it returns the hash of the respective node. + * it returns the hash of the respective node and its respective index. */ - uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector &vMatch); + uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector &vMatch, std::vector &vnIndex); public: @@ -110,10 +110,11 @@ public: CPartialMerkleTree(); /** - * extract the matching txid's represented by this partial merkle tree. + * extract the matching txid's represented by this partial merkle tree + * and their respective indices within the partial tree. * returns the merkle root, or 0 in case of failure */ - uint256 ExtractMatches(std::vector &vMatch); + uint256 ExtractMatches(std::vector &vMatch, std::vector &vnIndex); }; diff --git a/src/miner.cpp b/src/miner.cpp index e8cf02e74..5fd0c0634 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,6 +10,7 @@ #include "chainparams.h" #include "coins.h" #include "consensus/consensus.h" +#include "consensus/merkle.h" #include "consensus/validation.h" #include "hash.h" #include "main.h" @@ -28,6 +29,7 @@ #include #include +#include using namespace std; @@ -41,48 +43,18 @@ using namespace std; // transactions in the memory pool. When we select transactions from the // pool, we select by highest priority or fee rate, so we might consider // transactions that depend on transactions that aren't yet in the block. -// The COrphan class keeps track of these 'temporary orphans' while -// CreateBlock is figuring out which transactions to include. -// -class COrphan -{ -public: - const CTransaction* ptx; - set setDependsOn; - CFeeRate feeRate; - double dPriority; - - COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0) - { - } -}; uint64_t nLastBlockTx = 0; uint64_t nLastBlockSize = 0; -// We want to sort transactions by priority and fee rate, so: -typedef boost::tuple TxPriority; -class TxPriorityCompare +class ScoreCompare { - bool byFee; - public: - TxPriorityCompare(bool _byFee) : byFee(_byFee) { } + ScoreCompare() {} - bool operator()(const TxPriority& a, const TxPriority& b) + bool operator()(const CTxMemPool::txiter a, const CTxMemPool::txiter b) { - if (byFee) - { - if (a.get<1>() == b.get<1>()) - return a.get<0>() < b.get<0>(); - return a.get<1>() < b.get<1>(); - } - else - { - if (a.get<0>() == b.get<0>()) - return a.get<1>() < b.get<1>(); - return a.get<0>() < b.get<0>(); - } + return CompareTxMemPoolEntryByScore()(*b,*a); // Convert to less than } }; @@ -101,20 +73,14 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam return nNewTime - nOldTime; } -CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) +CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn) { - const CChainParams& chainparams = Params(); // Create new block auto_ptr pblocktemplate(new CBlockTemplate()); if(!pblocktemplate.get()) return NULL; CBlock *pblock = &pblocktemplate->block; // pointer for convenience - // -regtest only: allow overriding block.nVersion with - // -blockversion=N to test forking scenarios - if (Params().MineBlocksOnDemand()) - pblock->nVersion = GetArg("-blockversion", pblock->nVersion); - // Create coinbase tx CMutableTransaction txNew; txNew.vin.resize(1); @@ -129,7 +95,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Largest block you're willing to create: unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); - // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: + // Limit to between 1K and MAX_BLOCK_SIZE-1K for sanity: nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); // How much of the block should be dedicated to high-priority transactions, @@ -143,6 +109,22 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); // Collect memory pool transactions into the block + CTxMemPool::setEntries inBlock; + CTxMemPool::setEntries waitSet; + + // This vector will be sorted into a priority queue: + vector vecPriority; + TxCoinAgePriorityCompare pricomparer; + std::map waitPriMap; + typedef std::map::iterator waitPriIter; + double actualPriority = -1; + + std::priority_queue, ScoreCompare> clearedTxs; + bool fPrintPriority = GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY); + uint64_t nBlockSize = 1000; + uint64_t nBlockTx = 0; + unsigned int nBlockSigOps = 100; + int lastFewTxs = 0; CAmount nFees = 0; { @@ -156,147 +138,100 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) return NULL; } CClaimTrieCache trieCache(pclaimTrie); + const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); - // Priority order to process transactions - list vOrphan; // list memory doesn't move - map > mapDependers; - bool fPrintPriority = GetBoolArg("-printpriority", false); + pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); + // -regtest only: allow overriding block.nVersion with + // -blockversion=N to test forking scenarios + if (chainparams.MineBlocksOnDemand()) + pblock->nVersion = GetArg("-blockversion", pblock->nVersion); - // This vector will be sorted into a priority queue: - vector vecPriority; - vecPriority.reserve(mempool.mapTx.size()); - for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin(); - mi != mempool.mapTx.end(); ++mi) - { - const CTransaction& tx = mi->GetTx(); - if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, pblock->nTime)) - continue; + int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) + ? nMedianTimePast + : pblock->GetBlockTime(); - COrphan* porphan = NULL; - double dPriority = 0; - CAmount nTotalIn = 0; - bool fMissingInputs = false; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + bool fPriorityBlock = nBlockPrioritySize > 0; + if (fPriorityBlock) { + vecPriority.reserve(mempool.mapTx.size()); + for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin(); + mi != mempool.mapTx.end(); ++mi) { - // Read prev transaction - if (!view.HaveCoins(txin.prevout.hash)) - { - // This should never happen; all transactions in the memory - // pool should connect to either transactions in the chain - // or other transactions in the memory pool. - if (!mempool.mapTx.count(txin.prevout.hash)) - { - LogPrintf("ERROR: mempool transaction missing input\n"); - if (fDebug) assert("mempool transaction missing input" == 0); - fMissingInputs = true; - if (porphan) - vOrphan.pop_back(); - break; - } - - // Has to wait for dependencies - if (!porphan) - { - // Use list for automatic deletion - vOrphan.push_back(COrphan(&tx)); - porphan = &vOrphan.back(); - } - mapDependers[txin.prevout.hash].push_back(porphan); - porphan->setDependsOn.insert(txin.prevout.hash); - nTotalIn += mempool.mapTx.find(txin.prevout.hash)->GetTx().vout[txin.prevout.n].nValue; - continue; - } - const CCoins* coins = view.AccessCoins(txin.prevout.hash); - assert(coins); - - CAmount nValueIn = coins->vout[txin.prevout.n].nValue; - nTotalIn += nValueIn; - - int nConf = nHeight - coins->nHeight; - - dPriority += (double)nValueIn * nConf; + double dPriority = mi->GetPriority(nHeight); + CAmount dummy; + mempool.ApplyDeltas(mi->GetTx().GetHash(), dPriority, dummy); + vecPriority.push_back(TxCoinAgePriority(dPriority, mi)); } - if (fMissingInputs) continue; - - // Priority is sum(valuein * age) / modified_txsize - unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); - dPriority = tx.ComputePriority(dPriority, nTxSize); - - uint256 hash = tx.GetHash(); - mempool.ApplyDeltas(hash, dPriority, nTotalIn); - - CFeeRate feeRate(nTotalIn-tx.GetValueOut(), nTxSize); - - if (porphan) - { - porphan->dPriority = dPriority; - porphan->feeRate = feeRate; - } - else - vecPriority.push_back(TxPriority(dPriority, feeRate, &(mi->GetTx()))); + std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer); } - // Collect transactions into block - uint64_t nBlockSize = 1000; - uint64_t nBlockTx = 0; - int nBlockSigOps = 100; - bool fSortedByFee = (nBlockPrioritySize <= 0); + CTxMemPool::indexed_transaction_set::index::type::iterator mi = mempool.mapTx.get().begin(); + CTxMemPool::txiter iter; - TxPriorityCompare comparer(fSortedByFee); - std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); - - while (!vecPriority.empty()) + while (mi != mempool.mapTx.get().end() || !clearedTxs.empty()) { - // Take highest priority transaction off the priority queue: - double dPriority = vecPriority.front().get<0>(); - CFeeRate feeRate = vecPriority.front().get<1>(); - const CTransaction& tx = *(vecPriority.front().get<2>()); - - std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer); - vecPriority.pop_back(); - - // Size limits - unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); - if (nBlockSize + nTxSize >= nBlockMaxSize) - continue; - - // Legacy limits on sigOps: - unsigned int nTxSigOps = GetLegacySigOpCount(tx); - if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) - continue; - - // Skip free transactions if we're past the minimum block size: - const uint256& hash = tx.GetHash(); - double dPriorityDelta = 0; - CAmount nFeeDelta = 0; - mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta); - if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) - continue; - - // Prioritise by fee once past the priority size or we run out of high-priority - // transactions: - if (!fSortedByFee && - ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority))) - { - fSortedByFee = true; - comparer = TxPriorityCompare(fSortedByFee); - std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); + bool priorityTx = false; + if (fPriorityBlock && !vecPriority.empty()) { // add a tx from priority queue to fill the blockprioritysize + priorityTx = true; + iter = vecPriority.front().second; + actualPriority = vecPriority.front().first; + std::pop_heap(vecPriority.begin(), vecPriority.end(), pricomparer); + vecPriority.pop_back(); + } + else if (clearedTxs.empty()) { // add tx with next highest score + iter = mempool.mapTx.project<0>(mi); + mi++; + } + else { // try to add a previously postponed child tx + iter = clearedTxs.top(); + clearedTxs.pop(); } - if (!view.HaveInputs(tx)) + if (inBlock.count(iter)) + { + continue; // could have been added to the priorityBlock + } + + const CTransaction& tx = iter->GetTx(); + + bool fOrphan = false; + BOOST_FOREACH(CTxMemPool::txiter parent, mempool.GetMemPoolParents(iter)) + { + if (!inBlock.count(parent)) { + fOrphan = true; + break; + } + } + if (fOrphan) { + if (priorityTx) + waitPriMap.insert(std::make_pair(iter,actualPriority)); + else + waitSet.insert(iter); continue; + } - CAmount nTxFees = view.GetValueIn(tx)-tx.GetValueOut(); - - nTxSigOps += GetP2SHSigOpCount(tx, view); - if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) + unsigned int nTxSize = iter->GetTxSize(); + if (fPriorityBlock && + (nBlockSize + nTxSize >= nBlockPrioritySize || !AllowFree(actualPriority))) { + fPriorityBlock = false; + waitPriMap.clear(); + } + if (!priorityTx && + (iter->GetModifiedFee() < ::minRelayTxFee.GetFee(nTxSize) && nBlockSize >= nBlockMinSize)) { + break; + } + if (nBlockSize + nTxSize >= nBlockMaxSize) { + if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) { + break; + } + // Once we're within 1000 bytes of a full block, only look at 50 more txs + // to try to fill the remaining space. + if (nBlockSize > nBlockMaxSize - 1000) { + lastFewTxs++; + } continue; + } - // Note that flags: we don't want to set mempool/IsStandard() - // policy here, but we still have to ensure that the block we - // create only contains transactions that are valid in new blocks. - CValidationState state; - if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) + if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) continue; typedef std::vector > spentClaimsType; @@ -305,19 +240,44 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) BOOST_FOREACH(const CTxIn& txin, tx.vin) { const CCoins* coins = view.AccessCoins(txin.prevout.hash); - // This seems to happen during testing, and should never happen otherwise - if (!coins || txin.prevout.n >= coins->vout.size()) + int nTxinHeight = 0; + CScript scriptPubKey; + bool fGotCoins = false; + if (coins) { - LogPrintf("%s: !coins || txin.prevout.n >= coins->vout.size(). txin.prevout.hash = %s\n", __func__, txin.prevout.hash.GetHex()); - if (coins) - LogPrintf("coins is not null. txin.prevout.n = %d, coins->vout.size() = %d\n", txin.prevout.n, coins->vout.size()); - continue; + if (txin.prevout.n < coins->vout.size()) + { + nTxinHeight = coins->nHeight; + scriptPubKey = coins->vout[txin.prevout.n].scriptPubKey; + fGotCoins = true; + } + } + else // must be in block or else + { + BOOST_FOREACH(CTxMemPool::txiter inBlockEntry, inBlock) + { + CTransaction inBlockTx = inBlockEntry->GetTx(); + if (inBlockTx.GetHash() == txin.prevout.hash) + { + if (inBlockTx.vout.size() >= txin.prevout.n) + { + nTxinHeight = nHeight; + scriptPubKey = inBlockTx.vout[txin.prevout.n].scriptPubKey; + fGotCoins = true; + } + } + } + } + if (!fGotCoins) + { + LogPrintf("Tried to include a transaction but could not find the txout it was spending. This is bad. Please send this log file to the maintainers of this program.\n"); + throw std::runtime_error("Tried to include a transaction but could not find the txout it was spending."); } std::vector > vvchParams; int op; - if (DecodeClaimScript(coins->vout[txin.prevout.n].scriptPubKey, op, vvchParams)) + if (DecodeClaimScript(scriptPubKey, op, vvchParams)) { if (op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM) { @@ -334,7 +294,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) } std::string name(vvchParams[0].begin(), vvchParams[0].end()); int throwaway; - if (trieCache.spendClaim(name, COutPoint(txin.prevout.hash, txin.prevout.n), coins->nHeight, throwaway)) + if (trieCache.spendClaim(name, COutPoint(txin.prevout.hash, txin.prevout.n), nTxinHeight, throwaway)) { std::pair entry(name, claimId); spentClaims.push_back(entry); @@ -349,7 +309,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) assert(vvchParams.size() == 2); std::string name(vvchParams[0].begin(), vvchParams[0].end()); int throwaway; - if (!trieCache.spendSupport(name, COutPoint(txin.prevout.hash, txin.prevout.n), coins->nHeight, throwaway)) + if (!trieCache.spendSupport(name, COutPoint(txin.prevout.hash, txin.prevout.n), nTxinHeight, throwaway)) { LogPrintf("%s(): The support was not found in the trie or queue\n", __func__); } @@ -357,8 +317,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) } } - UpdateCoins(tx, state, view, nHeight); - for (unsigned int i = 0; i < tx.vout.size(); ++i) { const CTxOut& txout = tx.vout[i]; @@ -414,7 +372,17 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) } } } + CValidationState state; + unsigned int nTxSigOps = iter->GetSigOpCount(); + if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) { + if (nBlockSigOps > MAX_BLOCK_SIGOPS - 2) { + break; + } + continue; + } + + CAmount nTxFees = iter->GetFee(); // Added pblock->vtx.push_back(tx); pblocktemplate->vTxFees.push_back(nTxFees); @@ -426,31 +394,37 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if (fPrintPriority) { + double dPriority = iter->GetPriority(nHeight); + CAmount dummy; + mempool.ApplyDeltas(tx.GetHash(), dPriority, dummy); LogPrintf("priority %.1f fee %s txid %s\n", - dPriority, feeRate.ToString(), tx.GetHash().ToString()); + dPriority , CFeeRate(iter->GetModifiedFee(), nTxSize).ToString(), tx.GetHash().ToString()); } + inBlock.insert(iter); + // Add transactions that depend on this one to the priority queue - if (mapDependers.count(hash)) + BOOST_FOREACH(CTxMemPool::txiter child, mempool.GetMemPoolChildren(iter)) { - BOOST_FOREACH(COrphan* porphan, mapDependers[hash]) - { - if (!porphan->setDependsOn.empty()) - { - porphan->setDependsOn.erase(hash); - if (porphan->setDependsOn.empty()) - { - vecPriority.push_back(TxPriority(porphan->dPriority, porphan->feeRate, porphan->ptx)); - std::push_heap(vecPriority.begin(), vecPriority.end(), comparer); - } + if (fPriorityBlock) { + waitPriIter wpiter = waitPriMap.find(child); + if (wpiter != waitPriMap.end()) { + vecPriority.push_back(TxCoinAgePriority(wpiter->second,child)); + std::push_heap(vecPriority.begin(), vecPriority.end(), pricomparer); + waitPriMap.erase(wpiter); + } + } + else { + if (waitSet.count(child)) { + clearedTxs.push(child); + waitSet.erase(child); } } } } - nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; - LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); + LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOps); // Compute final coinbase transaction. txNew.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus()); @@ -460,8 +434,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - UpdateTime(pblock, Params().GetConsensus(), pindexPrev); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); + UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); insertUndoType dummyInsertUndo; @@ -473,8 +447,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) pblock->hashClaimTrie = trieCache.getMerkleHash(); CValidationState state; - if (!TestBlockValidity(state, *pblock, pindexPrev, false, false)) - throw std::runtime_error("CreateNewBlock(): TestBlockValidity failed"); + if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { + throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); + } } return pblocktemplate.release(); @@ -496,7 +471,7 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned assert(txCoinbase.vin[0].scriptSig.size() <= 100); pblock->vtx[0] = txCoinbase; - pblock->hashMerkleRoot = pblock->ComputeMerkleRoot(); + pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); } ////////////////////////////////////////////////////////////////////////////// @@ -521,7 +496,7 @@ static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainpar // Process this block the same as if we had received it from another node CValidationState state; - if (!ProcessNewBlock(state, NULL, pblock, true, NULL)) + if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) return error("BitcoinMiner: ProcessNewBlock, block not accepted"); return true; @@ -567,7 +542,7 @@ void static BitcoinMiner(const CChainParams& chainparams) unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrev = chainActive.Tip(); - auto_ptr pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); + auto_ptr pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript)); if (!pblocktemplate.get()) { LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n"); diff --git a/src/miner.h b/src/miner.h index 7e0e58d54..512494198 100644 --- a/src/miner.h +++ b/src/miner.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -17,6 +17,11 @@ class CScript; class CWallet; namespace Consensus { struct Params; }; +static const bool DEFAULT_GENERATE = false; +static const int DEFAULT_GENERATE_THREADS = 1; + +static const bool DEFAULT_PRINTPRIORITY = false; + struct CBlockTemplate { CBlock block; @@ -27,7 +32,7 @@ struct CBlockTemplate /** Run the miner threads */ void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams); /** Generate a new block, without valid proof-of-work */ -CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); +CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn); /** Modify the extranonce in a block */ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce); int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); diff --git a/src/mruset.h b/src/mruset.h deleted file mode 100644 index 398aa173b..000000000 --- a/src/mruset.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2012-2015 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_MRUSET_H -#define BITCOIN_MRUSET_H - -#include -#include -#include - -/** STL-like set container that only keeps the most recent N elements. */ -template -class mruset -{ -public: - typedef T key_type; - typedef T value_type; - typedef typename std::set::iterator iterator; - typedef typename std::set::const_iterator const_iterator; - typedef typename std::set::size_type size_type; - -protected: - std::set set; - std::vector order; - size_type first_used; - size_type first_unused; - const size_type nMaxSize; - -public: - mruset(size_type nMaxSizeIn = 1) : nMaxSize(nMaxSizeIn) { clear(); } - iterator begin() const { return set.begin(); } - iterator end() const { return set.end(); } - size_type size() const { return set.size(); } - bool empty() const { return set.empty(); } - iterator find(const key_type& k) const { return set.find(k); } - size_type count(const key_type& k) const { return set.count(k); } - void clear() - { - set.clear(); - order.assign(nMaxSize, set.end()); - first_used = 0; - first_unused = 0; - } - bool inline friend operator==(const mruset& a, const mruset& b) { return a.set == b.set; } - bool inline friend operator==(const mruset& a, const std::set& b) { return a.set == b; } - bool inline friend operator<(const mruset& a, const mruset& b) { return a.set < b.set; } - std::pair insert(const key_type& x) - { - std::pair ret = set.insert(x); - if (ret.second) { - if (set.size() == nMaxSize + 1) { - set.erase(order[first_used]); - order[first_used] = set.end(); - if (++first_used == nMaxSize) first_used = 0; - } - order[first_unused] = ret.first; - if (++first_unused == nMaxSize) first_unused = 0; - } - return ret; - } - size_type max_size() const { return nMaxSize; } -}; - -#endif // BITCOIN_MRUSET_H diff --git a/src/net.cpp b/src/net.cpp index 127d09c6f..0cf876170 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,6 +12,7 @@ #include "addrman.h" #include "chainparams.h" #include "clientversion.h" +#include "consensus/consensus.h" #include "crypto/common.h" #include "hash.h" #include "primitives/transaction.h" @@ -35,7 +36,9 @@ #include #include -// Dump addresses to peers.dat every 15 minutes (900s) +#include + +// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s) #define DUMP_ADDRESSES_INTERVAL 900 #if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) @@ -66,6 +69,8 @@ namespace { }; } +const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; + // // Global state variables // @@ -74,7 +79,6 @@ bool fListen = true; uint64_t nLocalServices = NODE_NETWORK; CCriticalSection cs_mapLocalHost; map mapLocalHost; -static bool vfReachable[NET_MAX] = {}; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; uint64_t nLocalHostNonce = 0; @@ -86,10 +90,10 @@ std::string strSubVersion; vector vNodes; CCriticalSection cs_vNodes; -map mapRelay; -deque > vRelayExpiration; +map mapRelay; +deque > vRelayExpiration; CCriticalSection cs_mapRelay; -limitedmap mapAlreadyAskedFor(MAX_INV_SZ); +limitedmap mapAlreadyAskedFor(MAX_INV_SZ); static deque vOneShots; CCriticalSection cs_vOneShots; @@ -200,7 +204,7 @@ bool IsPeerAddrLocalGood(CNode *pnode) } // pushes our own address to a peer -void AdvertizeLocal(CNode *pnode) +void AdvertiseLocal(CNode *pnode) { if (fListen && pnode->fSuccessfullyConnected) { @@ -215,19 +219,12 @@ void AdvertizeLocal(CNode *pnode) } if (addrLocal.IsRoutable()) { + LogPrintf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString()); pnode->PushAddress(addrLocal); } } } -void SetReachable(enum Network net, bool fFlag) -{ - LOCK(cs_mapLocalHost); - vfReachable[net] = fFlag; - if (net == NET_IPV6 && fFlag) - vfReachable[NET_IPV4] = true; -} - // learn a new local address bool AddLocal(const CService& addr, int nScore) { @@ -250,7 +247,6 @@ bool AddLocal(const CService& addr, int nScore) info.nScore = nScore + (fAlready ? 1 : 0); info.nPort = addr.GetPort(); } - SetReachable(addr.GetNetwork()); } return true; @@ -261,6 +257,14 @@ bool AddLocal(const CNetAddr &addr, int nScore) return AddLocal(CService(addr, GetListenPort()), nScore); } +bool RemoveLocal(const CService& addr) +{ + LOCK(cs_mapLocalHost); + LogPrintf("RemoveLocal(%s)\n", addr.ToString()); + mapLocalHost.erase(addr); + return true; +} + /** Make a particular network entirely off-limits (no automatic connects to it) */ void SetLimited(enum Network net, bool fLimited) { @@ -305,7 +309,7 @@ bool IsLocal(const CService& addr) bool IsReachable(enum Network net) { LOCK(cs_mapLocalHost); - return vfReachable[net] && !vfLimited[net]; + return !vfLimited[net]; } /** check whether a given address is in a network we can probably connect to */ @@ -326,6 +330,11 @@ uint64_t CNode::nTotalBytesSent = 0; CCriticalSection CNode::cs_totalBytesRecv; CCriticalSection CNode::cs_totalBytesSent; +uint64_t CNode::nMaxOutboundLimit = 0; +uint64_t CNode::nMaxOutboundTotalBytesSentInCycle = 0; +uint64_t CNode::nMaxOutboundTimeframe = 60*60*24; //1 day +uint64_t CNode::nMaxOutboundCycleStartTime = 0; + CNode* FindNode(const CNetAddr& ip) { LOCK(cs_vNodes); @@ -444,8 +453,8 @@ void CNode::PushVersion() LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id); else LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); - PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, strSubVersion, nBestHeight, true); + PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, + nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)); } @@ -506,12 +515,11 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti banEntry.banReason = banReason; if (bantimeoffset <= 0) { - bantimeoffset = GetArg("-bantime", 60*60*24); // Default 24-hour ban + bantimeoffset = GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME); sinceUnixEpoch = false; } banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset; - LOCK(cs_setBanned); if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) setBanned[subNet] = banEntry; @@ -555,11 +563,13 @@ void CNode::SweepBanned() banmap_t::iterator it = setBanned.begin(); while(it != setBanned.end()) { + CSubNet subNet = (*it).first; CBanEntry banEntry = (*it).second; if(now > banEntry.nBanUntil) { setBanned.erase(it++); setBannedIsDirty = true; + LogPrint("net", "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString()); } else ++it; @@ -602,6 +612,7 @@ void CNode::copyStats(CNodeStats &stats) { stats.nodeid = this->GetId(); X(nServices); + X(fRelayTxes); X(nLastSend); X(nLastRecv); X(nTimeConnected); @@ -612,7 +623,9 @@ void CNode::copyStats(CNodeStats &stats) X(fInbound); X(nStartingHeight); X(nSendBytes); + X(mapSendBytesPerMsgCmd); X(nRecvBytes); + X(mapRecvBytesPerMsgCmd); X(fWhitelisted); // It is common for nodes with good ping times to suddenly become lagged, @@ -667,6 +680,15 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes) nBytes -= handled; if (msg.complete()) { + + //store received bytes per message command + //to prevent a memory DOS, only allow valid commands + mapMsgCmdSize::iterator i = mapRecvBytesPerMsgCmd.find(msg.hdr.pchCommand); + if (i == mapRecvBytesPerMsgCmd.end()) + i = mapRecvBytesPerMsgCmd.find(NET_MESSAGE_COMMAND_OTHER); + assert(i != mapRecvBytesPerMsgCmd.end()); + i->second += msg.hdr.nMessageSize + CMessageHeader::HEADER_SIZE; + msg.nTime = GetTimeMicros(); messageHandlerCondition.notify_one(); } @@ -867,8 +889,6 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { continue; if (node->fDisconnect) continue; - if (node->addr.IsLocal()) - continue; vEvictionCandidates.push_back(CNodeRef(node)); } } @@ -899,15 +919,20 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { if (vEvictionCandidates.empty()) return false; - // Identify the network group with the most connections + // Identify the network group with the most connections and youngest member. + // (vEvictionCandidates is already sorted by reverse connect time) std::vector naMostConnections; unsigned int nMostConnections = 0; + int64_t nMostConnectionsTime = 0; std::map, std::vector > mapAddrCounts; BOOST_FOREACH(const CNodeRef &node, vEvictionCandidates) { mapAddrCounts[node->addr.GetGroup()].push_back(node); + int64_t grouptime = mapAddrCounts[node->addr.GetGroup()][0]->nTimeConnected; + size_t groupsize = mapAddrCounts[node->addr.GetGroup()].size(); - if (mapAddrCounts[node->addr.GetGroup()].size() > nMostConnections) { - nMostConnections = mapAddrCounts[node->addr.GetGroup()].size(); + if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) { + nMostConnections = groupsize; + nMostConnectionsTime = grouptime; naMostConnections = node->addr.GetGroup(); } } @@ -915,14 +940,13 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { // Reduce to the network group with the most connections vEvictionCandidates = mapAddrCounts[naMostConnections]; - // Do not disconnect peers if there is only 1 connection from their network group + // Do not disconnect peers if there is only one unprotected connection from their network group. if (vEvictionCandidates.size() <= 1) // unless we prefer the new connection (for whitelisted peers) if (!fPreferNewConnection) return false; - // Disconnect the most recent connection from the network group with the most connections - std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected); + // Disconnect from the network group with the most connections vEvictionCandidates[0]->fDisconnect = true; return true; @@ -963,6 +987,15 @@ static void AcceptConnection(const ListenSocket& hListenSocket) { return; } + // According to the internet TCP_NODELAY is not carried into accepted sockets + // on all platforms. Set it again here just to be sure. + int set = 1; +#ifdef WIN32 + setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int)); +#else + setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int)); +#endif + if (CNode::IsBanned(addr) && !whitelisted) { LogPrintf("connection from %s dropped (banned)\n", addr.ToString()); @@ -1331,7 +1364,7 @@ void ThreadMapPort() LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", port, port, lanaddr, r, strupnperror(r)); else - LogPrintf("UPnP Port Mapping successful.\n");; + LogPrintf("UPnP Port Mapping successful.\n"); MilliSleep(20*60*1000); // Refresh every 20 minutes } @@ -1389,7 +1422,7 @@ void ThreadDNSAddressSeed() { // goal: only query DNS seeds if address need is acute if ((addrman.size() > 0) && - (!GetBoolArg("-forcednsseed", false))) { + (!GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED))) { MilliSleep(11 * 1000); LOCK(cs_vNodes); @@ -1453,12 +1486,7 @@ void DumpAddresses() void DumpData() { DumpAddresses(); - - if (CNode::BannedSetIsDirty()) - { - DumpBanlist(); - CNode::SetBannedSetDirty(false); - } + DumpBanlist(); } void static ProcessOneShot() @@ -1696,11 +1724,6 @@ void ThreadMessageHandler() } } - // Poll the connected nodes for messages - CNode* pnodeTrickle = NULL; - if (!vNodesCopy.empty()) - pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())]; - bool fSleep = true; BOOST_FOREACH(CNode* pnode, vNodesCopy) @@ -1731,7 +1754,7 @@ void ThreadMessageHandler() { TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) - g_signals.SendMessages(pnode, pnode == pnodeTrickle || pnode->fWhitelisted); + g_signals.SendMessages(pnode); } boost::this_thread::interruption_point(); } @@ -1790,8 +1813,11 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste // Allow binding if the port is still in TIME_WAIT state after // the program was closed and restarted. setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)); + // Disable Nagle's algorithm + setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&nOne, sizeof(int)); #else setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOne, sizeof(int)); + setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&nOne, sizeof(int)); #endif // Set to non-blocking, incoming connections will also inherit this @@ -1821,7 +1847,7 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste { int nErr = WSAGetLastError(); if (nErr == WSAEADDRINUSE) - strError = strprintf(_("Unable to bind to %s on this computer. LBRYcrd Core is probably already running."), addrBind.ToString()); + strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToString(), _(PACKAGE_NAME)); else strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr)); LogPrintf("%s\n", strError); @@ -1901,31 +1927,41 @@ void static Discover(boost::thread_group& threadGroup) void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) { uiInterface.InitMessage(_("Loading addresses...")); - // Load addresses for peers.dat + // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); { CAddrDB adb; - if (!adb.Read(addrman)) + if (adb.Read(addrman)) + LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart); + else { LogPrintf("Invalid or missing peers.dat; recreating\n"); + DumpAddresses(); + } } - //try to read stored banlist + uiInterface.InitMessage(_("Loading banlist...")); + // Load addresses from banlist.dat + nStart = GetTimeMillis(); CBanDB bandb; banmap_t banmap; - if (!bandb.Read(banmap)) + if (bandb.Read(banmap)) { + CNode::SetBanned(banmap); // thread save setter + CNode::SetBannedSetDirty(false); // no need to write down, just read data + CNode::SweepBanned(); // sweep out unused entries + + LogPrint("net", "Loaded %d banned node ips/subnets from banlist.dat %dms\n", + banmap.size(), GetTimeMillis() - nStart); + } else { LogPrintf("Invalid or missing banlist.dat; recreating\n"); + CNode::SetBannedSetDirty(true); // force write + DumpBanlist(); + } - CNode::SetBanned(banmap); //thread save setter - CNode::SetBannedSetDirty(false); //no need to write down just read or nonexistent data - CNode::SweepBanned(); //sweap out unused entries - - LogPrintf("Loaded %i addresses from peers.dat %dms\n", - addrman.size(), GetTimeMillis() - nStart); fAddressesInitialized = true; if (semOutbound == NULL) { // initialize semaphore - int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); + int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); semOutbound = new CSemaphore(nMaxOutbound); } @@ -2017,20 +2053,7 @@ public: instance_of_cnetcleanup; - - - - - -void RelayTransaction(const CTransaction& tx) -{ - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss.reserve(10000); - ss << tx; - RelayTransaction(tx, ss); -} - -void RelayTransaction(const CTransaction& tx, const CDataStream& ss) +void RelayTransaction(const CTransaction& tx, CFeeRate feerate) { CInv inv(MSG_TX, tx.GetHash()); { @@ -2042,15 +2065,19 @@ void RelayTransaction(const CTransaction& tx, const CDataStream& ss) vRelayExpiration.pop_front(); } - // Save original serialized message so newer versions are preserved - mapRelay.insert(std::make_pair(inv, ss)); - vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv)); + mapRelay.insert(std::make_pair(inv.hash, tx)); + vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv.hash)); } LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { if(!pnode->fRelayTxes) continue; + { + LOCK(pnode->cs_feeFilter); + if (feerate.GetFeePerK() < pnode->minFeeFilter) + continue; + } LOCK(pnode->cs_filter); if (pnode->pfilter) { @@ -2071,6 +2098,94 @@ void CNode::RecordBytesSent(uint64_t bytes) { LOCK(cs_totalBytesSent); nTotalBytesSent += bytes; + + uint64_t now = GetTime(); + if (nMaxOutboundCycleStartTime + nMaxOutboundTimeframe < now) + { + // timeframe expired, reset cycle + nMaxOutboundCycleStartTime = now; + nMaxOutboundTotalBytesSentInCycle = 0; + } + + // TODO, exclude whitebind peers + nMaxOutboundTotalBytesSentInCycle += bytes; +} + +void CNode::SetMaxOutboundTarget(uint64_t limit) +{ + LOCK(cs_totalBytesSent); + uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SIZE; + nMaxOutboundLimit = limit; + + if (limit > 0 && limit < recommendedMinimum) + LogPrintf("Max outbound target is very small (%s bytes) and will be overshot. Recommended minimum is %s bytes.\n", nMaxOutboundLimit, recommendedMinimum); +} + +uint64_t CNode::GetMaxOutboundTarget() +{ + LOCK(cs_totalBytesSent); + return nMaxOutboundLimit; +} + +uint64_t CNode::GetMaxOutboundTimeframe() +{ + LOCK(cs_totalBytesSent); + return nMaxOutboundTimeframe; +} + +uint64_t CNode::GetMaxOutboundTimeLeftInCycle() +{ + LOCK(cs_totalBytesSent); + if (nMaxOutboundLimit == 0) + return 0; + + if (nMaxOutboundCycleStartTime == 0) + return nMaxOutboundTimeframe; + + uint64_t cycleEndTime = nMaxOutboundCycleStartTime + nMaxOutboundTimeframe; + uint64_t now = GetTime(); + return (cycleEndTime < now) ? 0 : cycleEndTime - GetTime(); +} + +void CNode::SetMaxOutboundTimeframe(uint64_t timeframe) +{ + LOCK(cs_totalBytesSent); + if (nMaxOutboundTimeframe != timeframe) + { + // reset measure-cycle in case of changing + // the timeframe + nMaxOutboundCycleStartTime = GetTime(); + } + nMaxOutboundTimeframe = timeframe; +} + +bool CNode::OutboundTargetReached(bool historicalBlockServingLimit) +{ + LOCK(cs_totalBytesSent); + if (nMaxOutboundLimit == 0) + return false; + + if (historicalBlockServingLimit) + { + // keep a large enough buffer to at least relay each block once + uint64_t timeLeftInCycle = GetMaxOutboundTimeLeftInCycle(); + uint64_t buffer = timeLeftInCycle / 600 * MAX_BLOCK_SIZE; + if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer) + return true; + } + else if (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) + return true; + + return false; +} + +uint64_t CNode::GetOutboundTargetBytesLeft() +{ + LOCK(cs_totalBytesSent); + if (nMaxOutboundLimit == 0) + return 0; + + return (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle; } uint64_t CNode::GetTotalBytesRecv() @@ -2221,13 +2336,13 @@ bool CAddrDB::Read(CAddrMan& addr) return true; } -unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } -unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); } +unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); } +unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); } CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addrKnown(5000, 0.001), - setInventoryKnown(SendBufferSize() / 1000) + filterInventoryKnown(50000, 0.000001) { nServices = 0; hSocket = hSocketIn; @@ -2254,14 +2369,26 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa nSendOffset = 0; hashContinue = uint256(); nStartingHeight = -1; + filterInventoryKnown.reset(); fGetAddr = false; + nNextLocalAddrSend = 0; + nNextAddrSend = 0; + nNextInvSend = 0; fRelayTxes = false; + fSentAddr = false; pfilter = new CBloomFilter(); nPingNonceSent = 0; nPingUsecStart = 0; nPingUsecTime = 0; fPingQueued = false; nMinPingUsecTime = std::numeric_limits::max(); + minFeeFilter = 0; + lastSentFeeFilter = 0; + nextSendTimeFeeFilter = 0; + + BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) + mapRecvBytesPerMsgCmd[msg] = 0; + mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0; { LOCK(cs_nLastNodeId); @@ -2292,12 +2419,16 @@ CNode::~CNode() void CNode::AskFor(const CInv& inv) { - if (mapAskFor.size() > MAPASKFOR_MAX_SZ) + if (mapAskFor.size() > MAPASKFOR_MAX_SZ || setAskFor.size() > SETASKFOR_MAX_SZ) return; + // a peer may not have multiple non-responded queue positions for a single inv item + if (!setAskFor.insert(inv.hash).second) + return; + // We're using mapAskFor as a priority queue, // the key is the earliest time the request can be sent int64_t nRequestTime; - limitedmap::const_iterator it = mapAlreadyAskedFor.find(inv); + limitedmap::const_iterator it = mapAlreadyAskedFor.find(inv.hash); if (it != mapAlreadyAskedFor.end()) nRequestTime = it->second; else @@ -2316,7 +2447,7 @@ void CNode::AskFor(const CInv& inv) if (it != mapAlreadyAskedFor.end()) mapAlreadyAskedFor.update(it, nRequestTime); else - mapAlreadyAskedFor.insert(std::make_pair(inv, nRequestTime)); + mapAlreadyAskedFor.insert(std::make_pair(inv.hash, nRequestTime)); mapAskFor.insert(std::make_pair(nRequestTime, inv)); } @@ -2337,7 +2468,7 @@ void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend) LogPrint("net", "(aborted)\n"); } -void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend) +void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend) { // The -*messagestest options are intentionally not documented in the help message, // since they are only used during development to debug the networking code and are @@ -2360,6 +2491,9 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend) unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE; WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize); + //log total amount of bytes per command + mapSendBytesPerMsgCmd[std::string(pszCommand)] += nSize + CMessageHeader::HEADER_SIZE; + // Set the checksum uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end()); unsigned int nChecksum = 0; @@ -2470,28 +2604,36 @@ bool CBanDB::Read(banmap_t& banSet) // ... verify the network matches ours if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) return error("%s: Invalid network magic number", __func__); - + // de-serialize address data into one CAddrMan object ssBanlist >> banSet; } catch (const std::exception& e) { return error("%s: Deserialize or I/O error - %s", __func__, e.what()); } - + return true; } void DumpBanlist() { - int64_t nStart = GetTimeMillis(); + CNode::SweepBanned(); // clean unused entries (if bantime has expired) - CNode::SweepBanned(); //clean unused entries (if bantime has expired) + if (!CNode::BannedSetIsDirty()) + return; + + int64_t nStart = GetTimeMillis(); CBanDB bandb; banmap_t banmap; CNode::GetBanned(banmap); - bandb.Write(banmap); + if (bandb.Write(banmap)) + CNode::SetBannedSetDirty(false); LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", - banmap.size(), GetTimeMillis() - nStart); + banmap.size(), GetTimeMillis() - nStart); +} + +int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { + return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } diff --git a/src/net.h b/src/net.h index 6842ee5ed..bf367684f 100644 --- a/src/net.h +++ b/src/net.h @@ -1,15 +1,15 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_NET_H #define BITCOIN_NET_H +#include "amount.h" #include "bloom.h" #include "compat.h" #include "limitedmap.h" -#include "mruset.h" #include "netbase.h" #include "protocol.h" #include "random.h" @@ -58,8 +58,21 @@ static const bool DEFAULT_UPNP = false; #endif /** The maximum number of entries in mapAskFor */ static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ; +/** The maximum number of entries in setAskFor (larger due to getdata latency)*/ +static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ; /** The maximum number of peer connections to maintain. */ static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125; +/** The default for -maxuploadtarget. 0 = Unlimited */ +static const uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0; +/** Default for blocks only*/ +static const bool DEFAULT_BLOCKSONLY = false; + +static const bool DEFAULT_FORCEDNSSEED = false; +static const size_t DEFAULT_MAXRECEIVEBUFFER = 5 * 1000; +static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000; + +// NOTE: When adjusting this, update rpcnet:setban's help ("24h") +static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban unsigned int ReceiveFloodSize(); unsigned int SendBufferSize(); @@ -101,7 +114,7 @@ struct CNodeSignals { boost::signals2::signal GetHeight; boost::signals2::signal ProcessMessages; - boost::signals2::signal SendMessages; + boost::signals2::signal SendMessages; boost::signals2::signal InitializeNode; boost::signals2::signal FinalizeNode; }; @@ -122,18 +135,18 @@ enum }; bool IsPeerAddrLocalGood(CNode *pnode); -void AdvertizeLocal(CNode *pnode); +void AdvertiseLocal(CNode *pnode); void SetLimited(enum Network net, bool fLimited = true); bool IsLimited(enum Network net); bool IsLimited(const CNetAddr& addr); bool AddLocal(const CService& addr, int nScore = LOCAL_NONE); bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE); +bool RemoveLocal(const CService& addr); bool SeenLocal(const CService& addr); bool IsLocal(const CService& addr); bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL); bool IsReachable(enum Network net); bool IsReachable(const CNetAddr &addr); -void SetReachable(enum Network net, bool fFlag = true); CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL); @@ -148,10 +161,10 @@ extern int nMaxConnections; extern std::vector vNodes; extern CCriticalSection cs_vNodes; -extern std::map mapRelay; -extern std::deque > vRelayExpiration; +extern std::map mapRelay; +extern std::deque > vRelayExpiration; extern CCriticalSection cs_mapRelay; -extern limitedmap mapAlreadyAskedFor; +extern limitedmap mapAlreadyAskedFor; extern std::vector vAddedNodes; extern CCriticalSection cs_vAddedNodes; @@ -169,12 +182,14 @@ struct LocalServiceInfo { extern CCriticalSection cs_mapLocalHost; extern std::map mapLocalHost; +typedef std::map mapMsgCmdSize; //command, total bytes class CNodeStats { public: NodeId nodeid; uint64_t nServices; + bool fRelayTxes; int64_t nLastSend; int64_t nLastRecv; int64_t nTimeConnected; @@ -185,7 +200,9 @@ public: bool fInbound; int nStartingHeight; uint64_t nSendBytes; + mapMsgCmdSize mapSendBytesPerMsgCmd; uint64_t nRecvBytes; + mapMsgCmdSize mapRecvBytesPerMsgCmd; bool fWhitelisted; double dPingTime; double dPingWait; @@ -285,7 +302,7 @@ public: { switch (banReason) { case BanReasonNodeMisbehaving: - return "node misbehabing"; + return "node misbehaving"; case BanReasonManuallyAdded: return "manually added"; default: @@ -339,8 +356,9 @@ public: // We use fRelayTxes for two purposes - // a) it allows us to not relay tx invs before receiving the peer's version message // b) the peer may tell us in its version message that we should not relay tx invs - // until it has initialized its bloom filter. + // unless it loads a bloom filter. bool fRelayTxes; + bool fSentAddr; CSemaphoreGrant grantOutbound; CCriticalSection cs_filter; CBloomFilter* pfilter; @@ -359,6 +377,9 @@ protected: static std::vector vWhitelistedRange; static CCriticalSection cs_vWhitelistedRange; + mapMsgCmdSize mapSendBytesPerMsgCmd; + mapMsgCmdSize mapRecvBytesPerMsgCmd; + // Basic fuzz-testing void Fuzz(int nChance); // modifies ssSend @@ -371,12 +392,19 @@ public: CRollingBloomFilter addrKnown; bool fGetAddr; std::set setKnown; + int64_t nNextAddrSend; + int64_t nNextLocalAddrSend; // inventory based relay - mruset setInventoryKnown; + CRollingBloomFilter filterInventoryKnown; std::vector vInventoryToSend; CCriticalSection cs_inventory; + std::set setAskFor; std::multimap mapAskFor; + int64_t nNextInvSend; + // Used for headers announcements - unfiltered blocks to relay + // Also protected by cs_inventory + std::vector vBlockHashesToAnnounce; // Ping time measurement: // The pong reply we're expecting, or 0 if no pong expected. @@ -389,6 +417,11 @@ public: int64_t nMinPingUsecTime; // Whether a ping is requested. bool fPingQueued; + // Minimum fee rate with which to filter inv's to this node + CAmount minFeeFilter; + CCriticalSection cs_feeFilter; + CAmount lastSentFeeFilter; + int64_t nextSendTimeFeeFilter; CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false); ~CNode(); @@ -400,6 +433,12 @@ private: static uint64_t nTotalBytesRecv; static uint64_t nTotalBytesSent; + // outbound limit & stats + static uint64_t nMaxOutboundTotalBytesSentInCycle; + static uint64_t nMaxOutboundCycleStartTime; + static uint64_t nMaxOutboundLimit; + static uint64_t nMaxOutboundTimeframe; + CNode(const CNode&); void operator=(const CNode&); @@ -472,7 +511,7 @@ public: { { LOCK(cs_inventory); - setInventoryKnown.insert(inv); + filterInventoryKnown.insert(inv.hash); } } @@ -480,11 +519,18 @@ public: { { LOCK(cs_inventory); - if (!setInventoryKnown.count(inv)) - vInventoryToSend.push_back(inv); + if (inv.type == MSG_TX && filterInventoryKnown.contains(inv.hash)) + return; + vInventoryToSend.push_back(inv); } } + void PushBlockHash(const uint256 &hash) + { + LOCK(cs_inventory); + vBlockHashesToAnnounce.push_back(hash); + } + void AskFor(const CInv& inv); // TODO: Document the postcondition of this function. Is cs_vSend locked? @@ -494,7 +540,7 @@ public: void AbortMessage() UNLOCK_FUNCTION(cs_vSend); // TODO: Document the precondition of this function. Is cs_vSend locked? - void EndMessage() UNLOCK_FUNCTION(cs_vSend); + void EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend); void PushVersion(); @@ -504,7 +550,7 @@ public: try { BeginMessage(pszCommand); - EndMessage(); + EndMessage(pszCommand); } catch (...) { @@ -520,7 +566,7 @@ public: { BeginMessage(pszCommand); ssSend << a1; - EndMessage(); + EndMessage(pszCommand); } catch (...) { @@ -536,7 +582,7 @@ public: { BeginMessage(pszCommand); ssSend << a1 << a2; - EndMessage(); + EndMessage(pszCommand); } catch (...) { @@ -552,7 +598,7 @@ public: { BeginMessage(pszCommand); ssSend << a1 << a2 << a3; - EndMessage(); + EndMessage(pszCommand); } catch (...) { @@ -568,7 +614,7 @@ public: { BeginMessage(pszCommand); ssSend << a1 << a2 << a3 << a4; - EndMessage(); + EndMessage(pszCommand); } catch (...) { @@ -584,7 +630,7 @@ public: { BeginMessage(pszCommand); ssSend << a1 << a2 << a3 << a4 << a5; - EndMessage(); + EndMessage(pszCommand); } catch (...) { @@ -600,7 +646,7 @@ public: { BeginMessage(pszCommand); ssSend << a1 << a2 << a3 << a4 << a5 << a6; - EndMessage(); + EndMessage(pszCommand); } catch (...) { @@ -616,7 +662,7 @@ public: { BeginMessage(pszCommand); ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7; - EndMessage(); + EndMessage(pszCommand); } catch (...) { @@ -632,7 +678,7 @@ public: { BeginMessage(pszCommand); ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8; - EndMessage(); + EndMessage(pszCommand); } catch (...) { @@ -648,7 +694,7 @@ public: { BeginMessage(pszCommand); ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9; - EndMessage(); + EndMessage(pszCommand); } catch (...) { @@ -701,13 +747,33 @@ public: static uint64_t GetTotalBytesRecv(); static uint64_t GetTotalBytesSent(); + + //!set the max outbound target in bytes + static void SetMaxOutboundTarget(uint64_t limit); + static uint64_t GetMaxOutboundTarget(); + + //!set the timeframe for the max outbound target + static void SetMaxOutboundTimeframe(uint64_t timeframe); + static uint64_t GetMaxOutboundTimeframe(); + + //!check if the outbound target is reached + // if param historicalBlockServingLimit is set true, the function will + // response true if the limit for serving historical blocks has been reached + static bool OutboundTargetReached(bool historicalBlockServingLimit); + + //!response the bytes left in the current max outbound cycle + // in case of no limit, it will always response 0 + static uint64_t GetOutboundTargetBytesLeft(); + + //!response the time in second left in the current max outbound cycle + // in case of no limit, it will always response 0 + static uint64_t GetMaxOutboundTimeLeftInCycle(); }; class CTransaction; -void RelayTransaction(const CTransaction& tx); -void RelayTransaction(const CTransaction& tx, const CDataStream& ss); +void RelayTransaction(const CTransaction& tx, CFeeRate feerate); /** Access to the (IP) address database (peers.dat) */ class CAddrDB @@ -733,4 +799,7 @@ public: void DumpBanlist(); +/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */ +int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds); + #endif // BITCOIN_NET_H diff --git a/src/netbase.cpp b/src/netbase.cpp index c3d56d918..281c6bcb7 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -40,7 +40,7 @@ static proxyType proxyInfo[NET_MAX]; static proxyType nameProxy; static CCriticalSection cs_proxyInfos; int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; -bool fNameLookup = false; +bool fNameLookup = DEFAULT_NAME_LOOKUP; static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; @@ -140,7 +140,7 @@ bool static LookupIntern(const char *pszName, std::vector& vIP, unsign return false; do { - // Should set the timeout limit to a resonable value to avoid + // Should set the timeout limit to a reasonable value to avoid // generating unnecessary checking call during the polling loop, // while it can still response to stop request quick enough. // 2 seconds looks fine in our situation. @@ -170,7 +170,8 @@ bool static LookupIntern(const char *pszName, std::vector& vIP, unsign if (aiTrav->ai_family == AF_INET6) { assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6)); - vIP.push_back(CNetAddr(((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr)); + struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr; + vIP.push_back(CNetAddr(s6->sin6_addr, s6->sin6_scope_id)); } aiTrav = aiTrav->ai_next; @@ -227,10 +228,7 @@ bool LookupNumeric(const char *pszName, CService& addr, int portDefault) return Lookup(pszName, addr, portDefault, false); } -/** - * Convert milliseconds to a struct timeval for select. - */ -struct timeval static MillisToTimeval(int64_t nTimeout) +struct timeval MillisToTimeval(int64_t nTimeout) { struct timeval timeout; timeout.tv_sec = nTimeout / 1000; @@ -444,12 +442,19 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe if (hSocket == INVALID_SOCKET) return false; -#ifdef SO_NOSIGPIPE int set = 1; +#ifdef SO_NOSIGPIPE // Different way of disabling SIGPIPE on BSD setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)); #endif + //Disable Nagle's algorithm +#ifdef WIN32 + setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int)); +#else + setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int)); +#endif + // Set to non-blocking if (!SetSocketNonBlocking(hSocket, true)) return error("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError())); @@ -625,6 +630,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest void CNetAddr::Init() { memset(ip, 0, sizeof(ip)); + scopeId = 0; } void CNetAddr::SetIP(const CNetAddr& ipIn) @@ -674,9 +680,10 @@ CNetAddr::CNetAddr(const struct in_addr& ipv4Addr) SetRaw(NET_IPV4, (const uint8_t*)&ipv4Addr); } -CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr) +CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr, const uint32_t scope) { SetRaw(NET_IPV6, (const uint8_t*)&ipv6Addr); + scopeId = scope; } CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup) @@ -1095,7 +1102,7 @@ CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), po assert(addr.sin_family == AF_INET); } -CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port)) +CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr, addr.sin6_scope_id), port(ntohs(addr.sin6_port)) { assert(addr.sin6_family == AF_INET6); } @@ -1188,6 +1195,7 @@ bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const memset(paddrin6, 0, *addrlen); if (!GetIn6Addr(&paddrin6->sin6_addr)) return false; + paddrin6->sin6_scope_id = scopeId; paddrin6->sin6_family = AF_INET6; paddrin6->sin6_port = htons(port); return true; diff --git a/src/netbase.h b/src/netbase.h index 6f8882b85..db736154f 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -19,8 +19,10 @@ extern int nConnectTimeout; extern bool fNameLookup; -/** -timeout default */ +//! -timeout default static const int DEFAULT_CONNECT_TIMEOUT = 5000; +//! -dns default +static const int DEFAULT_NAME_LOOKUP = true; #ifdef WIN32 // In MSVC, this is defined as a macro, undefine it to prevent a compile and link error @@ -42,6 +44,7 @@ class CNetAddr { protected: unsigned char ip[16]; // in network byte order + uint32_t scopeId; // for scoped/link-local ipv6 addresses public: CNetAddr(); @@ -87,7 +90,7 @@ class CNetAddr std::vector GetGroup() const; int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const; - CNetAddr(const struct in6_addr& pipv6Addr); + CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0); bool GetIn6Addr(struct in6_addr* pipv6Addr) const; friend bool operator==(const CNetAddr& a, const CNetAddr& b); @@ -215,5 +218,9 @@ std::string NetworkErrorString(int err); bool CloseSocket(SOCKET& hSocket); /** Disable or enable blocking-mode for a socket */ bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking); +/** + * Convert milliseconds to a struct timeval for e.g. select. + */ +struct timeval MillisToTimeval(int64_t nTimeout); #endif // BITCOIN_NETBASE_H diff --git a/src/noui.h b/src/noui.h index 15cd30a63..ff16cc9aa 100644 --- a/src/noui.h +++ b/src/noui.h @@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Bitcoin Core developers +// Copyright (c) 2013-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index ffe31d194..7b0e8b7d0 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -4,9 +4,11 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "policy/fees.h" +#include "policy/policy.h" #include "amount.h" #include "primitives/transaction.h" +#include "random.h" #include "streams.h" #include "txmempool.h" #include "util.h" @@ -86,7 +88,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal, int maxbucketindex = buckets.size() - 1; // requireGreater means we are looking for the lowest fee/priority such that all higher - // values pass, so we start at maxbucketindex (highest fee) and look at succesively + // values pass, so we start at maxbucketindex (highest fee) and look at successively // smaller buckets until we reach failure. Otherwise, we are looking for the highest // fee/priority such that all lower values fail, and we go in the opposite direction. unsigned int startbucket = requireGreater ? maxbucketindex : 0; @@ -504,6 +506,33 @@ CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) return CFeeRate(median); } +CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool) +{ + if (answerFoundAtTarget) + *answerFoundAtTarget = confTarget; + // Return failure if trying to analyze a target we're not tracking + if (confTarget <= 0 || (unsigned int)confTarget > feeStats.GetMaxConfirms()) + return CFeeRate(0); + + double median = -1; + while (median < 0 && (unsigned int)confTarget <= feeStats.GetMaxConfirms()) { + median = feeStats.EstimateMedianVal(confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight); + } + + if (answerFoundAtTarget) + *answerFoundAtTarget = confTarget - 1; + + // If mempool is limiting txs , return at least the min fee from the mempool + CAmount minPoolFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(); + if (minPoolFee > 0 && minPoolFee > median) + return CFeeRate(minPoolFee); + + if (median < 0) + return CFeeRate(0); + + return CFeeRate(median); +} + double CBlockPolicyEstimator::estimatePriority(int confTarget) { // Return failure if trying to analyze a target we're not tracking @@ -513,6 +542,30 @@ double CBlockPolicyEstimator::estimatePriority(int confTarget) return priStats.EstimateMedianVal(confTarget, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBestSeenHeight); } +double CBlockPolicyEstimator::estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool) +{ + if (answerFoundAtTarget) + *answerFoundAtTarget = confTarget; + // Return failure if trying to analyze a target we're not tracking + if (confTarget <= 0 || (unsigned int)confTarget > priStats.GetMaxConfirms()) + return -1; + + // If mempool is limiting txs, no priority txs are allowed + CAmount minPoolFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(); + if (minPoolFee > 0) + return INF_PRIORITY; + + double median = -1; + while (median < 0 && (unsigned int)confTarget <= priStats.GetMaxConfirms()) { + median = priStats.EstimateMedianVal(confTarget++, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBestSeenHeight); + } + + if (answerFoundAtTarget) + *answerFoundAtTarget = confTarget - 1; + + return median; +} + void CBlockPolicyEstimator::Write(CAutoFile& fileout) { fileout << nBestSeenHeight; @@ -528,3 +581,21 @@ void CBlockPolicyEstimator::Read(CAutoFile& filein) priStats.Read(filein); nBestSeenHeight = nFileBestSeenHeight; } + +FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee) +{ + CAmount minFeeLimit = minIncrementalFee.GetFeePerK() / 2; + feeset.insert(0); + for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) { + feeset.insert(bucketBoundary); + } +} + +CAmount FeeFilterRounder::round(CAmount currentMinFee) +{ + std::set::iterator it = feeset.lower_bound(currentMinFee); + if ((it != feeset.begin() && insecure_rand() % 3 != 0) || it == feeset.end()) { + it--; + } + return *it; +} diff --git a/src/policy/fees.h b/src/policy/fees.h index 15577d128..463f62f71 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -15,6 +15,7 @@ class CAutoFile; class CFeeRate; class CTxMemPoolEntry; +class CTxMemPool; /** \class CBlockPolicyEstimator * The BlockPolicyEstimator is used for estimating the fee or priority needed @@ -28,7 +29,7 @@ class CTxMemPoolEntry; * included in blocks before transactions of lower fee/priority. So for * example if you wanted to know what fee you should put on a transaction to * be included in a block within the next 5 blocks, you would start by looking - * at the bucket with with the highest fee transactions and verifying that a + * at the bucket with the highest fee transactions and verifying that a * sufficiently high percentage of them were confirmed within 5 blocks and * then you would look at the next highest fee bucket, and so on, stopping at * the last bucket to pass the test. The average fee of transactions in this @@ -86,13 +87,13 @@ private: // Count the total # of txs in each bucket // Track the historical moving average of this total over blocks std::vector txCtAvg; - // and calcuate the total for the current block to update the moving average + // and calculate the total for the current block to update the moving average std::vector curBlockTxCt; // Count the total # of txs confirmed within Y blocks in each bucket // Track the historical moving average of theses totals over blocks std::vector > confAvg; // confAvg[Y][X] - // and calcuate the totals for the current block to update the moving averages + // and calculate the totals for the current block to update the moving averages std::vector > curBlockConf; // curBlockConf[Y][X] // Sum the total priority/fee of all tx's in each bucket @@ -182,8 +183,8 @@ static const unsigned int MAX_BLOCK_CONFIRMS = 25; /** Decay of .998 is a half-life of 346 blocks or about 2.4 days */ static const double DEFAULT_DECAY = .998; -/** Require greater than 85% of X fee transactions to be confirmed within Y blocks for X to be big enough */ -static const double MIN_SUCCESS_PCT = .85; +/** Require greater than 95% of X fee transactions to be confirmed within Y blocks for X to be big enough */ +static const double MIN_SUCCESS_PCT = .95; static const double UNLIKELY_PCT = .5; /** Require an avg of 1 tx in the combined fee bucket per block to have stat significance */ @@ -242,9 +243,21 @@ public: /** Return a fee estimate */ CFeeRate estimateFee(int confTarget); + /** Estimate fee rate needed to get be included in a block within + * confTarget blocks. If no answer can be given at confTarget, return an + * estimate at the lowest target where one can be given. + */ + CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool); + /** Return a priority estimate */ double estimatePriority(int confTarget); + /** Estimate priority needed to get be included in a block within + * confTarget blocks. If no answer can be given at confTarget, return an + * estimate at the lowest target where one can be given. + */ + double estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool); + /** Write estimation data to a file */ void Write(CAutoFile& fileout); @@ -252,8 +265,8 @@ public: void Read(CAutoFile& filein); private: - CFeeRate minTrackedFee; //! Passed to constructor to avoid dependency on main - double minTrackedPriority; //! Set to AllowFreeThreshold + CFeeRate minTrackedFee; //!< Passed to constructor to avoid dependency on main + double minTrackedPriority; //!< Set to AllowFreeThreshold unsigned int nBestSeenHeight; struct TxStatsInfo { @@ -273,4 +286,17 @@ private: CFeeRate feeLikely, feeUnlikely; double priLikely, priUnlikely; }; + +class FeeFilterRounder +{ +public: + /** Create new FeeFilterRounder */ + FeeFilterRounder(const CFeeRate& minIncrementalFee); + + /** Quantize a minimum fee for privacy purpose before broadcast **/ + CAmount round(CAmount currentMinFee); + +private: + std::set feeset; +}; #endif /*BITCOIN_POLICYESTIMATOR_H */ diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 3bcdcf100..8d29b5602 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2015 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -24,9 +24,6 @@ * 2. P2SH scripts with a crazy number of expensive * CHECKSIG/CHECKMULTISIG operations * - * Check transaction inputs, and make sure any - * pay-to-script-hash transactions are evaluating IsStandard scripts - * * Why bother? To avoid denial-of-service attacks; an attacker * can submit a standard HASH... OP_EQUAL transaction, * which will get accepted into blocks. The redemption @@ -51,7 +48,7 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) if (m < 1 || m > n) return false; } else if (whichType == TX_NULL_DATA && - (!GetBoolArg("-datacarrier", true) || scriptPubKey.size() > nMaxDatacarrierBytes)) + (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) return false; return whichType != TX_NONSTANDARD; @@ -59,7 +56,7 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) bool IsStandardTx(const CTransaction& tx, std::string& reason) { - if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) { + if (tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < 1) { reason = "version"; return false; } @@ -77,12 +74,12 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason) BOOST_FOREACH(const CTxIn& txin, tx.vin) { // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed - // keys. (remember the 520 byte limit on redeemScript size) That works + // keys (remember the 520 byte limit on redeemScript size). That works // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627 // bytes of scriptSig, which we round off to 1650 bytes for some minor // future-proofing. That's also enough to spend a 20-of-20 // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not - // considered standard) + // considered standard. if (txin.scriptSig.size() > 1650) { reason = "scriptsig-size"; return false; @@ -139,45 +136,20 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) const CScript& prevScript = StripClaimScriptPrefix(prev.scriptPubKey); if (!Solver(prevScript, whichType, vSolutions)) return false; - int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions); - if (nArgsExpected < 0) - return false; - - // Transactions with extra stuff in their scriptSigs are - // non-standard. Note that this EvalScript() call will - // be quick, because if there are any operations - // beside "push data" in the scriptSig - // IsStandardTx() will have already returned false - // and this method isn't called. - std::vector > stack; - if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker())) - return false; if (whichType == TX_SCRIPTHASH) { + std::vector > stack; + // convert the scriptSig into a stack, so we can inspect the redeemScript + if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), 0)) + return false; if (stack.empty()) return false; CScript subscript(stack.back().begin(), stack.back().end()); - std::vector > vSolutions2; - txnouttype whichType2; - if (Solver(subscript, whichType2, vSolutions2)) - { - int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2); - if (tmpExpected < 0) - return false; - nArgsExpected += tmpExpected; - } - else - { - // Any other Script with less than 15 sigops OK: - unsigned int sigops = subscript.GetSigOpCount(true); - // ... extra data left on the stack after execution is OK, too: - return (sigops <= MAX_P2SH_SIGOPS); + if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) { + return false; } } - - if (stack.size() != (unsigned int)nArgsExpected) - return false; } return true; diff --git a/src/policy/policy.h b/src/policy/policy.h index 0ea0d435a..4f9354e36 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -1,10 +1,10 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2015 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_POLICY_H -#define BITCOIN_POLICY_H +#ifndef BITCOIN_POLICY_POLICY_H +#define BITCOIN_POLICY_POLICY_H #include "consensus/consensus.h" #include "script/interpreter.h" @@ -18,13 +18,15 @@ class CCoinsViewCache; static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000; static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0; /** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/ -static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000; +static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 0; /** The maximum size for transactions we're willing to relay/mine */ static const unsigned int MAX_STANDARD_TX_SIZE = 100000; /** Maximum number of signature check operations in an IsStandard() P2SH script */ static const unsigned int MAX_P2SH_SIGOPS = 15; /** The maximum number of sigops we're willing to relay/mine in a single tx */ static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5; +/** Default for -maxmempool, maximum megabytes of mempool memory usage */ +static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300; /** * Standard script verification flags that standard transactions will comply * with. However scripts violating these flags may still be present in valid @@ -38,11 +40,16 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS | SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | + SCRIPT_VERIFY_CHECKSEQUENCEVERIFY | SCRIPT_VERIFY_LOW_S; /** For convenience, standard but not mandatory verify flags. */ static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; +/** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */ +static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE | + LOCKTIME_MEDIAN_TIME_PAST; + bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType); /** * Check for standard transaction types @@ -56,4 +63,4 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason); */ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); -#endif // BITCOIN_POLICY_H +#endif // BITCOIN_POLICY_POLICY_H diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp new file mode 100644 index 000000000..133cff611 --- /dev/null +++ b/src/policy/rbf.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2016 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "policy/rbf.h" + +bool SignalsOptInRBF(const CTransaction &tx) +{ + BOOST_FOREACH(const CTxIn &txin, tx.vin) { + if (txin.nSequence < std::numeric_limits::max()-1) { + return true; + } + } + return false; +} + +RBFTransactionState IsRBFOptIn(const CTransaction &tx, CTxMemPool &pool) +{ + AssertLockHeld(pool.cs); + + CTxMemPool::setEntries setAncestors; + + // First check the transaction itself. + if (SignalsOptInRBF(tx)) { + return RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125; + } + + // If this transaction is not in our mempool, then we can't be sure + // we will know about all its inputs. + if (!pool.exists(tx.GetHash())) { + return RBF_TRANSACTIONSTATE_UNKNOWN; + } + + // If all the inputs have nSequence >= maxint-1, it still might be + // signaled for RBF if any unconfirmed parents have signaled. + uint64_t noLimit = std::numeric_limits::max(); + std::string dummy; + CTxMemPoolEntry entry = *pool.mapTx.find(tx.GetHash()); + pool.CalculateMemPoolAncestors(entry, setAncestors, noLimit, noLimit, noLimit, noLimit, dummy, false); + + BOOST_FOREACH(CTxMemPool::txiter it, setAncestors) { + if (SignalsOptInRBF(it->GetTx())) { + return RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125; + } + } + return RBF_TRANSACTIONSTATE_FINAL; +} diff --git a/src/policy/rbf.h b/src/policy/rbf.h new file mode 100644 index 000000000..5a711dba0 --- /dev/null +++ b/src/policy/rbf.h @@ -0,0 +1,26 @@ +// Copyright (c) 2016 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_POLICY_RBF_H +#define BITCOIN_POLICY_RBF_H + +#include "txmempool.h" + +enum RBFTransactionState { + RBF_TRANSACTIONSTATE_UNKNOWN, + RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125, + RBF_TRANSACTIONSTATE_FINAL +}; + +// Check whether the sequence numbers on this transaction are signaling +// opt-in to replace-by-fee, according to BIP 125 +bool SignalsOptInRBF(const CTransaction &tx); + +// Determine whether an in-mempool transaction is signaling opt-in to RBF +// according to BIP 125 +// This involves checking sequence numbers of the transaction, as well +// as the sequence numbers of all in-mempool ancestors. +RBFTransactionState IsRBFOptIn(const CTransaction &tx, CTxMemPool &pool); + +#endif // BITCOIN_POLICY_RBF_H diff --git a/src/pow.cpp b/src/pow.cpp index 5ace3fbc9..058404f35 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,7 +9,6 @@ #include "chain.h" #include "primitives/block.h" #include "uint256.h" -#include "util.h" unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { @@ -57,7 +56,6 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF // Limit adjustment step int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime; - LogPrintf(" nActualTimespan = %d before bounds\n", nActualTimespan); if (nActualTimespan < params.nPowTargetTimespan/4) nActualTimespan = params.nPowTargetTimespan/4; if (nActualTimespan > params.nPowTargetTimespan*4) @@ -75,12 +73,6 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF if (bnNew > bnPowLimit) bnNew = bnPowLimit; - /// debug print - LogPrintf("GetNextWorkRequired RETARGET\n"); - LogPrintf("params.nPowTargetTimespan = %d nActualTimespan = %d\n", params.nPowTargetTimespan, nActualTimespan); - LogPrintf("Before: %08x %s\n", pindexLast->nBits, bnOld.ToString()); - LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); - return bnNew.GetCompact(); } @@ -94,43 +86,11 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& // Check range if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) - return error("CheckProofOfWork(): nBits below minimum work"); + return false; // Check proof of work matches claimed amount if (UintToArith256(hash) > bnTarget) - return error("CheckProofOfWork(): hash doesn't match nBits"); + return false; return true; } - -arith_uint256 GetBlockProof(const CBlockIndex& block) -{ - arith_uint256 bnTarget; - bool fNegative; - bool fOverflow; - bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - if (fNegative || fOverflow || bnTarget == 0) - return 0; - // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 - // as it's too large for a arith_uint256. However, as 2**256 is at least as large - // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, - // or ~bnTarget / (nTarget+1) + 1. - return (~bnTarget / (bnTarget + 1)) + 1; -} - -int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params) -{ - arith_uint256 r; - int sign = 1; - if (to.nChainWork > from.nChainWork) { - r = to.nChainWork - from.nChainWork; - } else { - r = from.nChainWork - to.nChainWork; - sign = -1; - } - r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip); - if (r.bits() > 63) { - return sign * std::numeric_limits::max(); - } - return sign * r.GetLow64(); -} diff --git a/src/pow.h b/src/pow.h index e864a474c..23e9c1c35 100644 --- a/src/pow.h +++ b/src/pow.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,16 +13,11 @@ class CBlockHeader; class CBlockIndex; class uint256; -class arith_uint256; unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&); unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params&); /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); -arith_uint256 GetBlockProof(const CBlockIndex& block); - -/** 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. */ -int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&); #endif // BITCOIN_POW_H diff --git a/src/prevector.h b/src/prevector.h new file mode 100644 index 000000000..a0e1e140b --- /dev/null +++ b/src/prevector.h @@ -0,0 +1,481 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef _BITCOIN_PREVECTOR_H_ +#define _BITCOIN_PREVECTOR_H_ + +#include +#include +#include + +#include + +#pragma pack(push, 1) +/** Implements a drop-in replacement for std::vector which stores up to N + * elements directly (without heap allocation). The types Size and Diff are + * used to store element counts, and can be any unsigned + signed type. + * + * Storage layout is either: + * - Direct allocation: + * - Size _size: the number of used elements (between 0 and N) + * - T direct[N]: an array of N elements of type T + * (only the first _size are initialized). + * - Indirect allocation: + * - Size _size: the number of used elements plus N + 1 + * - Size capacity: the number of allocated elements + * - T* indirect: a pointer to an array of capacity elements of type T + * (only the first _size are initialized). + * + * The data type T must be movable by memmove/realloc(). Once we switch to C++, + * move constructors can be used instead. + */ +template +class prevector { +public: + typedef Size size_type; + typedef Diff difference_type; + typedef T value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + + class iterator { + T* ptr; + public: + typedef Diff difference_type; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef std::random_access_iterator_tag iterator_category; + iterator(T* ptr_) : ptr(ptr_) {} + T& operator*() const { return *ptr; } + T* operator->() const { return ptr; } + T& operator[](size_type pos) { return ptr[pos]; } + const T& operator[](size_type pos) const { return ptr[pos]; } + iterator& operator++() { ptr++; return *this; } + iterator& operator--() { ptr--; return *this; } + iterator operator++(int) { iterator copy(*this); ++(*this); return copy; } + iterator operator--(int) { iterator copy(*this); --(*this); return copy; } + difference_type friend operator-(iterator a, iterator b) { return (&(*a) - &(*b)); } + iterator operator+(size_type n) { return iterator(ptr + n); } + iterator& operator+=(size_type n) { ptr += n; return *this; } + iterator operator-(size_type n) { return iterator(ptr - n); } + iterator& operator-=(size_type n) { ptr -= n; return *this; } + bool operator==(iterator x) const { return ptr == x.ptr; } + bool operator!=(iterator x) const { return ptr != x.ptr; } + bool operator>=(iterator x) const { return ptr >= x.ptr; } + bool operator<=(iterator x) const { return ptr <= x.ptr; } + bool operator>(iterator x) const { return ptr > x.ptr; } + bool operator<(iterator x) const { return ptr < x.ptr; } + }; + + class reverse_iterator { + T* ptr; + public: + typedef Diff difference_type; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef std::bidirectional_iterator_tag iterator_category; + reverse_iterator(T* ptr_) : ptr(ptr_) {} + T& operator*() { return *ptr; } + const T& operator*() const { return *ptr; } + T* operator->() { return ptr; } + const T* operator->() const { return ptr; } + reverse_iterator& operator--() { ptr++; return *this; } + reverse_iterator& operator++() { ptr--; return *this; } + reverse_iterator operator++(int) { reverse_iterator copy(*this); ++(*this); return copy; } + reverse_iterator operator--(int) { reverse_iterator copy(*this); --(*this); return copy; } + bool operator==(reverse_iterator x) const { return ptr == x.ptr; } + bool operator!=(reverse_iterator x) const { return ptr != x.ptr; } + }; + + class const_iterator { + const T* ptr; + public: + typedef Diff difference_type; + typedef const T value_type; + typedef const T* pointer; + typedef const T& reference; + typedef std::random_access_iterator_tag iterator_category; + const_iterator(const T* ptr_) : ptr(ptr_) {} + const_iterator(iterator x) : ptr(&(*x)) {} + const T& operator*() const { return *ptr; } + const T* operator->() const { return ptr; } + const T& operator[](size_type pos) const { return ptr[pos]; } + const_iterator& operator++() { ptr++; return *this; } + const_iterator& operator--() { ptr--; return *this; } + const_iterator operator++(int) { const_iterator copy(*this); ++(*this); return copy; } + const_iterator operator--(int) { const_iterator copy(*this); --(*this); return copy; } + difference_type friend operator-(const_iterator a, const_iterator b) { return (&(*a) - &(*b)); } + const_iterator operator+(size_type n) { return const_iterator(ptr + n); } + const_iterator& operator+=(size_type n) { ptr += n; return *this; } + const_iterator operator-(size_type n) { return const_iterator(ptr - n); } + const_iterator& operator-=(size_type n) { ptr -= n; return *this; } + bool operator==(const_iterator x) const { return ptr == x.ptr; } + bool operator!=(const_iterator x) const { return ptr != x.ptr; } + bool operator>=(const_iterator x) const { return ptr >= x.ptr; } + bool operator<=(const_iterator x) const { return ptr <= x.ptr; } + bool operator>(const_iterator x) const { return ptr > x.ptr; } + bool operator<(const_iterator x) const { return ptr < x.ptr; } + }; + + class const_reverse_iterator { + const T* ptr; + public: + typedef Diff difference_type; + typedef const T value_type; + typedef const T* pointer; + typedef const T& reference; + typedef std::bidirectional_iterator_tag iterator_category; + const_reverse_iterator(T* ptr_) : ptr(ptr_) {} + const_reverse_iterator(reverse_iterator x) : ptr(&(*x)) {} + const T& operator*() const { return *ptr; } + const T* operator->() const { return ptr; } + const_reverse_iterator& operator--() { ptr++; return *this; } + const_reverse_iterator& operator++() { ptr--; return *this; } + const_reverse_iterator operator++(int) { const_reverse_iterator copy(*this); ++(*this); return copy; } + const_reverse_iterator operator--(int) { const_reverse_iterator copy(*this); --(*this); return copy; } + bool operator==(const_reverse_iterator x) const { return ptr == x.ptr; } + bool operator!=(const_reverse_iterator x) const { return ptr != x.ptr; } + }; + +private: + size_type _size; + union direct_or_indirect { + char direct[sizeof(T) * N]; + struct { + size_type capacity; + char* indirect; + }; + } _union; + + T* direct_ptr(difference_type pos) { return reinterpret_cast(_union.direct) + pos; } + const T* direct_ptr(difference_type pos) const { return reinterpret_cast(_union.direct) + pos; } + T* indirect_ptr(difference_type pos) { return reinterpret_cast(_union.indirect) + pos; } + const T* indirect_ptr(difference_type pos) const { return reinterpret_cast(_union.indirect) + pos; } + bool is_direct() const { return _size <= N; } + + void change_capacity(size_type new_capacity) { + if (new_capacity <= N) { + if (!is_direct()) { + T* indirect = indirect_ptr(0); + T* src = indirect; + T* dst = direct_ptr(0); + memcpy(dst, src, size() * sizeof(T)); + free(indirect); + _size -= N + 1; + } + } else { + if (!is_direct()) { + _union.indirect = static_cast(realloc(_union.indirect, ((size_t)sizeof(T)) * new_capacity)); + _union.capacity = new_capacity; + } else { + char* new_indirect = static_cast(malloc(((size_t)sizeof(T)) * new_capacity)); + T* src = direct_ptr(0); + T* dst = reinterpret_cast(new_indirect); + memcpy(dst, src, size() * sizeof(T)); + _union.indirect = new_indirect; + _union.capacity = new_capacity; + _size += N + 1; + } + } + } + + T* item_ptr(difference_type pos) { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); } + const T* item_ptr(difference_type pos) const { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); } + +public: + void assign(size_type n, const T& val) { + clear(); + if (capacity() < n) { + change_capacity(n); + } + while (size() < n) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(val); + } + } + + template + void assign(InputIterator first, InputIterator last) { + size_type n = last - first; + clear(); + if (capacity() < n) { + change_capacity(n); + } + while (first != last) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(*first); + ++first; + } + } + + prevector() : _size(0) {} + + explicit prevector(size_type n) : _size(0) { + resize(n); + } + + explicit prevector(size_type n, const T& val = T()) : _size(0) { + change_capacity(n); + while (size() < n) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(val); + } + } + + template + prevector(InputIterator first, InputIterator last) : _size(0) { + size_type n = last - first; + change_capacity(n); + while (first != last) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(*first); + ++first; + } + } + + prevector(const prevector& other) : _size(0) { + change_capacity(other.size()); + const_iterator it = other.begin(); + while (it != other.end()) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(*it); + ++it; + } + } + + prevector& operator=(const prevector& other) { + if (&other == this) { + return *this; + } + resize(0); + change_capacity(other.size()); + const_iterator it = other.begin(); + while (it != other.end()) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(*it); + ++it; + } + return *this; + } + + size_type size() const { + return is_direct() ? _size : _size - N - 1; + } + + bool empty() const { + return size() == 0; + } + + iterator begin() { return iterator(item_ptr(0)); } + const_iterator begin() const { return const_iterator(item_ptr(0)); } + iterator end() { return iterator(item_ptr(size())); } + const_iterator end() const { return const_iterator(item_ptr(size())); } + + reverse_iterator rbegin() { return reverse_iterator(item_ptr(size() - 1)); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(item_ptr(size() - 1)); } + reverse_iterator rend() { return reverse_iterator(item_ptr(-1)); } + const_reverse_iterator rend() const { return const_reverse_iterator(item_ptr(-1)); } + + size_t capacity() const { + if (is_direct()) { + return N; + } else { + return _union.capacity; + } + } + + T& operator[](size_type pos) { + return *item_ptr(pos); + } + + const T& operator[](size_type pos) const { + return *item_ptr(pos); + } + + void resize(size_type new_size) { + if (size() > new_size) { + erase(item_ptr(new_size), end()); + } + if (new_size > capacity()) { + change_capacity(new_size); + } + while (size() < new_size) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(); + } + } + + void reserve(size_type new_capacity) { + if (new_capacity > capacity()) { + change_capacity(new_capacity); + } + } + + void shrink_to_fit() { + change_capacity(size()); + } + + void clear() { + resize(0); + } + + iterator insert(iterator pos, const T& value) { + size_type p = pos - begin(); + size_type new_size = size() + 1; + if (capacity() < new_size) { + change_capacity(new_size + (new_size >> 1)); + } + memmove(item_ptr(p + 1), item_ptr(p), (size() - p) * sizeof(T)); + _size++; + new(static_cast(item_ptr(p))) T(value); + return iterator(item_ptr(p)); + } + + void insert(iterator pos, size_type count, const T& value) { + size_type p = pos - begin(); + size_type new_size = size() + count; + if (capacity() < new_size) { + change_capacity(new_size + (new_size >> 1)); + } + memmove(item_ptr(p + count), item_ptr(p), (size() - p) * sizeof(T)); + _size += count; + for (size_type i = 0; i < count; i++) { + new(static_cast(item_ptr(p + i))) T(value); + } + } + + template + void insert(iterator pos, InputIterator first, InputIterator last) { + size_type p = pos - begin(); + difference_type count = last - first; + size_type new_size = size() + count; + if (capacity() < new_size) { + change_capacity(new_size + (new_size >> 1)); + } + memmove(item_ptr(p + count), item_ptr(p), (size() - p) * sizeof(T)); + _size += count; + while (first != last) { + new(static_cast(item_ptr(p))) T(*first); + ++p; + ++first; + } + } + + iterator erase(iterator pos) { + return erase(pos, pos + 1); + } + + iterator erase(iterator first, iterator last) { + iterator p = first; + char* endp = (char*)&(*end()); + while (p != last) { + (*p).~T(); + _size--; + ++p; + } + memmove(&(*first), &(*last), endp - ((char*)(&(*last)))); + return first; + } + + void push_back(const T& value) { + size_type new_size = size() + 1; + if (capacity() < new_size) { + change_capacity(new_size + (new_size >> 1)); + } + new(item_ptr(size())) T(value); + _size++; + } + + void pop_back() { + erase(end() - 1, end()); + } + + T& front() { + return *item_ptr(0); + } + + const T& front() const { + return *item_ptr(0); + } + + T& back() { + return *item_ptr(size() - 1); + } + + const T& back() const { + return *item_ptr(size() - 1); + } + + void swap(prevector& other) { + std::swap(_union, other._union); + std::swap(_size, other._size); + } + + ~prevector() { + clear(); + if (!is_direct()) { + free(_union.indirect); + _union.indirect = NULL; + } + } + + bool operator==(const prevector& other) const { + if (other.size() != size()) { + return false; + } + const_iterator b1 = begin(); + const_iterator b2 = other.begin(); + const_iterator e1 = end(); + while (b1 != e1) { + if ((*b1) != (*b2)) { + return false; + } + ++b1; + ++b2; + } + return true; + } + + bool operator!=(const prevector& other) const { + return !(*this == other); + } + + bool operator<(const prevector& other) const { + if (size() < other.size()) { + return true; + } + if (size() > other.size()) { + return false; + } + const_iterator b1 = begin(); + const_iterator b2 = other.begin(); + const_iterator e1 = end(); + while (b1 != e1) { + if ((*b1) < (*b2)) { + return true; + } + if ((*b2) < (*b1)) { + return false; + } + ++b1; + ++b2; + } + return false; + } + + size_t allocated_memory() const { + if (is_direct()) { + return 0; + } else { + return ((size_t)(sizeof(T))) * _union.capacity; + } + } +}; +#pragma pack(pop) + +#endif diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 7e7a0b63b..76128b39f 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -24,73 +24,10 @@ uint256 CBlockHeader::GetPoWHash() const return PoWHash(input); } -uint256 CBlock::ComputeMerkleRoot(bool* fMutated) const -{ - /* WARNING! If you're reading this because you're learning about crypto - and/or designing a new system that will use merkle trees, keep in mind - that the following merkle tree algorithm has a serious flaw related to - duplicate txids, resulting in a vulnerability (CVE-2012-2459). - - The reason is that if the number of hashes in the list at a given time - is odd, the last one is duplicated before computing the next level (which - is unusual in Merkle trees). This results in certain sequences of - transactions leading to the same merkle root. For example, these two - trees: - - A A - / \ / \ - B C B C - / \ | / \ / \ - D E F D E F F - / \ / \ / \ / \ / \ / \ / \ - 1 2 3 4 5 6 1 2 3 4 5 6 5 6 - - for transaction lists [1,2,3,4,5,6] and [1,2,3,4,5,6,5,6] (where 5 and - 6 are repeated) result in the same root hash A (because the hash of both - of (F) and (F,F) is C). - - The vulnerability results from being able to send a block with such a - transaction list, with the same merkle root, and the same block hash as - the original without duplication, resulting in failed validation. If the - receiving node proceeds to mark that block as permanently invalid - however, it will fail to accept further unmodified (and thus potentially - valid) versions of the same block. We defend against this by detecting - the case where we would hash two identical hashes at the end of the list - together, and treating that identically to the block having an invalid - merkle root. Assuming no double-SHA256 collisions, this will detect all - known ways of changing the transactions without affecting the merkle - root. - */ - std::vector vMerkleTree; - vMerkleTree.reserve(vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes. - for (std::vector::const_iterator it(vtx.begin()); it != vtx.end(); ++it) - vMerkleTree.push_back(it->GetHash()); - int j = 0; - bool mutated = false; - for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) - { - for (int i = 0; i < nSize; i += 2) - { - int i2 = std::min(i+1, nSize-1); - if (i2 == i + 1 && i2 + 1 == nSize && vMerkleTree[j+i] == vMerkleTree[j+i2]) { - // Two identical hashes at the end of the list at a particular level. - mutated = true; - } - vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), - BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); - } - j += nSize; - } - if (fMutated) { - *fMutated = mutated; - } - return (vMerkleTree.empty() ? uint256() : vMerkleTree.back()); -} - std::string CBlock::ToString() const { std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n", + s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), diff --git a/src/primitives/block.h b/src/primitives/block.h index 49420956a..dadd6d3f8 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -21,7 +21,6 @@ class CBlockHeader { public: // header - static const int32_t CURRENT_VERSION=3; int32_t nVersion; uint256 hashPrevBlock; uint256 hashMerkleRoot; @@ -51,7 +50,7 @@ public: void SetNull() { - nVersion = CBlockHeader::CURRENT_VERSION; + nVersion = 0; hashPrevBlock.SetNull(); hashMerkleRoot.SetNull(); hashClaimTrie.SetNull(); @@ -124,12 +123,6 @@ public: return block; } - // Build the merkle tree for this block and return the merkle root. - // If non-NULL, *mutated is set to whether mutation was detected in the merkle - // tree (a duplication of transactions in the block leading to an identical - // merkle root). - uint256 ComputeMerkleRoot(bool* mutated = NULL) const; - std::string ToString() const; }; diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 46d3cbbe2..947f2e6a7 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -37,7 +37,7 @@ std::string CTxIn::ToString() const str += strprintf(", coinbase %s", HexStr(scriptSig)); else str += strprintf(", scriptSig=%s", HexStr(scriptSig).substr(0, 24)); - if (nSequence != std::numeric_limits::max()) + if (nSequence != SEQUENCE_FINAL) str += strprintf(", nSequence=%u", nSequence); str += ")"; return str; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 28ed32f31..067b1fcc0 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -34,7 +34,8 @@ public: friend bool operator<(const COutPoint& a, const COutPoint& b) { - return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n)); + int cmp = a.hash.Compare(b.hash); + return cmp < 0 || (cmp == 0 && a.n < b.n); } friend bool operator==(const COutPoint& a, const COutPoint& b) @@ -61,28 +62,50 @@ public: CScript scriptSig; uint32_t nSequence; + /* Setting nSequence to this value for every input in a transaction + * disables nLockTime. */ + static const uint32_t SEQUENCE_FINAL = 0xffffffff; + + /* Below flags apply in the context of BIP 68*/ + /* If this flag set, CTxIn::nSequence is NOT interpreted as a + * relative lock-time. */ + static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31); + + /* If CTxIn::nSequence encodes a relative lock-time and this flag + * is set, the relative lock-time has units of 512 seconds, + * otherwise it specifies blocks with a granularity of 1. */ + static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22); + + /* If CTxIn::nSequence encodes a relative lock-time, this mask is + * applied to extract that lock-time from the sequence field. */ + static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff; + + /* In order to use the same number of bits to encode roughly the + * same wall-clock duration, and because blocks are naturally + * limited to occur every 600s on average, the minimum granularity + * for time-based relative lock-time is fixed at 512 seconds. + * Converting from CTxIn::nSequence to seconds is performed by + * multiplying by 512 = 2^9, or equivalently shifting up by + * 9 bits. */ + static const int SEQUENCE_LOCKTIME_GRANULARITY = 9; + CTxIn() { - nSequence = std::numeric_limits::max(); + nSequence = SEQUENCE_FINAL; } - explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits::max()); - CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits::max()); + explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL); + CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(prevout); - READWRITE(scriptSig); + READWRITE(*(CScriptBase*)(&scriptSig)); READWRITE(nSequence); } - bool IsFinal() const - { - return (nSequence == std::numeric_limits::max()); - } - friend bool operator==(const CTxIn& a, const CTxIn& b) { return (a.prevout == b.prevout && @@ -119,7 +142,7 @@ public: template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(nValue); - READWRITE(scriptPubKey); + READWRITE(*(CScriptBase*)(&scriptPubKey)); } void SetNull() @@ -143,8 +166,8 @@ public: // to spend something, then we consider it dust. // A typical spendable txout is 34 bytes big, and will // need a CTxIn of at least 148 bytes to spend: - // so dust is a spendable txout less than 546 satoshis - // with default minRelayTxFee. + // so dust is a spendable txout less than + // 546*minRelayTxFee/1000 (in satoshis) if (scriptPubKey.IsUnspendable()) return 0; @@ -185,8 +208,15 @@ private: void UpdateHash() const; public: + // Default transaction version. static const int32_t CURRENT_VERSION=1; + // Changing the default transaction version requires a two step process: first + // adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date + // bumping the default CURRENT_VERSION at which point both CURRENT_VERSION and + // MAX_STANDARD_VERSION will be equal. + static const int32_t MAX_STANDARD_VERSION=2; + // The local variables are made const to prevent unintended modification // without updating the cached hash value. However, CTransaction is not // actually immutable; deserialization and assignment are implemented, diff --git a/src/protocol.cpp b/src/protocol.cpp index dd855aa33..8c4bd0572 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,14 +12,68 @@ # include #endif +namespace NetMsgType { +const char *VERSION="version"; +const char *VERACK="verack"; +const char *ADDR="addr"; +const char *INV="inv"; +const char *GETDATA="getdata"; +const char *MERKLEBLOCK="merkleblock"; +const char *GETBLOCKS="getblocks"; +const char *GETHEADERS="getheaders"; +const char *TX="tx"; +const char *HEADERS="headers"; +const char *BLOCK="block"; +const char *GETADDR="getaddr"; +const char *MEMPOOL="mempool"; +const char *PING="ping"; +const char *PONG="pong"; +const char *NOTFOUND="notfound"; +const char *FILTERLOAD="filterload"; +const char *FILTERADD="filteradd"; +const char *FILTERCLEAR="filterclear"; +const char *REJECT="reject"; +const char *SENDHEADERS="sendheaders"; +const char *FEEFILTER="feefilter"; +}; + static const char* ppszTypeName[] = { - "ERROR", - "tx", - "block", - "filtered block" + "ERROR", // Should never occur + NetMsgType::TX, + NetMsgType::BLOCK, + "filtered block" // Should never occur }; +/** All known message types. Keep this in the same order as the list of + * messages above and in protocol.h. + */ +const static std::string allNetMessageTypes[] = { + NetMsgType::VERSION, + NetMsgType::VERACK, + NetMsgType::ADDR, + NetMsgType::INV, + NetMsgType::GETDATA, + NetMsgType::MERKLEBLOCK, + NetMsgType::GETBLOCKS, + NetMsgType::GETHEADERS, + NetMsgType::TX, + NetMsgType::HEADERS, + NetMsgType::BLOCK, + NetMsgType::GETADDR, + NetMsgType::MEMPOOL, + NetMsgType::PING, + NetMsgType::PONG, + NetMsgType::NOTFOUND, + NetMsgType::FILTERLOAD, + NetMsgType::FILTERADD, + NetMsgType::FILTERCLEAR, + NetMsgType::REJECT, + NetMsgType::SENDHEADERS, + NetMsgType::FEEFILTER +}; +const static std::vector allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes)); + CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn) { memcpy(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE); @@ -140,3 +194,8 @@ std::string CInv::ToString() const { return strprintf("%s %s", GetCommand(), hash.ToString()); } + +const std::vector &getAllNetMessageTypes() +{ + return allNetMessageTypesVec; +} diff --git a/src/protocol.h b/src/protocol.h index 50aeaf44b..1b049e52a 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -65,6 +65,163 @@ public: unsigned int nChecksum; }; +/** + * Bitcoin protocol message types. When adding new message types, don't forget + * to update allNetMessageTypes in protocol.cpp. + */ +namespace NetMsgType { + +/** + * The version message provides information about the transmitting node to the + * receiving node at the beginning of a connection. + * @see https://bitcoin.org/en/developer-reference#version + */ +extern const char *VERSION; +/** + * The verack message acknowledges a previously-received version message, + * informing the connecting node that it can begin to send other messages. + * @see https://bitcoin.org/en/developer-reference#verack + */ +extern const char *VERACK; +/** + * The addr (IP address) message relays connection information for peers on the + * network. + * @see https://bitcoin.org/en/developer-reference#addr + */ +extern const char *ADDR; +/** + * The inv message (inventory message) transmits one or more inventories of + * objects known to the transmitting peer. + * @see https://bitcoin.org/en/developer-reference#inv + */ +extern const char *INV; +/** + * The getdata message requests one or more data objects from another node. + * @see https://bitcoin.org/en/developer-reference#getdata + */ +extern const char *GETDATA; +/** + * The merkleblock message is a reply to a getdata message which requested a + * block using the inventory type MSG_MERKLEBLOCK. + * @since protocol version 70001 as described by BIP37. + * @see https://bitcoin.org/en/developer-reference#merkleblock + */ +extern const char *MERKLEBLOCK; +/** + * The getblocks message requests an inv message that provides block header + * hashes starting from a particular point in the block chain. + * @see https://bitcoin.org/en/developer-reference#getblocks + */ +extern const char *GETBLOCKS; +/** + * The getheaders message requests a headers message that provides block + * headers starting from a particular point in the block chain. + * @since protocol version 31800. + * @see https://bitcoin.org/en/developer-reference#getheaders + */ +extern const char *GETHEADERS; +/** + * The tx message transmits a single transaction. + * @see https://bitcoin.org/en/developer-reference#tx + */ +extern const char *TX; +/** + * The headers message sends one or more block headers to a node which + * previously requested certain headers with a getheaders message. + * @since protocol version 31800. + * @see https://bitcoin.org/en/developer-reference#headers + */ +extern const char *HEADERS; +/** + * The block message transmits a single serialized block. + * @see https://bitcoin.org/en/developer-reference#block + */ +extern const char *BLOCK; +/** + * The getaddr message requests an addr message from the receiving node, + * preferably one with lots of IP addresses of other receiving nodes. + * @see https://bitcoin.org/en/developer-reference#getaddr + */ +extern const char *GETADDR; +/** + * The mempool message requests the TXIDs of transactions that the receiving + * node has verified as valid but which have not yet appeared in a block. + * @since protocol version 60002. + * @see https://bitcoin.org/en/developer-reference#mempool + */ +extern const char *MEMPOOL; +/** + * The ping message is sent periodically to help confirm that the receiving + * peer is still connected. + * @see https://bitcoin.org/en/developer-reference#ping + */ +extern const char *PING; +/** + * The pong message replies to a ping message, proving to the pinging node that + * the ponging node is still alive. + * @since protocol version 60001 as described by BIP31. + * @see https://bitcoin.org/en/developer-reference#pong + */ +extern const char *PONG; +/** + * The notfound message is a reply to a getdata message which requested an + * object the receiving node does not have available for relay. + * @ince protocol version 70001. + * @see https://bitcoin.org/en/developer-reference#notfound + */ +extern const char *NOTFOUND; +/** + * The filterload message tells the receiving peer to filter all relayed + * transactions and requested merkle blocks through the provided filter. + * @since protocol version 70001 as described by BIP37. + * Only available with service bit NODE_BLOOM since protocol version + * 70011 as described by BIP111. + * @see https://bitcoin.org/en/developer-reference#filterload + */ +extern const char *FILTERLOAD; +/** + * The filteradd message tells the receiving peer to add a single element to a + * previously-set bloom filter, such as a new public key. + * @since protocol version 70001 as described by BIP37. + * Only available with service bit NODE_BLOOM since protocol version + * 70011 as described by BIP111. + * @see https://bitcoin.org/en/developer-reference#filteradd + */ +extern const char *FILTERADD; +/** + * The filterclear message tells the receiving peer to remove a previously-set + * bloom filter. + * @since protocol version 70001 as described by BIP37. + * Only available with service bit NODE_BLOOM since protocol version + * 70011 as described by BIP111. + * @see https://bitcoin.org/en/developer-reference#filterclear + */ +extern const char *FILTERCLEAR; +/** + * The reject message informs the receiving node that one of its previous + * messages has been rejected. + * @since protocol version 70002 as described by BIP61. + * @see https://bitcoin.org/en/developer-reference#reject + */ +extern const char *REJECT; +/** + * Indicates that a node prefers to receive new block announcements via a + * "headers" message rather than an "inv". + * @since protocol version 70012 as described by BIP130. + * @see https://bitcoin.org/en/developer-reference#sendheaders + */ +extern const char *SENDHEADERS; +/** + * The feefilter message tells the receiving peer not to inv us any txs + * which do not meet the specified min fee rate. + * @since protocol version 70013 as described by BIP133 + */ +extern const char *FEEFILTER; +}; + +/* Get a vector of all valid message types (see above) */ +const std::vector &getAllNetMessageTypes(); + /** nServices flags */ enum { // NODE_NETWORK means that the node is capable of serving the block chain. It is currently diff --git a/src/pubkey.cpp b/src/pubkey.cpp index bdab13760..be4ee27cd 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -1,22 +1,187 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "pubkey.h" -#include "eccryptoverify.h" +#include +#include -#include "ecwrapper.h" +namespace +{ +/* Global secp256k1_context object used for verification. */ +secp256k1_context* secp256k1_context_verify = NULL; +} + +/** This function is taken from the libsecp256k1 distribution and implements + * DER parsing for ECDSA signatures, while supporting an arbitrary subset of + * format violations. + * + * Supported violations include negative integers, excessive padding, garbage + * at the end, and overly long length descriptors. This is safe to use in + * Bitcoin because since the activation of BIP66, signatures are verified to be + * strict DER before being passed to this module, and we know it supports all + * violations present in the blockchain before that point. + */ +static int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + size_t rpos, rlen, spos, slen; + size_t pos = 0; + size_t lenbyte; + unsigned char tmpsig[64] = {0}; + int overflow = 0; + + /* Hack to initialize sig with a correctly-parsed but invalid signature. */ + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + + /* Sequence tag byte */ + if (pos == inputlen || input[pos] != 0x30) { + return 0; + } + pos++; + + /* Sequence length bytes */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + pos += lenbyte; + } + + /* Integer tag byte for R */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for R */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + rlen = 0; + while (lenbyte > 0) { + rlen = (rlen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + rlen = lenbyte; + } + if (rlen > inputlen - pos) { + return 0; + } + rpos = pos; + pos += rlen; + + /* Integer tag byte for S */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for S */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + slen = 0; + while (lenbyte > 0) { + slen = (slen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + slen = lenbyte; + } + if (slen > inputlen - pos) { + return 0; + } + spos = pos; + pos += slen; + + /* Ignore leading zeroes in R */ + while (rlen > 0 && input[rpos] == 0) { + rlen--; + rpos++; + } + /* Copy R value */ + if (rlen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 32 - rlen, input + rpos, rlen); + } + + /* Ignore leading zeroes in S */ + while (slen > 0 && input[spos] == 0) { + slen--; + spos++; + } + /* Copy S value */ + if (slen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 64 - slen, input + spos, slen); + } + + if (!overflow) { + overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + if (overflow) { + /* Overwrite the result again with a correctly-parsed but invalid + signature if parsing failed. */ + memset(tmpsig, 0, 64); + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + return 1; +} bool CPubKey::Verify(const uint256 &hash, const std::vector& vchSig) const { if (!IsValid()) return false; - CECKey key; - if (!key.SetPubKey(begin(), size())) + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) { return false; - if (!key.Verify(hash, vchSig)) + } + if (vchSig.size() == 0) { return false; - return true; + } + if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) { + return false; + } + /* libsecp256k1's ECDSA verification requires lower-S signatures, which have + * not historically been enforced in Bitcoin, so normalize them first. */ + secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, &sig, &sig); + return secp256k1_ecdsa_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey); } bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector& vchSig) { @@ -24,33 +189,39 @@ bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector pubkey; - key.GetPubKey(pubkey, fComp); - Set(pubkey.begin(), pubkey.end()); + } + if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) { + return false; + } + unsigned char pub[65]; + size_t publen = 65; + secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); + Set(pub, pub + publen); return true; } bool CPubKey::IsFullyValid() const { if (!IsValid()) return false; - CECKey key; - if (!key.SetPubKey(begin(), size())) - return false; - return true; + secp256k1_pubkey pubkey; + return secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size()); } bool CPubKey::Decompress() { if (!IsValid()) return false; - CECKey key; - if (!key.SetPubKey(begin(), size())) + secp256k1_pubkey pubkey; + if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) { return false; - std::vector pubkey; - key.GetPubKey(pubkey, false); - Set(pubkey.begin(), pubkey.end()); + } + unsigned char pub[65]; + size_t publen = 65; + secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + Set(pub, pub + publen); return true; } @@ -61,16 +232,21 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi unsigned char out[64]; BIP32Hash(cc, nChild, *begin(), begin()+1, out); memcpy(ccChild.begin(), out+32, 32); - CECKey key; - bool ret = key.SetPubKey(begin(), size()); - ret &= key.TweakPublic(out); - std::vector pubkey; - key.GetPubKey(pubkey, true); - pubkeyChild.Set(pubkey.begin(), pubkey.end()); - return ret; + secp256k1_pubkey pubkey; + if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) { + return false; + } + if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) { + return false; + } + unsigned char pub[33]; + size_t publen = 33; + secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED); + pubkeyChild.Set(pub, pub + publen); + return true; } -void CExtPubKey::Encode(unsigned char code[74]) const { +void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const { code[0] = nDepth; memcpy(code+1, vchFingerprint, 4); code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF; @@ -80,12 +256,12 @@ void CExtPubKey::Encode(unsigned char code[74]) const { memcpy(code+41, pubkey.begin(), 33); } -void CExtPubKey::Decode(const unsigned char code[74]) { +void CExtPubKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) { nDepth = code[0]; memcpy(vchFingerprint, code+1, 4); nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8]; memcpy(chaincode.begin(), code+9, 32); - pubkey.Set(code+41, code+74); + pubkey.Set(code+41, code+BIP32_EXTKEY_SIZE); } bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const { @@ -95,3 +271,33 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const { out.nChild = nChild; return pubkey.Derive(out.pubkey, out.chaincode, nChild, chaincode); } + +/* static */ bool CPubKey::CheckLowS(const std::vector& vchSig) { + secp256k1_ecdsa_signature sig; + if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) { + return false; + } + return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, NULL, &sig)); +} + +/* static */ int ECCVerifyHandle::refcount = 0; + +ECCVerifyHandle::ECCVerifyHandle() +{ + if (refcount == 0) { + assert(secp256k1_context_verify == NULL); + secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + assert(secp256k1_context_verify != NULL); + } + refcount++; +} + +ECCVerifyHandle::~ECCVerifyHandle() +{ + refcount--; + if (refcount == 0) { + assert(secp256k1_context_verify != NULL); + secp256k1_context_destroy(secp256k1_context_verify); + secp256k1_context_verify = NULL; + } +} diff --git a/src/pubkey.h b/src/pubkey.h index cce9c826e..db5444ea9 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -23,6 +23,8 @@ * script supports up to 75 for single byte push */ +const unsigned int BIP32_EXTKEY_SIZE = 74; + /** A reference to a CKey: the Hash160 of its serialized public key */ class CKeyID : public uint160 { @@ -177,6 +179,11 @@ public: */ bool Verify(const uint256& hash, const std::vector& vchSig) const; + /** + * Check whether a signature is normalized (lower-S). + */ + static bool CheckLowS(const std::vector& vchSig); + //! Recover a public key from a compact signature. bool RecoverCompact(const uint256& hash, const std::vector& vchSig); @@ -200,9 +207,44 @@ struct CExtPubKey { a.chaincode == b.chaincode && a.pubkey == b.pubkey; } - void Encode(unsigned char code[74]) const; - void Decode(const unsigned char code[74]); + void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; + void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); bool Derive(CExtPubKey& out, unsigned int nChild) const; + + unsigned int GetSerializeSize(int nType, int nVersion) const + { + return BIP32_EXTKEY_SIZE+1; //add one byte for the size (compact int) + } + template + void Serialize(Stream& s, int nType, int nVersion) const + { + unsigned int len = BIP32_EXTKEY_SIZE; + ::WriteCompactSize(s, len); + unsigned char code[BIP32_EXTKEY_SIZE]; + Encode(code); + s.write((const char *)&code[0], len); + } + template + void Unserialize(Stream& s, int nType, int nVersion) + { + unsigned int len = ::ReadCompactSize(s); + unsigned char code[BIP32_EXTKEY_SIZE]; + if (len != BIP32_EXTKEY_SIZE) + throw std::runtime_error("Invalid extended key size\n"); + s.read((char *)&code[0], len); + Decode(code); + } +}; + +/** Users of this module must hold an ECCVerifyHandle. The constructor and + * destructor of these are not allowed to run in parallel, though. */ +class ECCVerifyHandle +{ + static int refcount; + +public: + ECCVerifyHandle(); + ~ECCVerifyHandle(); }; #endif // BITCOIN_PUBKEY_H diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 8bd158644..135f15ffa 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 92e6cab9a..c22566d47 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index c5ac07cfc..71ed3618e 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -218,7 +218,7 @@ QVariant AddressTableModel::data(const QModelIndex &index, int role) const QFont font; if(index.column() == Address) { - font = GUIUtil::bitcoinAddressFont(); + font = GUIUtil::fixedPitchFont(); } return font; } diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index 2b7475c4e..d04b95eba 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 441814ff0..415bffb99 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -1,7 +1,11 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + #include "askpassphrasedialog.h" #include "ui_askpassphrasedialog.h" @@ -119,9 +123,9 @@ void AskPassphraseDialog::accept() { QMessageBox::warning(this, tr("Wallet encrypted"), "" + - tr("Bitcoin Core will close now to finish the encryption process. " + tr("%1 will close now to finish the encryption process. " "Remember that encrypting your wallet cannot fully protect " - "your bitcoins from being stolen by malware infecting your computer.") + + "your bitcoins from being stolen by malware infecting your computer.").arg(tr(PACKAGE_NAME)) + "

" + tr("IMPORTANT: Any previous backups you have made of your wallet file " "should be replaced with the newly generated, encrypted wallet file. " diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h index d4d832825..727b5a1ad 100644 --- a/src/qt/askpassphrasedialog.h +++ b/src/qt/askpassphrasedialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index 33792af5b..d95106b5a 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -103,7 +103,7 @@ int BanTableModel::rowCount(const QModelIndex &parent) const int BanTableModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); - return columns.length();; + return columns.length(); } QVariant BanTableModel::data(const QModelIndex &index, int role) const @@ -178,4 +178,4 @@ bool BanTableModel::shouldShow() if (priv->size() > 0) return true; return false; -} \ No newline at end of file +} diff --git a/src/qt/bantablemodel.h b/src/qt/bantablemodel.h index c21dd04e3..fe9600ac0 100644 --- a/src/qt/bantablemodel.h +++ b/src/qt/bantablemodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 89d2d44fd..9c21bb24c 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -26,7 +26,7 @@ #endif #include "init.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "scheduler.h" #include "ui_interface.h" #include "util.h" @@ -201,8 +201,10 @@ public: /// Create payment server void createPaymentServer(); #endif + /// parameter interaction/setup based on rules + void parameterSetup(); /// Create options model - void createOptionsModel(); + void createOptionsModel(bool resetSettings); /// Create main window void createWindow(const NetworkStyle *networkStyle); /// Create splash screen @@ -309,14 +311,8 @@ BitcoinApplication::BitcoinApplication(int &argc, char **argv): // UI per-platform customization // This must be done inside the BitcoinApplication constructor, or after it, because // PlatformStyle::instantiate requires a QApplication -#if defined(Q_OS_MAC) - std::string platformName = "macosx"; -#elif defined(Q_OS_WIN) - std::string platformName = "windows"; -#else - std::string platformName = "other"; -#endif - platformName = GetArg("-uiplatform", platformName); + std::string platformName; + platformName = GetArg("-uiplatform", BitcoinGUI::DEFAULT_UIPLATFORM); platformStyle = PlatformStyle::instantiate(QString::fromStdString(platformName)); if (!platformStyle) // Fall back to "other" if specified name not found platformStyle = PlatformStyle::instantiate("other"); @@ -352,9 +348,9 @@ void BitcoinApplication::createPaymentServer() } #endif -void BitcoinApplication::createOptionsModel() +void BitcoinApplication::createOptionsModel(bool resetSettings) { - optionsModel = new OptionsModel(); + optionsModel = new OptionsModel(NULL, resetSettings); } void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) @@ -397,6 +393,12 @@ void BitcoinApplication::startThread() coreThread->start(); } +void BitcoinApplication::parameterSetup() +{ + InitLogging(); + InitParameterInteraction(); +} + void BitcoinApplication::requestInitialize() { qDebug() << __func__ << ": Requesting initialize"; @@ -563,7 +565,7 @@ int main(int argc, char *argv[]) // Show help message immediately after parsing command-line options (for "-lang") and setting locale, // but before showing splash screen. - if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) + if (mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) { HelpMessageDialog help(NULL, mapArgs.count("-version")); help.showOrPrint(); @@ -578,14 +580,14 @@ int main(int argc, char *argv[]) /// - Do not call GetDataDir(true) before this step finishes if (!boost::filesystem::is_directory(GetDataDir(false))) { - QMessageBox::critical(0, QObject::tr("Bitcoin Core"), + QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"]))); return 1; } try { ReadConfigFile(mapArgs, mapMultiArgs); } catch (const std::exception& e) { - QMessageBox::critical(0, QObject::tr("Bitcoin Core"), + QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what())); return false; } @@ -600,7 +602,7 @@ int main(int argc, char *argv[]) try { SelectParams(ChainNameFromCommandLine()); } catch(std::exception &e) { - QMessageBox::critical(0, QObject::tr("Bitcoin Core"), QObject::tr("Error: %1").arg(e.what())); + QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what())); return 1; } #ifdef ENABLE_WALLET @@ -644,13 +646,15 @@ int main(int argc, char *argv[]) // Install qDebug() message handler to route to debug.log qInstallMessageHandler(DebugMessageHandler); #endif + // Allow parameter interaction before we create the options model + app.parameterSetup(); // Load GUI settings from QSettings - app.createOptionsModel(); + app.createOptionsModel(mapArgs.count("-resetguisettings") != 0); // Subscribe to global signals from core uiInterface.InitMessage.connect(InitMessage); - if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false)) + if (GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !GetBoolArg("-min", false)) app.createSplashScreen(networkStyle.data()); try @@ -658,7 +662,7 @@ int main(int argc, char *argv[]) app.createWindow(networkStyle.data()); app.requestInitialize(); #if defined(Q_OS_WIN) && QT_VERSION >= 0x050000 - WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("Bitcoin Core didn't yet exit safely..."), (HWND)app.getMainWinId()); + WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId()); #endif app.exec(); app.requestShutdown(); diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index c899e9550..24b0bae3e 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -46,6 +46,10 @@ res/icons/about_qt.png res/icons/verify.png res/icons/warning.png + res/icons/fontbigger.png + res/icons/fontsmaller.png + res/icons/chevron.png + res/icons/transaction_abandoned.png res/movies/spinner-000.png diff --git a/src/qt/bitcoin_locale.qrc b/src/qt/bitcoin_locale.qrc index b70a10739..a8a0253b0 100644 --- a/src/qt/bitcoin_locale.qrc +++ b/src/qt/bitcoin_locale.qrc @@ -1,36 +1,40 @@ - locale/bitcoin_ach.qm locale/bitcoin_af_ZA.qm locale/bitcoin_ar.qm locale/bitcoin_be_BY.qm + locale/bitcoin_bg_BG.qm locale/bitcoin_bg.qm locale/bitcoin_bs.qm locale/bitcoin_ca_ES.qm locale/bitcoin_ca.qm locale/bitcoin_ca@valencia.qm - locale/bitcoin_cmn.qm + locale/bitcoin_cs_CZ.qm locale/bitcoin_cs.qm locale/bitcoin_cy.qm locale/bitcoin_da.qm locale/bitcoin_de.qm locale/bitcoin_el_GR.qm + locale/bitcoin_el.qm + locale/bitcoin_en_GB.qm locale/bitcoin_en.qm locale/bitcoin_eo.qm locale/bitcoin_es_CL.qm locale/bitcoin_es_DO.qm + locale/bitcoin_es_ES.qm locale/bitcoin_es_MX.qm locale/bitcoin_es.qm locale/bitcoin_es_UY.qm + locale/bitcoin_es_VE.qm locale/bitcoin_et.qm locale/bitcoin_eu_ES.qm locale/bitcoin_fa_IR.qm locale/bitcoin_fa.qm locale/bitcoin_fi.qm locale/bitcoin_fr_CA.qm + locale/bitcoin_fr_FR.qm locale/bitcoin_fr.qm locale/bitcoin_gl.qm - locale/bitcoin_gu_IN.qm locale/bitcoin_he.qm locale/bitcoin_hi_IN.qm locale/bitcoin_hr.qm @@ -45,6 +49,7 @@ locale/bitcoin_la.qm locale/bitcoin_lt.qm locale/bitcoin_lv_LV.qm + locale/bitcoin_mk_MK.qm locale/bitcoin_mn.qm locale/bitcoin_ms_MY.qm locale/bitcoin_nb.qm @@ -54,14 +59,15 @@ locale/bitcoin_pt_BR.qm locale/bitcoin_pt_PT.qm locale/bitcoin_ro_RO.qm + locale/bitcoin_ru_RU.qm locale/bitcoin_ru.qm - locale/bitcoin_sah.qm locale/bitcoin_sk.qm locale/bitcoin_sl_SI.qm locale/bitcoin_sq.qm locale/bitcoin_sr.qm locale/bitcoin_sv.qm locale/bitcoin_th_TH.qm + locale/bitcoin_tr_TR.qm locale/bitcoin_tr.qm locale/bitcoin_uk.qm locale/bitcoin_ur_PK.qm @@ -69,7 +75,7 @@ locale/bitcoin_vi.qm locale/bitcoin_vi_VN.qm locale/bitcoin_zh_CN.qm - locale/bitcoin_zh_HK.qm + locale/bitcoin_zh.qm locale/bitcoin_zh_TW.qm diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index d19b9fd4a..73eb35a54 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h index 3703b1f8d..2f03a3d17 100644 --- a/src/qt/bitcoinamountfield.h +++ b/src/qt/bitcoinamountfield.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index d930d1595..b00cdfcaf 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1,7 +1,11 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + #include "bitcoingui.h" #include "bitcoinunits.h" @@ -44,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +63,16 @@ #include #endif +const std::string BitcoinGUI::DEFAULT_UIPLATFORM = +#if defined(Q_OS_MAC) + "macosx" +#elif defined(Q_OS_WIN) + "windows" +#else + "other" +#endif + ; + const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent) : @@ -104,7 +119,7 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n { GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this); - QString windowTitle = tr("Bitcoin Core") + " - "; + QString windowTitle = tr(PACKAGE_NAME) + " - "; #ifdef ENABLE_WALLET /* if compiled with wallet support, -disablewallet can still disable the wallet */ enableWallet = !GetBoolArg("-disablewallet", false); @@ -302,14 +317,14 @@ void BitcoinGUI::createActions() quitAction->setStatusTip(tr("Quit application")); quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); quitAction->setMenuRole(QAction::QuitRole); - aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About Bitcoin Core"), this); - aboutAction->setStatusTip(tr("Show information about Bitcoin Core")); + aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About %1").arg(tr(PACKAGE_NAME)), this); + aboutAction->setStatusTip(tr("Show information about %1").arg(tr(PACKAGE_NAME))); aboutAction->setMenuRole(QAction::AboutRole); aboutQtAction = new QAction(platformStyle->TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this); aboutQtAction->setStatusTip(tr("Show information about Qt")); aboutQtAction->setMenuRole(QAction::AboutQtRole); optionsAction = new QAction(platformStyle->TextColorIcon(":/icons/options"), tr("&Options..."), this); - optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin Core")); + optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(tr(PACKAGE_NAME))); optionsAction->setMenuRole(QAction::PreferencesRole); toggleHideAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&Show / Hide"), this); toggleHideAction->setStatusTip(tr("Show or hide the main Window")); @@ -339,7 +354,7 @@ void BitcoinGUI::createActions() showHelpMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/info"), tr("&Command-line options"), this); showHelpMessageAction->setMenuRole(QAction::NoRole); - showHelpMessageAction->setStatusTip(tr("Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options")); + showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(tr(PACKAGE_NAME))); connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked())); @@ -364,6 +379,9 @@ void BitcoinGUI::createActions() connect(openAction, SIGNAL(triggered()), this, SLOT(openClicked())); } #endif // ENABLE_WALLET + + new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C), this, SLOT(showDebugWindowActivateConsole())); + new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D), this, SLOT(showDebugWindow())); } void BitcoinGUI::createMenuBar() @@ -439,8 +457,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) setNumConnections(clientModel->getNumConnections()); connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); - setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate()); - connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime)), this, SLOT(setNumBlocks(int,QDateTime))); + setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate(), clientModel->getVerificationProgress(NULL)); + connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(setNumBlocks(int,QDateTime,double))); // Receive and report messages from client model connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); @@ -514,7 +532,7 @@ void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle) { #ifndef Q_OS_MAC trayIcon = new QSystemTrayIcon(this); - QString toolTip = tr("Bitcoin Core client") + " " + networkStyle->getTitleAddText(); + QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText(); trayIcon->setToolTip(toolTip); trayIcon->setIcon(networkStyle->getTrayAndWindowIcon()); trayIcon->show(); @@ -597,6 +615,12 @@ void BitcoinGUI::showDebugWindow() rpcConsole->activateWindow(); } +void BitcoinGUI::showDebugWindowActivateConsole() +{ + rpcConsole->setTabFocus(RPCConsole::TAB_CONSOLE); + showDebugWindow(); +} + void BitcoinGUI::showHelpMessageClicked() { helpMessageDialog->show(); @@ -662,7 +686,7 @@ void BitcoinGUI::setNumConnections(int count) labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count)); } -void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate) +void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress) { if(!clientModel) return; @@ -739,7 +763,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate) progressBarLabel->setVisible(true); progressBar->setFormat(tr("%1 behind").arg(timeBehindText)); progressBar->setMaximum(1000000000); - progressBar->setValue(clientModel->getVerificationProgress() * 1000000000.0 + 0.5); + progressBar->setValue(nVerificationProgress * 1000000000.0 + 0.5); progressBar->setVisible(true); tooltip = tr("Catching up...") + QString("
") + tooltip; diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 717f2bd12..871ca1ba3 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -48,6 +48,7 @@ class BitcoinGUI : public QMainWindow public: static const QString DEFAULT_WALLET; + static const std::string DEFAULT_UIPLATFORM; explicit BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = 0); ~BitcoinGUI(); @@ -149,7 +150,7 @@ public Q_SLOTS: /** Set number of connections shown in the UI */ void setNumConnections(int count); /** Set number of blocks and last block date shown in the UI */ - void setNumBlocks(int count, const QDateTime& blockDate); + void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress); /** Notify the user of an event from the core network or transaction handling code. @param[in] title the message box / notification title @@ -198,6 +199,8 @@ private Q_SLOTS: void aboutClicked(); /** Show debug window */ void showDebugWindow(); + /** Show debug window and set focus to the console */ + void showDebugWindowActivateConsole(); /** Show help message dialog */ void showHelpMessageClicked(); #ifndef Q_OS_MAC diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 3cde2657c..41f1d5841 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -1,4 +1,6 @@ - +// Copyright (c) 2013-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. #include @@ -13,6 +15,12 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "(1 = keep tx meta data e.g. account owner and payment request information, 2 " "= drop tx meta data)"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"-maxtxfee is set very high! Fees this large could be paid on a single " +"transaction."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"-paytxfee is set very high! This is the transaction fee you will pay if you " +"send a transaction."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Allow JSON-RPC connections from specified source. Valid for 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"), @@ -42,10 +50,12 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Distributed under the MIT software license, see the accompanying file " "COPYING or ."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Error: Listening for incoming connections failed (listen returned error %s)"), +"Do not keep transactions in the mempool longer than hours (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Error: Unsupported argument -socks found. Setting SOCKS version isn't " -"possible anymore, only SOCKS5 proxies are supported."), +"Error reading wallet.dat! All keys read correctly, but transaction data or " +"address book entries might be missing or incorrect."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error: Listening for incoming connections failed (listen returned error %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "" "Execute command when a relevant alert is received or we see a really long " "fork (%s in cmd is replaced by message)"), @@ -56,8 +66,11 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Execute command when the best block changes (%s in cmd is replaced by block " "hash)"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Fees (in %s/kB) smaller than this are considered zero fee for relaying " -"(default: %s)"), +"Fees (in %s/kB) smaller than this are considered zero fee for relaying, " +"mining and transaction creation (default: %s)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Fees (in %s/kB) smaller than this are considered zero fee for transaction " +"creation (default: %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "" "How thorough the block verification of -checkblocks is (0-4, default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -113,6 +126,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Set the number of threads for coin generation if enabled (-1 = all cores, " "default: %d)"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Support filtering of blocks and transaction with bloom filters (default: %u)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "The block database contains a block which appears to be from the future. " "This may be due to your computer's date and time being set incorrectly. Only " "rebuild the block database if you are sure that your computer's date and " @@ -127,35 +142,39 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "the OpenSSL Toolkit and cryptographic software " "written by Eric Young and UPnP software written by Thomas Bernard."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Total length of network version string (%i) exceeds maximum length (%i). " +"Reduce the number or size of uacomments."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = " +"no limit (default: %d)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Unable to bind to %s on this computer. Bitcoin Core is probably already " "running."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Unsupported argument -socks found. Setting SOCKS version isn't possible " +"anymore, only SOCKS5 proxies are supported."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Use UPnP to map the listening port (default: 1 when listening and no -proxy)"), QT_TRANSLATE_NOOP("bitcoin-core", "" "Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: " "%s)"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Username and hashed password for JSON-RPC connections. The field " +"comes in the format: :$. A canonical python script is " +"included in share/rpcuser. This option can be specified multiple times"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "WARNING: abnormally high number of blocks generated, %d blocks received in " "the last %d hours (%d expected)"), QT_TRANSLATE_NOOP("bitcoin-core", "" "WARNING: check your network connection, %d blocks received in the last %d " "hours (%d expected)"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Warning: -maxtxfee is set very high! Fees this large could be paid on a " -"single transaction."), -QT_TRANSLATE_NOOP("bitcoin-core", "" -"Warning: -paytxfee is set very high! This is the transaction fee you will " -"pay if you send a transaction."), -QT_TRANSLATE_NOOP("bitcoin-core", "" "Warning: The network does not appear to fully agree! Some miners appear to " "be experiencing issues."), QT_TRANSLATE_NOOP("bitcoin-core", "" "Warning: We do not appear to fully agree with our peers! You may need to " "upgrade, or other nodes may need to upgrade."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Warning: error reading wallet.dat! All keys read correctly, but transaction " -"data or address book entries might be missing or incorrect."), -QT_TRANSLATE_NOOP("bitcoin-core", "" "Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as " "wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect " "you should restore from a backup."), @@ -170,7 +189,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "mode. This will redownload the entire blockchain"), QT_TRANSLATE_NOOP("bitcoin-core", "(default: %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "(default: %u)"), -QT_TRANSLATE_NOOP("bitcoin-core", "(default: 1)"), +QT_TRANSLATE_NOOP("bitcoin-core", "-maxmempool must be at least %d MB"), QT_TRANSLATE_NOOP("bitcoin-core", " can be:"), QT_TRANSLATE_NOOP("bitcoin-core", "Accept command line and JSON-RPC commands"), QT_TRANSLATE_NOOP("bitcoin-core", "Accept connections from outside (default: 1 if no -proxy or -connect)"), @@ -179,14 +198,15 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Activating best chain..."), QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep the connection open"), QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"), QT_TRANSLATE_NOOP("bitcoin-core", "Always query for peer addresses via DNS lookup (default: %u)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to recover private keys from a corrupt wallet.dat"), +QT_TRANSLATE_NOOP("bitcoin-core", "Always relay transactions received from whitelisted peers (default: %d)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to recover private keys from a corrupt wallet.dat on startup"), +QT_TRANSLATE_NOOP("bitcoin-core", "Automatically create Tor hidden service (default: %d)"), QT_TRANSLATE_NOOP("bitcoin-core", "Block creation options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -bind address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -externalip address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -whitebind address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write default address"), -QT_TRANSLATE_NOOP("bitcoin-core", "Choose data directory on startup (default: 0)"), QT_TRANSLATE_NOOP("bitcoin-core", "Connect only to the specified node(s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Connect through SOCKS5 proxy"), QT_TRANSLATE_NOOP("bitcoin-core", "Connect to a node to retrieve peer addresses, and disconnect"), @@ -212,13 +232,12 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error reading from database, shutting down.") QT_TRANSLATE_NOOP("bitcoin-core", "Error"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: A fatal internal error occurred, see debug.log for details"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"), -QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unsupported argument -tor found, use -onion."), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."), QT_TRANSLATE_NOOP("bitcoin-core", "Fee (in %s/kB) to add to transactions you send (default: %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: %u, 0 = all)"), QT_TRANSLATE_NOOP("bitcoin-core", "Importing..."), -QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000??.dat file"), +QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000??.dat file on startup"), QT_TRANSLATE_NOOP("bitcoin-core", "Include IP addresses in debug output (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"), QT_TRANSLATE_NOOP("bitcoin-core", "Information"), @@ -233,6 +252,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=: '%s' ( QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Keep at most unconnectable transactions in memory (default: %u)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Keep the transaction memory pool below megabytes (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "Listen for JSON-RPC connections on (default: %u or testnet: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on (default: %u or testnet: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."), @@ -258,20 +278,17 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Receive and display P2P network alerts (defau QT_TRANSLATE_NOOP("bitcoin-core", "Reducing -maxconnections from %d to %d, because of system limitations."), QT_TRANSLATE_NOOP("bitcoin-core", "Relay and mine data carrier transactions (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "Relay non-P2SH multisig (default: %u)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions"), +QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions on startup"), QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."), QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"), QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to console instead of debug.log file"), QT_TRANSLATE_NOOP("bitcoin-core", "Send transactions as zero-fee transactions if possible (default: %u)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Set SSL root certificates for payment request (default: -system-)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set database cache size in megabytes (%d to %d, default: %d)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to (default: %u)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Set language, for example \"de_DE\" (default: system locale)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum block size in bytes (default: %d)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set minimum block size in bytes (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set the number of threads to service RPC calls (default: %d)"), QT_TRANSLATE_NOOP("bitcoin-core", "Show all debugging options (usage: --help -help-debug)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Show splash screen on startup (default: 1)"), QT_TRANSLATE_NOOP("bitcoin-core", "Shrink debug.log file on client startup (default: 1 when no -debug)"), QT_TRANSLATE_NOOP("bitcoin-core", "Signing transaction failed"), QT_TRANSLATE_NOOP("bitcoin-core", "Specify configuration file (default: %s)"), @@ -281,22 +298,25 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Specify wallet file (within data directory)"), QT_TRANSLATE_NOOP("bitcoin-core", "Specify your own public address"), QT_TRANSLATE_NOOP("bitcoin-core", "Spend unconfirmed change when sending transactions (default: %u)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Start minimized"), QT_TRANSLATE_NOOP("bitcoin-core", "The transaction amount is too small to pay the fee"), QT_TRANSLATE_NOOP("bitcoin-core", "This help message"), QT_TRANSLATE_NOOP("bitcoin-core", "This is experimental software."), QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: %u)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Tor control port password (default: empty)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Tor control port to use if onion listening enabled (default: %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amount too small"), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amounts must be positive"), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large for fee policy"), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large"), -QT_TRANSLATE_NOOP("bitcoin-core", "UI Options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to start HTTP server. See debug log for details."), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"), -QT_TRANSLATE_NOOP("bitcoin-core", "Upgrade wallet to latest format"), +QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -benchmark ignored, use -debug=bench."), +QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -debugnet ignored, use -debug=net."), +QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -tor found, use -onion."), +QT_TRANSLATE_NOOP("bitcoin-core", "Upgrade wallet to latest format on startup"), QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: %u)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Use the test network"), +QT_TRANSLATE_NOOP("bitcoin-core", "User Agent comment (%s) contains unsafe characters."), QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"), QT_TRANSLATE_NOOP("bitcoin-core", "Verifying blocks..."), QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet..."), @@ -305,11 +325,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart Bitcoi QT_TRANSLATE_NOOP("bitcoin-core", "Wallet options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Warning"), QT_TRANSLATE_NOOP("bitcoin-core", "Warning: This version is obsolete; upgrade required!"), -QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Unsupported argument -benchmark ignored, use -debug=bench."), -QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Unsupported argument -debugnet ignored, use -debug=net."), +QT_TRANSLATE_NOOP("bitcoin-core", "Whether to operate in a blocks only mode (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "You need to rebuild the database using -reindex to change -txindex"), QT_TRANSLATE_NOOP("bitcoin-core", "Zapping all transactions from wallet..."), QT_TRANSLATE_NOOP("bitcoin-core", "ZeroMQ notification options:"), -QT_TRANSLATE_NOOP("bitcoin-core", "on startup"), QT_TRANSLATE_NOOP("bitcoin-core", "wallet.dat corrupt, salvage failed"), }; diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp index 425b45d91..649005789 100644 --- a/src/qt/bitcoinunits.cpp +++ b/src/qt/bitcoinunits.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -111,13 +111,6 @@ QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, Separator } -// TODO: Review all remaining calls to BitcoinUnits::formatWithUnit to -// TODO: determine whether the output is used in a plain text context -// TODO: or an HTML context (and replace with -// TODO: BtcoinUnits::formatHtmlWithUnit in the latter case). Hopefully -// TODO: there aren't instances where the result could be used in -// TODO: either context. - // NOTE: Using formatWithUnit in an HTML context risks wrapping // quantities at the thousands separator. More subtly, it also results // in a standard space rather than a thin space, due to a bug in Qt's diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h index 1871c33a7..fda067b0b 100644 --- a/src/qt/bitcoinunits.h +++ b/src/qt/bitcoinunits.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -88,6 +88,7 @@ public: static QString format(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard); //! Format as string (with unit) static QString formatWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard); + //! Format as HTML string (with unit) static QString formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard); //! Parse string to coin amount static bool parse(int unit, const QString &value, CAmount *val_out); diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 0900a35cc..697736cc8 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,11 +8,11 @@ #include "guiconstants.h" #include "peertablemodel.h" -#include "alert.h" #include "chainparams.h" #include "checkpoints.h" #include "clientversion.h" #include "net.h" +#include "txmempool.h" #include "ui_interface.h" #include "util.h" @@ -21,17 +21,16 @@ #include #include +class CBlockIndex; + static const int64_t nClientStartupTime = GetTime(); +static int64_t nLastBlockTipUpdateNotification = 0; ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) : QObject(parent), optionsModel(optionsModel), peerTableModel(0), banTableModel(0), - cachedNumBlocks(0), - cachedBlockDate(QDateTime()), - cachedReindexing(0), - cachedImporting(0), pollTimer(0) { peerTableModel = new PeerTableModel(this); @@ -88,40 +87,32 @@ QDateTime ClientModel::getLastBlockDate() const return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network } -double ClientModel::getVerificationProgress() const +long ClientModel::getMempoolSize() const { - LOCK(cs_main); - return Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()); + return mempool.size(); +} + +size_t ClientModel::getMempoolDynamicUsage() const +{ + return mempool.DynamicMemoryUsage(); +} + +double ClientModel::getVerificationProgress(const CBlockIndex *tipIn) const +{ + CBlockIndex *tip = const_cast(tipIn); + if (!tip) + { + LOCK(cs_main); + tip = chainActive.Tip(); + } + return Checkpoints::GuessVerificationProgress(Params().Checkpoints(), tip); } void ClientModel::updateTimer() { - // Get required lock upfront. This avoids the GUI from getting stuck on - // periodical polls if the core is holding the locks for a longer time - - // for example, during a wallet rescan. - TRY_LOCK(cs_main, lockMain); - if (!lockMain) - return; - - // Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change. - // Periodically check and update with a timer. - int newNumBlocks = getNumBlocks(); - QDateTime newBlockDate = getLastBlockDate(); - - // check for changed number of blocks we have, number of blocks peers claim to have, reindexing state and importing state - if (cachedNumBlocks != newNumBlocks || - cachedBlockDate != newBlockDate || - cachedReindexing != fReindex || - cachedImporting != fImporting) - { - cachedNumBlocks = newNumBlocks; - cachedBlockDate = newBlockDate; - cachedReindexing = fReindex; - cachedImporting = fImporting; - - Q_EMIT numBlocksChanged(newNumBlocks, newBlockDate); - } - + // no locking required at this point + // the following calls will acquire the required lock + Q_EMIT mempoolSizeChanged(getMempoolSize(), getMempoolDynamicUsage()); Q_EMIT bytesChanged(getTotalBytesRecv(), getTotalBytesSent()); } @@ -130,20 +121,8 @@ void ClientModel::updateNumConnections(int numConnections) Q_EMIT numConnectionsChanged(numConnections); } -void ClientModel::updateAlert(const QString &hash, int status) +void ClientModel::updateAlert() { - // Show error message notification for new alert - if(status == CT_NEW) - { - uint256 hash_256; - hash_256.SetHex(hash.toStdString()); - CAlert alert = CAlert::getAlertByHash(hash_256); - if(!alert.IsNull()) - { - Q_EMIT message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR); - } - } - Q_EMIT alertsChanged(getStatusBarWarnings()); } @@ -166,7 +145,7 @@ enum BlockSource ClientModel::getBlockSource() const QString ClientModel::getStatusBarWarnings() const { - return QString::fromStdString(GetWarnings("statusbar")); + return QString::fromStdString(GetWarnings("gui")); } OptionsModel *ClientModel::getOptionsModel() @@ -194,11 +173,6 @@ QString ClientModel::formatSubVersion() const return QString::fromStdString(strSubVersion); } -QString ClientModel::formatBuildDate() const -{ - return QString::fromStdString(CLIENT_DATE); -} - bool ClientModel::isReleaseVersion() const { return CLIENT_VERSION_IS_RELEASE; @@ -214,6 +188,11 @@ QString ClientModel::formatClientStartupTime() const return QDateTime::fromTime_t(nClientStartupTime).toString(); } +QString ClientModel::dataDir() const +{ + return QString::fromStdString(GetDataDir().string()); +} + void ClientModel::updateBanlist() { banTableModel->refresh(); @@ -235,12 +214,10 @@ static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConn Q_ARG(int, newNumConnections)); } -static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status) +static void NotifyAlertChanged(ClientModel *clientmodel) { - qDebug() << "NotifyAlertChanged: " + QString::fromStdString(hash.GetHex()) + " status=" + QString::number(status); - QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(hash.GetHex())), - Q_ARG(int, status)); + qDebug() << "NotifyAlertChanged"; + QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection); } static void BannedListChanged(ClientModel *clientmodel) @@ -249,13 +226,34 @@ static void BannedListChanged(ClientModel *clientmodel) QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection); } +static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CBlockIndex *pIndex) +{ + // lock free async UI updates in case we have a new block tip + // during initial sync, only update the UI if the last update + // was > 250ms (MODEL_UPDATE_DELAY) ago + int64_t now = 0; + if (initialSync) + now = GetTimeMillis(); + + // if we are in-sync, update the UI regardless of last update time + if (!initialSync || now - nLastBlockTipUpdateNotification > MODEL_UPDATE_DELAY) { + //pass a async signal to the UI thread + QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection, + Q_ARG(int, pIndex->nHeight), + Q_ARG(QDateTime, QDateTime::fromTime_t(pIndex->GetBlockTime())), + Q_ARG(double, clientmodel->getVerificationProgress(pIndex))); + nLastBlockTipUpdateNotification = now; + } +} + void ClientModel::subscribeToCoreSignals() { // Connect signals to client uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1)); - uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2)); + uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this)); uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this)); + uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2)); } void ClientModel::unsubscribeFromCoreSignals() @@ -263,6 +261,7 @@ void ClientModel::unsubscribeFromCoreSignals() // Disconnect signals from client uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1)); - uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2)); + uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this)); uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this)); + uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2)); } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 627bdf862..109f95a2a 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,6 +15,7 @@ class PeerTableModel; class TransactionTableModel; class CWallet; +class CBlockIndex; QT_BEGIN_NAMESPACE class QTimer; @@ -51,10 +52,15 @@ public: int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const; int getNumBlocks() const; + //! Return number of transactions in the mempool + long getMempoolSize() const; + //! Return the dynamic memory usage of the mempool + size_t getMempoolDynamicUsage() const; + quint64 getTotalBytesRecv() const; quint64 getTotalBytesSent() const; - double getVerificationProgress() const; + double getVerificationProgress(const CBlockIndex *tip) const; QDateTime getLastBlockDate() const; //! Return true if core is doing initial block download @@ -66,21 +72,16 @@ public: QString formatFullVersion() const; QString formatSubVersion() const; - QString formatBuildDate() const; bool isReleaseVersion() const; QString clientName() const; QString formatClientStartupTime() const; + QString dataDir() const; private: OptionsModel *optionsModel; PeerTableModel *peerTableModel; BanTableModel *banTableModel; - int cachedNumBlocks; - QDateTime cachedBlockDate; - bool cachedReindexing; - bool cachedImporting; - QTimer *pollTimer; void subscribeToCoreSignals(); @@ -88,7 +89,8 @@ private: Q_SIGNALS: void numConnectionsChanged(int count); - void numBlocksChanged(int count, const QDateTime& blockDate); + void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress); + void mempoolSizeChanged(long count, size_t mempoolSizeInBytes); void alertsChanged(const QString &warnings); void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut); @@ -101,7 +103,7 @@ Q_SIGNALS: public Q_SLOTS: void updateTimer(); void updateNumConnections(int numConnections); - void updateAlert(const QString &hash, int status); + void updateAlert(); void updateBanlist(); }; diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 51008ad2d..f90949995 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -130,7 +130,7 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget ui->treeWidget->setColumnWidth(COLUMN_DATE, 110); ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 100); ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100); - ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transacton hash in this column, but don't show it + ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transaction hash in this column, but don't show it ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but don't show it ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but don't show it ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but don't show it @@ -408,10 +408,8 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column) CoinControlDialog::updateLabels(model, this); } - // todo: this is a temporary qt5 fix: when clicking a parent node in tree mode, the parent node - // including all children are partially selected. But the parent node should be fully selected - // as well as the children. Children should never be partially selected in the first place. - // Please remove this ugly fix, once the bug is solved upstream. + // TODO: Remove this temporary qt5 fix after Qt5.3 and Qt5.4 are no longer used. + // Fixed in Qt5.5 and above: https://bugreports.qt.io/browse/QTBUG-43473 #if QT_VERSION >= 0x050000 else if (column == COLUMN_CHECKBOX && item->childCount() > 0) { @@ -538,7 +536,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 ? CoinControlDialog::payAmounts.size() + 1 : 2) * 34) + 10; // always assume +1 output for change here // Priority - double mempoolEstimatePriority = mempool.estimatePriority(nTxConfirmTarget); + double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget); dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority) sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority); @@ -549,11 +547,12 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) // Fee nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool); + if (nPayFee > 0 && coinControl->nMinimumTotalFee > nPayFee) + nPayFee = coinControl->nMinimumTotalFee; - // Allow free? - double dPriorityNeeded = mempoolEstimatePriority; - if (dPriorityNeeded <= 0) - dPriorityNeeded = AllowFreeThreshold(); // not enough data, back to hard-coded + + // Allow free? (require at least hard-coded threshold and default to that if no estimate) + double dPriorityNeeded = std::max(mempoolEstimatePriority, AllowFreeThreshold()); fAllowFree = (dPriority >= dPriorityNeeded); if (fSendFreeTransactions) @@ -567,7 +566,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) nChange -= nPayFee; // Never create dust outputs; if we would, just add the dust to the fee. - if (nChange > 0 && nChange < CENT) + if (nChange > 0 && nChange < MIN_CHANGE) { CTxOut txout(nChange, (CScript)std::vector(24, 0)); if (txout.IsDust(::minRelayTxFee)) @@ -621,7 +620,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) l6->setText(sPriorityLabel); // Priority l7->setText(fDust ? tr("yes") : tr("no")); // Dust l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change - if (nPayFee > 0 && !(payTxFee.GetFeePerK() > 0 && fPayAtLeastCustomFee && nBytes < 1000)) + if (nPayFee > 0 && (coinControl->nMinimumTotalFee < nPayFee)) { l3->setText(ASYMP_UTF8 + l3->text()); l4->setText(ASYMP_UTF8 + l4->text()); @@ -636,21 +635,22 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) // tool tips QString toolTip1 = tr("This label turns red if the transaction size is greater than 1000 bytes.") + "

"; - toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::minTxFee.GetFeePerK())) + "

"; + toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000))) + "

"; toolTip1 += tr("Can vary +/- 1 byte per input."); QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "

"; toolTip2 += tr("This label turns red if the priority is smaller than \"medium\".") + "

"; - toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::minTxFee.GetFeePerK())); + toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000))); - QString toolTip3 = tr("This label turns red if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, ::minRelayTxFee.GetFee(546))); + QString toolTip3 = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold."); // how many satoshis the estimated fee can vary per byte we guess wrong double dFeeVary; if (payTxFee.GetFeePerK() > 0) - dFeeVary = (double)std::max(CWallet::minTxFee.GetFeePerK(), payTxFee.GetFeePerK()) / 1000; - else - dFeeVary = (double)std::max(CWallet::minTxFee.GetFeePerK(), mempool.estimateFee(nTxConfirmTarget).GetFeePerK()) / 1000; + dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), payTxFee.GetFeePerK()) / 1000; + else { + dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), mempool.estimateSmartFee(nTxConfirmTarget).GetFeePerK()) / 1000; + } QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary); l3->setToolTip(toolTip4); @@ -686,7 +686,7 @@ void CoinControlDialog::updateView() QFlags flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; int nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); - double mempoolEstimatePriority = mempool.estimatePriority(nTxConfirmTarget); + double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget); std::map > mapCoins; model->listCoins(mapCoins); @@ -796,7 +796,7 @@ void CoinControlDialog::updateView() } // set checkbox - if (coinControl->IsSelected(txhash, out.i)) + if (coinControl->IsSelected(COutPoint(txhash, out.i))) itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked); } diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 8ff1eac70..1a467eb2f 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/coincontroltreewidget.cpp b/src/qt/coincontroltreewidget.cpp index 5dcbf0c3f..f86bc0851 100644 --- a/src/qt/coincontroltreewidget.cpp +++ b/src/qt/coincontroltreewidget.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/coincontroltreewidget.h b/src/qt/coincontroltreewidget.h index 98a7d32f0..62645fcdb 100644 --- a/src/qt/coincontroltreewidget.h +++ b/src/qt/coincontroltreewidget.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp index 55c595708..8a1a49bb0 100644 --- a/src/qt/csvmodelwriter.cpp +++ b/src/qt/csvmodelwriter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/csvmodelwriter.h b/src/qt/csvmodelwriter.h index a2bf379f4..edea369ad 100644 --- a/src/qt/csvmodelwriter.h +++ b/src/qt/csvmodelwriter.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index 1c22594cd..5f45031e9 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h index d59fce2d4..ddb67ece7 100644 --- a/src/qt/editaddressdialog.h +++ b/src/qt/editaddressdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index 4117da57f..c17efcf1b 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -7,7 +7,7 @@ 0 0 740 - 450 + 430 @@ -23,7 +23,7 @@ &Information - + 12 @@ -47,7 +47,7 @@ - + IBeamCursor @@ -70,7 +70,7 @@ - + IBeamCursor @@ -96,7 +96,7 @@ - + IBeamCursor @@ -113,32 +113,6 @@ - - - Using OpenSSL version - - - 10 - - - - - - - IBeamCursor - - - N/A - - - Qt::PlainText - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - Using BerkeleyDB version @@ -148,7 +122,7 @@ - + IBeamCursor @@ -164,15 +138,15 @@ - + - Build date + Datadir - - + + IBeamCursor @@ -182,19 +156,22 @@ Qt::PlainText + + true + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - + Startup time - + IBeamCursor @@ -210,27 +187,27 @@ - - - - - 75 - true - - - - Network - - + + + + + 75 + true + + + + Network + + - + Name - + IBeamCursor @@ -246,14 +223,14 @@ - + Number of connections - + IBeamCursor @@ -269,7 +246,7 @@ - + @@ -282,14 +259,14 @@ - + Current number of blocks - + IBeamCursor @@ -305,14 +282,14 @@ - - + + Last block time - + IBeamCursor @@ -328,21 +305,8 @@ - - - - Qt::Vertical - - - - 20 - 20 - - - - - - + + 75 @@ -350,24 +314,97 @@ - Debug log file + Memory Pool - - - - Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. + + + + Current number of transactions + + + + + + + IBeamCursor - &Open + N/A - - false + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - + + + + Memory usage + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + 3 + + + + + Qt::Vertical + + + + 10 + 5 + + + + + + + + Debug log file + + + + + + + Open the %1 debug log file from the current data directory. This can take a few seconds for large log files. + + + &Open + + + false + + + + + + Qt::Vertical @@ -390,6 +427,125 @@ 3 + + 5 + + + + + 4 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + + + Decrease font size + + + + :/icons/fontsmaller:/icons/fontsmaller + + + + 24 + 16 + + + + false + + + true + + + + + + + + 24 + 24 + + + + Increase font size + + + + + + + :/icons/fontbigger:/icons/fontbigger + + + + 24 + 16 + + + + false + + + true + + + + + + + + 24 + 24 + + + + Clear console + + + Qt::LeftToRight + + + + + + + :/icons/remove:/icons/remove + + + Ctrl+L + + + false + + + true + + + + + @@ -410,44 +566,48 @@ - + 3 - - - > + + + false - - - - - - - - 24 + 16 24 - - Clear console - - :/icons/remove:/icons/remove + :/icons/prompticon + :/icons/prompticon:/icons/prompticon - - Ctrl+L + + + 14 + 14 + false + + true + + + + + + + + @@ -722,6 +882,9 @@ Qt::ScrollBarAsNeeded + + false + true @@ -783,6 +946,9 @@ Qt::ScrollBarAsNeeded + + false + true @@ -1117,7 +1283,7 @@ - Bytes Sent + Sent @@ -1140,7 +1306,7 @@ - Bytes Received + Received diff --git a/src/qt/forms/helpmessagedialog.ui b/src/qt/forms/helpmessagedialog.ui index dc7df9d6c..b7f941f70 100644 --- a/src/qt/forms/helpmessagedialog.ui +++ b/src/qt/forms/helpmessagedialog.ui @@ -10,9 +10,6 @@ 400 - - Bitcoin Core - Command-line options - 0 diff --git a/src/qt/forms/intro.ui b/src/qt/forms/intro.ui index 09e7bdb02..e4ff3da1a 100644 --- a/src/qt/forms/intro.ui +++ b/src/qt/forms/intro.ui @@ -15,12 +15,12 @@ - + QLabel { font-style:italic; } - Welcome to Bitcoin Core. + Welcome to %1. true @@ -44,9 +44,9 @@ - + - As this is the first time the program is launched, you can choose where Bitcoin Core will store its data. + As this is the first time the program is launched, you can choose where %1 will store its data. true @@ -56,7 +56,7 @@ - Bitcoin Core will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. + %1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. true diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 22c67b804..c712e6ea0 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -30,10 +30,10 @@ - Automatically start Bitcoin Core after logging in to the system. + Automatically start %1 after logging in to the system. - &Start Bitcoin Core on system login + &Start %1 on system login @@ -562,7 +562,7 @@ - The user interface language can be set here. This setting will take effect after restarting Bitcoin Core. + The user interface language can be set here. This setting will take effect after restarting %1. diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 8911b41cb..12d6a62c0 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -617,7 +617,7 @@ 0 0 830 - 68 + 104 @@ -1167,59 +1167,6 @@ - - - - 8 - - - 4 - - - - - Send as zero-fee transaction if possible - - - - - - - (confirmation may take longer) - - - 5 - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - - - Qt::Vertical - - - - 1 - 1 - - - - diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 7d3e48ff3..4b2c10dd4 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,6 +14,8 @@ static const int MAX_PASSPHRASE_SIZE = 1024; /* BitcoinGUI -- Size of icons in status bar */ static const int STATUSBAR_ICONSIZE = 16; +static const bool DEFAULT_SPLASHSCREEN = true; + /* Invalid field background style */ #define STYLE_INVALID "background:#FF8080" @@ -27,6 +29,8 @@ static const int STATUSBAR_ICONSIZE = 16; #define COLOR_TX_STATUS_OPENUNTILDATE QColor(64, 64, 255) /* Transaction list -- TX status decoration - offline */ #define COLOR_TX_STATUS_OFFLINE QColor(192, 192, 192) +/* Transaction list -- TX status decoration - danger, tx needs attention */ +#define COLOR_TX_STATUS_DANGER QColor(200, 100, 100) /* Transaction list -- TX status decoration - default color */ #define COLOR_BLACK QColor(0, 0, 0) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 8917f77f2..ff4320b36 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -62,6 +62,10 @@ #include #endif +#if QT_VERSION >= 0x50200 +#include +#endif + #if BOOST_FILESYSTEM_VERSION >= 3 static boost::filesystem::detail::utf8_codecvt_facet utf8; #endif @@ -88,8 +92,11 @@ QString dateTimeStr(qint64 nTime) return dateTimeStr(QDateTime::fromTime_t((qint32)nTime)); } -QFont bitcoinAddressFont() +QFont fixedPitchFont() { +#if QT_VERSION >= 0x50200 + return QFontDatabase::systemFont(QFontDatabase::FixedFont); +#else QFont font("Monospace"); #if QT_VERSION >= 0x040800 font.setStyleHint(QFont::Monospace); @@ -97,13 +104,14 @@ QFont bitcoinAddressFont() font.setStyleHint(QFont::TypeWriter); #endif return font; +#endif } void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent) { parent->setFocusProxy(widget); - widget->setFont(bitcoinAddressFont()); + widget->setFont(fixedPitchFont()); #if QT_VERSION >= 0x040700 // We don't want translators to use own addresses in translations // and this is the only place, where this address is supplied. @@ -217,7 +225,7 @@ QString formatBitcoinURI(const SendCoinsRecipient &info) if (!info.message.isEmpty()) { - QString msg(QUrl::toPercentEncoding(info.message));; + QString msg(QUrl::toPercentEncoding(info.message)); ret += QString("%1message=%2").arg(paramCount == 0 ? "?" : "&").arg(msg); paramCount++; } @@ -581,12 +589,12 @@ TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* t #ifdef WIN32 boost::filesystem::path static StartupShortcutPath() { - if (GetBoolArg("-testnet", false)) + std::string chain = ChainNameFromCommandLine(); + if (chain == CBaseChainParams::MAIN) + return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin.lnk"; + if (chain == CBaseChainParams::TESTNET) // Remove this special case when CBaseChainParams::TESTNET = "testnet4" return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin (testnet).lnk"; - else if (GetBoolArg("-regtest", false)) - return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin (regtest).lnk"; - - return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin.lnk"; + return GetSpecialFolderPath(CSIDL_STARTUP) / strprintf("Bitcoin (%s).lnk", chain); } bool GetStartOnSystemStartup() @@ -681,7 +689,10 @@ boost::filesystem::path static GetAutostartDir() boost::filesystem::path static GetAutostartFilePath() { - return GetAutostartDir() / "bitcoin.desktop"; + std::string chain = ChainNameFromCommandLine(); + if (chain == CBaseChainParams::MAIN) + return GetAutostartDir() / "bitcoin.desktop"; + return GetAutostartDir() / strprintf("bitcoin-%s.lnk", chain); } bool GetStartOnSystemStartup() @@ -719,15 +730,14 @@ bool SetStartOnSystemStartup(bool fAutoStart) boost::filesystem::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc); if (!optionFile.good()) return false; + std::string chain = ChainNameFromCommandLine(); // Write a bitcoin.desktop file to the autostart directory: optionFile << "[Desktop Entry]\n"; optionFile << "Type=Application\n"; - if (GetBoolArg("-testnet", false)) - optionFile << "Name=Bitcoin (testnet)\n"; - else if (GetBoolArg("-regtest", false)) - optionFile << "Name=Bitcoin (regtest)\n"; - else + if (chain == CBaseChainParams::MAIN) optionFile << "Name=Bitcoin\n"; + else + optionFile << strprintf("Name=Bitcoin (%s)\n", chain); optionFile << "Exec=" << pszExePath << strprintf(" -min -testnet=%d -regtest=%d\n", GetBoolArg("-testnet", false), GetBoolArg("-regtest", false)); optionFile << "Terminal=false\n"; optionFile << "Hidden=false\n"; @@ -896,6 +906,9 @@ QString formatServicesStr(quint64 mask) case NODE_GETUTXO: strList.append("GETUTXO"); break; + case NODE_BLOOM: + strList.append("BLOOM"); + break; default: strList.append(QString("%1[%2]").arg("UNKNOWN").arg(check)); } diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 0ac3db632..9267e0a6c 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -37,8 +37,8 @@ namespace GUIUtil QString dateTimeStr(const QDateTime &datetime); QString dateTimeStr(qint64 nTime); - // Render Bitcoin addresses in monospace font - QFont bitcoinAddressFont(); + // Return a monospace font + QFont fixedPitchFont(); // Set up widgets for address and amounts void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent); diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 4ab87e0f3..6d6af5429 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -1,7 +1,11 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + #include "intro.h" #include "ui_intro.h" @@ -15,9 +19,15 @@ #include #include -/* Minimum free space (in bytes) needed for data directory */ +#include + static const uint64_t GB_BYTES = 1000000000LL; -static const uint64_t BLOCK_CHAIN_SIZE = 20LL * GB_BYTES; +/* Minimum free space (in GB) needed for data directory */ +static const uint64_t BLOCK_CHAIN_SIZE = 80; +/* Minimum free space (in GB) needed for data directory when pruned; Does not include prune target */ +static const uint64_t CHAIN_STATE_SIZE = 2; +/* Total required space (in GB) depending on user choice (prune, not prune) */ +static uint64_t requiredSpace; /* Check free space asynchronously to prevent hanging the UI thread. @@ -112,7 +122,13 @@ Intro::Intro(QWidget *parent) : signalled(false) { ui->setupUi(this); - ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(BLOCK_CHAIN_SIZE/GB_BYTES)); + ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME))); + ui->storageLabel->setText(ui->storageLabel->text().arg(tr(PACKAGE_NAME))); + uint64_t pruneTarget = std::max(0, GetArg("-prune", 0)); + requiredSpace = BLOCK_CHAIN_SIZE; + if (pruneTarget) + requiredSpace = CHAIN_STATE_SIZE + std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES); + ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(tr(PACKAGE_NAME)).arg(requiredSpace)); startThread(); } @@ -162,7 +178,7 @@ void Intro::pickDataDirectory() /* 2) Allow QSettings to override default dir */ dataDir = settings.value("strDataDir", dataDir).toString(); - if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", false)) + if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR)) { /* If current default data directory does not exist, let the user choose one */ Intro intro; @@ -181,7 +197,7 @@ void Intro::pickDataDirectory() TryCreateDirectory(GUIUtil::qstringToBoostPath(dataDir)); break; } catch (const fs::filesystem_error&) { - QMessageBox::critical(0, tr("Bitcoin Core"), + QMessageBox::critical(0, tr(PACKAGE_NAME), tr("Error: Specified data directory \"%1\" cannot be created.").arg(dataDir)); /* fall through, back to choosing screen */ } @@ -216,9 +232,9 @@ void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable ui->freeSpace->setText(""); } else { QString freeString = tr("%n GB of free space available", "", bytesAvailable/GB_BYTES); - if(bytesAvailable < BLOCK_CHAIN_SIZE) + if(bytesAvailable < requiredSpace * GB_BYTES) { - freeString += " " + tr("(of %n GB needed)", "", BLOCK_CHAIN_SIZE/GB_BYTES); + freeString += " " + tr("(of %n GB needed)", "", requiredSpace); ui->freeSpace->setStyleSheet("QLabel { color: #800000 }"); } else { ui->freeSpace->setStyleSheet(""); diff --git a/src/qt/intro.h b/src/qt/intro.h index 50783f722..9e2e96dc9 100644 --- a/src/qt/intro.h +++ b/src/qt/intro.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,6 +9,8 @@ #include #include +static const bool DEFAULT_CHOOSE_DATADIR = false; + class FreespaceChecker; namespace Ui { diff --git a/src/qt/locale/bitcoin_ach.ts b/src/qt/locale/bitcoin_ach.ts deleted file mode 100644 index ddb9fb85c..000000000 --- a/src/qt/locale/bitcoin_ach.ts +++ /dev/null @@ -1,110 +0,0 @@ - - - AddressBookPage - - - AddressTableModel - - - AskPassphraseDialog - - - BitcoinGUI - - - ClientModel - - - CoinControlDialog - - - EditAddressDialog - - - FreespaceChecker - - - HelpMessageDialog - - - Intro - - - OpenURIDialog - - - OptionsDialog - - - OverviewPage - - - PaymentServer - - - PeerTableModel - - - QObject - - - QRImageWidget - - - RPCConsole - - - ReceiveCoinsDialog - - - ReceiveRequestDialog - - - RecentRequestsTableModel - - - SendCoinsDialog - - - SendCoinsEntry - - - ShutdownWindow - - - SignVerifyMessageDialog - - - SplashScreen - - - TrafficGraphWidget - - - TransactionDesc - - - TransactionDescDialog - - - TransactionTableModel - - - TransactionView - - - UnitDisplayStatusBarControl - - - WalletFrame - - - WalletModel - - - WalletView - - - bitcoin-core - - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_af_ZA.ts b/src/qt/locale/bitcoin_af_ZA.ts index 3767a4c83..d77aa77f8 100644 --- a/src/qt/locale/bitcoin_af_ZA.ts +++ b/src/qt/locale/bitcoin_af_ZA.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -100,6 +100,9 @@ Beursie dekripsie het misluk + + BanTableModel + BitcoinGUI @@ -211,6 +214,14 @@ EditAddressDialog + + &Label + &Etiket + + + &Address + &Adres + New receiving address Nuwe ontvangende adres @@ -258,6 +269,10 @@ Options Opsies + + W&allet + &Beursie + OverviewPage @@ -291,6 +306,14 @@ ReceiveCoinsDialog + + &Amount: + &Bedrag: + + + &Message: + &Boodskap: + Copy amount Kopieer bedrag @@ -344,10 +367,18 @@ Send Coins Stuur Munstukke + + Insufficient funds! + Onvoldoende fondse + Amount: Bedrag: + + Transaction Fee: + Transaksie fooi: + Send to multiple recipients at once Stuur aan vele ontvangers op eens @@ -371,6 +402,10 @@ SendCoinsEntry + + A&mount: + &Bedrag: + Message: Boodskap: @@ -450,6 +485,10 @@ Transaction ID Transaksie ID + + Transaction + Transaksie + Amount Bedrag @@ -630,10 +669,6 @@ Options: Opsies: - - Use the test network - Gebruik die toets netwerk - Error: Disk space is low! Fout: Hardeskyf spasie is baie laag! diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts index e56083fa2..88ce05bbd 100644 --- a/src/qt/locale/bitcoin_ar.ts +++ b/src/qt/locale/bitcoin_ar.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -93,7 +93,11 @@ Exporting Failed فشل التصدير - + + There was an error trying to save the address list to %1. Please try again. + لقد حدث خطأ أثناء حفظ قائمة العناوين إلى %1. يرجى المحاولة مرة أخرى. + + AddressTableModel @@ -163,6 +167,10 @@ Are you sure you wish to encrypt your wallet? هل أنت متأكد من رغبتك في تشفير محفظتك ؟ + + Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + بتكوين سوف يغلق الآن لإنهاء عملية التشفير. تذكر أن التشفير لا يستطيع حماية محفظتك تمامًا من السرقة من خلال البرمجيات الخبيثة التي تصيب جهازك + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. هام: أي نسخة إحتياطية سابقة قمت بها لمحفظتك يجب استبدالها بأخرى حديثة، مشفرة. لأسباب أمنية، النسخ الاحتياطية السابقة لملفات المحفظة الغير مشفرة تصبح عديمة الفائدة مع بداية استخدام المحفظة المشفرة الجديدة. @@ -179,6 +187,10 @@ Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. أدخل عبارة مرور جديدة إلى المحفظة. الرجاء استخدام عبارة مرور تتكون من10 حروف عشوائية على الاقل, أو أكثر من 7 كلمات + + Enter the old passphrase and new passphrase to the wallet. + أدخل كلمة المرور القديمة والجديدة للمحفظة. + Wallet encryption failed فشل تشفير المحفظة @@ -208,6 +220,9 @@ لقد تم تغير عبارة مرور المحفظة بنجاح + + BanTableModel + BitcoinGUI @@ -322,6 +337,10 @@ Wallet محفظة + + &Send + &ارسل + &Receive &استقبل @@ -366,6 +385,10 @@ &About Bitcoin Core حول bitcoin core + + %1 and %2 + %1 و %2 + Error خطأ @@ -768,6 +791,10 @@ PaymentServer + + Bad response from server %1 + استجابة سيئة من الملقم %1 + PeerTableModel @@ -778,6 +805,14 @@ Amount المبلغ + + %1 h + %1 ساعة + + + %1 m + %1 دقيقة + N/A غير معروف @@ -820,6 +855,10 @@ &Information المعلومات + + Debug window + نافذة المعالجة + General عام @@ -897,12 +936,32 @@ استخدم اسهم الاعلى و الاسفل للتنقل بين السجلات و <b>Ctrl-L</b> لمسح الشاشة - Unknown - غير معرف + %1 B + %1 بايت - Fetching... - جاري الجلب... + %1 KB + %1 كيلو بايت + + + %1 MB + %1 ميقا بايت + + + %1 GB + %1 قيقا بايت + + + Yes + نعم + + + No + لا + + + Unknown + غير معرف @@ -1060,6 +1119,10 @@ Change: تعديل : + + Transaction Fee: + رسوم المعاملة: + Send to multiple recipients at once إرسال إلى عدة مستلمين في وقت واحد @@ -1092,6 +1155,10 @@ Confirm send coins تأكيد الإرسال Coins + + %1 to %2 + %1 الى %2 + Copy quantity نسخ الكمية @@ -1116,10 +1183,6 @@ Copy change نسخ التعديل - - Total Amount %1 (= %2) - مجموع المبلغ %1 (= %2) - or أو @@ -1132,6 +1195,10 @@ The amount exceeds your balance. القيمة تتجاوز رصيدك + + The total exceeds your balance when the %1 transaction fee is included. + المجموع يتجاوز رصيدك عندما يتم اضافة %1 رسوم العملية + (no label) (لا وصف) @@ -1139,6 +1206,10 @@ SendCoinsEntry + + A&mount: + &القيمة + Pay &To: ادفع &الى : @@ -1167,6 +1238,10 @@ Message: الرسائل + + Pay To: + ادفع &الى : + ShutdownWindow @@ -1286,10 +1361,22 @@ TransactionDesc + + Open until %1 + مفتوح حتى %1 + conflicted يتعارض + + %1/offline + %1 غير متواجد + + + %1/unconfirmed + غير مؤكدة/%1 + %1 confirmations تأكيد %1 @@ -1400,6 +1487,10 @@ Type النوع + + Open until %1 + مفتوح حتى %1 + This block was not received by any other nodes and will probably not be accepted! لم يتم تلقى هذه الكتلة (Block) من قبل أي العقد الأخرى وربما لن تكون مقبولة! @@ -1416,6 +1507,10 @@ Label وصف + + Conflicted + يتعارض + Received with استقبل مع @@ -1630,10 +1725,6 @@ Specify data directory حدد مجلد المعلومات - - Use the test network - استخدم التحقق من الشبكه - Accept connections from outside (default: 1 if no -proxy or -connect) قبول الاتصالات من خارج @@ -1682,10 +1773,6 @@ Warning تحذير - - Upgrade wallet to latest format - تحديث المحفظة للنسخة الاخيرة - This help message رسالة المساعدة هذه diff --git a/src/qt/locale/bitcoin_be_BY.ts b/src/qt/locale/bitcoin_be_BY.ts index 5f7f6f89b..2709ff37e 100644 --- a/src/qt/locale/bitcoin_be_BY.ts +++ b/src/qt/locale/bitcoin_be_BY.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,9 @@ Парольная фраза гаманца паспяхова зменена. + + BanTableModel + BitcoinGUI @@ -795,7 +798,7 @@ command-line options опцыі каманднага радка - + Intro @@ -840,6 +843,10 @@ MB Мб + + W&allet + Гаманец + OverviewPage @@ -866,9 +873,21 @@ RPCConsole + + &Information + Інфармацыя + + + Debug window + Вакно адладкі + ReceiveCoinsDialog + + &Amount: + &Колькасць: + &Label: Метка: @@ -884,6 +903,10 @@ ReceiveRequestDialog + + Copy &Address + Капіяваць адрас + Address Адрас @@ -930,6 +953,10 @@ Send Coins Даслаць Манеты + + Insufficient funds! + Недастаткова сродкаў + Quantity: Колькасць: @@ -1041,6 +1068,14 @@ Alt+P Alt+P + + Message: + Паведамленне: + + + Pay To: + Заплаціць да: + Memo: Памятка: @@ -1372,10 +1407,6 @@ Run in the background as a daemon and accept commands Запусціць у фоне як дэман і прымаць каманды - - Use the test network - Ужываць тэставае сеціва - Do you want to rebuild the block database now? Ці жадаеце вы перабудаваць зараз базу звестак блокаў? @@ -1396,10 +1427,6 @@ Error opening block database Памылка адчынення базы звестак блокаў - - Error: A fatal internal error occured, see debug.log for details - Памылка: здарылася Фатальная унутраная памылка, глядзі debug.log для падрабязнасцяў - Error: Disk space is low! Памылка: Замала вольнага месца на дыску! @@ -1428,10 +1455,6 @@ Wallet options: Опцыі гаманца: - - Imports blocks from external blk000??.dat file - Імпартаванне блокаў з вонкавага blk000??.dat файла - Activating best chain... Актывацыя лепшага ланцуга... @@ -1452,10 +1475,6 @@ Signing transaction failed Памылка подпісу транзакцыі - - Start minimized - Стартаваць ммінімізаванай - This is experimental software. Гэта эксперыментальная праграма. @@ -1484,18 +1503,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Выканаць каманду калі лепшы блок зменіцца (%s замяняецца на хэш блока) - - Upgrade wallet to latest format - Абнавіць гаманец на новы фармат - - - Rescan the block chain for missing wallet transactions - Перасканаваць ланцуг блокаў дзеля пошуку адсутных транзакцый - - - Use OpenSSL (https) for JSON-RPC connections - Ужываць OpenSSL (https) для JSON-RPC злучэнняў - Loading addresses... Загружаем адрасы... diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts index e2821dbde..ecd10e546 100644 --- a/src/qt/locale/bitcoin_bg.ts +++ b/src/qt/locale/bitcoin_bg.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -167,6 +167,10 @@ Are you sure you wish to encrypt your wallet? Наистина ли желаете да шифрирате портфейла си? + + Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + Биткоин сега ще се затоври за да завърши процеса на криптиране. Запомнете, че криптирането на вашия портефейл не може напълно да предпази вашите монети от кражба чрез зловреден софтуер, инфектирал вашия компютър + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. ВАЖНО: Всички стари запазвания, които сте направили на Вашият портфейл трябва да замените с запазване на новополучения, шифриран портфейл. От съображения за сигурност, предишните запазвания на нешифрирани портфейли ще станат неизползваеми веднага, щом започнете да използвате новият, шифриран портфейл. @@ -208,6 +212,9 @@ Паролата на портфейла беше променена успешно. + + BanTableModel + BitcoinGUI @@ -410,6 +417,10 @@ %1 behind %1 зад + + Last received block was generated %1 ago. + Последния получен блок е генериран преди %1. + Transactions after this will not yet be visible. Транзакции след това няма все още да бъдат видими. @@ -434,6 +445,36 @@ Catching up... Зарежда блокове... + + Date: %1 + + Дата: %1 + + + + Amount: %1 + + Сума: %1 + + + + Type: %1 + + Тип: %1 + + + + Label: %1 + + Етикет: %1 + + + + Address: %1 + + Адрес: %1 + + Sent transaction Изходяща транзакция @@ -632,6 +673,10 @@ none нищо + + This label turns red if the transaction size is greater than 1000 bytes. + Този етикет става червен, когато размера на транзакцията е по-голяма от 1000 бита. + yes да @@ -761,7 +806,7 @@ command-line options Списък с налични команди - + Intro @@ -818,6 +863,10 @@ MB Мегабайта + + Number of script &verification threads + Брой на скриптове и &нишки за потвърждение + Accept connections from outside Приемай връзки отвън @@ -846,6 +895,10 @@ &Network &Мрежа + + Automatically start Bitcoin Core after logging in to the system. + Автоматично стартиране на Bitcoin Core след влизане в системата. + W&allet По&ртфейл @@ -854,6 +907,10 @@ Expert Експерт + + Enable coin &control features + Позволяване на монетите и &техните възможности + &Spend unconfirmed change &Похарчете непотвърденото ресто @@ -1044,13 +1101,21 @@ Payment request file handling Файл за справяне със заявки + + Payment request expired. + Заявката за плащане е изтекла. + + + Invalid payment request. + Невалидна заявка за плащане. + Refund from %1 Възстановяване на сума от %1 - Payment request DoS protection - Дос защита на заявката за плащане + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + Заявката за плащане %1 е твърде голям (%2 байта, позволени %3 байта). Error communicating with %1: %2 @@ -1224,10 +1289,6 @@ Services Услуги - - Starting Height - Стартова височина - Connection Time Продължителност на връзката @@ -1240,14 +1301,6 @@ Last Receive Получени за последно - - Bytes Sent - Изпратени байтове - - - Bytes Received - Получени байтове - Ping Time Време за отговор @@ -1337,12 +1390,16 @@ Изходящи - Unknown - Неизвестен + Yes + Да - Fetching... - Прихващане... + No + Не + + + Unknown + Неизвестен @@ -1544,6 +1601,10 @@ per kilobyte за килобайт + + Hide + Скрий + total at least Крайна сума поне @@ -1632,10 +1693,6 @@ Copy change Копирай рестото - - Total Amount %1 (= %2) - Пълна сума %1 (= %2) - or или @@ -1657,8 +1714,8 @@ Грешка при създаването на транзакция! - Pay only the minimum fee of %1 - Платете минималната такса от %1 + Payment request expired. + Заявката за плащане е изтекла. Warning: Invalid Bitcoin address @@ -1938,6 +1995,10 @@ own address собствен адрес + + watch-only + само гледане + label име @@ -2100,6 +2161,10 @@ Mined Емитирани + + watch-only + само гледане + (n/a) (n/a) @@ -2207,6 +2272,10 @@ Export Transaction History Изнасяне историята на транзакциите + + Watch-only + само гледане + Exporting Failed Грешка при изнасянето @@ -2326,26 +2395,14 @@ Specify your own public address Въведете Ваш публичен адрес - - Use the test network - Използвайте тестовата мрежа - Accept connections from outside (default: 1 if no -proxy or -connect) Приемайте връзки отвън.(по подразбиране:1 в противен случай -proxy или -connect) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Внимание: -paytxfee е с мното голяма зададена стойност! Това е транзакционната такса, която ще платите ако направите транзакция. - Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. Сложете в бял списък пиъри,свързващи се от дадената интернет маска или айпи адрес.Може да бъде заложено неколкократно. - - (default: 1) - (по подразбиране 1) - <category> can be: <category> може да бъде: @@ -2390,14 +2447,6 @@ Set the number of threads for coin generation if enabled (-1 = all cores, default: %d) Заложете броя на нишки за генерация на монети ако е включено(-1 = всички ядра, по подразбиране: %d) - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Внимание: -maxtxfee има много висока стойност! Толкова високи такси могат да бъдат заплатени на една транзакция. - - - Choose data directory on startup (default: 0) - Изберете директория при стартиране на програмата.( настройка по подразбиране:0) - Connect through SOCKS5 proxy Свързване чрез SOCKS5 прокси @@ -2410,6 +2459,10 @@ Information Информация + + Invalid amount for -maxtxfee=<amount>: '%s' + Невалидна сума за -maxtxfee=<amount>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' Невалидна сума за -minrelaytxfee=<amount>: '%s' @@ -2422,14 +2475,6 @@ Send trace/debug info to console instead of debug.log file Изпрати локализиращата или дебъг информацията към конзолата, вместо файлът debug.log - - Set language, for example "de_DE" (default: system locale) - Задаване на език,например "de_DE" (по подразбиране: system locale) - - - Start minimized - Стартирай минимизирано - This is experimental software. Това е експериментален софтуер. @@ -2454,26 +2499,10 @@ Warning Предупреждение - - on startup - по време на стартирането - Password for JSON-RPC connections Парола за JSON-RPC връзките - - Upgrade wallet to latest format - Обновяване на портфейла до най-новия формат - - - Rescan the block chain for missing wallet transactions - Повторно сканиране на блок-връзка за липсващи портфейлни транзакции - - - Use OpenSSL (https) for JSON-RPC connections - Използвайте OpenSSL (https) за JSON-RPC връзките - This help message Това помощно съобщение diff --git a/src/qt/locale/bitcoin_cmn.ts b/src/qt/locale/bitcoin_bg_BG.ts similarity index 58% rename from src/qt/locale/bitcoin_cmn.ts rename to src/qt/locale/bitcoin_bg_BG.ts index 37c937b86..353f6d771 100644 --- a/src/qt/locale/bitcoin_cmn.ts +++ b/src/qt/locale/bitcoin_bg_BG.ts @@ -1,9 +1,25 @@ - + AddressBookPage + + Right-click to edit address or label + Клик с десен бутон на мишката за промяна на адрес или етикет + Create a new address - 创建新地址 + Създай нов адрес + + + &New + Нов + + + &Copy + Копирай + + + C&lose + Затвори @@ -12,8 +28,19 @@ AskPassphraseDialog + + BanTableModel + BitcoinGUI + + Bitcoin Core + Биткойн ядро + + + &About Bitcoin Core + За Биткойн ядрото + ClientModel @@ -29,9 +56,21 @@ HelpMessageDialog + + Bitcoin Core + Биткойн ядро + + + About Bitcoin Core + За Биткойн ядрото + Intro + + Bitcoin Core + Биткойн ядро + OpenURIDialog @@ -80,6 +119,10 @@ SplashScreen + + Bitcoin Core + Биткойн ядро + TrafficGraphWidget diff --git a/src/qt/locale/bitcoin_bs.ts b/src/qt/locale/bitcoin_bs.ts index 86526022f..a18684220 100644 --- a/src/qt/locale/bitcoin_bs.ts +++ b/src/qt/locale/bitcoin_bs.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -8,6 +8,9 @@ AskPassphraseDialog + + BanTableModel + BitcoinGUI diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts index ceb71469c..38e770f18 100644 --- a/src/qt/locale/bitcoin_ca.ts +++ b/src/qt/locale/bitcoin_ca.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,17 @@ La contrasenya del moneder ha estat modificada correctament. + + BanTableModel + + IP/Netmask + IP / Màscara de xarxa + + + Banned Until + Bandejat fins + + BitcoinGUI @@ -871,6 +882,34 @@ command-line options Opcions de la línia d'ordres + + UI Options: + Opcions d'interfície d'usuari: + + + Choose data directory on startup (default: %u) + Trieu el directori de dades a l'inici (per defecte: %u) + + + Set language, for example "de_DE" (default: system locale) + Defineix la llengua, per exemple «de_DE» (per defecte: la definida pel sistema) + + + Start minimized + Inicia minimitzat + + + Set SSL root certificates for payment request (default: -system-) + Defineix els certificats arrel SSL per a la sol·licitud de pagament (per defecte: els del sistema) + + + Show splash screen on startup (default: %u) + Mostra la pantalla de benvinguda a l'inici (per defecte: %u) + + + Reset all settings changes made over the GUI + Reinicialitza tots els canvis de configuració fets des de la interfície gràfica + Intro @@ -1068,6 +1107,18 @@ Port of the proxy (e.g. 9050) Port del proxy (per exemple 9050) + + Used for reaching peers via: + Utilitzat per arribar als iguals mitjançant: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Mostra si el proxy SOCKS5 per defecte proporcionat s'utilitza per arribar als iguals mitjançant aquest tipus de xarxa. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Utilitza un proxy SOCKS4 apart per a arribar als iguals a través de serveis ocults de Tor: + &Window &Finestra @@ -1286,10 +1337,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). La sol·licitud de pagament %1 és massa gran (%2 bytes, permès %3 bytes). - - Payment request DoS protection - Protecció de DoS per a la sol·licitud de pagament - Error communicating with %1: %2 Error en comunicar amb %1: %2 @@ -1458,10 +1505,18 @@ &Peers &Iguals + + Banned peers + Iguals bandejats + Select a peer to view detailed information. Seleccioneu un igual per mostrar informació detallada. + + Whitelisted + A la llista blanca + Direction Direcció @@ -1470,6 +1525,18 @@ Version Versió + + Starting Block + Bloc d'inici + + + Synced Headers + Capçaleres sincronitzades + + + Synced Blocks + Blocs sincronitzats + User Agent Agent d'usuari @@ -1478,14 +1545,6 @@ Services Serveis - - Starting Height - Alçada inicial - - - Sync Height - Sincronitza l'alçada - Ban Score Puntuació de bandeig @@ -1502,18 +1561,18 @@ Last Receive Darrera recepció - - Bytes Sent - Bytes enviats - - - Bytes Received - Bytes rebuts - Ping Time Temps de ping + + The duration of a currently outstanding ping. + La duració d'un ping més destacat actualment. + + + Ping Wait + Espera de ping + Time Offset Diferència horària @@ -1562,6 +1621,34 @@ Clear console Neteja la consola + + &Disconnect Node + &Desconnecta el node + + + Ban Node for + Bandeja el node durant + + + 1 &hour + 1 &hora + + + 1 &day + 1 &dia + + + 1 &week + 1 &setmana + + + 1 &year + 1 &any + + + &Unban Node + &Desbandeja el node + Welcome to the Bitcoin Core RPC console. Us donem la benviguda a la consola RPC del Bitcoin Core. @@ -1590,6 +1677,10 @@ %1 GB %1 GB + + (node id: %1) + (id del node: %1) + via %1 a través de %1 @@ -1607,12 +1698,16 @@ Sortint - Unknown - Desconegut + Yes + - Fetching... - S'està obtenint... + No + No + + + Unknown + Desconegut @@ -1979,8 +2074,8 @@ Copia el canvi - Total Amount %1 (= %2) - Import total %1 (= %2) + Total Amount %1 + Import total %1 or @@ -2014,14 +2109,14 @@ Payment request expired. La sol·licitud de pagament ha vençut. + + Pay only the required fee of %1 + Paga només la comissió necessària de %1 + Estimated to begin confirmation within %n block(s). Estimat per començar la confirmació en %n bloc.Estimat per començar la confirmació en %n blocs. - - Pay only the minimum fee of %1 - Paga només la comissió mínima de %1 - The recipient address is not valid. Please recheck. L'adreça de destinatari no és vàlida. Torneu-la a comprovar. @@ -2801,12 +2896,16 @@ Accepta la línia d'ordres i ordres JSON-RPC - Run in the background as a daemon and accept commands - Executa en segon pla com a programa dimoni i accepta ordres + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Comissions totals màximes (en %s) per utilitzar en una única transacció de moneder; definir-ne una massa baixa pot interrompre les transaccions més grans (per defecte: %s) - Use the test network - Utilitza la xarxa de prova + Fee (in %s/kB) to add to transactions you send (default: %s) + Comissió (en %s/kB) per afegir a les transaccions que envieu (per defecte: %s) + + + Run in the background as a daemon and accept commands + Executa en segon pla com a programa dimoni i accepta ordres Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2828,14 +2927,6 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Executa una ordre quan una transacció del moneder canviï (%s en cmd es canvia per TxID) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Comissions totals màximes que s'utilitzaran en una única transacció de moneder; si s'estableix un valor massa baix es poden interrompre transaccions grans (per defecte: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Redueix els requeriments d'emmagatzemament podant (suprimint) els blocs antics. Aquest mode inhabilita l'ús de moneders i és incompatible amb -tindex. Avís: Revertir aquesta configuració comporta tornar a baixar la cadena de blocs sencera. (per defecte: 0 = inhabilita la poda de blocs, >%u = mida objectiu en MiB per utilitzar els fitxers de blocs) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Defineix el nombre de fils de verificació d'scripts (%u a %d, 0 = auto, <0 = deixa tants nuclis lliures, per defecte: %d) @@ -2856,10 +2947,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) AVÍS: comproveu la vostra connexió a la xarxa, %d blocs rebuts en les darreres %d hores (se n'esperaven %d) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Avís: el -paytxfee és molt elevat! Aquesta és la comissió de transacció que pagareu si envieu una transacció. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Avís: la xarxa no sembla que hi estigui plenament d'acord. Alguns miners sembla que estan experimentant problemes. @@ -2868,10 +2955,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Avís: sembla que no estem plenament d'acord amb els nostres iguals! Podria caler que actualitzar l'aplicació, o potser que ho facin altres nodes. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Avís: error en llegir el fitxer wallet.dat! Totes les claus es llegeixen correctament, però hi ha dades de transaccions o entrades de la llibreta d'adreces absents o bé son incorrectes. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Avís: el fitxer wallet.dat és corrupte, dades rescatades! L'arxiu wallet.dat original ha estat desat com wallet.{estampa_temporal}.bak al directori %s; si el teu balanç o transaccions son incorrectes hauries de restaurar-lo de un backup. @@ -2880,18 +2963,10 @@ Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. Afegeix a la llista blanca els iguals que es connecten de la màscara de xarxa o adreça IP donada. Es pot especificar moltes vegades. - - (default: 1) - (per defecte: 1) - <category> can be: <category> pot ser: - - Attempt to recover private keys from a corrupt wallet.dat - Intenta recuperar les claus privades d'un fitxer wallet.dat corrupte - Block creation options: Opcions de la creació de blocs: @@ -2936,10 +3011,6 @@ Error opening block database Error en obrir la base de dades de blocs - - Error: A fatal internal error occured, see debug.log for details - Error: s'ha produït un error intern fatal. Consulteu debug.log per a més detalls - Error: Disk space is low! Error: Espai al disc baix! @@ -2948,10 +3019,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Ha fallat escoltar a qualsevol port. Feu servir -listen=0 si voleu fer això. - - If <category> is not supplied, output all debugging information. - Si no se subministra <category>, mostra tota la informació de depuració. - Importing... S'està important... @@ -3020,10 +3087,6 @@ You need to rebuild the database using -reindex to change -txindex Cal que reconstruïu la base de dades fent servir -reindex per canviar -txindex - - Imports blocks from external blk000??.dat file - Importa blocs de un fitxer blk000??.dat extern - 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 Permet les connexions JSON-RPC d'una font específica. Vàlid per a <ip> són una IP individual (p. ex., 1.2.3.4), una xarxa / màscara de xarxa (p. ex., 1.2.3.4/255.255.255.0) o una xarxa/CIDR (p. ex., 1.2.3.4/24). Es pot especificar aquesta opció moltes vegades @@ -3052,18 +3115,10 @@ Error: Listening for incoming connections failed (listen returned error %s) Error: ha fallat escoltar les connexions entrants (l'escoltament ha retornat l'error %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Error: s'ha trobat un argument no permès de -socks. Ja no es pot definir més la versió de SOCKS, només s'accepten els proxies de SOCKS5.ç - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Executa l'ordre quan es rebi un avís rellevant o veiem una forquilla molt llarga (%s en cmd és reemplaçat per un missatge) - - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Comissions (en BTC/Kb) inferiors a això es consideren de comissió zero per a la transmissió (per defecte: %s) - If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) Si no s'especifica una paytxfee (comissió de transacció de pagament), inclogueu suficient comissió per tal que les transaccions comencin a confirmar-se en una mitja de n blocs (per defecte: %u) @@ -3076,10 +3131,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) Mida màxima de les dades en les transaccions de l'operador en què confiem i en les meves (per defecte: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - Poda configurada per sota el mínim de %d MB. Feu servir un nombre superior. - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Consulta a adreces d'iguals a través de DNS, si es troba baix en adreces (per defecte: 1 a menys que -connect) @@ -3104,37 +3155,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Aquest producte inclou programari desenvolupat pel projecte OpenSSL per a ús a l'OpenSSL Toolkit <https://www.openssl.org/> i programari criptogràfic escrit per Eric Young i programari UPnP escrit per Thomas Bernard. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - Per utilitzar bitcoind, o l'opció de serviddor de bitcoin-qt, heu de definir una rpcpassword en el fitxer de configuració: -%s -Es recomana que utilitzeu la contrasenya aleatòria següent: -rpcuser=bitcoinrpc -rpcpassword=%s -(no cal que recordeu la contrasenya) -El nom d'usuari i la contrasenya NO han de ser els mateixos. -Si el fitxer no existeix, creeu-ne un amb permisos de lectura només per al seu propietari. -Es recomana definir alertnotify per tal de ser notificat de qualsevol problema; -per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.com - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Avís: s'ha especificat un -maxtxfee molt alt! Comissions tan grans podrien pagar-se en una única transacció. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Avís: comproveu que la data i hora del vostre ordinador siguin correctes! Si el vostre rellotge no és correcte, el Bitcoin Core no funcionarà correctament. - 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 Els iguals en la llista blanca no poden ser bandejats per DoS i es transmetran sempre llurs transaccions, fins i tot si ja són a la mempool. Això és útil, p. ex., per a una passarel·la @@ -3155,18 +3175,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comActivating best chain... S'està activant la millor cadena... - - Can't run with a wallet in prune mode. - No es pot executar amb un moneder en mode poda. - Cannot resolve -whitebind address: '%s' No es pot resoldre l'adreça -whitebind: «%s» - - Choose data directory on startup (default: 0) - Tria el directori de dades a l'inici (per defecte: 0) - Connect through SOCKS5 proxy Connecta a través del proxy SOCKS5 @@ -3175,10 +3187,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comCopyright (C) 2009-%i The Bitcoin Core Developers Copyright (C) 2009-%i Els desenvolupadors del Bitcoin Core - - Could not parse -rpcbind value %s as network address - No s'ha pogut analitzar el valor -rpcbind %s com una adreça de xarxa - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Error en carregar wallet.dat: el moneder requereix una versió més nova del Bitcoin core @@ -3187,14 +3195,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comError reading from database, shutting down. Error en llegir la base de dades, tancant. - - Error: Unsupported argument -tor found, use -onion. - Error: s'ha trobat un argument -tor no acceptat. Feu servir -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Comissió en (BTC/kB) per afegir a les transaccions que envieu (per defecte: %s) - Information &Informació @@ -3235,18 +3235,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comNode relay options: Opcions de transmissió del node: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Opcions RPC SSL: (veieu el wiki del Bitcoin per a instruccions de configuració de l'SSL) - RPC server options: Opcions del servidor RPC: - - RPC support for HTTP persistent connections (default: %d) - Suport RPC per a connexions HTTP persistents (per defecte: %d) - Rebuild block chain index from current blk000??.dat files on startup Reconstrueix l'índex de la cadena de blocs dels fitxers blk000??.dat actuals a l'inici. @@ -3263,22 +3255,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comSend transactions as zero-fee transactions if possible (default: %u) Envia les transaccions com a transaccions de comissió zero sempre que sigui possible (per defecte: %u) - - Set SSL root certificates for payment request (default: -system-) - Defineix certificats arrel SSL per a la sol·licitud de pagament (per defecte: -sistema-) - - - Set language, for example "de_DE" (default: system locale) - Defineix un idioma, per exemple «de_DE» (per defecte: preferències locals de sistema) - Show all debugging options (usage: --help -help-debug) Mostra totes les opcions de depuració (ús: --help --help-debug) - - Show splash screen on startup (default: 1) - Mostra la finestra de benvinguda a l'inici (per defecte: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Redueix el fitxer debug.log durant l'inici del client (per defecte: 1 quan no -debug) @@ -3287,10 +3267,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comSigning transaction failed Ha fallat la signatura de la transacció - - Start minimized - Inicia minimitzat - The transaction amount is too small to pay the fee L'import de la transacció és massa petit per pagar-ne una comissió @@ -3315,18 +3291,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comTransaction too large La transacció és massa gran - - UI Options: - Opcions d'interfície: - Unable to bind to %s on this computer (bind returned error %s) No s'ha pogut vincular a %s en aquest ordinador (la vinculació ha retornat l'error %s) - - Use UPnP to map the listening port (default: 1 when listening) - Utilitza UPnP per a mapejar els ports d'escolta (per defecte: 1 quan s'escolta) - Username for JSON-RPC connections Nom d'usuari per a connexions JSON-RPC @@ -3339,22 +3307,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comWarning Avís - - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Avís: s'ha ignorat l'argument no acceptat de -benchmark. Feu servir -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Avís: s'ha ignorat l'argument no acceptat de -debugnet. Feu servir -debug=net. - Zapping all transactions from wallet... Se suprimeixen totes les transaccions del moneder... - - on startup - a l'inici de l'aplicació - wallet.dat corrupt, salvage failed El fitxer wallet.data és corrupte. El rescat de les dades ha fallat @@ -3367,18 +3323,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comExecute command when the best block changes (%s in cmd is replaced by block hash) Executa l'ordre quan el millor bloc canviï (%s en cmd es reemplaça per un resum de bloc) - - Upgrade wallet to latest format - Actualitza el moneder a l'últim format - - - Rescan the block chain for missing wallet transactions - Reescaneja la cadena de blocs en les transaccions de moneder perdudes - - - Use OpenSSL (https) for JSON-RPC connections - Utilitza OpenSSL (https) per a connexions JSON-RPC - This help message Aquest misatge d'ajuda @@ -3423,10 +3367,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.com(default: %s) (per defecte: %s) - - Acceptable ciphers (default: %s) - Xifrats acceptables (per defecte: %s) - Always query for peer addresses via DNS lookup (default: %u) Demana sempre les adreces dels iguals a través de consultes DNS (per defecte: %u) @@ -3487,14 +3427,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comRelay non-P2SH multisig (default: %u) Retransmet multisig no P2SH (per defecte: %u) - - Server certificate file (default: %s) - Fitxer de certificat del servidor (per defecte: %s) - - - Server private key (default: %s) - Clau privada del servidor (per defecte: %s) - Set key pool size to <n> (default: %u) Defineix la mida clau disponible a <n> (per defecte: %u) diff --git a/src/qt/locale/bitcoin_ca@valencia.ts b/src/qt/locale/bitcoin_ca@valencia.ts index b77845cfb..2c41ec78d 100644 --- a/src/qt/locale/bitcoin_ca@valencia.ts +++ b/src/qt/locale/bitcoin_ca@valencia.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,9 @@ La contrasenya del moneder ha estat modificada correctament. + + BanTableModel + BitcoinGUI @@ -430,6 +433,10 @@ No block source available... No hi ha cap font de bloc disponible... + + Processed %n block(s) of transaction history. + Proccessats %n bloc de l'historial de transaccions.Proccessats %n blocs de l'historial de transaccions. + %n hour(s) %n hora%n hores @@ -867,7 +874,7 @@ command-line options Opcions de la línia d'ordes - + Intro @@ -1064,6 +1071,10 @@ Port of the proxy (e.g. 9050) Port del proxy (per exemple 9050) + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Utilitza un proxy SOCKS4 apart per a arribar als iguals a través de serveis ocults de Tor: + &Window &Finestra @@ -1282,10 +1293,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). La sol·licitud de pagament %1 és massa gran (%2 bytes, permés %3 bytes). - - Payment request DoS protection - Protecció de DoS per a la sol·licitud de pagament - Error communicating with %1: %2 Error en comunicar amb %1: %2 @@ -1474,14 +1481,6 @@ Services Serveis - - Starting Height - Alçada inicial - - - Sync Height - Sincronitza l'alçada - Ban Score Puntuació de bandeig @@ -1498,14 +1497,6 @@ Last Receive Darrera recepció - - Bytes Sent - Bytes enviats - - - Bytes Received - Bytes rebuts - Ping Time Temps de ping @@ -1603,12 +1594,16 @@ Eixint - Unknown - Desconegut + Yes + - Fetching... - S'està obtenint... + No + No + + + Unknown + Desconegut @@ -1974,10 +1969,6 @@ Copy change Copia el canvi - - Total Amount %1 (= %2) - Import total %1 (= %2) - or o @@ -2014,10 +2005,6 @@ Estimated to begin confirmation within %n block(s). Estimat per començar la confirmació en %n bloc.Estimat per començar la confirmació en %n blocs. - - Pay only the minimum fee of %1 - Paga només la comissió mínima de %1 - The recipient address is not valid. Please recheck. L'adreça de destinatari no és vàlida. Torneu-la a comprovar. @@ -2800,10 +2787,6 @@ Run in the background as a daemon and accept commands Executa en segon pla com a programa dimoni i accepta ordes - - Use the test network - Utilitza la xarxa de prova - Accept connections from outside (default: 1 if no -proxy or -connect) Accepta connexions de fora (per defecte: 1 si no -proxy o -connect) @@ -2824,14 +2807,6 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Executa una orde quan una transacció del moneder canvie (%s en cmd es canvia per TxID) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Comissions totals màximes que s'utilitzaran en una única transacció de moneder; si s'estableix un valor massa baix es poden interrompre transaccions grans (per defecte: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Redueix els requeriments d'emmagatzemament podant (suprimint) els blocs antics. Este mode inhabilita l'ús de moneders i és incompatible amb -tindex. Avís: Revertir esta configuració comporta tornar a baixar la cadena de blocs sencera. (per defecte: 0 = inhabilita la poda de blocs, >%u = mida objectiu en MiB per utilitzar els fitxers de blocs) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Defineix el nombre de fils de verificació d'scripts (%u a %d, 0 = auto, <0 = deixa tants nuclis lliures, per defecte: %d) @@ -2852,10 +2827,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) AVÍS: comproveu la vostra connexió a la xarxa, %d blocs rebuts en les darreres %d hores (se n'esperaven %d) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Avís: el -paytxfee és molt elevat! Esta és la comissió de transacció que pagareu si envieu una transacció. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Avís: la xarxa no pareix que hi estiga plenament d'acord. Alguns miners pareix que estan experimentant problemes. @@ -2864,10 +2835,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Avís: pareix que no estem plenament d'acord amb els nostres iguals! Podria caldre que actualitzar l'aplicació, o potser que ho facen altres nodes. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Avís: error en llegir el fitxer wallet.dat! Totes les claus es lligen correctament, però hi ha dades de transaccions o entrades de la llibreta d'adreces absents o bé son incorrectes. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Avís: el fitxer wallet.dat és corrupte, dades rescatades! L'arxiu wallet.dat original ha estat guardat com wallet.{estampa_temporal}.bak al directori %s; si el teu balanç o transaccions son incorrectes hauries de restaurar-lo de un backup. @@ -2876,18 +2843,10 @@ Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. Afig a la llista blanca els iguals que es connecten de la màscara de xarxa o adreça IP donada. Es pot especificar moltes vegades. - - (default: 1) - (per defecte: 1) - <category> can be: <category> pot ser: - - Attempt to recover private keys from a corrupt wallet.dat - Intenta recuperar les claus privades d'un fitxer wallet.dat corrupte - Block creation options: Opcions de la creació de blocs: @@ -2932,10 +2891,6 @@ Error opening block database Error en obrir la base de dades de blocs - - Error: A fatal internal error occured, see debug.log for details - Error: s'ha produït un error intern fatal. Consulteu debug.log per a més detalls - Error: Disk space is low! Error: Espai al disc baix! @@ -2944,10 +2899,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Ha fallat escoltar a qualsevol port. Feu servir -listen=0 si voleu fer això. - - If <category> is not supplied, output all debugging information. - Si no se subministra <category>, mostra tota la informació de depuració. - Importing... S'està important... @@ -3016,10 +2967,6 @@ You need to rebuild the database using -reindex to change -txindex Cal que reconstruïu la base de dades fent servir -reindex per canviar -txindex - - Imports blocks from external blk000??.dat file - Importa blocs d'un fitxer blk000??.dat extern - 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 Permet les connexions JSON-RPC d'una font específica. Vàlid per a <ip> són una IP individual (p. ex., 1.2.3.4), una xarxa / màscara de xarxa (p. ex., 1.2.3.4/255.255.255.0) o una xarxa/CIDR (p. ex., 1.2.3.4/24). Es pot especificar esta opció moltes vegades @@ -3048,18 +2995,10 @@ Error: Listening for incoming connections failed (listen returned error %s) Error: ha fallat escoltar les connexions entrants (l'escoltament ha retornat l'error %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Error: s'ha trobat un argument no permés de -socks. Ja no es pot definir més la versió de SOCKS, només s'accepten els proxies de SOCKS5.ç - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Executa l'orde quan es reba un avís rellevant o veiem una forquilla molt llarga (%s en cmd és reemplaçat per un missatge) - - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Comissions (en BTC/Kb) inferiors a això es consideren de comissió zero per a la transmissió (per defecte: %s) - If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) Si no s'especifica una paytxfee (comissió de transacció de pagament), inclogueu suficient comissió per tal que les transaccions comencen a confirmar-se en una mitja de n blocs (per defecte: %u) @@ -3072,10 +3011,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) Mida màxima de les dades en les transaccions de l'operador en què confiem i en les meues (per defecte: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - Poda configurada per sota el mínim de %d MB. Feu servir un nombre superior. - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Consulta a adreces d'iguals a través de DNS, si es troba baix en adreces (per defecte: 1 a menys que -connect) @@ -3100,37 +3035,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Este producte inclou programari desenvolupat pel projecte OpenSSL per a ús a l'OpenSSL Toolkit <https://www.openssl.org/> i programari criptogràfic escrit per Eric Young i programari UPnP escrit per Thomas Bernard. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - Per utilitzar bitcoind, o l'opció de serviddor de bitcoin-qt, heu de definir una rpcpassword en el fitxer de configuració: -%s -Es recomana que utilitzeu la contrasenya aleatòria següent: -rpcuser=bitcoinrpc -rpcpassword=%s -(no cal que recordeu la contrasenya) -El nom d'usuari i la contrasenya NO han de ser els mateixos. -Si el fitxer no existeix, creeu-ne un amb permisos de lectura només per al seu propietari. -Es recomana definir alertnotify per tal de ser notificat de qualsevol problema; -per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.com - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Avís: s'ha especificat un -maxtxfee molt alt! Comissions tan grans podrien pagar-se en una única transacció. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Avís: comproveu que la data i hora del vostre ordinador siguen correctes! Si el vostre rellotge no és correcte, el Bitcoin Core no funcionarà correctament. - 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 Els iguals en la llista blanca no poden ser bandejats per DoS i es transmetran sempre llurs transaccions, fins i tot si ja són a la mempool. Això és útil, p. ex., per a una passarel·la @@ -3151,18 +3055,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comActivating best chain... S'està activant la millor cadena... - - Can't run with a wallet in prune mode. - No es pot executar amb un moneder en mode poda. - Cannot resolve -whitebind address: '%s' No es pot resoldre l'adreça -whitebind: «%s» - - Choose data directory on startup (default: 0) - Tria el directori de dades a l'inici (per defecte: 0) - Connect through SOCKS5 proxy Connecta a través del proxy SOCKS5 @@ -3171,10 +3067,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comCopyright (C) 2009-%i The Bitcoin Core Developers Copyright (C) 2009-%i Els desenvolupadors del Bitcoin Core - - Could not parse -rpcbind value %s as network address - No s'ha pogut analitzar el valor -rpcbind %s com una adreça de xarxa - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Error en carregar wallet.dat: el moneder requereix una versió més nova del Bitcoin core @@ -3183,14 +3075,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comError reading from database, shutting down. Error en llegir la base de dades, tancant. - - Error: Unsupported argument -tor found, use -onion. - Error: s'ha trobat un argument -tor no acceptat. Feu servir -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Comissió en (BTC/kB) per afegir a les transaccions que envieu (per defecte: %s) - Information &Informació @@ -3231,18 +3115,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comNode relay options: Opcions de transmissió del node: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Opcions RPC SSL: (veieu el wiki del Bitcoin per a instruccions de configuració de l'SSL) - RPC server options: Opcions del servidor RPC: - - RPC support for HTTP persistent connections (default: %d) - Suport RPC per a connexions HTTP persistents (per defecte: %d) - Rebuild block chain index from current blk000??.dat files on startup Reconstrueix l'índex de la cadena de blocs dels fitxers blk000??.dat actuals a l'inici. @@ -3259,22 +3135,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comSend transactions as zero-fee transactions if possible (default: %u) Envia les transaccions com a transaccions de comissió zero sempre que siga possible (per defecte: %u) - - Set SSL root certificates for payment request (default: -system-) - Defineix certificats arrel SSL per a la sol·licitud de pagament (per defecte: -sistema-) - - - Set language, for example "de_DE" (default: system locale) - Defineix un idioma, per exemple «de_DE» (per defecte: preferències locals de sistema) - Show all debugging options (usage: --help -help-debug) Mostra totes les opcions de depuració (ús: --help --help-debug) - - Show splash screen on startup (default: 1) - Mostra la finestra de benvinguda a l'inici (per defecte: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Redueix el fitxer debug.log durant l'inici del client (per defecte: 1 quan no -debug) @@ -3283,10 +3147,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comSigning transaction failed Ha fallat la signatura de la transacció - - Start minimized - Inicia minimitzat - The transaction amount is too small to pay the fee L'import de la transacció és massa petit per pagar-ne una comissió @@ -3311,18 +3171,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comTransaction too large La transacció és massa gran - - UI Options: - Opcions d'interfície: - Unable to bind to %s on this computer (bind returned error %s) No s'ha pogut vincular a %s en este ordinador (la vinculació ha retornat l'error %s) - - Use UPnP to map the listening port (default: 1 when listening) - Utilitza UPnP per a mapejar els ports d'escolta (per defecte: 1 quan s'escolta) - Username for JSON-RPC connections Nom d'usuari per a connexions JSON-RPC @@ -3335,22 +3187,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comWarning Avís - - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Avís: s'ha ignorat l'argument no acceptat de -benchmark. Feu servir -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Avís: s'ha ignorat l'argument no acceptat de -debugnet. Feu servir -debug=net. - Zapping all transactions from wallet... Se suprimeixen totes les transaccions del moneder... - - on startup - a l'inici de l'aplicació - wallet.dat corrupt, salvage failed El fitxer wallet.data és corrupte. El rescat de les dades ha fallat @@ -3363,18 +3203,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comExecute command when the best block changes (%s in cmd is replaced by block hash) Executa l'orde quan el millor bloc canvie (%s en cmd es reemplaça per un resum de bloc) - - Upgrade wallet to latest format - Actualitza el moneder a l'últim format - - - Rescan the block chain for missing wallet transactions - Reescaneja la cadena de blocs en les transaccions de moneder perdudes - - - Use OpenSSL (https) for JSON-RPC connections - Utilitza OpenSSL (https) per a connexions JSON-RPC - This help message Este misatge d'ajuda @@ -3419,10 +3247,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.com(default: %s) (per defecte: %s) - - Acceptable ciphers (default: %s) - Xifrats acceptables (per defecte: %s) - Always query for peer addresses via DNS lookup (default: %u) Demana sempre les adreces dels iguals a través de consultes DNS (per defecte: %u) @@ -3483,14 +3307,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comRelay non-P2SH multisig (default: %u) Retransmet multisig no P2SH (per defecte: %u) - - Server certificate file (default: %s) - Fitxer de certificat del servidor (per defecte: %s) - - - Server private key (default: %s) - Clau privada del servidor (per defecte: %s) - Set key pool size to <n> (default: %u) Defineix la mida clau disponible a <n> (per defecte: %u) diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts index 898b7f33b..e6a932ebe 100644 --- a/src/qt/locale/bitcoin_ca_ES.ts +++ b/src/qt/locale/bitcoin_ca_ES.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,17 @@ La contrasenya del moneder ha estat modificada correctament. + + BanTableModel + + IP/Netmask + IP / Màscara de xarxa + + + Banned Until + Bandejat fins + + BitcoinGUI @@ -871,6 +882,34 @@ command-line options Opcions de la línia d'ordres + + UI Options: + Opcions d'interfície d'usuari: + + + Choose data directory on startup (default: %u) + Trieu el directori de dades a l'inici (per defecte: %u) + + + Set language, for example "de_DE" (default: system locale) + Defineix la llengua, per exemple «de_DE» (per defecte: la definida pel sistema) + + + Start minimized + Inicia minimitzat + + + Set SSL root certificates for payment request (default: -system-) + Defineix els certificats arrel SSL per a la sol·licitud de pagament (per defecte: els del sistema) + + + Show splash screen on startup (default: %u) + Mostra la pantalla de benvinguda a l'inici (per defecte: %u) + + + Reset all settings changes made over the GUI + Reinicialitza tots els canvis de configuració fets des de la interfície gràfica + Intro @@ -1068,6 +1107,18 @@ Port of the proxy (e.g. 9050) Port del proxy (per exemple 9050) + + Used for reaching peers via: + Utilitzat per arribar als iguals mitjançant: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Mostra si el proxy SOCKS5 per defecte proporcionat s'utilitza per arribar als iguals mitjançant aquest tipus de xarxa. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Utilitza un proxy SOCKS4 apart per a arribar als iguals a través de serveis ocults de Tor: + &Window &Finestra @@ -1286,10 +1337,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). La sol·licitud de pagament %1 és massa gran (%2 bytes, permès %3 bytes). - - Payment request DoS protection - Protecció de DoS per a la sol·licitud de pagament - Error communicating with %1: %2 Error en comunicar amb %1: %2 @@ -1458,10 +1505,18 @@ &Peers &Iguals + + Banned peers + Iguals bandejats + Select a peer to view detailed information. Seleccioneu un igual per mostrar informació detallada. + + Whitelisted + A la llista blanca + Direction Direcció @@ -1470,6 +1525,18 @@ Version Versió + + Starting Block + Bloc d'inici + + + Synced Headers + Capçaleres sincronitzades + + + Synced Blocks + Blocs sincronitzats + User Agent Agent d'usuari @@ -1478,14 +1545,6 @@ Services Serveis - - Starting Height - Alçada inicial - - - Sync Height - Sincronitza l'alçada - Ban Score Puntuació de bandeig @@ -1502,18 +1561,18 @@ Last Receive Darrera recepció - - Bytes Sent - Bytes enviats - - - Bytes Received - Bytes rebuts - Ping Time Temps de ping + + The duration of a currently outstanding ping. + La duració d'un ping més destacat actualment. + + + Ping Wait + Espera de ping + Time Offset Diferència horària @@ -1562,6 +1621,34 @@ Clear console Neteja la consola + + &Disconnect Node + &Desconnecta el node + + + Ban Node for + Bandeja el node durant + + + 1 &hour + 1 &hora + + + 1 &day + 1 &dia + + + 1 &week + 1 &setmana + + + 1 &year + 1 &any + + + &Unban Node + &Desbandeja el node + Welcome to the Bitcoin Core RPC console. Us donem la benviguda a la consola RPC del Bitcoin Core. @@ -1590,6 +1677,10 @@ %1 GB %1 GB + + (node id: %1) + (id del node: %1) + via %1 a través de %1 @@ -1607,12 +1698,16 @@ Sortint - Unknown - Desconegut + Yes + - Fetching... - S'està obtenint... + No + No + + + Unknown + Desconegut @@ -1979,8 +2074,8 @@ Copia el canvi - Total Amount %1 (= %2) - Import total %1 (= %2) + Total Amount %1 + Import total %1 or @@ -2014,14 +2109,14 @@ Payment request expired. La sol·licitud de pagament ha vençut. + + Pay only the required fee of %1 + Paga només la comissió necessària de %1 + Estimated to begin confirmation within %n block(s). Estimat per començar la confirmació en %n bloc.Estimat per començar la confirmació en %n blocs. - - Pay only the minimum fee of %1 - Paga només la comissió mínima de %1 - The recipient address is not valid. Please recheck. L'adreça de destinatari no és vàlida. Torneu-la a comprovar. @@ -2801,12 +2896,16 @@ Accepta la línia d'ordres i ordres JSON-RPC - Run in the background as a daemon and accept commands - Executa en segon pla com a programa dimoni i accepta ordres + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Comissions totals màximes (en %s) per utilitzar en una única transacció de moneder; definir-ne una massa baixa pot interrompre les transaccions més grans (per defecte: %s) - Use the test network - Utilitza la xarxa de prova + Fee (in %s/kB) to add to transactions you send (default: %s) + Comissió (en %s/kB) per afegir a les transaccions que envieu (per defecte: %s) + + + Run in the background as a daemon and accept commands + Executa en segon pla com a programa dimoni i accepta ordres Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2828,14 +2927,6 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Executa una ordre quan una transacció del moneder canviï (%s en cmd es canvia per TxID) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Comissions totals màximes que s'utilitzaran en una única transacció de moneder; si s'estableix un valor massa baix es poden interrompre transaccions grans (per defecte: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Redueix els requeriments d'emmagatzemament podant (suprimint) els blocs antics. Aquest mode inhabilita l'ús de moneders i és incompatible amb -tindex. Avís: Revertir aquesta configuració comporta tornar a baixar la cadena de blocs sencera. (per defecte: 0 = inhabilita la poda de blocs, >%u = mida objectiu en MiB per utilitzar els fitxers de blocs) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Defineix el nombre de fils de verificació d'scripts (%u a %d, 0 = auto, <0 = deixa tants nuclis lliures, per defecte: %d) @@ -2856,10 +2947,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) AVÍS: comproveu la vostra connexió a la xarxa, %d blocs rebuts en les darreres %d hores (se n'esperaven %d) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Avís: el -paytxfee és molt elevat! Aquesta és la comissió de transacció que pagareu si envieu una transacció. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Avís: la xarxa no sembla que hi estigui plenament d'acord. Alguns miners sembla que estan experimentant problemes. @@ -2868,10 +2955,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Avís: sembla que no estem plenament d'acord amb els nostres iguals! Podria caler que actualitzar l'aplicació, o potser que ho facin altres nodes. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Avís: error en llegir el fitxer wallet.dat! Totes les claus es llegeixen correctament, però hi ha dades de transaccions o entrades de la llibreta d'adreces absents o bé son incorrectes. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Avís: el fitxer wallet.dat és corrupte, dades rescatades! L'arxiu wallet.dat original ha estat desat com wallet.{estampa_temporal}.bak al directori %s; si el teu balanç o transaccions son incorrectes hauries de restaurar-lo de un backup. @@ -2880,18 +2963,10 @@ Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. Afegeix a la llista blanca els iguals que es connecten de la màscara de xarxa o adreça IP donada. Es pot especificar moltes vegades. - - (default: 1) - (per defecte: 1) - <category> can be: <category> pot ser: - - Attempt to recover private keys from a corrupt wallet.dat - Intenta recuperar les claus privades d'un fitxer wallet.dat corrupte - Block creation options: Opcions de la creació de blocs: @@ -2936,10 +3011,6 @@ Error opening block database Error en obrir la base de dades de blocs - - Error: A fatal internal error occured, see debug.log for details - Error: s'ha produït un error intern fatal. Consulteu debug.log per a més detalls - Error: Disk space is low! Error: Espai al disc baix! @@ -2948,10 +3019,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Ha fallat escoltar a qualsevol port. Feu servir -listen=0 si voleu fer això. - - If <category> is not supplied, output all debugging information. - Si no se subministra <category>, mostra tota la informació de depuració. - Importing... S'està important... @@ -3020,10 +3087,6 @@ You need to rebuild the database using -reindex to change -txindex Cal que reconstruïu la base de dades fent servir -reindex per canviar -txindex - - Imports blocks from external blk000??.dat file - Importa blocs de un fitxer blk000??.dat extern - 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 Permet les connexions JSON-RPC d'una font específica. Vàlid per a <ip> són una IP individual (p. ex., 1.2.3.4), una xarxa / màscara de xarxa (p. ex., 1.2.3.4/255.255.255.0) o una xarxa/CIDR (p. ex., 1.2.3.4/24). Es pot especificar aquesta opció moltes vegades @@ -3052,18 +3115,10 @@ Error: Listening for incoming connections failed (listen returned error %s) Error: ha fallat escoltar les connexions entrants (l'escoltament ha retornat l'error %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Error: s'ha trobat un argument no permès de -socks. Ja no es pot definir més la versió de SOCKS, només s'accepten els proxies de SOCKS5.ç - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Executa l'ordre quan es rebi un avís rellevant o veiem una forquilla molt llarga (%s en cmd és reemplaçat per un missatge) - - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Comissions (en BTC/Kb) inferiors a això es consideren de comissió zero per a la transmissió (per defecte: %s) - If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) Si no s'especifica una paytxfee (comissió de transacció de pagament), inclogueu suficient comissió per tal que les transaccions comencin a confirmar-se en una mitja de n blocs (per defecte: %u) @@ -3076,10 +3131,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) Mida màxima de les dades en les transaccions de l'operador en què confiem i en les meves (per defecte: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - Poda configurada per sota el mínim de %d MB. Feu servir un nombre superior. - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Consulta a adreces d'iguals a través de DNS, si es troba baix en adreces (per defecte: 1 a menys que -connect) @@ -3104,37 +3155,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Aquest producte inclou programari desenvolupat pel projecte OpenSSL per a ús a l'OpenSSL Toolkit <https://www.openssl.org/> i programari criptogràfic escrit per Eric Young i programari UPnP escrit per Thomas Bernard. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - Per utilitzar bitcoind, o l'opció de serviddor de bitcoin-qt, heu de definir una rpcpassword en el fitxer de configuració: -%s -Es recomana que utilitzeu la contrasenya aleatòria següent: -rpcuser=bitcoinrpc -rpcpassword=%s -(no cal que recordeu la contrasenya) -El nom d'usuari i la contrasenya NO han de ser els mateixos. -Si el fitxer no existeix, creeu-ne un amb permisos de lectura només per al seu propietari. -Es recomana definir alertnotify per tal de ser notificat de qualsevol problema; -per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.com - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Avís: s'ha especificat un -maxtxfee molt alt! Comissions tan grans podrien pagar-se en una única transacció. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Avís: comproveu que la data i hora del vostre ordinador siguin correctes! Si el vostre rellotge no és correcte, el Bitcoin Core no funcionarà correctament. - 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 Els iguals en la llista blanca no poden ser bandejats per DoS i es transmetran sempre llurs transaccions, fins i tot si ja són a la mempool. Això és útil, p. ex., per a una passarel·la @@ -3155,18 +3175,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comActivating best chain... S'està activant la millor cadena... - - Can't run with a wallet in prune mode. - No es pot executar amb un moneder en mode poda. - Cannot resolve -whitebind address: '%s' No es pot resoldre l'adreça -whitebind: «%s» - - Choose data directory on startup (default: 0) - Tria el directori de dades a l'inici (per defecte: 0) - Connect through SOCKS5 proxy Connecta a través del proxy SOCKS5 @@ -3175,10 +3187,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comCopyright (C) 2009-%i The Bitcoin Core Developers Copyright (C) 2009-%i Els desenvolupadors del Bitcoin Core - - Could not parse -rpcbind value %s as network address - No s'ha pogut analitzar el valor -rpcbind %s com una adreça de xarxa - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Error en carregar wallet.dat: el moneder requereix una versió més nova del Bitcoin core @@ -3187,14 +3195,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comError reading from database, shutting down. Error en llegir la base de dades, tancant. - - Error: Unsupported argument -tor found, use -onion. - Error: s'ha trobat un argument -tor no acceptat. Feu servir -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Comissió en (BTC/kB) per afegir a les transaccions que envieu (per defecte: %s) - Information &Informació @@ -3235,18 +3235,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comNode relay options: Opcions de transmissió del node: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Opcions RPC SSL: (veieu el wiki del Bitcoin per a instruccions de configuració de l'SSL) - RPC server options: Opcions del servidor RPC: - - RPC support for HTTP persistent connections (default: %d) - Suport RPC per a connexions HTTP persistents (per defecte: %d) - Rebuild block chain index from current blk000??.dat files on startup Reconstrueix l'índex de la cadena de blocs dels fitxers blk000??.dat actuals a l'inici. @@ -3263,22 +3255,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comSend transactions as zero-fee transactions if possible (default: %u) Envia les transaccions com a transaccions de comissió zero sempre que sigui possible (per defecte: %u) - - Set SSL root certificates for payment request (default: -system-) - Defineix certificats arrel SSL per a la sol·licitud de pagament (per defecte: -sistema-) - - - Set language, for example "de_DE" (default: system locale) - Defineix un idioma, per exemple «de_DE» (per defecte: preferències locals de sistema) - Show all debugging options (usage: --help -help-debug) Mostra totes les opcions de depuració (ús: --help --help-debug) - - Show splash screen on startup (default: 1) - Mostra la finestra de benvinguda a l'inici (per defecte: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Redueix el fitxer debug.log durant l'inici del client (per defecte: 1 quan no -debug) @@ -3287,10 +3267,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comSigning transaction failed Ha fallat la signatura de la transacció - - Start minimized - Inicia minimitzat - The transaction amount is too small to pay the fee L'import de la transacció és massa petit per pagar-ne una comissió @@ -3315,18 +3291,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comTransaction too large La transacció és massa gran - - UI Options: - Opcions d'interfície: - Unable to bind to %s on this computer (bind returned error %s) No s'ha pogut vincular a %s en aquest ordinador (la vinculació ha retornat l'error %s) - - Use UPnP to map the listening port (default: 1 when listening) - Utilitza UPnP per a mapejar els ports d'escolta (per defecte: 1 quan s'escolta) - Username for JSON-RPC connections Nom d'usuari per a connexions JSON-RPC @@ -3339,22 +3307,10 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comWarning Avís - - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Avís: s'ha ignorat l'argument no acceptat de -benchmark. Feu servir -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Avís: s'ha ignorat l'argument no acceptat de -debugnet. Feu servir -debug=net. - Zapping all transactions from wallet... Se suprimeixen totes les transaccions del moneder... - - on startup - a l'inici de l'aplicació - wallet.dat corrupt, salvage failed El fitxer wallet.data és corrupte. El rescat de les dades ha fallat @@ -3367,18 +3323,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comExecute command when the best block changes (%s in cmd is replaced by block hash) Executa l'ordre quan el millor bloc canviï (%s en cmd es reemplaça per un resum de bloc) - - Upgrade wallet to latest format - Actualitza el moneder a l'últim format - - - Rescan the block chain for missing wallet transactions - Reescaneja la cadena de blocs en les transaccions de moneder perdudes - - - Use OpenSSL (https) for JSON-RPC connections - Utilitza OpenSSL (https) per a connexions JSON-RPC - This help message Aquest misatge d'ajuda @@ -3423,10 +3367,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.com(default: %s) (per defecte: %s) - - Acceptable ciphers (default: %s) - Xifrats acceptables (per defecte: %s) - Always query for peer addresses via DNS lookup (default: %u) Demana sempre les adreces dels iguals a través de consultes DNS (per defecte: %u) @@ -3487,14 +3427,6 @@ per exemple: alertnotify=echo %%s | mail -s "Avís de Bitcoin" admin@foo.comRelay non-P2SH multisig (default: %u) Retransmet multisig no P2SH (per defecte: %u) - - Server certificate file (default: %s) - Fitxer de certificat del servidor (per defecte: %s) - - - Server private key (default: %s) - Clau privada del servidor (per defecte: %s) - Set key pool size to <n> (default: %u) Defineix la mida clau disponible a <n> (per defecte: %u) diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index 6e7ffec27..ef1903edd 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,9 @@ Heslo k peněžence bylo v pořádku změněno. + + BanTableModel + BitcoinGUI @@ -871,7 +874,7 @@ command-line options možnosti příkazové řádky - + Intro @@ -1068,6 +1071,10 @@ Port of the proxy (e.g. 9050) Port proxy (např. 9050) + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Použít samostatnou SOCKS5 proxy ke spojení s protějšky přes skryté služby v Toru: + &Window O&kno @@ -1286,10 +1293,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Platební požadavek %1 je moc velký (%2 bajtů, povoleno %3 bajtů). - - Payment request DoS protection - DoS ochrana platebního požadavku - Error communicating with %1: %2 Chyba při komunikaci s %1: %2 @@ -1478,14 +1481,6 @@ Services Služby - - Starting Height - Prvotní výška - - - Sync Height - Aktuální výška - Ban Score Skóre pro klatbu @@ -1502,14 +1497,6 @@ Last Receive Poslední příjem - - Bytes Sent - Bajtů odesláno - - - Bytes Received - Bajtů přijato - Ping Time Odezva @@ -1607,12 +1594,16 @@ Ven - Unknown - Neznámá + Yes + Ano - Fetching... - Stahuji... + No + Ne + + + Unknown + Neznámá @@ -1978,10 +1969,6 @@ Copy change Kopíruj drobné - - Total Amount %1 (= %2) - Celková částka %1 (= %2) - or nebo @@ -2018,10 +2005,6 @@ Estimated to begin confirmation within %n block(s). Potvrzování by podle odhadu mělo začít během %n bloku.Potvrzování by podle odhadu mělo začít během %n bloků.Potvrzování by podle odhadu mělo začít během %n bloků. - - Pay only the minimum fee of %1 - Zaplatit pouze minimální poplatek %1 - The recipient address is not valid. Please recheck. Adresa příjemce je neplatná – překontroluj ji prosím. @@ -2804,10 +2787,6 @@ Run in the background as a daemon and accept commands Běžet na pozadí jako démon a akceptovat příkazy - - Use the test network - Použít testovací síť (testnet) - Accept connections from outside (default: 1 if no -proxy or -connect) Přijímat spojení zvenčí (výchozí: 1, pokud není zadáno -proxy nebo -connect) @@ -2828,14 +2807,6 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Spustit příkaz, když se objeví transakce týkající se peněženky (%s se v příkazu nahradí za TxID) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Horní hranice pro celkový poplatek za jednu transakci z peněženky; příliš nízká hodnota může zmařit velké transakce (výchozí: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Omezit nároky na úložný prostor prořezáváním (mazáním) starých bloků. V tomto režimu chybí peněženka a rovněž tento režim není slučitelný s -txindex. Upozornění: opětovná změna tohoto nastavení bude vyžadovat nové stažení celého řetězce bloků. (výchozí: 0 = bloky neprořezávat, >%u = cílová velikost souborů s bloky, v MiB) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Nastavení počtu vláken pro verifikaci skriptů (%u až %d, 0 = automaticky, <0 = nechat daný počet jader volný, výchozí: %d) @@ -2856,10 +2827,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) UPOZORNĚNÍ: zkontroluj své spojení do sítě – bylo přijato %d bloků za posledních %d hodin (očekáváno %d) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Upozornění: -paytxfee je nastaveno velmi vysoko! Toto je transakční poplatek, který zaplatíš za každou poslanou transakci. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Upozornění: Síť podle všeho není v konzistentním stavu. Někteří těžaři jsou zřejmě v potížích. @@ -2868,10 +2835,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Upozornění: Nesouhlasím zcela se svými protějšky! Možná potřebuji aktualizovat nebo ostatní uzly potřebují aktualizovat. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Upozornění: nastala chyba při čtení souboru wallet.dat! Všechny klíče se přečetly správně, ale data o transakcích nebo záznamy v adresáři mohou chybět či být nesprávné. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Upozornění: soubor wallet.dat je poškozený, data jsou však zachráněna! Původní soubor wallet.dat je uložený jako wallet.{timestamp}.bak v %s. Pokud je stav tvého účtu nebo transakce nesprávné, zřejmě bys měl obnovit zálohu. @@ -2880,18 +2843,10 @@ Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. Umístit na bílou listinu protějšky připojující se z dané podsítě či IP adresy. Lze zadat i vícekrát. - - (default: 1) - (výchozí: 1) - <category> can be: <category> může být: - - Attempt to recover private keys from a corrupt wallet.dat - Pokusit se zachránit soukromé klíče z poškozeného souboru wallet.dat - Block creation options: Možnosti vytváření bloku: @@ -2936,10 +2891,6 @@ Error opening block database Chyba při otevírání databáze bloků - - Error: A fatal internal error occured, see debug.log for details - Chyba: Stala se fatální vnitřní chyba. detaily viz v debug.log - Error: Disk space is low! Problém: Na disku je málo místa! @@ -2948,10 +2899,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Nepodařilo se naslouchat na žádném portu. Použij -listen=0, pokud to byl tvůj záměr. - - If <category> is not supplied, output all debugging information. - Pokud není <category> zadána, bude tisknout veškeré ladicí informace. - Importing... Importuji... @@ -3020,18 +2967,10 @@ You need to rebuild the database using -reindex to change -txindex Je třeba přestavět databázi použitím -reindex, aby bylo možné změnit -txindex - - Imports blocks from external blk000??.dat file - Importovat bloky z externího souboru blk000??.dat - 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 Povolit JSON-RPC spojení ze specifikovaného zdroje. Platnou hodnotou <ip> je jednotlivá IP adresa (např. 1.2.3.4), síť/maska (např. 1.2.3.4/255.255.255.0) nebo síť/CIDR (např. 1.2.3.4/24). Tuto volbu lze použít i vícekrát - - An error occurred while setting up the RPC address %s port %u for listening: %s - Při nastavování naslouchací RPC adresy %s a portu %u nastala chyba: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Obsadit zadanou adresu a protějšky, které se na ní připojí, umístit na bílou listinu. Pro zápis IPv6 adresy použij notaci [adresa]:port @@ -3056,18 +2995,10 @@ Error: Listening for incoming connections failed (listen returned error %s) Chyba: Nelze naslouchat příchozí spojení (listen vrátil chybu %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Chyba: Byl použit nepodporovaný argument -socks. Nastavení verze SOCKS už není možné, podporovány jsou pouze SOCKS5 proxy. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Spustit příkaz, když přijde relevantní upozornění nebo když dojde k opravdu dlouhému rozštěpení řetezce bloků (%s se v příkazu nahradí zprávou) - - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Poplatky (v BTC/kB) menší než tato hodnota jsou považovány za nulové pro účely přeposílání transakcí (výchozí: %s) - If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) Pokud paytxfee není nastaveno, platit dostatečný poplatek na to, aby začaly být transakce potvrzovány v průměru během n bloků (výchozí: %u) @@ -3080,10 +3011,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) Maximální velikost dat v transakcích nesoucích data, se kterou jsme ochotni je ještě přeposílat a těžit (výchozí: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - Prořezávání je nastaveno pod minimum %d MB. Použij prosím nějaké vyšší číslo. - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Při nedostatku adres získat další protějšky z DNS (výchozí: 1, pokud není použito -connect) @@ -3108,38 +3035,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v OpenSSL Toolkitu <https://www.openssl.org/> a kryptografický program od Erika Younga a program UPnP od Thomase Bernarda. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - K používání bitcoind nebo volby -server u bitcoin-qt musíš nastavit rpcpassword v konfiguračním souboru: -%s -Je vhodné použít následující náhodné heslo: -rpcuser=bitcoinrpc -rpcpassword=%s -(není potřeba si ho pamatovat) -rpcuser a rpcpassword NESMÍ být stejné. -Pokud konfigurační soubor ještě neexistuje, vytvoř ho tak, aby ho mohl číst pouze vlastník. -Je také doporučeno si nastavit alertnotify, abys byl upozorněn na případné problémy; -například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Upozornění: -maxtxfee je nastaveno velmi vysoko! Takto vysoký poplatek může být zaplacen v jednotlivé transakci. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Upozornění: Zkontroluj, že máš v počítači správně nastavený datum a čas! Pokud jsou nastaveny špatně, Bitcoin Core nebude fungovat správně. - 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 Na protějšky na bílé listině se nevztahuje DoS klatba a jejich transakce jsou vždy přeposílány, i když už třeba jsou v mempoolu, což je užitečné např. pro bránu @@ -3160,18 +3055,10 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Activating best chain... Aktivuji nejlepší řetězec... - - Can't run with a wallet in prune mode. - V prořezávacím režimu se s pěněženkou nemůžu spustit. - Cannot resolve -whitebind address: '%s' Nemohu přeložit -whitebind adresu: '%s' - - Choose data directory on startup (default: 0) - Zvolit adresář pro data při startu (výchozí: 0) - Connect through SOCKS5 proxy Připojit se přes SOCKS5 proxy @@ -3180,10 +3067,6 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Copyright (C) 2009-%i The Bitcoin Core Developers Copyright (C) 2009-%i Vývojáři Bitcoin Core - - Could not parse -rpcbind value %s as network address - Nejde mi přečíst hodnotu -rpcbind %s jako síťovou adresu - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Chyba při načítání wallet.dat: peněženka vyžaduje novější verzi Bitcoin Core @@ -3192,14 +3075,6 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Error reading from database, shutting down. Chyba při čtení z databáze, ukončuji se. - - Error: Unsupported argument -tor found, use -onion. - Chyba: Argument -tor již není podporovaný, použij -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Poplatek (v BTC/kB), který se přidá ke každé odeslané transakci (výchozí: %s) - Information Informace @@ -3240,18 +3115,10 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Node relay options: Možnosti přeposílání: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Možnosti SSL pro RPC: (viz instrukce nastavení SSL na Bitcoin Wiki) - RPC server options: Možnosti RPC serveru: - - RPC support for HTTP persistent connections (default: %d) - Podpora RPC pro perzistentní HTTP spojení (výchozí: %d) - Rebuild block chain index from current blk000??.dat files on startup Při startu znovu vytvořit index řetězce bloků z aktuálních blk000??.dat souborů @@ -3268,22 +3135,10 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Send transactions as zero-fee transactions if possible (default: %u) Posílat transakce pokud možno bez poplatků (výchozí: %u) - - Set SSL root certificates for payment request (default: -system-) - Nastavit kořenové SSL certifikáty pro platební požadavky (výchozí: -system-) - - - Set language, for example "de_DE" (default: system locale) - Nastavit jazyk, například „de_DE“ (výchozí: systémové nastavení) - Show all debugging options (usage: --help -help-debug) Zobrazit všechny možnosti ladění (užití: --help -help-debug) - - Show splash screen on startup (default: 1) - Zobrazit startovací obrazovku (výchozí: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Při spuštění klienta zmenšit soubor debug.log (výchozí: 1, pokud není zadáno -debug) @@ -3292,10 +3147,6 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Signing transaction failed Nepodařilo se podepsat transakci - - Start minimized - Nastartovat minimalizovaně - The transaction amount is too small to pay the fee Částka v transakci je příliš malá na pokrytí poplatku @@ -3320,18 +3171,10 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Transaction too large Transakce je příliš velká - - UI Options: - Možnosti UI: - Unable to bind to %s on this computer (bind returned error %s) Nedaří se mi připojit na %s na tomhle počítači (operace bind vrátila chybu %s) - - Use UPnP to map the listening port (default: 1 when listening) - Použít UPnP k namapování naslouchacího portu (výchozí: 1, pokud naslouchá) - Username for JSON-RPC connections Uživatelské jméno pro JSON-RPC spojení @@ -3344,22 +3187,10 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Warning Upozornění - - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Upozornění: Nepodporovaný argument -benchmark se ignoruje, použij -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Upozornění: Nepodporovaný argument -debugnet se ignoruje, použij -debug=net. - Zapping all transactions from wallet... Vymazat všechny transakce z peněženky... - - on startup - při startu - wallet.dat corrupt, salvage failed Soubor wallet.dat je poškozen, jeho záchrana se nezdařila @@ -3372,18 +3203,6 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Execute command when the best block changes (%s in cmd is replaced by block hash) Spustit příkaz, když se změní nejlepší blok (%s se v příkazu nahradí hashem bloku) - - Upgrade wallet to latest format - Převést peněženku na nejnovější formát - - - Rescan the block chain for missing wallet transactions - Přeskenovat řetězec bloků na chybějící transakce tvé pěněženky - - - Use OpenSSL (https) for JSON-RPC connections - Použít OpenSSL (https) pro JSON-RPC spojení - This help message Tato nápověda @@ -3428,10 +3247,6 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com (default: %s) (výchozí: %s) - - Acceptable ciphers (default: %s) - Akceptovatelné šifry (výchozí: %s) - Always query for peer addresses via DNS lookup (default: %u) Vždy získávat adresy dalších protějšků přes DNS (výchozí: %u) @@ -3492,14 +3307,6 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Relay non-P2SH multisig (default: %u) Přeposílat ne-P2SH multisig (výchozí: %u) - - Server certificate file (default: %s) - Soubor se serverovým certifikátem (výchozí: %s) - - - Server private key (default: %s) - Soubor se serverovým soukromým klíčem (výchozí: %s) - Set key pool size to <n> (default: %u) Nastavit zásobník klíčů na velikost <n> (výchozí: %u) @@ -3520,6 +3327,10 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Specify connection timeout in milliseconds (minimum: 1, default: %d) Zadej časový limit spojení v milivteřinách (minimum: 1, výchozí: %d) + + Specify pid file (default: %s) + PID soubor (výchozí: %s) + Spend unconfirmed change when sending transactions (default: %u) Utrácet i ještě nepotvrzené drobné při posílání transakcí (výchozí: %u) diff --git a/src/qt/locale/bitcoin_cs_CZ.ts b/src/qt/locale/bitcoin_cs_CZ.ts new file mode 100644 index 000000000..cc0c79115 --- /dev/null +++ b/src/qt/locale/bitcoin_cs_CZ.ts @@ -0,0 +1,645 @@ + + + AddressBookPage + + Create a new address + Vytvořit novou adresu + + + Copy the currently selected address to the system clipboard + Kopírovat aktuálně vybrané adresy do schránky + + + &Delete + &Odstranit + + + Comma separated file (*.csv) + Textový soubor oddělený středníkem (*.csv) + + + + AddressTableModel + + Label + Popis + + + Address + Adresa + + + (no label) + (bez popisu) + + + + AskPassphraseDialog + + Enter passphrase + Zadej heslo + + + New passphrase + Nové heslo + + + Repeat new passphrase + Zopakujte nové heslo + + + Encrypt wallet + Zašifrovat peněženku + + + This operation needs your wallet passphrase to unlock the wallet. + Tato operace vyžaduje heslo k odemknutí peněženky. + + + Unlock wallet + Odemknout peněženku + + + This operation needs your wallet passphrase to decrypt the wallet. + Tato operace vyžaduje heslo k dešifrování peněženky. + + + Decrypt wallet + Dešifrovat peněženku + + + Change passphrase + Změnit heslo + + + Confirm wallet encryption + Potvrďte zašifrování peněženky + + + Wallet encrypted + Peněženka zašifrována + + + Wallet encryption failed + Zašifrování peněženky selhalo + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Šifrování peněženky selhalo vinou vnitřní chyby. Vaše peněženka nebyla zašifrována. + + + The supplied passphrases do not match. + Zadaná hesla nejsou shodná. + + + Wallet unlock failed + Odemčení peněženky selhalo + + + The passphrase entered for the wallet decryption was incorrect. + Heslo zadané k dešifrování peněženky nebylo správné + + + Wallet decryption failed + Deěifrování peněženky selhalo + + + + BanTableModel + + + BitcoinGUI + + Synchronizing with network... + Synchronizuji se sítí... + + + &Overview + &Přehled + + + Show general overview of wallet + Zobrazit základní přehled o peněžence + + + &Transactions + &Transakce + + + Browse transaction history + Procházení historií transakcí + + + Quit application + Ukončit aplikaci + + + &Options... + &Možnosti... + + + Change the passphrase used for wallet encryption + Změnit heslo k šifrování peněženky + + + Bitcoin + Bitcoin + + + &File + &Soubor + + + &Settings + &Nastavení + + + &Help + Nápo&věda + + + Tabs toolbar + Panely + + + Up to date + Aktuální + + + Catching up... + Zachytávám... + + + Sent transaction + Odeslané transakce + + + Incoming transaction + Příchozí transakce + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + Peněženka je <b>zašifrována</b> a momentálně <b>odemčená</b> + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + Peněženka je <b>zašifrována</b> a momentálně <b>uzamčená</b> + + + + ClientModel + + + CoinControlDialog + + Amount: + Množství: + + + Amount + Množství + + + Date + Datum + + + Confirmed + Potvrzeno + + + Copy address + Kopírovat sdresu + + + Copy label + Kopírovat popis + + + (no label) + (bez popisu) + + + + EditAddressDialog + + Edit Address + Upravit adresu + + + &Label + &Popisek + + + &Address + &Adresa + + + New receiving address + Nová adresa pro příjem + + + New sending address + Nová adresa k odeslání + + + Edit receiving address + Upravit adresu pro příjem + + + Edit sending address + Upravit adresu k odeslání + + + The entered address "%1" is already in the address book. + Zadaná adresa "%1" se již v seznamu adres nachází. + + + Could not unlock wallet. + Nemohu odemknout peněženku + + + New key generation failed. + Generování nového klíče selhalo. + + + + FreespaceChecker + + + HelpMessageDialog + + Usage: + Použití: + + + + Intro + + + OpenURIDialog + + + OptionsDialog + + Options + Možnosti + + + Map port using &UPnP + Mapovat port pomocí &UPnP + + + &Minimize to the tray instead of the taskbar + &Minimalizovat do systémové lišty (tray) namísto do hlavního panelu + + + M&inimize on close + M&inimalizovat při zavření + + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + Amount + Množství + + + + QRImageWidget + + + RPCConsole + + Name + Jméno + + + + ReceiveCoinsDialog + + &Label: + &Popisek: + + + &Message: + Zpráva: + + + Copy label + Kopírovat popis + + + + ReceiveRequestDialog + + Address + Adresa + + + Amount + Množství + + + Label + Popis + + + Message + Zpráva + + + + RecentRequestsTableModel + + Date + Datum + + + Label + Popis + + + Message + Zpráva + + + Amount + Množství + + + (no label) + (bez popisu) + + + + SendCoinsDialog + + Amount: + Množství: + + + Balance: + Zůstatek: + + + The amount to pay must be larger than 0. + Částka k zaplacení musí být větší než 0. + + + (no label) + (bez popisu) + + + + SendCoinsEntry + + &Label: + &Popisek: + + + Message: + Zpráva: + + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + [testnet] + [testnet] + + + + TrafficGraphWidget + + + TransactionDesc + + %1/unconfirmed + %1 potvrzeno + + + %1 confirmations + %1 potvrzení + + + Status + Stav + + + Date + Datum + + + Message + Zpráva + + + Transaction + Transakce + + + Amount + Množství + + + + TransactionDescDialog + + Transaction details + Detaily transakce + + + This pane shows a detailed description of the transaction + Toto podokno zobrazuje detailní popis transakce + + + + TransactionTableModel + + Date + Datum + + + Type + Typ + + + Confirmed (%1 confirmations) + Potvrzeno (%1 potvrzení) + + + This block was not received by any other nodes and will probably not be accepted! + Tento blok nebyl přijat žádným dalším uzlem a pravděpodobně nebude akceptován! + + + Label + Popis + + + Received with + Přijato s + + + Sent to + Odesláno na + + + Payment to yourself + Platba sobě samému + + + Mined + Vytěženo + + + Type of transaction. + Typ transakce. + + + + TransactionView + + All + Vše + + + Today + Dnes + + + This week + Tento týden + + + This month + Tento měsíc + + + Last month + Minulý měsíc + + + This year + Tento rok + + + Range... + Rozsah... + + + Received with + Přijato s + + + Sent to + Odesláno na + + + To yourself + Sobě samému + + + Mined + Vytěženo + + + Other + Ostatní + + + Min amount + Min. množství + + + Copy address + Kopírovat sdresu + + + Copy label + Kopírovat popis + + + Edit label + Upravit popis + + + Comma separated file (*.csv) + Textový soubor oddělený středníkem (*.csv) + + + Confirmed + Potvrzeno + + + Date + Datum + + + Type + Typ + + + Label + Popis + + + Address + Adresa + + + ID + ID + + + Range: + Rozsah: + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + + bitcoin-core + + Options: + Možnosti: + + + Loading addresses... + Načítání adres... + + + Loading wallet... + Načítání peněženky... + + + Done loading + Načítání dokončeno + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_cy.ts b/src/qt/locale/bitcoin_cy.ts index 1b8eb3dc4..c32d236a9 100644 --- a/src/qt/locale/bitcoin_cy.ts +++ b/src/qt/locale/bitcoin_cy.ts @@ -1,18 +1,66 @@ - + AddressBookPage Create a new address Creu cyfeiriad newydd + + &New + &Newydd + Copy the currently selected address to the system clipboard Copio'r cyfeiriad sydd wedi'i ddewis i'r clipfwrdd system + + &Copy + &Copïo + + + C&lose + C&au + + + &Copy Address + &Cyfeiriad Copi + + + &Export + &Allforio + &Delete &Dileu + + C&hoose + &Dewis + + + Sending addresses + Cyfeiriadau anfon + + + Receiving addresses + Cyfeiriadau derbyn + + + Copy &Label + Copïo &Label + + + &Edit + &Golygu + + + Export Address List + Allforio Rhestr Cyfeiriad + + + Exporting Failed + Methodd Allfor + AddressTableModel @@ -71,6 +119,10 @@ Confirm wallet encryption Cadarnau amgryptiad y waled + + Are you sure you wish to encrypt your wallet? + Ydych chi'n siwr eich bod chi eisiau amgryptio dy waled di? + Wallet encrypted Waled wedi'i amgryptio @@ -96,6 +148,9 @@ Methodd dadgryptiad y waled + + BanTableModel + BitcoinGUI @@ -118,18 +173,70 @@ Browse transaction history Pori hanes trafodion + + E&xit + A&llanfa + Quit application Gadael rhaglen + + About &Qt + Ynghylch &Qt + &Options... &Opsiynau + + &Encrypt Wallet... + &Amgryptio'r waled... + + + &Change Passphrase... + &Newid cyfrinymadrodd... + + + &Sending addresses... + &Cyfeiriadau anfon... + + + &Receiving addresses... + &Cyfeiriadau derbyn... + + + Open &URI... + Agor &URI... + Change the passphrase used for wallet encryption Newid y cyfrinymadrodd a ddefnyddiwyd ar gyfer amgryptio'r waled + + Bitcoin + Bitcoin + + + Wallet + Waled + + + &Send + &Anfon + + + &Receive + &Derbyn + + + Show information about Bitcoin Core + Dangos gwybodaeth am Graidd Bitcoin + + + &Show / Hide + &Dangos / Cuddio + &File &Ffeil @@ -146,6 +253,34 @@ Tabs toolbar Bar offer tabiau + + Bitcoin Core + Craidd Bitcoin + + + &About Bitcoin Core + &Ynghylch Craidd Bitcoin + + + %n hour(s) + %n awr%n awr%n awr%n awr + + + %n day(s) + %n dydd%n dydd%n dydd%n dydd + + + %n week(s) + %n wythnos%n wythnos%n wythnos%n wythnos + + + %1 and %2 + %1 a %2 + + + %n year(s) + %n blwydd%n blwydd%n blwydd%n blwydd + Error Gwall @@ -166,6 +301,30 @@ Catching up... Dal i fyny + + Date: %1 + + Dyddiad: %1 + + + + Type: %1 + + Math: %1 + + + + Label: %1 + + Label: %1 + + + + Address: %1 + + Cyfeiriad: %1 + + Sent transaction Trafodiad a anfonwyd @@ -188,15 +347,31 @@ CoinControlDialog + + Amount: + Maint + Date Dyddiad + + Copy address + Cyfeiriad copi + + + Copy label + Copïo label + (no label) (heb label) - + + (change) + (newid) + + EditAddressDialog @@ -242,12 +417,40 @@ FreespaceChecker + + name + enw + HelpMessageDialog + + Bitcoin Core + Craidd Bitcoin + + + About Bitcoin Core + Ynghylch Craidd Bitcoin + + + Usage: + Cynefod: + Intro + + Welcome + Croeso + + + Welcome to Bitcoin Core. + Croeso i Graidd Bitcoin + + + Bitcoin Core + Craidd Bitcoin + Error Gwall @@ -255,6 +458,14 @@ OpenURIDialog + + Open URI + Agor URI + + + URI: + URI: + OptionsDialog @@ -262,6 +473,34 @@ Options Opsiynau + + &Network + &Rhwydwaith + + + W&allet + W&aled + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + &Window + &Ffenestr + + + &Display + &Dangos + OverviewPage @@ -288,6 +527,14 @@ &Information Gwybodaeth + + Network + Rhwydwaith + + + &Open + &Agor + ReceiveCoinsDialog @@ -295,9 +542,17 @@ &Label: &Label: + + Copy label + Copïo label + ReceiveRequestDialog + + Copy &Address + &Cyfeiriad Copi + Address Cyfeiriad @@ -336,6 +591,10 @@ Send Coins Anfon arian + + Amount: + Maint + Send to multiple recipients at once Anfon at pobl lluosog ar yr un pryd @@ -379,6 +638,10 @@ Alt+P Alt+P + + Message: + Neges: + ShutdownWindow @@ -400,6 +663,14 @@ SplashScreen + + Bitcoin Core + Craidd Bitcoin + + + The Bitcoin Core developers + Datblygwyr Graidd Bitcoin + [testnet] [testnet] @@ -455,6 +726,18 @@ This year Eleni + + Copy address + Cyfeiriad copi + + + Copy label + Copïo label + + + Exporting Failed + Methodd Allfor + Date Dyddiad @@ -487,9 +770,17 @@ WalletView + + &Export + &Allforio + bitcoin-core + + Options: + Opsiynau: + Information Gwybodaeth diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts index 60b8925e8..aa2724a1e 100644 --- a/src/qt/locale/bitcoin_da.ts +++ b/src/qt/locale/bitcoin_da.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,15 +220,26 @@ Tegnebogens adgangskode blev ændret. + + BanTableModel + + IP/Netmask + IP/Netmaske + + + Banned Until + Bandlyst indtil + + BitcoinGUI Sign &message... - Underskriv &besked … + Underskriv &besked… Synchronizing with network... - Synkroniserer med netværk … + Synkroniserer med netværk… &Overview @@ -268,31 +279,31 @@ &Options... - &Indstillinger … + &Indstillinger… &Encrypt Wallet... - &Kryptér tegnebog … + &Kryptér tegnebog… &Backup Wallet... - &Sikkerhedskopiér tegnebog … + &Sikkerhedskopiér tegnebog… &Change Passphrase... - &Skift adgangskode … + &Skift adgangskode… &Sending addresses... - &Afsendelsesadresser … + &Afsendelsesadresser… &Receiving addresses... - &Modtagelsesadresser … + &Modtagelsesadresser… Open &URI... - &Åbn URI … + &Åbn URI… Bitcoin Core client @@ -300,11 +311,11 @@ Importing blocks from disk... - Importerer blokke fra disken … + Importerer blokke fra disken… Reindexing blocks on disk... - Genindekserer blokke på disken … + Genindekserer blokke på disken… Send coins to a Bitcoin address @@ -328,7 +339,7 @@ &Verify message... - &Verificér besked … + &Verificér besked… Bitcoin @@ -428,7 +439,7 @@ No block source available... - Ingen blokkilde tilgængelig … + Ingen blokkilde tilgængelig… Processed %n block(s) of transaction history. @@ -484,7 +495,7 @@ Catching up... - Indhenter … + Indhenter… Date: %1 @@ -871,6 +882,34 @@ command-line options kommandolinjetilvalg + + UI Options: + Indstillinger for brugergrænseflade: + + + Choose data directory on startup (default: %u) + Vælg datamappe under opstart (standard: %u) + + + Set language, for example "de_DE" (default: system locale) + Vælg sprog; fx "da_DK" (standard: systemsprog) + + + Start minimized + Start minimeret + + + Set SSL root certificates for payment request (default: -system-) + Opsæt SSL-rodcertifikater til betalingsadmodninger (standard: -system-) + + + Show splash screen on startup (default: %u) + Vis startskærm under opstart (standard: %u) + + + Reset all settings changes made over the GUI + Nulstil alle indstillinger, der er foretaget i den grafiske brugerflade + Intro @@ -914,7 +953,11 @@ %n GB of free space available %n GB fri plads tilgængelig%n GB fri plads tilgængelig - + + (of %n GB needed) + (ud af %n GB behøvet)(ud af %n GB behøvet) + + OpenURIDialog @@ -1064,6 +1107,34 @@ Port of the proxy (e.g. 9050) Port for proxyen (fx 9050) + + Used for reaching peers via: + Bruges til at nå knuder via: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Viser om den angivne standard-SOCKS5-proxy bruges til at nå knuder via denne netværkstype. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Forbind til Bitcoin-netværket gennem en separat SOCKS5-proxy for skjulte Tor-tjenester. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Brug separat SOCKS5-proxy for at nå knuder via skjulte Tor-tjenester. + &Window &Vindue @@ -1090,7 +1161,7 @@ &Unit to show amounts in: - &Enhed at vise beløb i: + &Enhed, som beløb vises i: Choose the default subdivision unit to show in the interface and when sending coins. @@ -1102,7 +1173,7 @@ &OK - &O.k. + &Ok &Cancel @@ -1161,7 +1232,7 @@ Pending: - Uafgjort: + Afventende: Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance @@ -1282,10 +1353,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Betalingsanmodning %1 er for stor (%2 byte, %3 byte tilladt). - - Payment request DoS protection - Beskyttelse mod DoS-angreb via betalingsanmodninger - Error communicating with %1: %2 Fejl under kommunikation med %1: %2 @@ -1365,7 +1432,7 @@ QRImageWidget &Save Image... - &Gem billede … + &Gem billede… &Copy Image @@ -1438,6 +1505,18 @@ Current number of blocks Nuværende antal blokke + + Memory Pool + Hukommelsespulje + + + Current number of transactions + Aktuelt antal transaktioner + + + Memory usage + Hukommelsesforbrug + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. Åbn Bitcoin Cores fejlsøgningslogfil fra den aktuelle datamappe. Dette kan tage nogle få sekunder for store logfiler. @@ -1454,10 +1533,18 @@ &Peers Andre &knuder + + Banned peers + Bandlyste knuder + Select a peer to view detailed information. Vælg en anden knude for at se detaljeret information. + + Whitelisted + På hvidliste + Direction Retning @@ -1466,6 +1553,18 @@ Version Version + + Starting Block + Startblok + + + Synced Headers + Synkroniserede headers + + + Synced Blocks + Synkroniserede blokke + User Agent Brugeragent @@ -1474,14 +1573,6 @@ Services Tjenester - - Starting Height - Starthøjde - - - Sync Height - Synkroniseringshøjde - Ban Score Bandlysningsscore @@ -1498,18 +1589,18 @@ Last Receive Seneste modtagelse - - Bytes Sent - Byte sendt - - - Bytes Received - Byte modtaget - Ping Time Ping-tid + + The duration of a currently outstanding ping. + Varigheden af den aktuelt igangværende ping. + + + Ping Wait + Ping-ventetid + Time Offset Tidsforskydning @@ -1558,6 +1649,34 @@ Clear console Ryd konsol + + &Disconnect Node + &Afbryd forbindelse til knude + + + Ban Node for + Bandlys knude i + + + 1 &hour + 1 &time + + + 1 &day + 1 &dag + + + 1 &week + 1 &uge + + + 1 &year + 1 &år + + + &Unban Node + &Fjern bandlysning af knude + Welcome to the Bitcoin Core RPC console. Velkommen til Bitcoin Cores RPC-konsol. @@ -1586,6 +1705,10 @@ %1 GB %1 GB + + (node id: %1) + (knude-id: %1) + via %1 via %1 @@ -1603,12 +1726,16 @@ Udgående - Unknown - Ukendt + Yes + Ja - Fetching... - Henter … + No + Nej + + + Unknown + Ukendt @@ -1710,7 +1837,7 @@ &Save Image... - &Gem billede … + &Gem billede… Request payment to %1 @@ -1792,7 +1919,7 @@ Inputs... - Inputs … + Inputs… automatically selected @@ -1844,7 +1971,7 @@ Choose... - Vælg … + Vælg… collapse fee-settings @@ -1884,7 +2011,7 @@ (Smart fee not initialized yet. This usually takes a few blocks...) - (Smart-gebyr er ikke initialiseret endnu. Dette tager typisk nogle få blokke …) + (Smart-gebyr er ikke initialiseret endnu. Dette tager typisk nogle få blokke…) Confirmation time: @@ -1975,8 +2102,8 @@ Kopiér byttepenge - Total Amount %1 (= %2) - Totalbeløb %1 (= %2) + Total Amount %1 + Totalbeløb %1 or @@ -2010,14 +2137,14 @@ Payment request expired. Betalingsanmodning er udløbet. + + Pay only the required fee of %1 + Betal kun det påkrævede gebyr på %1 + Estimated to begin confirmation within %n block(s). Bekræftelse estimeres til at begynde inden for %n blok.Bekræftelse estimeres til at begynde inden for %n blokke. - - Pay only the minimum fee of %1 - Betal kun det minimale gebyr på %1 - The recipient address is not valid. Please recheck. Modtageradressen er ikke gyldig. Tjek venligst igen. @@ -2138,7 +2265,7 @@ ShutdownWindow Bitcoin Core is shutting down... - Bitcoin Core lukker ned … + Bitcoin Core lukker ned… Do not shut down the computer until this window disappears. @@ -2603,7 +2730,7 @@ Range... - Interval … + Interval… Received with @@ -2649,6 +2776,10 @@ Copy transaction ID Kopiér transaktions-ID + + Copy raw transaction + Kopiér rå transaktion + Edit label Redigér mærkat @@ -2796,13 +2927,53 @@ Accept command line and JSON-RPC commands Acceptér kommandolinje- og JSON-RPC-kommandoer + + If <category> is not supplied or if <category> = 1, output all debugging information. + Hvis <category> ikke angives eller hvis <category> = 1, udskriv al fejlretningsinformation. + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Maksimalt totalgebyr (i %s) for brug i en enkelt tegnebogstransaktion; ved at sætte dette for lavt, kan store transaktioner afbrydes (standard: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + Kontrollér venligst, at din computers dato og tid er korrekt! Hvis uret ikke passer, vil Bitcoin Core ikke fungere korrekt. + + + Prune configured below the minimum of %d MiB. Please use a higher number. + Beskæring er sat under minimumsgrænsen på %d MiB. Brug venligst et større tal. + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + Beskæring: Seneste synkronisering rækker udover beskårne data. Du er nødt til at bruge -reindex (downloade hele blokkæden igen i fald af beskåret knude) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + Reducér lagringskravene ved at beskære (slette) gamle blokke. Denne tilstand er ikke kompatibel med -txindex og -rescan. Advarsel: Fortrydelse af denne indstilling kræver gendownload af hele blokkæden. (standard: 0 = slå beskæring af blokke fra, >%u = målstørrelse i MiB der skal bruges på blokfiler) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + Genindlæsninger er ikke mulige i beskåret tilstand. Du er nødt til at bruge -reindex, hvilket vil downloade hele blokkæden igen. + + + Error: A fatal internal error occurred, see debug.log for details + Fejl: En alvorlig intern fejl er opstået. Se debug.log for detaljer + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Gebyr (i %s/kB) der skal lægges til de transaktioner du sender (standard: %s) + + + Pruning blockstore... + Beskærer bloklager… + Run in the background as a daemon and accept commands Kør i baggrunden som en service, og acceptér kommandoer - Use the test network - Brug testnetværket + Unable to start HTTP server. See debug log for details. + Kunne ikke starte HTTP-server. Se fejlretningslog for detaljer. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2824,18 +2995,14 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Udfør kommando, når en transaktion i tegnebogen ændres (%s i kommandoen erstattes med TxID) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Maksimalt totalt gebyr der kan bruges i en enkelt tegnebogstransaktion. For lav en værdi kan afbryde store transaktioner (standard: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Reducér pladskravene ved at beskære (slette, "prune") gamle blokke. Denne tilstand slår understøttelse af tegnebogen fra og er ikke kompatibel med -txindex. Advarsel: Fortrydelse af denne indstilling kræver download af hele blokkæden igen. (standard: 0 = slå beskæring af blokke fra, >%u = målstørrelse i MiB der skal bruges til blokfiler) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Sæt antallet af scriptverificeringstråde (%u til %d, 0 = auto, <0 = efterlad det antal kernet fri, standard: %d) + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + Blokdatabasen indeholder en blok, som ser ud til at være fra fremtiden. Dette kan skyldes, at din computers dato og tid ikke er sat korrekt. Genopbyg kun blokdatabasen, hvis du er sikker på, at din computers dato og tid er korrekt + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Dette er en foreløbig testudgivelse - brug på eget ansvar - brug ikke til udvinding eller handelsprogrammer @@ -2844,6 +3011,10 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. Ikke i stand til at tildele til %s på denne computer. Bitcoin Core kører sansynligvis allerede. + + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + Brug UPnP for at konfigurere den lyttende port (standard: 1 under lytning og ingen -proxy) + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) ADVARSEL: unormalt mange blokke er genereret; %d blokke er modtaget i løbet af de seneste %d timer (%d forventet) @@ -2852,10 +3023,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) ADVARSEL: tjek din netværksforbindelse; %d blokke er modtaget i løbet af de seneste %d timer (%d forventet) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Advarsel: -paytxfee er sat meget højt! Dette er det gebyr du vil betale, hvis du sender en transaktion. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Advarsel: Netværket ser ikke ud til at være fuldt ud enige! Enkelte minere ser ud til at opleve problemer. @@ -2864,10 +3031,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Advarsel: Vi ser ikke ud til at være fuldt ud enige med andre knuder! Du kan være nødt til at opgradere, eller andre knuder kan være nødt til at opgradere. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Advarsel: fejl under læsning af wallet.dat! Alle nøgler blev læst korrekt, men transaktionsdata eller adressebogsposter kan mangle eller være forkerte. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Advarsel: wallet.dat ødelagt, data reddet! Oprindelig wallet.dat gemt som wallet.{timestamp}.bak i %s; hvis din saldo eller dine transaktioner er forkert, bør du genskabe fra en sikkerhedskopi. @@ -2877,17 +3040,13 @@ Sæt andre knuder, der forbinder fra den angivne netmaske eller IP, på hvidliste. Kan angives flere gange. - (default: 1) - (standard: 1) + -maxmempool must be at least %d MB + -maxmempool skal være mindst %d MB <category> can be: <kategori> kan være: - - Attempt to recover private keys from a corrupt wallet.dat - Forsøg at genskabe private nøgler fra ødelagt wallet.dat - Block creation options: Blokoprettelsestilvalg: @@ -2916,6 +3075,22 @@ Do you want to rebuild the block database now? Ønsker du at genopbygge blokdatabasen nu? + + Enable publish hash block in <address> + Aktivér offentliggørelse af hash-blok i <address> + + + Enable publish hash transaction in <address> + Aktivér offentliggørelse af hash-transaktion i <address> + + + Enable publish raw block in <address> + Aktivér offentliggørelse af rå blok i <address> + + + Enable publish raw transaction in <address> + Aktivér offentliggørelse af rå transaktion i <address> + Error initializing block database Klargøring af blokdatabase mislykkedes @@ -2932,10 +3107,6 @@ Error opening block database Åbning af blokdatabase mislykkedes - - Error: A fatal internal error occured, see debug.log for details - Fejl: En fatal intern fejl opstod; se debug.log for detaljer - Error: Disk space is low! Fejl: Mangel på ledig diskplads! @@ -2944,13 +3115,9 @@ Failed to listen on any port. Use -listen=0 if you want this. Lytning på enhver port mislykkedes. Brug -listen=0, hvis du ønsker dette. - - If <category> is not supplied, output all debugging information. - Hvis <kategori> ikke angives, udskriv al fejlsøgningsinformation. - Importing... - Importerer … + Importerer… Incorrect or no genesis block found. Wrong datadir for network? @@ -2960,6 +3127,10 @@ Invalid -onion address: '%s' Ugyldig -onion adresse: "%s" + + Keep the transaction memory pool below <n> megabytes (default: %u) + Hold hukommelsespuljen med transaktioner under <n> megabyte (standard: %u) + Not enough file descriptors available. For få tilgængelige fildeskriptorer. @@ -2988,17 +3159,33 @@ Specify wallet file (within data directory) Angiv tegnebogsfil (inden for datamappe) + + Unsupported argument -benchmark ignored, use -debug=bench. + Argument -benchmark understøttes ikke og ignoreres; brug -debug=bench. + + + Unsupported argument -debugnet ignored, use -debug=net. + Argument -debugnet understøttes ikke og ignoreres; brug -debug=net. + + + Unsupported argument -tor found, use -onion. + Argument -tor understøttes ikke; brug -onion. + Use UPnP to map the listening port (default: %u) Brug UPnP til at konfigurere den lyttende port (standard: %u) + + User Agent comment (%s) contains unsafe characters. + Brugeragent-kommentar (%s) indeholder usikre tegn. + Verifying blocks... - Verificerer blokke … + Verificerer blokke… Verifying wallet... - Verificerer tegnebog … + Verificerer tegnebog… Wallet %s resides outside data directory %s @@ -3016,18 +3203,10 @@ You need to rebuild the database using -reindex to change -txindex Du er nødt til at genopbygge databasen ved hjælp af -reindex for at ændre -txindex - - Imports blocks from external blk000??.dat file - Importerer blokke fra ekstern blk000??.dat fil - 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 Tillad JSON-RPC-forbindelser fra angivet kilde. Gyldig for <ip> er en enkelt IP (fx 1.2.3.4), et netværk/netmaske (fx 1.2.3.4/255.255.255.0) eller et netværk/CIDR (fx 1.2.3.4/24). Dette tilvalg kan angives flere gange - - An error occurred while setting up the RPC address %s port %u for listening: %s - Der opstod en fejl under opsætning af RPC-adresse %s port %u for lytning: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Tildel given adresse og sæt andre knuder, der forbinder til den, på hvidliste. Brug [vært]:port notation for IPv6 @@ -3052,17 +3231,13 @@ Error: Listening for incoming connections failed (listen returned error %s) Fejl: Lytning efter indkommende forbindelser mislykkedes (lytning resultarede i fejl %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Fejl: Ikke understøttet argument -socks blev fundet. Det er ikke muligt at angive SOCKS-version længere, da kun SOCKS5-proxier er understøttet. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Udfør kommando, når en relevant alarm modtages eller vi ser en virkelig lang udsplitning (%s i cmd erstattes af besked) - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Gebyrer (i BTC/Kb) mindre end dette opfattes som nulgebyr for videresendelse (standard: %s) + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + Gebyrer (i %s/kB) mindre end dette opfattes som intet gebyr for videresendelse, mining og oprettelse af transaktioner (standard: %s) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -3076,10 +3251,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) Maksimal størrelse på data i transaktioner til dataoverførsel, som vi videresender og miner (standard: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - Beskæring opsat under minimumsværdien %d MB. Brug venligst en højere værdi. - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Forespørgsel @@ -3104,38 +3275,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Dette produkt indeholder software, der er udviklet af OpenSSL-projektet for brug i OpenSSL-værktøjskassen <https://www.openssl.org/>, samt kryptografisk software, der er skrevet af Eric Young, samt UPnP-software, der er skrevet af Thomas Bernard. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - For at bruge bitcoind eller valgmuligheden -server i bitcoin-qt skal du oprette et rpcpassword i konfigurationsfilen: -%s -Det anbefales, at du bruger følgende tilfældige adgangskode: -rpcuser=bitcoinrpc -rpcpassword=%s -(du behøver ikke at huske adgangskoden) -Brugernavnet og adgangskoden MÅ IKKE være det samme. -Hvis filen ikke eksisterer, opret den da så kun ejeren har læserettigheder. -Det anbefales også at sætte alertnotify, så du får besked omkring problemer; -for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Advarsel: -maxtxfee er sat meget højt! Så store gebyrer kan betales på en enkelt transaktion. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Advarsel: Undersøg venligst at din computers dato og klokkeslet er korrekt indstillet! Hvis der er fejl i disse vil Bitcoin Core ikke fungere korrekt. - 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 Andre knuder på hvidliste kan ikke DoS-bandlyses, og deres transaktioner videresendes altid, selv hvis de allerede er i mempool'en. Brugbart til fx et adgangspunkt @@ -3154,20 +3293,24 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Activating best chain... - Aktiverer bedste kæde … + Aktiverer bedste kæde… - Can't run with a wallet in prune mode. - Kan ikke køre med en tegnebog i beskåret tilstand. + Always relay transactions received from whitelisted peers (default: %d) + Videresend altid transaktioner, der modtages fra hvidlistede knuder (standard: %d) + + + Attempt to recover private keys from a corrupt wallet.dat on startup + Forsøg at genskabe private nøgler fra en ødelagt wallet.dat under opstart + + + Automatically create Tor hidden service (default: %d) + Opret automatisk skjult Tor-tjeneste (standard: %d) Cannot resolve -whitebind address: '%s' Kan ikke løse -whitebind adresse: "%s" - - Choose data directory on startup (default: 0) - Vælg datamappe ved opstart (standard: 0) - Connect through SOCKS5 proxy Forbind gennem SOCKS5-proxy @@ -3176,10 +3319,6 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Copyright (C) 2009-%i The Bitcoin Core Developers Ophavsret © 2009-%i Udviklerne af Bitcoin Core - - Could not parse -rpcbind value %s as network address - Kunne ikke tolke -rpcbind-værdi %s som en netværksadresse - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Fejl ved indlæsning af wallet.dat: Tegnebog kræver en nyere version af Bitcoin Core @@ -3189,12 +3328,8 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Fejl under læsning fra database; lukker ned. - Error: Unsupported argument -tor found, use -onion. - Fejl: Ikke understøttet argument -tor fundet, brug -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Gebyr (i BTC/kB) som skal føjes til transaktioner, du sender (standard: %s) + Imports blocks from external blk000??.dat file on startup + Importerer blokeringer fra ekstern blk000??.dat-fil under opstart Information @@ -3236,18 +3371,10 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Node relay options: Videresendelsesvalgmuligheder for knude: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Tilvalg for RPC SSL: (se Bitcoin Wiki for instruktioner i SSL-opstart) - RPC server options: Tilvalg for RPC-server: - - RPC support for HTTP persistent connections (default: %d) - RPC-understøttelse for HTTP-persistente forbindelser (standard: %d) - Rebuild block chain index from current blk000??.dat files on startup Genopbyg blokkædeindeks fra nuværende blk000??.dat-filer ved opstart @@ -3256,6 +3383,14 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Receive and display P2P network alerts (default: %u) Modtag og vis P2P-netværksadvarsler (standard: %u) + + Reducing -maxconnections from %d to %d, because of system limitations. + Reducerer -maxconnections fra %d til %d på grund af systembegrænsninger. + + + Rescan the block chain for missing wallet transactions on startup + Genindlæs blokkæden efter manglende tegnebogstransaktioner under opstart + Send trace/debug info to console instead of debug.log file Send sporings-/fejlsøgningsinformation til konsollen i stedet for debug.log filen @@ -3264,22 +3399,10 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Send transactions as zero-fee transactions if possible (default: %u) Send transaktioner som nul-gebyr-transaktioner hvis muligt (standard: %u) - - Set SSL root certificates for payment request (default: -system-) - Sæt SSL-rodcertifikater for betalingsanmodning (standard: -system-) - - - Set language, for example "de_DE" (default: system locale) - Angiv sprog, fx "da_DK" (standard: systemlokalitet) - Show all debugging options (usage: --help -help-debug) Vis alle tilvalg for fejlsøgning (brug: --help -help-debug) - - Show splash screen on startup (default: 1) - Vis opstartsbillede ved opstart (standard: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Formindsk debug.log filen ved klientopstart (standard: 1 hvis ikke -debug) @@ -3288,10 +3411,6 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Signing transaction failed Underskrift af transaktion mislykkedes - - Start minimized - Start minimeret - The transaction amount is too small to pay the fee Transaktionsbeløbet er for lille til at betale gebyret @@ -3300,6 +3419,14 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com This is experimental software. Dette er eksperimentelt software. + + Tor control port password (default: empty) + Adgangskode for Tor kontrolport (standard: tom) + + + Tor control port to use if onion listening enabled (default: %s) + Tor kontrolport, der skal bruges, hvis onion-lytning er slået til (standard: %s) + Transaction amount too small Transaktionsbeløb er for lavt @@ -3316,17 +3443,13 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Transaction too large Transaktionen er for stor - - UI Options: - Indstillinger for brugerflade: - Unable to bind to %s on this computer (bind returned error %s) Ikke i stand til at tildele til %s på denne computer (bind returnerede fejl %s) - Use UPnP to map the listening port (default: 1 when listening) - Brug UPnP til at konfigurere den lyttende port (standard: 1 under lytning) + Upgrade wallet to latest format on startup + Opgradér tegnebog til seneste format under opstart Username for JSON-RPC connections @@ -3341,20 +3464,16 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Advarsel - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Advarsel: Ikke understøttet argument -benchmark ignoreret, brug -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Advarsel: Ikke understøttet argument -debugnet ignoreret, brug -debug=net. + Whether to operate in a blocks only mode (default: %u) + Hvorvidt der skal arbejdes i kun-blokke-tilstand (standard: %u) Zapping all transactions from wallet... - Zapper alle transaktioner fra tegnebog … + Zapper alle transaktioner fra tegnebog… - on startup - under opstart + ZeroMQ notification options: + ZeroMQ-notifikationsindstillinger: wallet.dat corrupt, salvage failed @@ -3368,18 +3487,6 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Execute command when the best block changes (%s in cmd is replaced by block hash) Udfør kommando, når den bedste blok ændres (%s i kommandoen erstattes med blokhash) - - Upgrade wallet to latest format - Opgrader tegnebog til seneste format - - - Rescan the block chain for missing wallet transactions - Gennemsøg blokkæden for manglende tegnebogstransaktioner - - - Use OpenSSL (https) for JSON-RPC connections - Brug OpenSSL (https) for JSON-RPC-forbindelser - This help message Denne hjælpebesked @@ -3390,7 +3497,7 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Loading addresses... - Indlæser adresser … + Indlæser adresser… Error loading wallet.dat: Wallet corrupted @@ -3400,6 +3507,26 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = behold metadata for transaktion, fx kontoindehaver og information om betalingsanmodning, 2 = drop metadata for transaktion) + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + -maxtxfee er sat meget højt! Gebyrer så store risikeres betalt på en enkelt transaktion. + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + -paytxfee er sat meget højt! Dette er transaktionsgebyret, som du betaler, hvis du sender en transaktion. + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + Behold ikke transaktioner i hukommelsespuljen i mere end <n> timer (default: %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Fejl under læsning af wallet.dat! Alle nøgler blev læst korrekt, men transaktionsdata eller indgange i adressebogen kan mangle eller være ukorrekte. + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + Gebyrer (i %s/kB) mindre end dette opfattes som intet gebyr under oprettelse af transaktioner (standard: %s) + How thorough the block verification of -checkblocks is (0-4, default: %u) Hvor gennemarbejdet blokverificeringen for -checkblocks er (0-4; standard: %u) @@ -3416,18 +3543,34 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Output debugging information (default: %u, supplying <category> is optional) Udskriv fejlsøgningsinformation (standard: %u, angivelse af <kategori> er valgfri) + + Support filtering of blocks and transaction with bloom filters (default: %u) + Understøt filtrering af blokke og transaktioner med Bloom-filtre (standard: %u) + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + Den totale længde på netværksversionsstrengen (%i) overstiger maksimallængden (%i). Reducér antaller af eller størrelsen på uacomments. + + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + Prøver at holde udadgående traffik under det givne mål (i MiB pr. 24 timer), 0 = ingen grænse (standard: %d) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Argument -socks understøttes ikke. Det er ikke længere muligt at sætte SOCKS-version; kun SOCKS5-proxier understøttes. + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) - Brug separat SOCS5-proxy for at nå andre knuder via Tor skjulte tjenester (standard: %s) + Brug separat SOCS5-proxy for at nå knuder via skjulte Tor-tjenester (standard: %s) + + + 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. This option can be specified multiple times + Brugernavn og hashet adgangskode for JSON-RPC-forbindelser. Feltet <userpw> er i formatet: <BRUGERNAVN>:<SALT>$<HASH>. Et kanonisk Python-skript inkluderes i share/rpcuser. Dette tilvalg kan angives flere gange (default: %s) (standard: %s) - - Acceptable ciphers (default: %s) - Accepterede kodninger (standard: %s) - Always query for peer addresses via DNS lookup (default: %u) Forespørg altid adresser på andre knuder via DNS-opslag (default: %u) @@ -3488,15 +3631,6 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Relay non-P2SH multisig (default: %u) Videresend ikke-P2SH multisig (standard: %u) - - Server certificate file (default: %s) - Servercertifikat-fil (standard: %s) - - - - Server private key (default: %s) - Serverens private nøgle (standard: %s) - Set key pool size to <n> (default: %u) Sæt nøglepuljestørrelse til <n> (standard: %u) @@ -3552,7 +3686,7 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Loading block index... - Indlæser blokindeks … + Indlæser blokindeks… Add a node to connect to and attempt to keep the connection open @@ -3560,7 +3694,7 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Loading wallet... - Indlæser tegnebog … + Indlæser tegnebog… Cannot downgrade wallet @@ -3572,7 +3706,7 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Rescanning... - Genindlæser … + Genindlæser… Done loading diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index a50a6e60c..84de80aff 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,17 @@ Die Wallet-Passphrase wurde erfolgreich geändert. + + BanTableModel + + IP/Netmask + IP/Netzmaske + + + Banned Until + Gesperrt bis + + BitcoinGUI @@ -871,6 +882,34 @@ command-line options Kommandozeilenoptionen + + UI Options: + UI Einstellungen: + + + Choose data directory on startup (default: %u) + Datenverzeichnis beim Starten auswählen (Standard: %u) + + + Set language, for example "de_DE" (default: system locale) + Sprache einstellen, zum Beispiel "de_DE" (default: system locale) + + + Start minimized + Minimiert starten + + + Set SSL root certificates for payment request (default: -system-) + SSL-Wurzelzertifikate für Zahlungsanforderungen festlegen (Standard: -system-) + + + Show splash screen on startup (default: %u) + Startbildschirm beim Starten anzeigen (Standard: %u) + + + Reset all settings changes made over the GUI + Setze alle Einstellungen zurück, die über die grafische Oberfläche geändert wurden. + Intro @@ -1068,6 +1107,34 @@ Port of the proxy (e.g. 9050) Port des Proxies (z.B. 9050) + + Used for reaching peers via: + Benutzt um Gegenstellen zu erreichen über: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Zeigt an, ob der eingegebene Standard SOCKS5 Proxy genutzt wird um Peers mit dem Netzwerktyp zu erreichen. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Über einen separaten SOCKS5 Proxy für Tor Services mit dem Bitcoint Netzwerk verbinden. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Separaten SOCKS5-Proxy verwenden, um Gegenstellen über versteckte Tor-Dienste zu erreichen: + &Window &Programmfenster @@ -1286,10 +1353,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Zahlungsanforderung %1 ist zu groß (%2 Byte, erlaubt sind %3 Byte). - - Payment request DoS protection - Zahlungsanforderungs-DoS-Schutz - Error communicating with %1: %2 Kommunikationsfehler mit %1: %2 @@ -1442,6 +1505,18 @@ Current number of blocks Aktuelle Anzahl Blöcke + + Memory Pool + Speicherpool + + + Current number of transactions + Aktuelle Anzahl der Transaktionen + + + Memory usage + Speichernutzung + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. Öffnet die "Bitcoin Core"-Debugprotokolldatei aus dem aktuellen Datenverzeichnis. Dies kann bei großen Protokolldateien einige Sekunden dauern. @@ -1458,10 +1533,18 @@ &Peers &Gegenstellen + + Banned peers + Gesperrte Peers + Select a peer to view detailed information. Gegenstelle auswählen, um detaillierte Informationen zu erhalten. + + Whitelisted + Zugelassene + Direction Richtung @@ -1470,6 +1553,18 @@ Version Version + + Starting Block + Start Block + + + Synced Headers + Synchronisierte Kopfdaten + + + Synced Blocks + Synchronisierte Blöcke + User Agent User-Agent @@ -1478,14 +1573,6 @@ Services Dienste - - Starting Height - Start-Höhe - - - Sync Height - Sync-Höhe - Ban Score Sperrpunktzahl @@ -1502,18 +1589,18 @@ Last Receive Letzter Empfang - - Bytes Sent - Übertragene Byte - - - Bytes Received - Empfangene Byte - Ping Time Pingzeit + + The duration of a currently outstanding ping. + Die Laufzeit eines aktuell ausstehenden Ping. + + + Ping Wait + Ping Wartezeit + Time Offset Zeitversatz @@ -1562,6 +1649,34 @@ Clear console Konsole zurücksetzen + + &Disconnect Node + Knoten &trennen + + + Ban Node for + Knoten gebannt für + + + 1 &hour + 1 &Stunde + + + 1 &day + 1 &Tag + + + 1 &week + 1 &Woche + + + 1 &year + 1 &Jahr + + + &Unban Node + &Node entsperren + Welcome to the Bitcoin Core RPC console. Willkommen in der "Bitcoin Core"-RPC-Konsole. @@ -1590,6 +1705,10 @@ %1 GB %1 GB + + (node id: %1) + (Knotenkennung: %1) + via %1 über %1 @@ -1607,12 +1726,16 @@ ausgehend - Unknown - Unbekannt + Yes + Ja - Fetching... - Aktualisiere... + No + Nein + + + Unknown + Unbekannt @@ -1979,8 +2102,8 @@ Wechselgeld kopieren - Total Amount %1 (= %2) - Gesamtbetrag %1 (= %2) + Total Amount %1 + Gesamtbetrag %1 or @@ -2014,14 +2137,14 @@ Payment request expired. Zahlungsanforderung abgelaufen. + + Pay only the required fee of %1 + Nur die notwendige Gebühr in Höhe von %1 zahlen + Estimated to begin confirmation within %n block(s). Voraussichtlicher Beginn der Bestätigung innerhalb von %n Block.Voraussichtlicher Beginn der Bestätigung innerhalb von %n Blöcken. - - Pay only the minimum fee of %1 - Nur die minimale Gebühr in Höhe von %1 zahlen - The recipient address is not valid. Please recheck. Die Zahlungsadresse ist ungültig, bitte nochmals überprüfen. @@ -2653,6 +2776,10 @@ Copy transaction ID Transaktions-ID kopieren + + Copy raw transaction + Kopiere rohe Transaktion + Edit label Bezeichnung bearbeiten @@ -2800,13 +2927,29 @@ Accept command line and JSON-RPC commands Kommandozeilen- und JSON-RPC-Befehle annehmen + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Maximale Gesamtgebühr (in %s) in einer Börsentransaktion; wird dies zu niedrig gesetzten können große Transaktionen abgebrochen werden (Standard: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + Bitte korrigieren Sie die Datums- und Uhrzeiteinstellungen Ihres Computers, da Bitcoin Core ansonsten nicht ordnungsgemäß funktionieren wird. + + + Error: A fatal internal error occurred, see debug.log for details + Fehler: Ein schwerer interner Fehler ist aufgetreten, siehe debug.log für Details. + + + Pruning blockstore... + Kürze Blockspeicher... + Run in the background as a daemon and accept commands Als Hintergrunddienst ausführen und Befehle annehmen - Use the test network - Das Testnetz verwenden + Unable to start HTTP server. See debug log for details. + Kann HTTP Server nicht starten. Siehe debug log für Details. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2828,14 +2971,6 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Befehl ausführen wenn sich eine Wallet-Transaktion verändert (%s im Befehl wird durch die Transaktions-ID ersetzt) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Maximale Gesamtgebühren je Wallet-Transaktion, ein zu niedriger Wert kann große Transaktionen abbrechen (Standard: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Speicherplatzanforderung durch kürzen (löschen) alter Blöcke reduzieren. Dieser Modus deaktiviert die Wallet-Unterstützung und ist nicht mit -txindex kompatibel. Warnung: Die Umkehr dieser Einstellung erfordert das erneute Herunterladen der gesamten Blockkette. (Standard: 0 = deaktiviert das Kürzen von Blöcken, >%u = Zielgröße in MiB, die für Blockdateien verwendet werden darf) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Maximale Anzahl an Skript-Verifizierungs-Threads festlegen (%u bis %d, 0 = automatisch, <0 = so viele Kerne frei lassen, Standard: %d) @@ -2856,10 +2991,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) Warnung: Überprüpfen Sie ihre Netzwerkverbindung, %d Blöcke wurden in den letzten %d Stunden empfangen (%d wurden erwartet). - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Warnung: -paytxfee ist auf einen sehr hohen Wert festgelegt! Dies ist die Gebühr die beim Senden einer Transaktion fällig wird. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Warnung: Das Netzwerk scheint nicht vollständig übereinzustimmen! Einige Miner scheinen Probleme zu haben. @@ -2868,10 +2999,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Warnung: Wir scheinen nicht vollständig mit unseren Gegenstellen übereinzustimmen! Sie oder die anderen Knoten müssen unter Umständen Ihre Client-Software aktualisieren. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Warnung: Lesen von wallet.dat fehlgeschlagen! Alle Schlüssel wurden korrekt gelesen, Transaktionsdaten bzw. Adressbucheinträge fehlen aber möglicherweise oder sind inkorrekt. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Warnung: wallet.dat beschädigt, Datenrettung erfolgreich! Original wallet.dat wurde als wallet.{Zeitstempel}.dat in %s gespeichert. Falls Ihr Kontostand oder Transaktionen nicht korrekt sind, sollten Sie von einer Datensicherung wiederherstellen. @@ -2881,17 +3008,13 @@ Gegenstellen die sich von der angegebenen Netzmaske oder IP-Adresse aus verbinden immer zulassen. Kann mehrmals angegeben werden. - (default: 1) - (Standard: 1) + -maxmempool must be at least %d MB + -maxmempool muss mindestens %d MB betragen <category> can be: <category> kann sein: - - Attempt to recover private keys from a corrupt wallet.dat - Versuchen, private Schlüssel aus einer beschädigten wallet.dat wiederherzustellen - Block creation options: Blockerzeugungsoptionen: @@ -2920,6 +3043,18 @@ Do you want to rebuild the block database now? Möchten Sie die Blockdatenbank jetzt neu aufbauen? + + Enable publish hash block in <address> + Aktiviere das Veröffentlichen des Hash-Blocks in <address> + + + Enable publish hash transaction in <address> + Aktiviere das Veröffentlichen der Hash-Transaktion in <address> + + + Enable publish raw block in <address> + Aktiviere das Veröffentlichen des Raw-Blocks in <address> + Error initializing block database Fehler beim Initialisieren der Blockdatenbank @@ -2936,10 +3071,6 @@ Error opening block database Fehler beim Öffnen der Blockdatenbank - - Error: A fatal internal error occured, see debug.log for details - Fehler: Ein schwerer Fehler ist aufgetreten, für Details debug.log ansehen. - Error: Disk space is low! Fehler: Zu wenig freier Speicherplatz auf dem Datenträger! @@ -2948,10 +3079,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Fehler, es konnte kein Port abgehört werden. Wenn dies so gewünscht wird -listen=0 verwenden. - - If <category> is not supplied, output all debugging information. - Wenn <category> nicht angegeben wird, jegliche Debugginginformationen ausgeben. - Importing... Importiere... @@ -2992,6 +3119,18 @@ Specify wallet file (within data directory) Wallet-Datei angeben (innerhalb des Datenverzeichnisses) + + Unsupported argument -benchmark ignored, use -debug=bench. + Nicht unterstütztes Argument -benchmark wurde ignoriert, bitte -debug=bench verwenden. + + + Unsupported argument -debugnet ignored, use -debug=net. + Nicht unterstütztes Argument -debugnet wurde ignoriert, bitte -debug=net verwenden. + + + Unsupported argument -tor found, use -onion. + Nicht unterstütztes Argument -tor gefunden, bitte -onion verwenden. + Use UPnP to map the listening port (default: %u) UPnP verwenden, um eine Portweiterleitung einzurichten (Standard: %u) @@ -3020,18 +3159,10 @@ You need to rebuild the database using -reindex to change -txindex Sie müssen die Datenbank mit Hilfe von -reindex neu aufbauen, um -txindex zu verändern - - Imports blocks from external blk000??.dat file - Blöcke aus externer Datei blk000??.dat importieren - 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 JSON-RPC-Verbindungen von der angegeben Quelle erlauben. Gültig für <ip> ist eine einzelne IP-Adresse (z.B. 1.2.3.4), ein Netzwerk bzw. eine Netzmaske (z.B. 1.2.3.4/255.255.255.0), oder die CIDR-Notation (z.B. 1.2.3.4/24). Kann mehrmals angegeben werden. - - An error occurred while setting up the RPC address %s port %u for listening: %s - Beim Einrichten der abzuhörenden RPC-Adresse %s auf Port %u ist ein Fehler aufgetreten: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 An die angegebene Adresse binden und Gegenstellen, die sich dorthin verbinden, immer zulassen. Für IPv6 "[Host]:Port"-Notation verwenden @@ -3056,18 +3187,10 @@ Error: Listening for incoming connections failed (listen returned error %s) Fehler: Abhören nach eingehenden Verbindungen fehlgeschlagen (listen meldete Fehler %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Fehler: Nicht unterstütztes Argument -socks gefunden. Das Festlegen der SOCKS-Version ist nicht mehr möglich, nur noch SOCKS5-Proxies werden unterstützt. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Befehl ausführen wenn ein relevanter Alarm empfangen wird oder wir einen wirklich langen Fork entdecken (%s im Befehl wird durch die Nachricht ersetzt) - - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Niedrigere Gebühren (in BTC/Kb) als diese werden bei der Weiterleitung als gebührenfrei angesehen (Standard: %s) - If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) Wenn -paytxfee nicht festgelegt wurde Gebühren einschließen, so dass mit der Bestätigung von Transaktionen im Schnitt innerhalb von n Blöcken begonnen wird (Standard: %u) @@ -3080,10 +3203,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) Maximale Datengröße in "Data Carrier"-Transaktionen die weitergeleitet und erarbeitet werden (Standard: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - Kürzungsmodus wurde kleiner als das Minimum in Höhe von %d MiB konfiguriert. Bitte verwenden Sie einen größeren Wert. - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Adressen von Gegenstellen via DNS-Namensauflösung finden, falls zu wenige Adressen verfügbar sind (Standard: 1, außer bei -connect) @@ -3108,38 +3227,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im OpenSSL-Toolkit <https://www.openssl.org/> entwickelt wird, sowie von Eric Young geschriebene kryptographische Software und von Thomas Bernard geschriebene UPnP-Software. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - Um bitcoind oder die Option -server mit bitcoin-qt verwenden zu können, müssen Sie rpcpassword in der Konfigurationsdatei angeben: -%s -Es wird empfohlen das folgende Zufallspasswort zu verwenden. -rpcuser=bitcoinrpc -rpcpassword=%s -(Sie müssen sich dieses Passwort nicht merken!) -Der Benutzername und das Passwort dürfen NICHT identisch sein. -Falls die Konfigurationsdatei nicht existiert, erzeugen Sie diese bitte mit Leserechten nur für den Dateibesitzer. -Es wird ebenfalls empfohlen alertnotify anzugeben, um im Problemfall benachrichtigt zu werden. -Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Warnung: -maxtxfee ist auf einen sehr hohen Wert festgelegt! Gebühren dieser Höhe könnten für eine einzelne Transaktion bezahlt werden. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Warnung: Bitte korrigieren Sie die Datums- und Uhrzeiteinstellungen Ihres Computers, da Bitcoin Core ansonsten nicht ordnungsgemäß funktionieren wird. - 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 Erlaubte Gegenstellen werden nicht für DoS-Attacken gesperrt und ihre Transkationen werden immer weitergeleitet, auch wenn sie sich bereits im Speicherpool befinden, was z.B. für Gateways sinnvoll ist. @@ -3161,17 +3248,17 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Aktiviere beste Blockkette... - Can't run with a wallet in prune mode. - Eine Wallet kann im Kürzungsmodus nicht verwendet werden. + Attempt to recover private keys from a corrupt wallet.dat on startup + Versuchen, private Schlüssel beim Starten aus einer beschädigten wallet.dat wiederherzustellen + + + Automatically create Tor hidden service (default: %d) + Automatisch versteckten Tor-Dienst erstellen (Standard: %d) Cannot resolve -whitebind address: '%s' Kann Adresse in -whitebind nicht auflösen: '%s' - - Choose data directory on startup (default: 0) - Datenverzeichnis beim Starten auswählen (Standard: 0) - Connect through SOCKS5 proxy Über einen SOCKS5-Proxy &verbinden @@ -3180,10 +3267,6 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Copyright (C) 2009-%i The Bitcoin Core Developers Urheberrecht (C) 2009-%i Die "Bitcoin Core"-Entwickler - - Could not parse -rpcbind value %s as network address - Der Wert %s von -rpcbind wurde nicht als Netzwerkadresse erkannt - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Fehler beim Laden von wallet.dat: Wallet benötigt neuere Version von Bitcoin Core @@ -3193,12 +3276,8 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Fehler beim lesen der Datenbank, Ausführung wird beendet. - Error: Unsupported argument -tor found, use -onion. - Fehler: Nicht unterstütztes Argument -tor gefunden, bitte -onion verwenden. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Gebühr (in BTC/kB), die von Ihnen gesendeten Transaktionen hinzugefügt wird (Standard: %s) + Imports blocks from external blk000??.dat file on startup + Blöcke beim Starten aus externer Datei blk000??.dat importieren Information @@ -3240,18 +3319,10 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Node relay options: Knoten-Weiterleitungsoptionen: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - RPC-SSL-Optionen (siehe Bitcoin-Wiki für SSL-Einrichtung): - RPC server options: RPC-Serveroptionen: - - RPC support for HTTP persistent connections (default: %d) - Unterstützung für persistente HTTP-Verbindungen bei RPC (Standard: %d) - Rebuild block chain index from current blk000??.dat files on startup Blockkettenindex aus aktuellen Dateien blk000??.dat beim Starten wiederaufbauen @@ -3260,6 +3331,10 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Receive and display P2P network alerts (default: %u) P2P-Netzwerk-Alarme empfangen und anzeigen (Standard: %u) + + Rescan the block chain for missing wallet transactions on startup + Blockkette beim Starten erneut nach fehlenden Wallet-Transaktionen durchsuchen + Send trace/debug info to console instead of debug.log file Rückverfolgungs- und Debuginformationen an die Konsole senden, anstatt sie in debug.log zu schreiben @@ -3268,22 +3343,10 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Send transactions as zero-fee transactions if possible (default: %u) Transaktionen, wenn möglich, als gebührenfreie Transaktion senden (Standard: %u) - - Set SSL root certificates for payment request (default: -system-) - SSL-Wurzelzertifikate für Zahlungsanforderungen festlegen (Standard: -system-) - - - Set language, for example "de_DE" (default: system locale) - Sprache festlegen, z.B. "de_DE" (Standard: Systemstandard) - Show all debugging options (usage: --help -help-debug) Zeige alle Debuggingoptionen (Benutzung: --help -help-debug) - - Show splash screen on startup (default: 1) - Startbildschirm beim Starten anzeigen (Standard: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Protokolldatei debug.log beim Starten des Clients kürzen (Standard: 1, wenn kein -debug) @@ -3292,10 +3355,6 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Signing transaction failed Signierung der Transaktion fehlgeschlagen - - Start minimized - Minimiert starten - The transaction amount is too small to pay the fee Der Transaktionsbetrag ist zu niedrig, um die Gebühr zu bezahlen. @@ -3304,6 +3363,14 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com This is experimental software. Dies ist experimentelle Software. + + Tor control port password (default: empty) + TOR Kontrollport Passwort (Standard: leer) + + + Tor control port to use if onion listening enabled (default: %s) + Zu benutzender TOR Kontrollport wenn Onion Auflistung aktiv ist (Standard: %s) + Transaction amount too small Transaktionsbetrag zu niedrig @@ -3320,17 +3387,13 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Transaction too large Transaktion zu groß - - UI Options: - Benutzeroberflächenoptionen: - Unable to bind to %s on this computer (bind returned error %s) Kann auf diesem Computer nicht an %s binden (bind meldete Fehler %s) - Use UPnP to map the listening port (default: 1 when listening) - UPnP verwenden, um eine Portweiterleitung einzurichten (Standard: 1, wenn abgehört wird) + Upgrade wallet to latest format on startup + Wallet beim Starten auf das neueste Format aktualisieren Username for JSON-RPC connections @@ -3345,20 +3408,16 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Warnung - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Warnung: Nicht unterstütztes Argument -benchmark wurde ignoriert, bitte -debug=bench verwenden. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Warnung: Nicht unterstütztes Argument -debugnet wurde ignoriert, bitte -debug=net verwenden. + Whether to operate in a blocks only mode (default: %u) + Legt fest ob nur Blöcke Modus aktiv sein soll (Standard: %u) Zapping all transactions from wallet... Lösche alle Transaktionen aus Wallet... - on startup - beim Starten + ZeroMQ notification options: + ZeroMQ-Benachrichtigungsoptionen: wallet.dat corrupt, salvage failed @@ -3372,18 +3431,6 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Execute command when the best block changes (%s in cmd is replaced by block hash) Befehl ausführen wenn der beste Block wechselt (%s im Befehl wird durch den Hash des Blocks ersetzt) - - Upgrade wallet to latest format - Wallet auf das neueste Format aktualisieren - - - Rescan the block chain for missing wallet transactions - Blockkette erneut nach fehlenden Wallet-Transaktionen durchsuchen - - - Use OpenSSL (https) for JSON-RPC connections - OpenSSL (https) für JSON-RPC-Verbindungen verwenden - This help message Dieser Hilfetext @@ -3404,6 +3451,22 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = TX-Metadaten wie z.B. Accountbesitzer und Zahlungsanforderungsinformationen behalten, 2 = TX-Metadaten verwerfen) + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + -maxtxfee ist auf einen sehr hohen Wert festgelegt! Gebühren dieser Höhe könnten für eine einzelne Transaktion bezahlt werden. + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + -paytxfee ist auf einen sehr hohen Wert festgelegt! Dies ist die Gebühr die beim Senden einer Transaktion fällig wird. + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + Die Transaktion nicht länger im Speicherpool behalten als <n> Stunden (Standard: %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Lesen von wallet.dat fehlgeschlagen! Alle Schlüssel wurden korrekt gelesen, Transaktionsdaten bzw. Adressbucheinträge fehlen aber möglicherweise oder sind inkorrekt. + How thorough the block verification of -checkblocks is (0-4, default: %u) Legt fest, wie gründlich die Blockverifikation von -checkblocks ist (0-4, Standard: %u) @@ -3420,6 +3483,14 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Output debugging information (default: %u, supplying <category> is optional) Debugginginformationen ausgeben (Standard: %u, <category> anzugeben ist optional) + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + Versucht ausgehenden Datenverkehr unter dem gegebenen Wert zu halten (in MiB pro 24h), 0 = kein Limit (default: %d) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Nicht unterstütztes Argument -socks gefunden. Das Festlegen der SOCKS-Version ist nicht mehr möglich, nur noch SOCKS5-Proxies werden unterstützt. + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) Separaten SOCKS5-Proxy verwenden, um Gegenstellen über versteckte Tor-Dienste zu erreichen (Standard: %s) @@ -3428,10 +3499,6 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com (default: %s) (Standard: %s) - - Acceptable ciphers (default: %s) - Zulässige Chiffren (Standard: %s) - Always query for peer addresses via DNS lookup (default: %u) Adressen von Gegenstellen immer über DNS-Namensauflösung abfragen (Standard: %u) @@ -3460,6 +3527,10 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Listen for JSON-RPC connections on <port> (default: %u or testnet: %u) <port> nach JSON-RPC-Verbindungen abhören (Standard: %u oder Testnetz: %u) + + Listen for connections on <port> (default: %u or testnet: %u) + <port> nach Verbindungen abhören (Standard: %u oder Testnetz: %u) + Maintain at most <n> connections to peers (default: %u) Maximal <n> Verbindungen zu Gegenstellen aufrechterhalten (Standard: %u) @@ -3488,14 +3559,6 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Relay non-P2SH multisig (default: %u) Nicht-"P2SH-Multisig" weiterleiten (Standard: %u) - - Server certificate file (default: %s) - Serverzertifikat (Standard: %s) - - - Server private key (default: %s) - Privater Serverschlüssel (Standard: %s) - Set key pool size to <n> (default: %u) Größe des Schlüsselpools festlegen auf <n> (Standard: %u) diff --git a/src/qt/locale/bitcoin_el.ts b/src/qt/locale/bitcoin_el.ts new file mode 100644 index 000000000..6777961cb --- /dev/null +++ b/src/qt/locale/bitcoin_el.ts @@ -0,0 +1,321 @@ + + + AddressBookPage + + Create a new address + Δημιουργία νέου λογαριασμού + + + + AddressTableModel + + Label + Ετικέτα + + + Address + Διεύθυνση + + + + AskPassphraseDialog + + Enter passphrase + Εισάγετε συνθηματικό + + + New passphrase + Νέο συνθηματικό + + + Repeat new passphrase + Επαναλάβετε νέο συνθηματικό + + + Change passphrase + Αλλαγή συνθηματικού + + + + BanTableModel + + + BitcoinGUI + + Quit application + Κλείσιμο εφαρμογής + + + Wallet + Πορτοφόλι + + + Error + Σφάλμα + + + + ClientModel + + + CoinControlDialog + + Date + Ημερομηνία + + + Copy address + Αντιγραφή διεύθυνσης + + + Copy amount + Αντιγραφή ποσού + + + Copy quantity + Αντιγραφή ποσότητας + + + Copy change + Αντιγραφή αλλαγής + + + + EditAddressDialog + + &Label + Ετικέτα + + + &Address + Διεύθυνση + + + + FreespaceChecker + + + HelpMessageDialog + + version + έκδοση + + + + Intro + + Welcome + Καλώς Ήλθατε + + + Error + Σφάλμα + + + + OpenURIDialog + + + OptionsDialog + + W&allet + Πορτοφόλι + + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QRImageWidget + + + RPCConsole + + Services + Υπηρεσίες + + + + ReceiveCoinsDialog + + Remove + Αφαίρεση + + + Copy message + Αντιγραφή μηνύματος + + + Copy amount + Αντιγραφή ποσού + + + + ReceiveRequestDialog + + Address + Διεύθυνση + + + Label + Ετικέτα + + + Message + Μήνυμα + + + + RecentRequestsTableModel + + Date + Ημερομηνία + + + Label + Ετικέτα + + + Message + Μήνυμα + + + (no message) + (κανένα μήνυμα) + + + + SendCoinsDialog + + Insufficient funds! + Κεφάλαια μη επαρκή + + + Recommended: + Συνίσταται: + + + Copy quantity + Αντιγραφή ποσότητας + + + Copy amount + Αντιγραφή ποσού + + + Copy change + Αντιγραφή αλλαγής + + + + SendCoinsEntry + + Message: + Μήνυμα: + + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + Date + Ημερομηνία + + + Message + Μήνυμα + + + + TransactionDescDialog + + + TransactionTableModel + + Date + Ημερομηνία + + + Label + Ετικέτα + + + + TransactionView + + Copy address + Αντιγραφή διεύθυνσης + + + Copy amount + Αντιγραφή ποσού + + + Date + Ημερομηνία + + + Label + Ετικέτα + + + Address + Διεύθυνση + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + + bitcoin-core + + Insufficient funds + Κεφάλαια μη επαρκή + + + Loading wallet... + Φόρτωση πορτοφολιού... + + + Rescanning... + Επανάληψη σάρωσης + + + Done loading + Η φόρτωση ολοκληρώθηκε + + + Error + Σφάλμα + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts index 8a0958a7b..90c27c439 100644 --- a/src/qt/locale/bitcoin_el_GR.ts +++ b/src/qt/locale/bitcoin_el_GR.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -213,6 +213,9 @@ Ο κωδικος του πορτοφολιού άλλαξε με επιτυχία. + + BanTableModel + BitcoinGUI @@ -451,6 +454,36 @@ Catching up... Ενημέρωση... + + Date: %1 + + Ημερομηνία: %1 + + + + Amount: %1 + + Ποσό: %1 + + + + Type: %1 + + Τύπος: %1 + + + + Label: %1 + + Ετικέτα: %1 + + + + Address: %1 + + Διεύθυνση: %1 + + Sent transaction Η συναλλαγή απεστάλη @@ -649,6 +682,22 @@ none κανένα + + This label turns red if the transaction size is greater than 1000 bytes. + Αυτή η ετικέτα γίνεται κόκκινη αν το μέγεθος της συναλλαγής είναι μεγαλύτερο από 1000 bytes. + + + This label turns red if the priority is smaller than "medium". + Αυτή η ετικέτα γίνεται κόκκινη αν η προτεραιότητα είναι μικρότερη από "μεσαία". + + + This label turns red if any recipient receives an amount smaller than %1. + Αυτή η ετικέτα γίνεται κόκκινη αν οποιοσδήποτε παραλήπτης λάβει ποσό μικρότερο από %1. + + + Can vary +/- %1 satoshi(s) per input. + Μπορεί να διαφέρει +/- %1 Satoshi (ες) ανά εγγραφή. + yes ναι @@ -661,6 +710,10 @@ This means a fee of at least %1 per kB is required. Ελάχιστο χρεώσιμο ποσό τουλάχιστο %1 ανα kB + + Can vary +/- 1 byte per input. + Μπορεί να διαφέρει +/- 1 byte ανά εγγραφή. + Transactions with higher priority are more likely to get included into a block. Συναλλαγές με υψηλότερη προτεραιότητα είναι πιο πιθανό να περιλαμβάνονται σε ένα μπλοκ. @@ -787,7 +840,7 @@ command-line options επιλογής γραμμής εντολών - + Intro @@ -826,7 +879,15 @@ Error Σφάλμα - + + %n GB of free space available + %n GB ελεύθερου χώρου διαθέσιμα%n GB ελεύθερου χώρου διαθέσιμα + + + (of %n GB needed) + (από το %n GB που απαιτείται)(από τα %n GB που απαιτούνται) + + OpenURIDialog @@ -884,6 +945,10 @@ IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) Διεύθυνση IP του διαμεσολαβητή (π.χ. 127.0.0.1 / IPv6: ::1) + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu. + Ελαχιστοποίηση αντί για έξοδο κατά το κλείσιμο του παραθύρου. Όταν αυτή η επιλογή είναι ενεργοποιημένη, η εφαρμογή θα κλείνει μόνο αν επιλεχθεί η Έξοδος στο μενού. + Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. URLs από τρίτους (π.χ. ένας εξερευνητής μπλοκ) τα οποία εμφανίζονται στην καρτέλα συναλλαγών ως στοιχεία μενού. Το %s στα URL αντικαθιστάται από την τιμή της κατατεμαχισμένης συναλλαγής. @@ -1315,14 +1380,6 @@ Services Υπηρεσίες - - Starting Height - Αρχικό ύψος - - - Sync Height - Ύψος συγχονισμού - Ban Score Σκορ αποκλησμού @@ -1339,14 +1396,6 @@ Last Receive Τελευταία λήψη - - Bytes Sent - Σταλθέντα bytes - - - Bytes Received - Ληφθέντα bytes - Ping Time Χρόνος καθυστέρησης @@ -1439,10 +1488,6 @@ Unknown Άγνωστο(α) - - Fetching... - Ανάκτηση... - ReceiveCoinsDialog @@ -1655,6 +1700,14 @@ per kilobyte ανά kilobyte + + Hide + Απόκρυψη + + + total at least + συνολικά τουλάχιστον + Recommended: Προτεινόμενο: @@ -1747,10 +1800,6 @@ Copy change Αντιγραφή των ρέστων - - Total Amount %1 (= %2) - Ολικό Ποσό %1 (= %2) - or ή @@ -2481,10 +2530,6 @@ Run in the background as a daemon and accept commands Εκτέλεση στο παρασκήνιο κι αποδοχή εντολών - - Use the test network - Χρήση του δοκιμαστικού δικτύου - Accept connections from outside (default: 1 if no -proxy or -connect) Να δέχεσαι συνδέσεις από έξω(προεπιλογή:1) @@ -2501,26 +2546,10 @@ This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Αυτό είναι ένα προ-τεστ κυκλοφορίας - χρησιμοποιήστε το με δική σας ευθύνη - δεν χρησιμοποιείτε για εξόρυξη ή για αλλες εφαρμογές - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Προειδοποίηση: Η παράμετρος -paytxfee είναι πολύ υψηλή. Πρόκειται για την αμοιβή που θα πληρώνετε για κάθε συναλλαγή που θα στέλνετε. - - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Προειδοποίηση : Σφάλμα wallet.dat κατα την ανάγνωση ! Όλα τα κλειδιά αναγνωρισθηκαν σωστά, αλλά τα δεδομένα των συναλλαγών ή καταχωρήσεις στο βιβλίο διευθύνσεων μπορεί να είναι ελλιπείς ή λανθασμένα. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Προειδοποίηση : το αρχειο wallet.dat ειναι διεφθαρμένο, τα δεδομένα σώζονται ! Original wallet.dat αποθηκεύονται ως wallet.{timestamp}.bak στο %s . Αν το υπόλοιπο του ή τις συναλλαγές σας, είναι λάθος θα πρέπει να επαναφέρετε από ένα αντίγραφο ασφαλείας - - (default: 1) - (προεπιλογή: 1) - - - Attempt to recover private keys from a corrupt wallet.dat - Προσπάθεια για ανακτησει ιδιωτικων κλειδιων από ενα διεφθαρμένο αρχειο wallet.dat - Block creation options: Αποκλεισμός επιλογων δημιουργίας: @@ -2557,10 +2586,6 @@ Error opening block database Σφάλμα φορτωσης της βασης δεδομενων των μπλοκ - - Error: A fatal internal error occured, see debug.log for details - Σφάλμα: Παρουσιάστηκε ανεπανόρθωτο εσωτερικό σφάλμα, δείτε debug.log για λεπτομέρειες - Error: Disk space is low! Προειδοποίηση: Χαμηλός χώρος στο δίσκο @@ -2585,6 +2610,10 @@ Only connect to nodes in network <net> (ipv4, ipv6 or onion) Μόνο σύνδεση σε κόμβους του δικτύου <net> (ipv4, ipv6 ή onion) + + Set maximum block size in bytes (default: %d) + Ορίστε το μέγιστο μέγεθος block σε bytes (προεπιλογή: %d) + Specify wallet file (within data directory) Επιλέξτε αρχείο πορτοφολιού (μέσα απο κατάλογο δεδομένων) @@ -2605,29 +2634,17 @@ Wallet options: Επιλογές πορτοφολιού: - - Imports blocks from external blk000??.dat file - Εισαγωγή μπλοκ από εξωτερικό αρχείο blk000?.dat - Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running. Αδυναμία κλειδώματος του φακέλου δεδομένων %s. Πιθανώς το Bitcoin να είναι ήδη ενεργό. - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Προειδοποίηση: Παρακαλώ ελέγξτε ότι η ημερομηνία και ώρα του υπολογιστή σας είναι σωστά ρυθμισμένες! Εάν το ρολόι σας είναι λάθος το Bitcoin Core δεν θα λειτουργήσει σωστά. - - - Choose data directory on startup (default: 0) - Επιλογή φακέλου δεδομένων στην εκκίνηση (προεπιλεγμένο: 0) - Connect through SOCKS5 proxy Σύνδεση μέσω διαμεσολαβητή SOCKS5 - Could not parse -rpcbind value %s as network address - Δεν μπόρεσε να αναλυθεί η παράμετρος -rpcbind value %s ως διεύθυνση δικτύου + Copyright (C) 2009-%i The Bitcoin Core Developers + Πνευματικά δικαιώματα 2009-%i Οι προγραμματιστές του Bitcoin Core Error loading wallet.dat: Wallet requires newer version of Bitcoin Core @@ -2637,10 +2654,6 @@ Error reading from database, shutting down. Σφάλμα ανάγνωσης από τη βάση δεδομένων, γίνεται τερματισμός. - - Error: Unsupported argument -tor found, use -onion. - Σφάλμα: Μη συμβατή παράμετρος -tor. Χρησιμοποιήσε την παράμετρο -onion - Information Πληροφορία @@ -2649,6 +2662,10 @@ Initialization sanity check failed. Bitcoin Core is shutting down. Η εκκίνηση ελέγχου ορθότητας απέτυχε. Γίνεται τερματισμός του Bitcoin Core. + + Invalid amount for -maxtxfee=<amount>: '%s' + Μη έγκυρο ποσό για την παράμετρο -maxtxfee=<amount>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' Μη έγκυρο ποσό για την παράμετρο -paytxfee=<amount>: '%s' @@ -2661,10 +2678,6 @@ Node relay options: Επιλογές αναμετάδοσης κόμβου: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Ρυθμίσεις SSL: (ανατρέξτε στο Bitcoin Wiki για οδηγίες ρυθμίσεων SSL) - RPC server options: Επιλογές διακομιστή RPC: @@ -2673,22 +2686,10 @@ Send trace/debug info to console instead of debug.log file Αποστολή πληροφοριών εντοπισμού σφαλμάτων στην κονσόλα αντί του αρχείου debug.log - - Set SSL root certificates for payment request (default: -system-) - Ορίστε SSL root certificates για αίτηση πληρωμής (default: -system-) - - - Set language, for example "de_DE" (default: system locale) - Όρισε γλώσσα, για παράδειγμα "de_DE"(προεπιλογή:τοπικές ρυθμίσεις) - Show all debugging options (usage: --help -help-debug) Προβολή όλων των επιλογών εντοπισμού σφαλμάτων (χρήση: --help -help-debug) - - Show splash screen on startup (default: 1) - Εμφάνισε την οθόνη εκκίνησης κατά την εκκίνηση(προεπιλογή:1) - Shrink debug.log file on client startup (default: 1 when no -debug) Συρρίκνωση του αρχείο debug.log κατα την εκκίνηση του πελάτη (προεπιλογή: 1 όταν δεν-debug) @@ -2697,10 +2698,6 @@ Signing transaction failed Η υπογραφή συναλλαγής απέτυχε - - Start minimized - Έναρξη ελαχιστοποιημένο - This is experimental software. Η εφαρμογή είναι σε πειραματικό στάδιο. @@ -2717,10 +2714,6 @@ Transaction too large Η συναλλαγή ειναι πολύ μεγάλη - - Use UPnP to map the listening port (default: 1 when listening) - Χρησιμοποίηση του UPnP για την χρήση της πόρτας αναμονής (προεπιλογή:1) - Username for JSON-RPC connections Όνομα χρήστη για τις συνδέσεις JSON-RPC @@ -2733,10 +2726,6 @@ Zapping all transactions from wallet... Μεταφορά όλων των συναλλαγών απο το πορτοφόλι - - on startup - κατά την εκκίνηση - wallet.dat corrupt, salvage failed Το αρχειο wallet.dat ειναι διεφθαρμένο, η διάσωση απέτυχε @@ -2749,18 +2738,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Εκτέλεσε την εντολή όταν το καλύτερο μπλοκ αλλάξει(%s στην εντολή αντικαθίσταται από το hash του μπλοκ) - - Upgrade wallet to latest format - Αναβάθμισε το πορτοφόλι στην τελευταία έκδοση - - - Rescan the block chain for missing wallet transactions - Επανέλεγχος της αλυσίδας μπλοκ για απούσες συναλλαγές - - - Use OpenSSL (https) for JSON-RPC connections - Χρήση του OpenSSL (https) για συνδέσεις JSON-RPC - This help message Αυτό το κείμενο βοήθειας @@ -2810,8 +2787,12 @@ Δεν είναι έγκυρη η διεύθυνση διαμεσολαβητή: '%s' - Server certificate file (default: %s) - Αρχείο πιστοποιητικού του διακομιστή (προεπιλογή: %s) + Maintain at most <n> connections to peers (default: %u) + Μέγιστες αριθμός συνδέσεων με τους peers <n> (προεπιλογή: %u) + + + Specify configuration file (default: %s) + Ορίστε αρχείο ρυθμίσεων (προεπιλογή: %s) Specify connection timeout in milliseconds (minimum: 1, default: %d) diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 3ebb4d0bf..00411741f 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -299,17 +299,17 @@ BitcoinGUI - + Sign &message... Sign &message... - + Synchronizing with network... Synchronizing with network... - + &Overview &Overview @@ -389,12 +389,12 @@ - + Bitcoin Core client - + Importing blocks from disk... Importing blocks from disk... @@ -404,7 +404,7 @@ Reindexing blocks on disk... - + Send coins to a Bitcoin address Send coins to a Bitcoin address @@ -434,12 +434,12 @@ &Verify message... - + Bitcoin Bitcoin - + Wallet Wallet @@ -484,7 +484,7 @@ Verify messages to ensure they were signed with specified Bitcoin addresses - + &File &File @@ -504,7 +504,7 @@ Tabs toolbar - + Bitcoin Core Bitcoin Core @@ -549,7 +549,7 @@ - + %n active connection(s) to Bitcoin network %n active connection to Bitcoin network @@ -701,7 +701,7 @@ ClientModel - + Network Alert Network Alert @@ -925,7 +925,7 @@ - + This label turns red if the transaction size is greater than 1000 bytes. @@ -940,12 +940,12 @@ - + Can vary +/- %1 satoshi(s) per input. - + yes @@ -971,7 +971,7 @@ - + (no label) (no label) @@ -1086,7 +1086,7 @@ HelpMessageDialog - + Bitcoin Core Bitcoin Core @@ -1121,6 +1121,41 @@ command-line options command-line options + + + UI Options: + + + + + Choose data directory on startup (default: %u) + + + + + Set language, for example "de_DE" (default: system locale) + + + + + Start minimized + + + + + Set SSL root certificates for payment request (default: -system-) + + + + + Show splash screen on startup (default: %u) + + + + + Reset all settings changed in the GUI + + Intro @@ -1469,17 +1504,17 @@ &Cancel - + default default - + none - + Confirm options reset Confirm options reset @@ -1500,7 +1535,7 @@ - + The supplied proxy address is invalid. The supplied proxy address is invalid. @@ -1756,7 +1791,7 @@ - + %1 d @@ -1830,11 +1865,13 @@ - + - + + + @@ -1855,7 +1892,7 @@ N/A - + Client version Client version @@ -1890,12 +1927,12 @@ Startup time - + Network Network - + Name @@ -1915,22 +1952,39 @@ Current number of blocks - + + Memory Pool + + + + + Current number of transactions + + + + + Memory usage + + + + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. - + + Received - + + Sent - + &Peers @@ -1941,8 +1995,8 @@ - - + + Select a peer to view detailed information. @@ -1977,8 +2031,8 @@ - - + + User Agent @@ -2008,17 +2062,7 @@ - - Bytes Sent - - - - - Bytes Received - - - - + Ping Time @@ -2038,17 +2082,17 @@ - + Last block time Last block time - + &Open &Open - + &Console &Console @@ -2068,7 +2112,7 @@ - + In: @@ -2078,22 +2122,22 @@ - + Build date Build date - + Debug log file Debug log file - + Clear console Clear console - + &Disconnect Node @@ -2131,7 +2175,7 @@ - + Welcome to the Bitcoin Core RPC console. @@ -2146,7 +2190,7 @@ Type <b>help</b> for an overview of available commands. - + %1 B @@ -2424,7 +2468,7 @@ SendCoinsDialog - + Send Coins Send Coins @@ -2626,7 +2670,7 @@ Confirm send coins - + @@ -2669,7 +2713,12 @@ - + + Total Amount %1 + + + + or @@ -2708,8 +2757,13 @@ Payment request expired. + + + Pay only the required fee of %1 + + - + Estimated to begin confirmation within %n block(s). Estimated to begin confirmation within %n block. @@ -2717,17 +2771,7 @@ - - Pay only the minimum fee of %1 - - - - - Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span> - - - - + The recipient address is not valid. Please recheck. @@ -2737,7 +2781,7 @@ - + Warning: Invalid Bitcoin address @@ -2752,7 +2796,7 @@ - + Copy dust @@ -2879,7 +2923,7 @@ ShutdownWindow - + Bitcoin Core is shutting down... @@ -3324,7 +3368,7 @@ TransactionTableModel - + Date Date @@ -3427,7 +3471,7 @@ (n/a) - + Transaction status. Hover over this field to show number of confirmations. Transaction status. Hover over this field to show number of confirmations. @@ -3550,6 +3594,11 @@ Copy transaction ID Copy transaction ID + + + Copy raw transaction + + Edit label @@ -3561,7 +3610,7 @@ Show transaction details - + Export Transaction History @@ -3626,7 +3675,7 @@ ID - + Range: Range: @@ -3706,37 +3755,32 @@ bitcoin-core - + Options: Options: - + Specify data directory Specify data directory - + Connect to a node to retrieve peer addresses, and disconnect Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address Specify your own public address - + Accept command line and JSON-RPC commands Accept command line and JSON-RPC commands - - Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s) - - - - + If <category> is not supplied or if <category> = 1, output all debugging information. @@ -3771,17 +3815,17 @@ - + Error: A fatal internal error occurred, see debug.log for details - + Fee (in %s/kB) to add to transactions you send (default: %s) - + Pruning blockstore... @@ -3791,22 +3835,17 @@ Run in the background as a daemon and accept commands - + Unable to start HTTP server. See debug log for details. - - Use the test network - Use the test network - - - + Accept connections from outside (default: 1 if no -proxy or -connect) Accept connections from outside (default: 1 if no -proxy or -connect) - + Bind to given address and always listen on it. Use [host]:port notation for IPv6 Bind to given address and always listen on it. Use [host]:port notation for IPv6 @@ -3821,17 +3860,17 @@ - + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) - + Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) - + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct @@ -3841,17 +3880,17 @@ This is a pre-release test build - use at your own risk - do not use for mining or merchant applications - + Unable to bind to %s on this computer. Bitcoin Core is probably already running. - + Use UPnP to map the listening port (default: 1 when listening and no -proxy) - + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) @@ -3860,11 +3899,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) - - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. @@ -3875,11 +3909,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. - - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. @@ -3892,7 +3921,7 @@ - (default: 1) + -maxmempool must be at least %d MB @@ -3901,17 +3930,12 @@ - - Attempt to recover private keys from a corrupt wallet.dat - Attempt to recover private keys from a corrupt wallet.dat - - - + Block creation options: Block creation options: - + Connect only to the specified node(s) Connect only to the specified node(s) @@ -3986,7 +4010,7 @@ Error: Disk space is low! - + Failed to listen on any port. Use -listen=0 if you want this. Failed to listen on any port. Use -listen=0 if you want this. @@ -4006,7 +4030,12 @@ - + + Keep the transaction memory pool below <n> megabytes (default: %u) + + + + Not enough file descriptors available. Not enough file descriptors available. @@ -4026,27 +4055,47 @@ - + Set database cache size in megabytes (%d to %d, default: %d) - + Set maximum block size in bytes (default: %d) - + Specify wallet file (within data directory) Specify wallet file (within data directory) - + + Unsupported argument -benchmark ignored, use -debug=bench. + + + + + Unsupported argument -debugnet ignored, use -debug=net. + + + + + Unsupported argument -tor found, use -onion. + + + + Use UPnP to map the listening port (default: %u) - + + User Agent comment (%s) contains unsafe characters. + + + + Verifying blocks... Verifying blocks... @@ -4071,17 +4120,12 @@ - + You need to rebuild the database using -reindex to change -txindex You need to rebuild the database using -reindex to change -txindex - - Imports blocks from external blk000??.dat file - Imports blocks from external blk000??.dat file - - - + 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 @@ -4111,22 +4155,22 @@ - + Error: Listening for incoming connections failed (listen returned error %s) - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - - - - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) - + + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + + + + If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -4161,7 +4205,7 @@ - + The transaction amount is too small to send after the fee has been deducted @@ -4171,12 +4215,7 @@ - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - - - - + 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 @@ -4201,17 +4240,27 @@ - + + Always relay transactions received from whitelisted peers (default: %d) + + + + + Attempt to recover private keys from a corrupt wallet.dat on startup + + + + + Automatically create Tor hidden service (default: %d) + + + + Cannot resolve -whitebind address: '%s' - - Choose data directory on startup (default: 0) - Choose data directory on startup (default: 0) - - - + Connect through SOCKS5 proxy @@ -4231,12 +4280,12 @@ - - Error: Unsupported argument -tor found, use -onion. + + Imports blocks from external blk000??.dat file on startup - + Information Information @@ -4276,7 +4325,7 @@ - + Need to specify a port with -whitebind: '%s' @@ -4306,7 +4355,12 @@ - + + Rescan the block chain for missing wallet transactions on startup + + + + Send trace/debug info to console instead of debug.log file Send trace/debug info to console instead of debug.log file @@ -4316,25 +4370,10 @@ - - Set SSL root certificates for payment request (default: -system-) - - - - - Set language, for example "de_DE" (default: system locale) - Set language, for example "de_DE" (default: system locale) - - - + Show all debugging options (usage: --help -help-debug) - - - Show splash screen on startup (default: 1) - Show splash screen on startup (default: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) @@ -4347,11 +4386,6 @@ - Start minimized - Start minimized - - - The transaction amount is too small to pay the fee @@ -4362,6 +4396,16 @@ + Tor control port password (default: empty) + + + + + Tor control port to use if onion listening enabled (default: %s) + + + + Transaction amount too small Transaction amount too small @@ -4380,11 +4424,6 @@ Transaction too large Transaction too large - - - UI Options: - - Unable to bind to %s on this computer (bind returned error %s) @@ -4392,6 +4431,11 @@ + Upgrade wallet to latest format on startup + + + + Username for JSON-RPC connections Username for JSON-RPC connections @@ -4407,12 +4451,7 @@ - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - - - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. + Whether to operate in a blocks only mode (default: %u) @@ -4425,48 +4464,33 @@ ZeroMQ notification options: - - - on startup - - wallet.dat corrupt, salvage failed wallet.dat corrupt, salvage failed - + Password for JSON-RPC connections Password for JSON-RPC connections - + Execute command when the best block changes (%s in cmd is replaced by block hash) Execute command when the best block changes (%s in cmd is replaced by block hash) - - Upgrade wallet to latest format - Upgrade wallet to latest format - - - - Rescan the block chain for missing wallet transactions - Rescan the block chain for missing wallet transactions - - - + This help message This help message - + Allow DNS lookups for -addnode, -seednode and -connect Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... Loading addresses... @@ -4476,12 +4500,37 @@ Error loading wallet.dat: Wallet corrupted - + (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) - + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + + + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + + + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + + + + How thorough the block verification of -checkblocks is (0-4, default: %u) @@ -4501,12 +4550,37 @@ - + + Support filtering of blocks and transaction with bloom filters (default: %u) + + + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + + + + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + + + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) - + + 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. This option can be specified multiple times + + + + (default: %s) @@ -4516,12 +4590,12 @@ - + Error loading wallet.dat Error loading wallet.dat - + Generate coins (default: %u) @@ -4541,7 +4615,7 @@ Invalid -proxy address: '%s' - + Listen for JSON-RPC connections on <port> (default: %u or testnet: %u) @@ -4586,12 +4660,12 @@ - + Set key pool size to <n> (default: %u) - + Set minimum block size in bytes (default: %u) @@ -4601,7 +4675,7 @@ - + Specify configuration file (default: %s) @@ -4621,17 +4695,17 @@ - + Threshold for disconnecting misbehaving peers (default: %u) - + Unknown network specified in -onlynet: '%s' Unknown network specified in -onlynet: '%s' - + Cannot resolve -bind address: '%s' Cannot resolve -bind address: '%s' @@ -4641,7 +4715,7 @@ Cannot resolve -externalip address: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Invalid amount for -paytxfee=<amount>: '%s' @@ -4651,22 +4725,22 @@ Insufficient funds - + Loading block index... Loading block index... - + Add a node to connect to and attempt to keep the connection open Add a node to connect to and attempt to keep the connection open - + Loading wallet... Loading wallet... - + Cannot downgrade wallet Cannot downgrade wallet @@ -4676,7 +4750,7 @@ Cannot write default address - + Rescanning... Rescanning... diff --git a/src/qt/locale/bitcoin_en_GB.ts b/src/qt/locale/bitcoin_en_GB.ts new file mode 100644 index 000000000..bf912d295 --- /dev/null +++ b/src/qt/locale/bitcoin_en_GB.ts @@ -0,0 +1,3719 @@ + + + AddressBookPage + + Right-click to edit address or label + Right-click to edit address or label + + + Create a new address + Create a new address + + + &New + &New + + + Copy the currently selected address to the system clipboard + Copy the currently selected address to the system clipboard + + + &Copy + &Copy + + + C&lose + C&lose + + + &Copy Address + &Copy Address + + + Delete the currently selected address from the list + Delete the currently selected address from the list + + + Export the data in the current tab to a file + Export the data in the current tab to a file + + + &Export + &Export + + + &Delete + &Delete + + + Choose the address to send coins to + Choose the address to send coins to + + + Choose the address to receive coins with + Choose the address to receive coins with + + + C&hoose + C&hoose + + + Sending addresses + Sending addresses + + + Receiving addresses + Receiving addresses + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + + + Copy &Label + Copy &Label + + + &Edit + &Edit + + + Export Address List + Export Address List + + + Comma separated file (*.csv) + Comma separated file (*.csv) + + + Exporting Failed + Exporting Failed + + + There was an error trying to save the address list to %1. Please try again. + There was an error trying to save the address list to %1. Please try again. + + + + AddressTableModel + + Label + Label + + + Address + Address + + + (no label) + (no label) + + + + AskPassphraseDialog + + Passphrase Dialog + Passphrase Dialog + + + Enter passphrase + Enter passphrase + + + New passphrase + New passphrase + + + Repeat new passphrase + Repeat new passphrase + + + Encrypt wallet + Encrypt wallet + + + This operation needs your wallet passphrase to unlock the wallet. + This operation needs your wallet passphrase to unlock the wallet. + + + Unlock wallet + Unlock wallet + + + This operation needs your wallet passphrase to decrypt the wallet. + This operation needs your wallet passphrase to decrypt the wallet. + + + Decrypt wallet + Decrypt wallet + + + Change passphrase + Change passphrase + + + Confirm wallet encryption + Confirm wallet encryption + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + + + Are you sure you wish to encrypt your wallet? + Are you sure you wish to encrypt your wallet? + + + Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + + + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + + + Warning: The Caps Lock key is on! + Warning: The Caps Lock key is on! + + + Wallet encrypted + Wallet encrypted + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + + + Enter the old passphrase and new passphrase to the wallet. + Enter the old passphrase and new passphrase to the wallet. + + + Wallet encryption failed + Wallet encryption failed + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + + + The supplied passphrases do not match. + The supplied passphrases do not match. + + + Wallet unlock failed + Wallet unlock failed + + + The passphrase entered for the wallet decryption was incorrect. + The passphrase entered for the wallet decryption was incorrect. + + + Wallet decryption failed + Wallet decryption failed + + + Wallet passphrase was successfully changed. + Wallet passphrase was successfully changed. + + + + BanTableModel + + IP/Netmask + IP/Netmask + + + Banned Until + Banned Until + + + + BitcoinGUI + + Sign &message... + Sign &message... + + + Synchronizing with network... + Synchronising with network... + + + &Overview + &Overview + + + Node + Node + + + Show general overview of wallet + Show general overview of wallet + + + &Transactions + &Transactions + + + Browse transaction history + Browse transaction history + + + E&xit + E&xit + + + Quit application + Quit application + + + About &Qt + About &Qt + + + Show information about Qt + Show information about Qt + + + &Options... + &Options... + + + &Encrypt Wallet... + &Encrypt Wallet... + + + &Backup Wallet... + &Backup Wallet... + + + &Change Passphrase... + &Change Passphrase... + + + &Sending addresses... + &Sending addresses... + + + &Receiving addresses... + &Receiving addresses... + + + Open &URI... + Open &URI... + + + Bitcoin Core client + Bitcoin Core client + + + Importing blocks from disk... + Importing blocks from disk... + + + Reindexing blocks on disk... + Reindexing blocks on disk... + + + Send coins to a Bitcoin address + Send coins to a Bitcoin address + + + Backup wallet to another location + Backup wallet to another location + + + Change the passphrase used for wallet encryption + Change the passphrase used for wallet encryption + + + &Debug window + &Debug window + + + Open debugging and diagnostic console + Open debugging and diagnostic console + + + &Verify message... + &Verify message... + + + Bitcoin + Bitcoin + + + Wallet + Wallet + + + &Send + &Send + + + &Receive + &Receive + + + Show information about Bitcoin Core + Show information about Bitcoin Core + + + &Show / Hide + &Show / Hide + + + Show or hide the main Window + Show or hide the main Window + + + Encrypt the private keys that belong to your wallet + Encrypt the private keys that belong to your wallet + + + Sign messages with your Bitcoin addresses to prove you own them + Sign messages with your Bitcoin addresses to prove you own them + + + Verify messages to ensure they were signed with specified Bitcoin addresses + Verify messages to ensure they were signed with specified Bitcoin addresses + + + &File + &File + + + &Settings + &Settings + + + &Help + &Help + + + Tabs toolbar + Tabs toolbar + + + Bitcoin Core + Bitcoin Core + + + Request payments (generates QR codes and bitcoin: URIs) + Request payments (generates QR codes and bitcoin: URIs) + + + &About Bitcoin Core + &About Bitcoin Core + + + Modify configuration options for Bitcoin Core + Modify configuration options for Bitcoin Core + + + Show the list of used sending addresses and labels + Show the list of used sending addresses and labels + + + Show the list of used receiving addresses and labels + Show the list of used receiving addresses and labels + + + Open a bitcoin: URI or payment request + Open a bitcoin: URI or payment request + + + &Command-line options + &Command-line options + + + Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options + Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options + + + %n active connection(s) to Bitcoin network + %n active connection to Bitcoin network%n active connections to Bitcoin network + + + No block source available... + No block source available... + + + Processed %n block(s) of transaction history. + Processed %n block of transaction history.Processed %n blocks of transaction history. + + + %n hour(s) + %n hour%n hours + + + %n day(s) + %n day%n days + + + %n week(s) + %n week%n weeks + + + %1 and %2 + %1 and %2 + + + %n year(s) + %n year%n years + + + %1 behind + %1 behind + + + Last received block was generated %1 ago. + Last received block was generated %1 ago. + + + Transactions after this will not yet be visible. + Transactions after this will not yet be visible. + + + Error + Error + + + Warning + Warning + + + Information + Information + + + Up to date + Up to date + + + Catching up... + Catching up... + + + Date: %1 + + Date: %1 + + + + Amount: %1 + + Amount: %1 + + + + Type: %1 + + Type: %1 + + + + Label: %1 + + Label: %1 + + + + Address: %1 + + Address: %1 + + + + Sent transaction + Sent transaction + + + Incoming transaction + Incoming transaction + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + Wallet is <b>encrypted</b> and currently <b>locked</b> + + + + ClientModel + + Network Alert + Network Alert + + + + CoinControlDialog + + Coin Selection + Coin Selection + + + Quantity: + Quantity: + + + Bytes: + Bytes: + + + Amount: + Amount: + + + Priority: + Priority: + + + Fee: + Fee: + + + Dust: + Dust: + + + After Fee: + After Fee: + + + Change: + Change: + + + (un)select all + (un)select all + + + Tree mode + Tree mode + + + List mode + List mode + + + Amount + Amount + + + Received with label + Received with label + + + Received with address + Received with address + + + Date + Date + + + Confirmations + Confirmations + + + Confirmed + Confirmed + + + Priority + Priority + + + Copy address + Copy address + + + Copy label + Copy label + + + Copy amount + Copy amount + + + Copy transaction ID + Copy transaction ID + + + Lock unspent + Lock unspent + + + Unlock unspent + Unlock unspent + + + Copy quantity + Copy quantity + + + Copy fee + Copy fee + + + Copy after fee + Copy after fee + + + Copy bytes + Copy bytes + + + Copy priority + Copy priority + + + Copy dust + Copy dust + + + Copy change + Copy change + + + highest + highest + + + higher + higher + + + high + high + + + medium-high + medium-high + + + medium + medium + + + low-medium + low-medium + + + low + low + + + lower + lower + + + lowest + lowest + + + (%1 locked) + (%1 locked) + + + none + none + + + This label turns red if the transaction size is greater than 1000 bytes. + This label turns red if the transaction size is greater than 1000 bytes. + + + This label turns red if the priority is smaller than "medium". + This label turns red if the priority is smaller than "medium". + + + This label turns red if any recipient receives an amount smaller than %1. + This label turns red if any recipient receives an amount smaller than %1. + + + Can vary +/- %1 satoshi(s) per input. + Can vary +/- %1 satoshi(s) per input. + + + yes + yes + + + no + no + + + This means a fee of at least %1 per kB is required. + This means a fee of at least %1 per kB is required. + + + Can vary +/- 1 byte per input. + Can vary +/- 1 byte per input. + + + Transactions with higher priority are more likely to get included into a block. + Transactions with higher priority are more likely to get included into a block. + + + (no label) + (no label) + + + change from %1 (%2) + change from %1 (%2) + + + (change) + (change) + + + + EditAddressDialog + + Edit Address + Edit Address + + + &Label + &Label + + + The label associated with this address list entry + The label associated with this address list entry + + + The address associated with this address list entry. This can only be modified for sending addresses. + The address associated with this address list entry. This can only be modified for sending addresses. + + + &Address + &Address + + + New receiving address + New receiving address + + + New sending address + New sending address + + + Edit receiving address + Edit receiving address + + + Edit sending address + Edit sending address + + + The entered address "%1" is already in the address book. + The entered address "%1" is already in the address book. + + + The entered address "%1" is not a valid Bitcoin address. + The entered address "%1" is not a valid Bitcoin address. + + + Could not unlock wallet. + Could not unlock wallet. + + + New key generation failed. + New key generation failed. + + + + FreespaceChecker + + A new data directory will be created. + A new data directory will be created. + + + name + name + + + Directory already exists. Add %1 if you intend to create a new directory here. + Directory already exists. Add %1 if you intend to create a new directory here. + + + Path already exists, and is not a directory. + Path already exists, and is not a directory. + + + Cannot create data directory here. + Cannot create data directory here. + + + + HelpMessageDialog + + Bitcoin Core + Bitcoin Core + + + version + version + + + (%1-bit) + (%1-bit) + + + About Bitcoin Core + About Bitcoin Core + + + Command-line options + Command-line options + + + Usage: + Usage: + + + command-line options + command-line options + + + UI Options: + UI Options: + + + Choose data directory on startup (default: %u) + Choose data directory on startup (default: %u) + + + Set language, for example "de_DE" (default: system locale) + Set language, for example "de_DE" (default: system locale) + + + Start minimized + Start minimised + + + Set SSL root certificates for payment request (default: -system-) + Set SSL root certificates for payment request (default: -system-) + + + Show splash screen on startup (default: %u) + Show splash screen on startup (default: %u) + + + Reset all settings changes made over the GUI + Reset all settings changes made over the GUI + + + + Intro + + Welcome + Welcome + + + Welcome to Bitcoin Core. + Welcome to Bitcoin Core. + + + As this is the first time the program is launched, you can choose where Bitcoin Core will store its data. + As this is the first time the program is launched, you can choose where Bitcoin Core will store its data. + + + Bitcoin Core will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. + Bitcoin Core will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. + + + Use the default data directory + Use the default data directory + + + Use a custom data directory: + Use a custom data directory: + + + Bitcoin Core + Bitcoin Core + + + Error: Specified data directory "%1" cannot be created. + Error: Specified data directory "%1" cannot be created. + + + Error + Error + + + %n GB of free space available + %n GB of free space available%n GB of free space available + + + (of %n GB needed) + (of %n GB needed)(of %n GB needed) + + + + OpenURIDialog + + Open URI + Open URI + + + Open payment request from URI or file + Open payment request from URI or file + + + URI: + URI: + + + Select payment request file + Select payment request file + + + Select payment request file to open + Select payment request file to open + + + + OptionsDialog + + Options + Options + + + &Main + &Main + + + Size of &database cache + Size of &database cache + + + MB + MB + + + Number of script &verification threads + Number of script &verification threads + + + Accept connections from outside + Accept connections from outside + + + Allow incoming connections + Allow incoming connections + + + IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) + IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu. + Minimise instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu. + + + The user interface language can be set here. This setting will take effect after restarting Bitcoin Core. + The user interface language can be set here. This setting will take effect after restarting Bitcoin Core. + + + Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + + + Third party transaction URLs + Third party transaction URLs + + + Active command-line options that override above options: + Active command-line options that override above options: + + + Reset all client options to default. + Reset all client options to default. + + + &Reset Options + &Reset Options + + + &Network + &Network + + + Automatically start Bitcoin Core after logging in to the system. + Automatically start Bitcoin Core after logging in to the system. + + + &Start Bitcoin Core on system login + &Start Bitcoin Core on system login + + + (0 = auto, <0 = leave that many cores free) + (0 = auto, <0 = leave that many cores free) + + + W&allet + W&allet + + + Expert + Expert + + + Enable coin &control features + Enable coin &control features + + + If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed. + If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed. + + + &Spend unconfirmed change + &Spend unconfirmed change + + + Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. + Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + Map port using &UPnP + Map port using &UPnP + + + Connect to the Bitcoin network through a SOCKS5 proxy. + Connect to the Bitcoin network through a SOCKS5 proxy. + + + &Connect through SOCKS5 proxy (default proxy): + &Connect through SOCKS5 proxy (default proxy): + + + Proxy &IP: + Proxy &IP: + + + &Port: + &Port: + + + Port of the proxy (e.g. 9050) + Port of the proxy (e.g. 9050) + + + Used for reaching peers via: + Used for reaching peers via: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + + + &Window + &Window + + + Show only a tray icon after minimizing the window. + Show on a tray icon after minimising the window. + + + &Minimize to the tray instead of the taskbar + &Minimise to the tray instead of the task bar + + + M&inimize on close + M&inimise on close + + + &Display + &Display + + + User Interface &language: + User Interface &language: + + + &Unit to show amounts in: + &Unit to show amounts in: + + + Choose the default subdivision unit to show in the interface and when sending coins. + Choose the default subdivision unit to show in the interface and when sending coins. + + + Whether to show coin control features or not. + Whether to show coin control features or not. + + + &OK + &OK + + + &Cancel + &Cancel + + + default + default + + + none + none + + + Confirm options reset + Confirm options reset + + + Client restart required to activate changes. + Client restart required to activate changes. + + + Client will be shut down. Do you want to proceed? + Client will be shut down. Do you want to proceed? + + + This change would require a client restart. + This change would require a client restart. + + + The supplied proxy address is invalid. + The supplied proxy address is invalid. + + + + OverviewPage + + Form + Form + + + The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet. + The displayed information may be out of date. Your Wallet automatically synchronises with the Bitcoin Network after a connection is established, but this process has not been completed yet. + + + Watch-only: + Watch-only: + + + Available: + Available: + + + Your current spendable balance + Your current spendable balance + + + Pending: + Pending: + + + Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance + Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance + + + Immature: + Immature: + + + Mined balance that has not yet matured + Mined balance that has not yet matured + + + Balances + Balances + + + Total: + Total: + + + Your current total balance + Your current total balance + + + Your current balance in watch-only addresses + Your current balance in watch-only addresses + + + Spendable: + Spendable: + + + Recent transactions + Recent transactions + + + Unconfirmed transactions to watch-only addresses + Unconfirmed transactions to watch-only addresses + + + Mined balance in watch-only addresses that has not yet matured + Mined balance in watch-only addresses that has not yet matured + + + Current total balance in watch-only addresses + Current total balance in watch-only addresses + + + + PaymentServer + + URI handling + URI handling + + + Invalid payment address %1 + Invalid payment address %1 + + + Payment request rejected + Payment request rejected + + + Payment request network doesn't match client network. + Payment request network doesn't match client network. + + + Payment request is not initialized. + Payment request is not initialised. + + + Requested payment amount of %1 is too small (considered dust). + Requested payment amount of %1 is too small (considered dust). + + + Payment request error + Payment request error + + + Cannot start bitcoin: click-to-pay handler + Cannot start bitcoin: click-to-pay handler + + + Payment request fetch URL is invalid: %1 + Payment request fetch URL is invalid: %1 + + + URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. + URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. + + + Payment request file handling + Payment request file handling + + + Payment request file cannot be read! This can be caused by an invalid payment request file. + Payment request file cannot be read! This can be caused by an invalid payment request file. + + + Payment request expired. + Payment request expired. + + + Unverified payment requests to custom payment scripts are unsupported. + Unverified payment requests to custom payment scripts are unsupported. + + + Invalid payment request. + Invalid payment request. + + + Refund from %1 + Refund from %1 + + + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + + + Error communicating with %1: %2 + Error communicating with %1: %2 + + + Payment request cannot be parsed! + Payment request cannot be parsed! + + + Bad response from server %1 + Bad response from server %1 + + + Payment acknowledged + Payment acknowledged + + + Network request error + Network request error + + + + PeerTableModel + + User Agent + User Agent + + + Node/Service + Node/Service + + + Ping Time + Ping Time + + + + QObject + + Amount + Amount + + + Enter a Bitcoin address (e.g. %1) + Enter a Bitcoin address (e.g. %1) + + + %1 d + %1 d + + + %1 h + %1 h + + + %1 m + %1 m + + + %1 s + %1 s + + + None + None + + + N/A + N/A + + + %1 ms + %1 ms + + + + QRImageWidget + + &Save Image... + &Save Image... + + + &Copy Image + &Copy Image + + + Save QR Code + Save QR Code + + + PNG Image (*.png) + PNG Image (*.png) + + + + RPCConsole + + Client name + Client name + + + N/A + N/A + + + Client version + Client version + + + &Information + &Information + + + Debug window + Debug window + + + General + General + + + Using OpenSSL version + Using OpenSSL version + + + Using BerkeleyDB version + Using BerkeleyDB version + + + Startup time + Startup time + + + Network + Network + + + Name + Name + + + Number of connections + Number of connections + + + Block chain + Block chain + + + Current number of blocks + Current number of blocks + + + Memory Pool + Memory Pool + + + Current number of transactions + Current number of transactions + + + Memory usage + Memory usage + + + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. + + + Received + Received + + + Sent + Sent + + + &Peers + &Peers + + + Banned peers + Banned peers + + + Select a peer to view detailed information. + Select a peer to view detailed information. + + + Whitelisted + Whitelisted + + + Direction + Direction + + + Version + Version + + + Starting Block + Starting Block + + + Synced Headers + Synced Headers + + + Synced Blocks + Synced Blocks + + + User Agent + User Agent + + + Services + Services + + + Ban Score + Ban Score + + + Connection Time + Connection Time + + + Last Send + Last Send + + + Last Receive + Last Receive + + + Ping Time + Ping Time + + + The duration of a currently outstanding ping. + The duration of a currently outstanding ping. + + + Ping Wait + Ping Wait + + + Time Offset + Time Offset + + + Last block time + Last block time + + + &Open + &Open + + + &Console + &Console + + + &Network Traffic + &Network Traffic + + + &Clear + &Clear + + + Totals + Totals + + + In: + In: + + + Out: + Out: + + + Build date + Build date + + + Debug log file + Debug log file + + + Clear console + Clear console + + + &Disconnect Node + &Disconnect Node + + + Ban Node for + Ban Node for + + + 1 &hour + 1 &hour + + + 1 &day + 1 &day + + + 1 &week + 1 &week + + + 1 &year + 1 &year + + + &Unban Node + &Unban Node + + + Welcome to the Bitcoin Core RPC console. + Welcome to the Bitcoin Core RPC console. + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + + Type <b>help</b> for an overview of available commands. + Type <b>help</b> for an overview of available commands. + + + %1 B + %1 B + + + %1 KB + %1 KB + + + %1 MB + %1 MB + + + %1 GB + %1 GB + + + (node id: %1) + (node id: %1) + + + via %1 + via %1 + + + never + never + + + Inbound + Inbound + + + Outbound + Outbound + + + Yes + Yes + + + No + No + + + Unknown + Unknown + + + + ReceiveCoinsDialog + + &Amount: + &Amount: + + + &Label: + &Label: + + + &Message: + &Message: + + + Reuse one of the previously used receiving addresses. Reusing addresses has security and privacy issues. Do not use this unless re-generating a payment request made before. + Reuse one of the previously used receiving addresses. Reusing addresses has security and privacy issues. Do not use this unless re-generating a payment request made before. + + + R&euse an existing receiving address (not recommended) + R&euse an existing receiving address (not recommended) + + + An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network. + An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network. + + + An optional label to associate with the new receiving address. + An optional label to associate with the new receiving address. + + + Use this form to request payments. All fields are <b>optional</b>. + Use this form to request payments. All fields are <b>optional</b>. + + + An optional amount to request. Leave this empty or zero to not request a specific amount. + An optional amount to request. Leave this empty or zero to not request a specific amount. + + + Clear all fields of the form. + Clear all fields of the form. + + + Clear + Clear + + + Requested payments history + Requested payments history + + + &Request payment + &Request payment + + + Show the selected request (does the same as double clicking an entry) + Show the selected request (does the same as double clicking an entry) + + + Show + Show + + + Remove the selected entries from the list + Remove the selected entries from the list + + + Remove + Remove + + + Copy label + Copy label + + + Copy message + Copy message + + + Copy amount + Copy amount + + + + ReceiveRequestDialog + + QR Code + QR Code + + + Copy &URI + Copy &URI + + + Copy &Address + Copy &Address + + + &Save Image... + &Save Image... + + + Request payment to %1 + Request payment to %1 + + + Payment information + Payment information + + + URI + URI + + + Address + Address + + + Amount + Amount + + + Label + Label + + + Message + Message + + + Resulting URI too long, try to reduce the text for label / message. + Resulting URI too long, try to reduce the text for label / message. + + + Error encoding URI into QR Code. + Error encoding URI into QR Code. + + + + RecentRequestsTableModel + + Date + Date + + + Label + Label + + + Message + Message + + + Amount + Amount + + + (no label) + (no label) + + + (no message) + (no message) + + + (no amount) + (no amount) + + + + SendCoinsDialog + + Send Coins + Send Coins + + + Coin Control Features + Coin Control Features + + + Inputs... + Inputs... + + + automatically selected + automatically selected + + + Insufficient funds! + Insufficient funds! + + + Quantity: + Quantity: + + + Bytes: + Bytes: + + + Amount: + Amount: + + + Priority: + Priority: + + + Fee: + Fee: + + + After Fee: + After Fee: + + + Change: + Change: + + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + + + Custom change address + Custom change address + + + Transaction Fee: + Transaction Fee: + + + Choose... + Choose... + + + collapse fee-settings + collapse fee-settings + + + per kilobyte + per kilobyte + + + If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then "per kilobyte" only pays 250 satoshis in fee, while "total at least" pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte. + If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then "per kilobyte" only pays 250 satoshis in fee, while "total at least" pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte. + + + Hide + Hide + + + total at least + total at least + + + Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process. + Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process. + + + (read the tooltip) + (read the tooltip) + + + Recommended: + Recommended: + + + Custom: + Custom: + + + (Smart fee not initialized yet. This usually takes a few blocks...) + (Smart fee not initialised yet. This usually takes a few blocks...) + + + Confirmation time: + Confirmation time: + + + normal + normal + + + fast + fast + + + Send as zero-fee transaction if possible + Send as zero-fee transaction if possible + + + (confirmation may take longer) + (confirmation may take longer) + + + Send to multiple recipients at once + Send to multiple recipients at once + + + Add &Recipient + Add &Recipient + + + Clear all fields of the form. + Clear all fields of the form. + + + Dust: + Dust: + + + Clear &All + Clear &All + + + Balance: + Balance: + + + Confirm the send action + Confirm the send action + + + S&end + S&end + + + Confirm send coins + Confirm send coins + + + %1 to %2 + %1 to %2 + + + Copy quantity + Copy quantity + + + Copy amount + Copy amount + + + Copy fee + Copy fee + + + Copy after fee + Copy after fee + + + Copy bytes + Copy bytes + + + Copy priority + Copy priority + + + Copy change + Copy change + + + Total Amount %1 + Total Amount %1 + + + or + or + + + The amount to pay must be larger than 0. + The amount to pay must be larger than 0. + + + The amount exceeds your balance. + The amount exceeds your balance. + + + The total exceeds your balance when the %1 transaction fee is included. + The total exceeds your balance when the %1 transaction fee is included. + + + Transaction creation failed! + Transaction creation failed! + + + The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + A fee higher than %1 is considered an absurdly high fee. + A fee higher than %1 is considered an absurdly high fee. + + + Payment request expired. + Payment request expired. + + + Pay only the required fee of %1 + Pay only the required fee of %1 + + + Estimated to begin confirmation within %n block(s). + Estimated to begin confirmation within %n block.Estimated to begin confirmation within %n blocks. + + + The recipient address is not valid. Please recheck. + The recipient address is not valid. Please recheck. + + + Duplicate address found: addresses should only be used once each. + Duplicate address found: addresses should only be used once each. + + + Warning: Invalid Bitcoin address + Warning: Invalid Bitcoin address + + + (no label) + (no label) + + + Warning: Unknown change address + Warning: Unknown change address + + + Copy dust + Copy dust + + + Are you sure you want to send? + Are you sure you want to send? + + + added as transaction fee + added as transaction fee + + + + SendCoinsEntry + + A&mount: + A&mount: + + + Pay &To: + Pay &To: + + + Enter a label for this address to add it to your address book + Enter a label for this address to add it to your address book + + + &Label: + &Label: + + + Choose previously used address + Choose previously used address + + + This is a normal payment. + This is a normal payment. + + + The Bitcoin address to send the payment to + The Bitcoin address to send the payment to + + + Alt+A + Alt+A + + + Paste address from clipboard + Paste address from clipboard + + + Alt+P + Alt+P + + + Remove this entry + Remove this entry + + + The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally. + The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally. + + + S&ubtract fee from amount + S&ubtract fee from amount + + + Message: + Message: + + + This is an unauthenticated payment request. + This is an unauthenticated payment request. + + + This is an authenticated payment request. + This is an authenticated payment request. + + + Enter a label for this address to add it to the list of used addresses + Enter a label for this address to add it to the list of used addresses + + + A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network. + A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network. + + + Pay To: + Pay To: + + + Memo: + Memo: + + + + ShutdownWindow + + Bitcoin Core is shutting down... + Bitcoin Core is shutting down... + + + Do not shut down the computer until this window disappears. + Do not shut down the computer until this window disappears. + + + + SignVerifyMessageDialog + + Signatures - Sign / Verify a Message + Signatures - Sign / Verify a Message + + + &Sign Message + &Sign Message + + + You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + The Bitcoin address to sign the message with + The Bitcoin address to sign the message with + + + Choose previously used address + Choose previously used address + + + Alt+A + Alt+A + + + Paste address from clipboard + Paste address from clipboard + + + Alt+P + Alt+P + + + Enter the message you want to sign here + Enter the message you want to sign here + + + Signature + Signature + + + Copy the current signature to the system clipboard + Copy the current signature to the system clipboard + + + Sign the message to prove you own this Bitcoin address + Sign the message to prove you own this Bitcoin address + + + Sign &Message + Sign &Message + + + Reset all sign message fields + Reset all sign message fields + + + Clear &All + Clear &All + + + &Verify Message + &Verify Message + + + Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction! + Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction! + + + The Bitcoin address the message was signed with + The Bitcoin address the message was signed with + + + Verify the message to ensure it was signed with the specified Bitcoin address + Verify the message to ensure it was signed with the specified Bitcoin address + + + Verify &Message + Verify &Message + + + Reset all verify message fields + Reset all verify message fields + + + Click "Sign Message" to generate signature + Click "Sign Message" to generate signature + + + The entered address is invalid. + The entered address is invalid. + + + Please check the address and try again. + Please check the address and try again. + + + The entered address does not refer to a key. + The entered address does not refer to a key. + + + Wallet unlock was cancelled. + Wallet unlock was cancelled. + + + Private key for the entered address is not available. + Private key for the entered address is not available. + + + Message signing failed. + Message signing failed. + + + Message signed. + Message signed. + + + The signature could not be decoded. + The signature could not be decoded. + + + Please check the signature and try again. + Please check the signature and try again. + + + The signature did not match the message digest. + The signature did not match the message digest. + + + Message verification failed. + Message verification failed. + + + Message verified. + Message verified. + + + + SplashScreen + + Bitcoin Core + Bitcoin Core + + + The Bitcoin Core developers + The Bitcoin Core developers + + + [testnet] + [testnet] + + + + TrafficGraphWidget + + KB/s + KB/s + + + + TransactionDesc + + Open until %1 + Open until %1 + + + conflicted + conflicted + + + %1/offline + %1/offline + + + %1/unconfirmed + %1/unconfirmed + + + %1 confirmations + %1 confirmations + + + Status + Status + + + , broadcast through %n node(s) + , broadcast through %n node, broadcast through %n nodes + + + Date + Date + + + Source + Source + + + Generated + Generated + + + From + From + + + To + To + + + own address + own address + + + watch-only + watch-only + + + label + label + + + Credit + Credit + + + matures in %n more block(s) + matures in %n more blockmatures in %n more blocks + + + not accepted + not accepted + + + Debit + Debit + + + Total debit + Total debit + + + Total credit + Total credit + + + Transaction fee + Transaction fee + + + Net amount + Net amount + + + Message + Message + + + Comment + Comment + + + Transaction ID + Transaction ID + + + Merchant + Merchant + + + Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. + Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. + + + Debug information + Debug information + + + Transaction + Transaction + + + Inputs + Inputs + + + Amount + Amount + + + true + true + + + false + false + + + , has not been successfully broadcast yet + , has not been successfully broadcast yet + + + Open for %n more block(s) + Open for %n more blockOpen for %n more blocks + + + unknown + unknown + + + + TransactionDescDialog + + Transaction details + Transaction details + + + This pane shows a detailed description of the transaction + This pane shows a detailed description of the transaction + + + + TransactionTableModel + + Date + Date + + + Type + Type + + + Immature (%1 confirmations, will be available after %2) + Immature (%1 confirmations, will be available after %2) + + + Open for %n more block(s) + Open for %n more blockOpen for %n more blocks + + + Open until %1 + Open until %1 + + + Confirmed (%1 confirmations) + Confirmed (%1 confirmations) + + + This block was not received by any other nodes and will probably not be accepted! + This block was not received by any other nodes and will probably not be accepted! + + + Generated but not accepted + Generated but not accepted + + + Offline + Offline + + + Label + Label + + + Unconfirmed + Unconfirmed + + + Confirming (%1 of %2 recommended confirmations) + Confirming (%1 of %2 recommended confirmations) + + + Conflicted + Conflicted + + + Received with + Received with + + + Received from + Received from + + + Sent to + Sent to + + + Payment to yourself + Payment to yourself + + + Mined + Mined + + + watch-only + watch-only + + + (n/a) + (n/a) + + + Transaction status. Hover over this field to show number of confirmations. + Transaction status. Hover over this field to show number of confirmations. + + + Date and time that the transaction was received. + Date and time that the transaction was received. + + + Type of transaction. + Type of transaction. + + + Whether or not a watch-only address is involved in this transaction. + Whether or not a watch-only address is involved in this transaction. + + + User-defined intent/purpose of the transaction. + User-defined intent/purpose of the transaction. + + + Amount removed from or added to balance. + Amount removed from or added to balance. + + + + TransactionView + + All + All + + + Today + Today + + + This week + This week + + + This month + This month + + + Last month + Last month + + + This year + This year + + + Range... + Range... + + + Received with + Received with + + + Sent to + Sent to + + + To yourself + To yourself + + + Mined + Mined + + + Other + Other + + + Enter address or label to search + Enter address or label to search + + + Min amount + Min amount + + + Copy address + Copy address + + + Copy label + Copy label + + + Copy amount + Copy amount + + + Copy transaction ID + Copy transaction ID + + + Copy raw transaction + Copy raw transaction + + + Edit label + Edit label + + + Show transaction details + Show transaction details + + + Export Transaction History + Export Transaction History + + + Watch-only + Watch-only + + + Exporting Failed + Exporting Failed + + + There was an error trying to save the transaction history to %1. + There was an error trying to save the transaction history to %1. + + + Exporting Successful + Exporting Successful + + + The transaction history was successfully saved to %1. + The transaction history was successfully saved to %1. + + + Comma separated file (*.csv) + Comma separated file (*.csv) + + + Confirmed + Confirmed + + + Date + Date + + + Type + Type + + + Label + Label + + + Address + Address + + + ID + ID + + + Range: + Range: + + + to + to + + + + UnitDisplayStatusBarControl + + Unit to show amounts in. Click to select another unit. + Unit to show amounts in. Click to select another unit. + + + + WalletFrame + + No wallet has been loaded. + No wallet has been loaded. + + + + WalletModel + + Send Coins + Send Coins + + + + WalletView + + &Export + &Export + + + Export the data in the current tab to a file + Export the data in the current tab to a file + + + Backup Wallet + Backup Wallet + + + Wallet Data (*.dat) + Wallet Data (*.dat) + + + Backup Failed + Backup Failed + + + There was an error trying to save the wallet data to %1. + There was an error trying to save the wallet data to %1. + + + The wallet data was successfully saved to %1. + The wallet data was successfully saved to %1. + + + Backup Successful + Backup Successful + + + + bitcoin-core + + Options: + Options: + + + Specify data directory + Specify data directory + + + Connect to a node to retrieve peer addresses, and disconnect + Connect to a node to retrieve peer addresses, and disconnect + + + Specify your own public address + Specify your own public address + + + Accept command line and JSON-RPC commands + Accept command line and JSON-RPC commands + + + If <category> is not supplied or if <category> = 1, output all debugging information. + If <category> is not supplied or if <category> = 1, output all debugging information. + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + + + Prune configured below the minimum of %d MiB. Please use a higher number. + Prune configured below the minimum of %d MiB. Please use a higher number. + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + + + Error: A fatal internal error occurred, see debug.log for details + Error: A fatal internal error occurred, see debug.log for details + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Fee (in %s/kB) to add to transactions you send (default: %s) + + + Pruning blockstore... + Pruning blockstore... + + + Run in the background as a daemon and accept commands + Run in the background as a daemon and accept commands + + + Unable to start HTTP server. See debug log for details. + Unable to start HTTP server. See debug log for details. + + + Accept connections from outside (default: 1 if no -proxy or -connect) + Accept connections from outside (default: 1 if no -proxy or -connect) + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup + Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup + + + Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. + Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) + Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) + + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + Unable to bind to %s on this computer. Bitcoin Core is probably already running. + Unable to bind to %s on this computer. Bitcoin Core is probably already running. + + + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + + + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) + + + WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) + WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) + + + Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. + Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. + + + Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. + Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. + Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. + + + -maxmempool must be at least %d MB + -maxmempool must be at least %d MB + + + <category> can be: + <category> can be: + + + Block creation options: + Block creation options: + + + Connect only to the specified node(s) + Connect only to the specified node(s) + + + Connection options: + Connection options: + + + Corrupted block database detected + Corrupted block database detected + + + Debugging/Testing options: + Debugging/Testing options: + + + Do not load the wallet and disable wallet RPC calls + Do not load the wallet and disable wallet RPC calls + + + Do you want to rebuild the block database now? + Do you want to rebuild the block database now? + + + Enable publish hash block in <address> + Enable publish hash block in <address> + + + Enable publish hash transaction in <address> + Enable publish hash transaction in <address> + + + Enable publish raw block in <address> + Enable publish raw block in <address> + + + Enable publish raw transaction in <address> + Enable publish raw transaction in <address> + + + Error initializing block database + Error initialising block database + + + Error initializing wallet database environment %s! + Error initialising wallet database environment %s! + + + Error loading block database + Error loading block database + + + Error opening block database + Error opening block database + + + Error: Disk space is low! + Error: Disk space is low! + + + Failed to listen on any port. Use -listen=0 if you want this. + Failed to listen on any port. Use -listen=0 if you want this. + + + Importing... + Importing... + + + Incorrect or no genesis block found. Wrong datadir for network? + Incorrect or no genesis block found. Wrong datadir for network? + + + Invalid -onion address: '%s' + Invalid -onion address: '%s' + + + Keep the transaction memory pool below <n> megabytes (default: %u) + Keep the transaction memory pool below <n> megabytes (default: %u) + + + Not enough file descriptors available. + Not enough file descriptors available. + + + Only connect to nodes in network <net> (ipv4, ipv6 or onion) + Only connect to nodes in network <net> (ipv4, ipv6 or onion) + + + Prune cannot be configured with a negative value. + Prune cannot be configured with a negative value. + + + Prune mode is incompatible with -txindex. + Prune mode is incompatible with -txindex. + + + Set database cache size in megabytes (%d to %d, default: %d) + Set database cache size in megabytes (%d to %d, default: %d) + + + Set maximum block size in bytes (default: %d) + Set maximum block size in bytes (default: %d) + + + Specify wallet file (within data directory) + Specify wallet file (within data directory) + + + Unsupported argument -benchmark ignored, use -debug=bench. + Unsupported argument -benchmark ignored, use -debug=bench. + + + Unsupported argument -debugnet ignored, use -debug=net. + Unsupported argument -debugnet ignored, use -debug=net. + + + Unsupported argument -tor found, use -onion. + Unsupported argument -tor found, use -onion. + + + Use UPnP to map the listening port (default: %u) + Use UPnP to map the listening port (default: %u) + + + User Agent comment (%s) contains unsafe characters. + User Agent comment (%s) contains unsafe characters. + + + Verifying blocks... + Verifying blocks... + + + Verifying wallet... + Verifying wallet... + + + Wallet %s resides outside data directory %s + Wallet %s resides outside data directory %s + + + Wallet options: + Wallet options: + + + Warning: This version is obsolete; upgrade required! + Warning: This version is obsolete; upgrade required! + + + You need to rebuild the database using -reindex to change -txindex + You need to rebuild the database using -reindex to change -txindex + + + 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 + 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 + + + Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 + Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 + + + Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces) + Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces) + + + Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running. + Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running. + + + Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality) + Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality) + + + Discover own IP addresses (default: 1 when listening and no -externalip or -proxy) + Discover own IP addresses (default: 1 when listening and no -externalip or -proxy) + + + Error: Listening for incoming connections failed (listen returned error %s) + Error: Listening for incoming connections failed (listen returned error %s) + + + Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) + Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) + + + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + + + If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) + If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) + + + Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + + + Maximum size of data in data carrier transactions we relay and mine (default: %u) + Maximum size of data in data carrier transactions we relay and mine (default: %u) + + + Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) + Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) + + + Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u) + Randomise credentials for every proxy connection. This enables Tor stream isolation (default: %u) + + + Set maximum size of high-priority/low-fee transactions in bytes (default: %d) + Set maximum size of high-priority/low-fee transactions in bytes (default: %d) + + + Set the number of threads for coin generation if enabled (-1 = all cores, default: %d) + Set the number of threads for coin generation if enabled (-1 = all cores, default: %d) + + + The transaction amount is too small to send after the fee has been deducted + The transaction amount is too small to send after the fee has been deducted + + + This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. + This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. + + + 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 + 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 + + + You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain + You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain + + + (default: %u) + (default: %u) + + + Accept public REST requests (default: %u) + Accept public REST requests (default: %u) + + + Activating best chain... + Activating best chain... + + + Always relay transactions received from whitelisted peers (default: %d) + Always relay transactions received from whitelisted peers (default: %d) + + + Attempt to recover private keys from a corrupt wallet.dat on startup + Attempt to recover private keys from a corrupt wallet.dat on startup + + + Automatically create Tor hidden service (default: %d) + Automatically create Tor hidden service (default: %d) + + + Cannot resolve -whitebind address: '%s' + Cannot resolve -whitebind address: '%s' + + + Connect through SOCKS5 proxy + Connect through SOCKS5 proxy + + + Copyright (C) 2009-%i The Bitcoin Core Developers + Copyright (C) 2009-%i The Bitcoin Core Developers + + + Error loading wallet.dat: Wallet requires newer version of Bitcoin Core + Error loading wallet.dat: Wallet requires newer version of Bitcoin Core + + + Error reading from database, shutting down. + Error reading from database, shutting down. + + + Imports blocks from external blk000??.dat file on startup + Imports blocks from external blk000??.dat file on startup + + + Information + Information + + + Initialization sanity check failed. Bitcoin Core is shutting down. + Initialisation sanity check failed. Bitcoin Core is shutting down. + + + Invalid amount for -maxtxfee=<amount>: '%s' + Invalid amount for -maxtxfee=<amount>: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + Invalid amount for -mintxfee=<amount>: '%s' + Invalid amount for -mintxfee=<amount>: '%s' + + + Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) + Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) + + + Invalid netmask specified in -whitelist: '%s' + Invalid netmask specified in -whitelist: '%s' + + + Keep at most <n> unconnectable transactions in memory (default: %u) + Keep at most <n> unconnectable transactions in memory (default: %u) + + + Need to specify a port with -whitebind: '%s' + Need to specify a port with -whitebind: '%s' + + + Node relay options: + Node relay options: + + + RPC server options: + RPC server options: + + + Rebuild block chain index from current blk000??.dat files on startup + Rebuild block chain index from current blk000??.dat files on startup + + + Receive and display P2P network alerts (default: %u) + Receive and display P2P network alerts (default: %u) + + + Reducing -maxconnections from %d to %d, because of system limitations. + Reducing -maxconnections from %d to %d, because of system limitations. + + + Rescan the block chain for missing wallet transactions on startup + Rescan the block chain for missing wallet transactions on startup + + + Send trace/debug info to console instead of debug.log file + Send trace/debug info to console instead of debug.log file + + + Send transactions as zero-fee transactions if possible (default: %u) + Send transactions as zero-fee transactions if possible (default: %u) + + + Show all debugging options (usage: --help -help-debug) + Show all debugging options (usage: --help -help-debug) + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + Signing transaction failed + + + The transaction amount is too small to pay the fee + The transaction amount is too small to pay the fee + + + This is experimental software. + This is experimental software. + + + Tor control port password (default: empty) + Tor control port password (default: empty) + + + Tor control port to use if onion listening enabled (default: %s) + Tor control port to use if onion listening enabled (default: %s) + + + Transaction amount too small + Transaction amount too small + + + Transaction amounts must be positive + Transaction amounts must be positive + + + Transaction too large for fee policy + Transaction too large for fee policy + + + Transaction too large + Transaction too large + + + Unable to bind to %s on this computer (bind returned error %s) + Unable to bind to %s on this computer (bind returned error %s) + + + Upgrade wallet to latest format on startup + Upgrade wallet to latest format on startup + + + Username for JSON-RPC connections + Username for JSON-RPC connections + + + Wallet needed to be rewritten: restart Bitcoin Core to complete + Wallet needed to be rewritten: restart Bitcoin Core to complete + + + Warning + Warning + + + Whether to operate in a blocks only mode (default: %u) + Whether to operate in a blocks only mode (default: %u) + + + Zapping all transactions from wallet... + Zapping all transactions from wallet... + + + ZeroMQ notification options: + ZeroMQ notification options: + + + wallet.dat corrupt, salvage failed + wallet.dat corrupt, salvage failed + + + Password for JSON-RPC connections + Password for JSON-RPC connections + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + This help message + This help message + + + Allow DNS lookups for -addnode, -seednode and -connect + Allow DNS lookups for -addnode, -seednode and -connect + + + Loading addresses... + Loading addresses... + + + Error loading wallet.dat: Wallet corrupted + Error loading wallet.dat: Wallet corrupted + + + (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) + (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) + + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + Do not keep transactions in the mempool longer than <n> hours (default: %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + + + How thorough the block verification of -checkblocks is (0-4, default: %u) + How thorough the block verification of -checkblocks is (0-4, default: %u) + + + Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u) + Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u) + + + Number of seconds to keep misbehaving peers from reconnecting (default: %u) + Number of seconds to keep misbehaving peers from reconnecting (default: %u) + + + Output debugging information (default: %u, supplying <category> is optional) + Output debugging information (default: %u, supplying <category> is optional) + + + Support filtering of blocks and transaction with bloom filters (default: %u) + Support filtering of blocks and transaction with bloom filters (default: %u) + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) + + + 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. This option can be specified multiple times + 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. This option can be specified multiple times + + + (default: %s) + (default: %s) + + + Always query for peer addresses via DNS lookup (default: %u) + Always query for peer addresses via DNS lookup (default: %u) + + + Error loading wallet.dat + Error loading wallet.dat + + + Generate coins (default: %u) + Generate coins (default: %u) + + + How many blocks to check at startup (default: %u, 0 = all) + How many blocks to check at startup (default: %u, 0 = all) + + + Include IP addresses in debug output (default: %u) + Include IP addresses in debug output (default: %u) + + + Invalid -proxy address: '%s' + Invalid -proxy address: '%s' + + + Listen for JSON-RPC connections on <port> (default: %u or testnet: %u) + Listen for JSON-RPC connections on <port> (default: %u or testnet: %u) + + + Listen for connections on <port> (default: %u or testnet: %u) + Listen for connections on <port> (default: %u or testnet: %u) + + + Maintain at most <n> connections to peers (default: %u) + Maintain at most <n> connections to peers (default: %u) + + + Make the wallet broadcast transactions + Make the wallet broadcast transactions + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: %u) + Maximum per-connection receive buffer, <n>*1000 bytes (default: %u) + + + Maximum per-connection send buffer, <n>*1000 bytes (default: %u) + Maximum per-connection send buffer, <n>*1000 bytes (default: %u) + + + Prepend debug output with timestamp (default: %u) + Prepend debug output with timestamp (default: %u) + + + Relay and mine data carrier transactions (default: %u) + Relay and mine data carrier transactions (default: %u) + + + Relay non-P2SH multisig (default: %u) + Relay non-P2SH multisig (default: %u) + + + Set key pool size to <n> (default: %u) + Set key pool size to <n> (default: %u) + + + Set minimum block size in bytes (default: %u) + Set minimum block size in bytes (default: %u) + + + Set the number of threads to service RPC calls (default: %d) + Set the number of threads to service RPC calls (default: %d) + + + Specify configuration file (default: %s) + Specify configuration file (default: %s) + + + Specify connection timeout in milliseconds (minimum: 1, default: %d) + Specify connection timeout in milliseconds (minimum: 1, default: %d) + + + Specify pid file (default: %s) + Specify pid file (default: %s) + + + Spend unconfirmed change when sending transactions (default: %u) + Spend unconfirmed change when sending transactions (default: %u) + + + Threshold for disconnecting misbehaving peers (default: %u) + Threshold for disconnecting misbehaving peers (default: %u) + + + Unknown network specified in -onlynet: '%s' + Unknown network specified in -onlynet: '%s' + + + Cannot resolve -bind address: '%s' + Cannot resolve -bind address: '%s' + + + Cannot resolve -externalip address: '%s' + Cannot resolve -externalip address: '%s' + + + Invalid amount for -paytxfee=<amount>: '%s' + Invalid amount for -paytxfee=<amount>: '%s' + + + Insufficient funds + Insufficient funds + + + Loading block index... + Loading block index... + + + Add a node to connect to and attempt to keep the connection open + Add a node to connect to and attempt to keep the connection open + + + Loading wallet... + Loading wallet... + + + Cannot downgrade wallet + Cannot downgrade wallet + + + Cannot write default address + Cannot write default address + + + Rescanning... + Rescanning... + + + Done loading + Done loading + + + Error + Error + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_eo.ts b/src/qt/locale/bitcoin_eo.ts index 17ce494f9..ab8dd65f8 100644 --- a/src/qt/locale/bitcoin_eo.ts +++ b/src/qt/locale/bitcoin_eo.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -208,6 +208,9 @@ Vi sukcese ŝanĝis la pasfrazon de la monujo. + + BanTableModel + BitcoinGUI @@ -406,10 +409,22 @@ No block source available... Neniu fonto de blokoj trovebla... + + %n day(s) + %n tago%n tagoj + + + %n week(s) + %n semajno%n semajnoj + %1 and %2 %1 kaj %2 + + %n year(s) + %n jaro%n jaroj + %1 behind mankas %1 @@ -442,6 +457,30 @@ Catching up... Ĝisdatigante... + + Date: %1 + + Dato: %1 + + + + Amount: %1 + + Sumo: %1 + + + + Type: %1 + + Tipo: %1 + + + + Label: %1 + + Etikedo: %1 + + Sent transaction Sendita transakcio @@ -773,7 +812,7 @@ command-line options komandliniaj agordaĵoj - + Intro @@ -850,6 +889,14 @@ MB MB + + Accept connections from outside + Akcepti konektojn el ekstere + + + Allow incoming connections + Permesi envenantajn konektojn + Reset all client options to default. Reagordi ĉion al defaŭlataj valoroj. @@ -862,6 +909,10 @@ &Network &Reto + + W&allet + Monujo + Expert Fakulo @@ -886,6 +937,14 @@ Port of the proxy (e.g. 9050) la pordo de la prokurilo (ekz. 9050) + + IPv4 + IPv4 + + + IPv6 + IPv6 + &Window &Fenestro @@ -973,6 +1032,10 @@ Mined balance that has not yet matured Minita saldo, kiu ankoraŭ ne maturiĝis + + Balances + Saldoj + Total: Totalo: @@ -981,6 +1044,14 @@ Your current total balance via aktuala totala saldo + + Spendable: + Elspezebla: + + + Recent transactions + Lastaj transakcioj + PaymentServer @@ -1042,6 +1113,10 @@ %1 m %1 m + + None + Neniu + N/A neaplikebla @@ -1121,8 +1196,20 @@ Aktuala nombro de blokoj - Bytes Sent - Bajtoj Senditaj: + Received + Ricevita + + + Sent + Sendita + + + Version + Versio + + + Services + Servoj Last block time @@ -1376,6 +1463,10 @@ Change: Restmono: + + Transaction Fee: + Krompago: + Send to multiple recipients at once Sendi samtempe al pluraj ricevantoj @@ -1444,10 +1535,6 @@ Copy change Kopii restmonon - - Total Amount %1 (= %2) - Totala Sumo %1 (= %2) - or @@ -2102,10 +2189,6 @@ Run in the background as a daemon and accept commands Ruli fone kiel demono kaj akcepti komandojn - - Use the test network - Uzi la test-reton - Accept connections from outside (default: 1 if no -proxy or -connect) Akcepti konektojn el ekstere (defaŭlte: 1 se ne estas -proxy nek -connect) @@ -2122,10 +2205,6 @@ This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Tiu ĉi estas antaŭeldona testa versio - uzu laŭ via propra risko - ne uzu por minado aŭ por aplikaĵoj por vendistoj - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Averto: -paytxfee estas agordita per tre alta valoro! Tio estas la krompago, kion vi pagos se vi sendas la transakcion. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Averto: La reto ne tute konsentas! Kelkaj minantoj ŝajne spertas problemojn aktuale. @@ -2134,10 +2213,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Averto: ŝajne ni ne tute konsentas kun niaj samtavolanoj! Eble vi devas ĝisdatigi vian klienton, aŭ eble aliaj nodoj faru same. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Averto: okazis eraro dum lego de wallet.dat! Ĉiuj ŝlosiloj sukcese legiĝis, sed la transakciaj datumoj aŭ la adresaro eble mankas aŭ malĝustas. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Averto: via wallet.dat estas difektita, sed la datumoj sukcese saviĝis! La originala wallet.dat estas nun konservita kiel wallet.{timestamp}.bak en %s; se via saldo aŭ transakcioj estas malĝustaj vi devus restaŭri per alia sekurkopio. @@ -2146,10 +2221,6 @@ <category> can be: <category> povas esti: - - Attempt to recover private keys from a corrupt wallet.dat - Provo ripari privatajn ŝlosilojn el difektita wallet.dat - Block creation options: Blok-kreaj agordaĵoj: @@ -2226,22 +2297,22 @@ You need to rebuild the database using -reindex to change -txindex Vi devas rekontrui la datumbazon kun -reindex por ŝanĝi -txindex - - Imports blocks from external blk000??.dat file - Importas blokojn el ekstera dosiero blk000??.dat - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Plenumi komandon kiam rilata alerto riceviĝas, aŭ kiam ni vidas tre longan forkon (%s en cms anstataŭiĝas per mesaĝo) - Choose data directory on startup (default: 0) - Elekti dosierujon por datumoj dum lanĉo (defaŭlte: 0) + Cannot resolve -whitebind address: '%s' + Ne eblas trovi la adreson -whitebind: '%s' Information Informoj + + Invalid amount for -maxtxfee=<amount>: '%s' + Nevalida sumo por -maxtxfee=<amount>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' Nevalida sumo por -minrelaytxfee=<amount>: '%s' @@ -2254,14 +2325,6 @@ Send trace/debug info to console instead of debug.log file Sendi spurajn/sencimigajn informojn al la konzolo anstataŭ al dosiero debug.log - - Set language, for example "de_DE" (default: system locale) - Agordi lingvon, ekzemple "de_DE" (defaŭlte: tiu de la sistemo) - - - Show splash screen on startup (default: 1) - Montri salutŝildon dum lanĉo (defaŭlte: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Malpligrandigi la sencimigan protokol-dosieron kiam kliento lanĉiĝas (defaŭlte: 1 kiam mankas -debug) @@ -2270,10 +2333,6 @@ Signing transaction failed Subskriba transakcio fiaskis - - Start minimized - Lanĉiĝi plejete - This is experimental software. ĝi estas eksperimenta programo @@ -2290,10 +2349,6 @@ Transaction too large Transakcio estas tro granda - - Use UPnP to map the listening port (default: 1 when listening) - Uzi UPnP por mapi la aŭskultan pordon (defaŭlte: 1 dum aŭskultado) - Username for JSON-RPC connections Salutnomo por konektoj JSON-RPC @@ -2314,18 +2369,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Plenumi komandon kiam plej bona bloko ŝanĝiĝas (%s en cmd anstataŭiĝas per bloka haketaĵo) - - Upgrade wallet to latest format - Ĝisdatigi monujon al plej lasta formato - - - Rescan the block chain for missing wallet transactions - Reskani la blokĉenon por mankantaj monujaj transakcioj - - - Use OpenSSL (https) for JSON-RPC connections - Uzi OpenSSL (https) por konektoj JSON-RPC - This help message Tiu ĉi helpmesaĝo diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index de55496c0..936074210 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -23,7 +23,7 @@ C&lose - &Cerrar + C&errar &Copy Address @@ -55,7 +55,7 @@ C&hoose - &Escoger + E&scoger Sending addresses @@ -93,7 +93,11 @@ Exporting Failed Fallo al exportar - + + There was an error trying to save the address list to %1. Please try again. + Hubo un error al tratar de guardar en la lista de direcciones a %1 . Por favor, vuelve a intentarlo . + + AddressTableModel @@ -216,6 +220,17 @@ Se ha cambiado correctamente la contraseña del monedero. + + BanTableModel + + IP/Netmask + IP/Máscara + + + Banned Until + Bloqueado Hasta + + BitcoinGUI @@ -248,7 +263,7 @@ E&xit - &Salir + S&alir Quit application @@ -867,7 +882,23 @@ command-line options opciones de la consola de comandos - + + Choose data directory on startup (default: %u) + Elegir directorio de datos al iniciar (predeterminado: %u) + + + Set language, for example "de_DE" (default: system locale) + Establecer el idioma, por ejemplo, "es_ES" (predeterminado: configuración regional del sistema) + + + Start minimized + Arrancar minimizado + + + Set SSL root certificates for payment request (default: -system-) + Establecer los certificados raíz SSL para solicitudes de pago (predeterminado: -system-) + + Intro @@ -1064,6 +1095,22 @@ Port of the proxy (e.g. 9050) Puerto del servidor proxy (ej. 9050) + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Usar distintos proxys SOCKS5 para comunicarse vía Tor de forma anónima: + &Window &Ventana @@ -1282,10 +1329,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). La petición de pago %1 es demasiado grande (%2 bytes, permitidos %3 bytes). - - Payment request DoS protection - Solicitud pago de protección DoS - Error communicating with %1: %2 Error en la comunicación con %1: %2 @@ -1454,6 +1497,10 @@ &Peers &Pares + + Banned peers + Peers Bloqueados + Select a peer to view detailed information. Seleccionar un par para ver su información detallada. @@ -1466,6 +1513,18 @@ Version Versión + + Starting Block + Importando bloques... + + + Synced Headers + Sincronizar Cabeceras + + + Synced Blocks + Bloques Sincronizados + User Agent User Agent @@ -1474,14 +1533,6 @@ Services Servicios - - Starting Height - Altura de comienzo - - - Sync Height - Altura de sincronización - Ban Score Puntuación de bloqueo @@ -1498,14 +1549,6 @@ Last Receive Ultima recepción - - Bytes Sent - Bytes enviados - - - Bytes Received - Bytes recibidos - Ping Time Ping @@ -1558,6 +1601,26 @@ Clear console Borrar consola + + &Disconnect Node + Nodo &Desconectado + + + 1 &hour + 1 &hora + + + 1 &day + 1 &día + + + 1 &week + 1 &semana + + + 1 &year + 1 &año + Welcome to the Bitcoin Core RPC console. Bienvenido a la consola RPC de Bitcoin Core. @@ -1586,6 +1649,10 @@ %1 GB %1 GB + + (node id: %1) + (nodo: %1) + via %1 via %1 @@ -1603,12 +1670,16 @@ Saliente - Unknown - Desconocido + Yes + - Fetching... - Adquiriendo.... + No + No + + + Unknown + Desconocido @@ -1975,8 +2046,8 @@ Copiar Cambio - Total Amount %1 (= %2) - Cuantía Total %1 (=%2) + Total Amount %1 + Monto Total %1 or @@ -2002,18 +2073,22 @@ The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. ¡La transacción fue rechazada! Esto puede haber ocurrido si alguno de los bitcoins de su monedero ya estaba gastado o si ha usado una copia de wallet.dat y los bitcoins estaban gastados en la copia pero no se habían marcado como gastados aqui. + + A fee higher than %1 is considered an absurdly high fee. + Una comisión mayor al %1 se considera demasiado alta. + Payment request expired. Solicitud de pago caducada. + + Pay only the required fee of %1 + Paga sólo la cuota mínima de %1 + Estimated to begin confirmation within %n block(s). Estimado para empezar la confirmación dentro de %n bloque.Estimado para empezar la confirmación dentro de %n bloques. - - Pay only the minimum fee of %1 - Paga sólo la cuota mínima de %1 - The recipient address is not valid. Please recheck. La dirección del destinatario no es válida. Por favor, compruébela de nuevo. @@ -2794,15 +2869,26 @@ Aceptar comandos consola y JSON-RPC + + Error: A fatal internal error occurred, see debug.log for details + Un error interno fatal ocurrió, ver debug.log para detalles + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Comisión (en %s/KB) para agregar a las transacciones que envíe (por defecto: %s) + + + Pruning blockstore... + Poda blockstore ... + Run in the background as a daemon and accept commands Ejecutar en segundo plano como daemon y aceptar comandos - Use the test network - Usar la red de pruebas - + Unable to start HTTP server. See debug log for details. + No se ha podido comenzar el servidor HTTP. Ver debug log para detalles. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2824,14 +2910,6 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Ejecutar comando cuando una transacción del monedero cambia (%s en cmd se remplazará por TxID) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Maximo Comisión totales para usar en una sola transacción billetera; establecer esta demasiado bajo puede abortar transacciones grandes (por defecto: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Reducir los requerimientos de almacenamiento mediante la poda (borrado) bloquea viejos. Este modo desactiva el apoyo cartera y es incompatible con -txindex. Advertencia: Revertir esta configuración requiere volver a descargar toda la blockchain. (por defecto: 0 = desactivar bloques de poda, >%u = tamaño de destino en MiB de usar para los archivos de bloques) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Establecer el número de hilos (threads) de verificación de scripts (entre %u y %d, 0 = automático, <0 = dejar libres ese número de núcleos; predeterminado: %d) @@ -2852,10 +2930,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) ADVERTENCIA: comprueba tu conexión de red, %d bloques recibidos en las últimas %d horas (%d esperados) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Aviso: ¡-paytxfee tiene un valor muy alto! Esta es la comisión que pagará si envía una transacción. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Atención: ¡Parece que la red no está totalmente de acuerdo! Algunos mineros están presentando inconvenientes. @@ -2864,10 +2938,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Atención: ¡Parece que no estamos completamente de acuerdo con nuestros pares! Podría necesitar una actualización, u otros nodos podrían necesitarla. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Aviso: ¡Error al leer wallet.dat! Todas las claves se han leído correctamente, pero podrían faltar o ser incorrectos los datos de transacciones o las entradas de la libreta de direcciones. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Aviso: ¡Recuperados datos de wallet.dat corrupto! El wallet.dat original se ha guardado como wallet.{timestamp}.bak en %s; si hubiera errores en su saldo o transacciones, deberá restaurar una copia de seguridad. @@ -2877,17 +2947,13 @@ Poner en lista blanca a los equipos que se conecten desde la máscara de subred o dirección IP especificada. Se puede especificar múltiples veces. - (default: 1) - (predeterminado: 1) + -maxmempool must be at least %d MB + -maxmempool debe ser por lo menos de %d MB <category> can be: <category> puede ser: - - Attempt to recover private keys from a corrupt wallet.dat - Intento de recuperar claves privadas de un wallet.dat corrupto - Block creation options: Opciones de creación de bloques: @@ -2932,10 +2998,6 @@ Error opening block database Error al abrir base de datos de bloques. - - Error: A fatal internal error occured, see debug.log for details - Error: un error grave interno ocurrió, sea debug.log para más detalles. - Error: Disk space is low! Error: ¡Espacio en disco bajo! @@ -2944,10 +3006,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Ha fallado la escucha en todos los puertos. Use -listen=0 si desea esto. - - If <category> is not supplied, output all debugging information. - Si no se proporciona <category>, mostrar toda la depuración - Importing... Importando... @@ -3016,18 +3074,10 @@ You need to rebuild the database using -reindex to change -txindex Usted necesita reconstruir la base de datos utilizando -reindex para cambiar -txindex - - Imports blocks from external blk000??.dat file - Importa los bloques desde un archivo blk000??.dat externo - 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 Permitir conexiones JSON-RPC de origen especificado. Válido para son una sola IP (por ejemplo 1.2.3.4), una red/máscara de red (por ejemplo 1.2.3.4/255.255.255.0) o una red/CIDR (e.g. 1.2.3.4/24). Esta opción se puede especificar varias veces - - An error occurred while setting up the RPC address %s port %u for listening: %s - Ocurrió un error al configurar la dirección de RPC %s puerto %u para escuchar en: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Ligar a las direcciones especificadas y poner en lista blanca a los equipos conectados a ellas. Usar la notación para IPv6 [host]:puerto. @@ -3052,29 +3102,21 @@ Error: Listening for incoming connections failed (listen returned error %s) Error: la escucha para conexiones entrantes falló (la escucha regresó el error %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Error: Unsupported argumento -socks encontrados. SOCKS versión ajuste ya no es posible, sólo SOCKS5 proxies son compatibles. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Ejecutar un comando cuando se reciba una alerta importante o cuando veamos un fork demasiado largo (%s en cmd se reemplazará por el mensaje) - - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Tarifas (en BTC/Kb) más pequeños que esto se consideran cero cuota de reinstalación (por defecto: %s) - If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) Si el pago de comisión no está establecido, incluir la cuota suficiente para que las transacciones comiencen la confirmación en una media de n bloques ( por defecto :%u) - Maximum size of data in data carrier transactions we relay and mine (default: %u) - El tamaño máximo de los datos en las operaciones de transporte de datos que transmitimos y el mio (default: %u) + Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Cantidad no válida para -maxtxfee=<amount>: '%s' (debe ser por lo menos la cuota de comisión mínima de %s para prevenir transacciones atascadas) - Prune configured below the minimum of %d MB. Please use a higher number. - Pode configurado por debajo del mínimo de %d MB. Por favor, use un número más alto. + Maximum size of data in data carrier transactions we relay and mine (default: %u) + El tamaño máximo de los datos en las operaciones de transporte de datos que transmitimos y el mio (default: %u) Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) @@ -3100,38 +3142,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Este producto incluye software desarrollado por el OpenSSL Project para su uso en OpenSSL Toolkit <https://www.openssl.org/>, software de cifrado escrito por Eric Young y software UPnP escrito por Thomas Bernard. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - Para utilizar bitcoind, o la -opción servidor a bitcoin-qt, debes establecer una rpcpassword en el fichero de configuración: -%s -Se recomienda utilizar la siguiente contraseña aleatoria: -rpcuser=bitcoinrpc -rpcpassword=%s -(no es necesario que recuerdes esta contraseña) -El nombre de usuario y contraseña NO DEBEN ser la misma. -Si no existe el archivo, crearlo con los permisos de archivos de propietarios de -sólo lectura-. -También se recomienda establecer una notificación de alerta para ser notificado de problemas; -por ejemplo: alertnotify=echo %% s | correo -s "Alerta Bitcoin" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Advertencia: ¡-maxtxfee se establece muy alta! Esta gran tarifa podría ser pagada en una sola transacción . - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Aviso: ¡Comprueba la fecha y hora de tu ordenador y verifica si es correcta! Si no es correcta Bitcoin Core no funcionará adecuadamente. - 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 A los equipos en lista blanca no se les pueden prohibir los ataques DoS y sus transacciones siempre son retransmitidas, incluso si ya están en el mempool, es útil por ejemplo para un gateway. @@ -3153,17 +3163,17 @@ por ejemplo: alertnotify=echo %% s | correo -s "Alerta Bitcoin" admin@foo.com Activando la mejor cadena... - Can't run with a wallet in prune mode. - No se puede ejecutar con un monedero en modo recorte. + Attempt to recover private keys from a corrupt wallet.dat on startup + Intento de recuperar claves privadas de un wallet.dat corrupto + + + Automatically create Tor hidden service (default: %d) + Automáticamente crea el servicio Tor oculto (por defecto: %d) Cannot resolve -whitebind address: '%s' No se puede resolver -whitebind address: '%s' - - Choose data directory on startup (default: 0) - Elegir directorio de datos al iniciar (predeterminado: 0) - Connect through SOCKS5 proxy Conectar usando SOCKS5 proxy @@ -3172,10 +3182,6 @@ por ejemplo: alertnotify=echo %% s | correo -s "Alerta Bitcoin" admin@foo.com Copyright (C) 2009-%i The Bitcoin Core Developers Copyright (C) 2009-%i The Bitcoin Core Developers - - Could not parse -rpcbind value %s as network address - No se pudo analizar -rpcbind valor%s como dirección de red - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Error al cargar wallet.dat: El monedero requiere una versión más reciente de Bitcoin Core @@ -3185,12 +3191,8 @@ por ejemplo: alertnotify=echo %% s | correo -s "Alerta Bitcoin" admin@foo.com Error al leer la base de datos, cerrando. - Error: Unsupported argument -tor found, use -onion. - Error: Argumento encontrado -tor no soportado, utilice -onion - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Cuota (in BTC/kB) para añadir a las transacciones que envíes (por defecto: %s) + Imports blocks from external blk000??.dat file on startup + Importa los bloques desde un archivo externo blk000?.dat Information @@ -3232,18 +3234,10 @@ por ejemplo: alertnotify=echo %% s | correo -s "Alerta Bitcoin" admin@foo.com Node relay options: Opciones de nodos de retransmisión: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Opciones SSL de RPC: (véase la wiki de Bitcoin para las instrucciones de instalación de SSL) - RPC server options: Opciones de servidor RPC: - - RPC support for HTTP persistent connections (default: %d) - Soporte RPC para conexiones HTTP persistentes (por defecto: %d) - Rebuild block chain index from current blk000??.dat files on startup Reconstruir el índice de la cadena de bloques en el arranque desde los actuales ficheros blk000??.dat @@ -3252,6 +3246,10 @@ por ejemplo: alertnotify=echo %% s | correo -s "Alerta Bitcoin" admin@foo.com Receive and display P2P network alerts (default: %u) Recibir y mostrar alertas de red P2P (default: %u) + + Rescan the block chain for missing wallet transactions on startup + Rescanea la cadena de bloques para transacciones perdidas de la cartera + Send trace/debug info to console instead of debug.log file Enviar información de trazas/depuración a la consola en lugar de al archivo debug.log @@ -3260,22 +3258,10 @@ por ejemplo: alertnotify=echo %% s | correo -s "Alerta Bitcoin" admin@foo.com Send transactions as zero-fee transactions if possible (default: %u) Mandar transacciones como comisión-cero si es posible (por defecto: %u) - - Set SSL root certificates for payment request (default: -system-) - Establecer los certificados raíz SSL para solicitudes de pago (predeterminado: -system-) - - - Set language, for example "de_DE" (default: system locale) - Establecer el idioma, por ejemplo, "es_ES" (predeterminado: configuración regional del sistema) - Show all debugging options (usage: --help -help-debug) Muestra todas las opciones de depuración (uso: --help -help-debug) - - Show splash screen on startup (default: 1) - Mostrar pantalla de bienvenida en el inicio (predeterminado: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Reducir el archivo debug.log al iniciar el cliente (predeterminado: 1 sin -debug) @@ -3284,10 +3270,6 @@ por ejemplo: alertnotify=echo %% s | correo -s "Alerta Bitcoin" admin@foo.com Signing transaction failed Transacción falló - - Start minimized - Arrancar minimizado - The transaction amount is too small to pay the fee Cantidad de la transacción demasiado pequeña para pagar la comisión @@ -3312,17 +3294,13 @@ por ejemplo: alertnotify=echo %% s | correo -s "Alerta Bitcoin" admin@foo.com Transaction too large Transacción demasiado grande - - UI Options: - Opciones de interfaz de usuario - Unable to bind to %s on this computer (bind returned error %s) No es posible conectar con %s en este sistema (bind ha dado el error %s) - Use UPnP to map the listening port (default: 1 when listening) - Usar UPnP para asignar el puerto de escucha (predeterminado: 1 al escuchar) + Upgrade wallet to latest format on startup + Actualizar el monedero al último formato Username for JSON-RPC connections @@ -3337,22 +3315,10 @@ por ejemplo: alertnotify=echo %% s | correo -s "Alerta Bitcoin" admin@foo.com Warning Aviso - - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Advertencia: Argumento no soportado -benchmark ignored, use -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Aviso: Argumento no sportado -debugnet anticuado, utilice -debug=net. - Zapping all transactions from wallet... Eliminando todas las transacciones del monedero... - - on startup - al iniciar - wallet.dat corrupt, salvage failed wallet.dat corrupto. Ha fallado la recuperación. @@ -3366,19 +3332,6 @@ por ejemplo: alertnotify=echo %% s | correo -s "Alerta Bitcoin" admin@foo.com Execute command when the best block changes (%s in cmd is replaced by block hash) Ejecutar un comando cuando cambia el mejor bloque (%s en cmd se sustituye por el hash de bloque) - - Upgrade wallet to latest format - Actualizar el monedero al último formato - - - Rescan the block chain for missing wallet transactions - Volver a examinar la cadena de bloques en busca de transacciones del monedero perdidas - - - Use OpenSSL (https) for JSON-RPC connections - Usar OpenSSL (https) para las conexiones JSON-RPC - - This help message Este mensaje de ayuda @@ -3424,10 +3377,6 @@ por ejemplo: alertnotify=echo %% s | correo -s "Alerta Bitcoin" admin@foo.com (default: %s) (predeterminado: %s) - - Acceptable ciphers (default: %s) - Aceptar cifrado (por defecto: %s) - Always query for peer addresses via DNS lookup (default: %u) Siempre consultar direcciones de otros equipos por medio de DNS lookup (por defecto: %u) @@ -3488,14 +3437,6 @@ por ejemplo: alertnotify=echo %% s | correo -s "Alerta Bitcoin" admin@foo.com Relay non-P2SH multisig (default: %u) Relay non-P2SH multisig (default: %u) - - Server certificate file (default: %s) - Archivo de certificado del servidor (por defecto: %s) - - - Server private key (default: %s) - Llave privada del servidor (por defecto: %s) - Set key pool size to <n> (default: %u) Ajustar el número de claves en reserva <n> (predeterminado: %u) diff --git a/src/qt/locale/bitcoin_es_CL.ts b/src/qt/locale/bitcoin_es_CL.ts index c35acf2c6..e6d48a29f 100644 --- a/src/qt/locale/bitcoin_es_CL.ts +++ b/src/qt/locale/bitcoin_es_CL.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -164,6 +164,9 @@ La contraseña de billetera ha sido cambiada con éxito. + + BanTableModel + BitcoinGUI @@ -298,6 +301,10 @@ Bitcoin Core bitcoin core + + %1 and %2 + %1 y %2 + Error Error @@ -348,6 +355,10 @@ Amount: Cantidad: + + Priority: + prioridad: + Amount Cantidad @@ -502,6 +513,10 @@ &Network &Red + + W&allet + Cartera + Expert experto @@ -633,6 +648,10 @@ &Information &Información + + Debug window + Ventana Debug + General General @@ -681,6 +700,10 @@ ReceiveCoinsDialog + + &Amount: + Cantidad: + &Label: &Etiqueta: @@ -758,10 +781,22 @@ Send Coins Enviar monedas + + Insufficient funds! + Fondos insuficientes + Amount: Cantidad: + + Priority: + prioridad: + + + Transaction Fee: + Comisión transacción: + Send to multiple recipients at once Enviar a múltiples destinatarios @@ -845,6 +880,10 @@ Message: Mensaje: + + Pay To: + Pagar a: + ShutdownWindow @@ -899,6 +938,10 @@ Click "Sign Message" to generate signature Click en "Firmar Mensage" para conseguir firma + + The entered address is invalid. + La dirección introducida no es una valida. + Please check the address and try again. Por favor, revise la dirección Bitcoin e inténtelo denuevo @@ -1288,15 +1331,6 @@ Correr como demonio y acepta comandos - - Use the test network - Usa la red de pruebas - - - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Precaución: -paytxfee es muy alta. Esta es la comisión que pagarás si envias una transacción. - Connect only to the specified node(s) Conecta solo al nodo especificado @@ -1310,27 +1344,26 @@ Error: Disk space is low! Atención: Poco espacio en el disco duro - - Imports blocks from external blk000??.dat file - Importar bloques desde el archivo externo blk000??.dat - Information Información + + Invalid amount for -maxtxfee=<amount>: '%s' + Cantidad inválida para -maxtxfee=<amount>: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Cantidad inválida para -minrelaytxfee=<amount>: '%s' + + + Invalid amount for -mintxfee=<amount>: '%s' + Cantidad inválida para -mintxfee=<amount>: '%s' + Send trace/debug info to console instead of debug.log file Enviar informacion de seguimiento a la consola en vez del archivo debug.log - - Start minimized - Arranca minimizado - - - - Use UPnP to map the listening port (default: 1 when listening) - Intenta usar UPnP para mapear el puerto de escucha (default: 1 when listening) - Username for JSON-RPC connections Usuario para las conexiones JSON-RPC @@ -1347,20 +1380,6 @@ Password for JSON-RPC connections Contraseña para las conexiones JSON-RPC - - - - Upgrade wallet to latest format - Actualizar billetera al formato actual - - - Rescan the block chain for missing wallet transactions - Rescanea la cadena de bloques para transacciones perdidas de la cartera - - - - Use OpenSSL (https) for JSON-RPC connections - Usa OpenSSL (https) para las conexiones JSON-RPC @@ -1389,6 +1408,14 @@ Invalid -proxy address: '%s' Dirección -proxy invalida: '%s' + + Cannot resolve -bind address: '%s' + No se pudo resolver la dirección fija: '%s' + + + Cannot resolve -externalip address: '%s' + No se pudo resolver la dirección ip: '%s' + Invalid amount for -paytxfee=<amount>: '%s' Cantidad inválida para -paytxfee=<amount>: '%s' @@ -1409,6 +1436,14 @@ Loading wallet... Cargando cartera... + + Cannot downgrade wallet + No es posible desactualizar la billetera + + + Cannot write default address + No se pudo escribir la dirección por defecto + Rescanning... Rescaneando... diff --git a/src/qt/locale/bitcoin_es_DO.ts b/src/qt/locale/bitcoin_es_DO.ts index 607170298..0463c0f6e 100644 --- a/src/qt/locale/bitcoin_es_DO.ts +++ b/src/qt/locale/bitcoin_es_DO.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -200,6 +200,9 @@ Se ha cambiado correctamente la contraseña del monedero. + + BanTableModel + BitcoinGUI @@ -737,7 +740,7 @@ command-line options opciones de la línea de órdenes - + Intro @@ -826,6 +829,10 @@ &Network &Red + + W&allet + Monedero + Expert Experto @@ -1364,6 +1371,10 @@ Custom change address Dirección propia + + Transaction Fee: + Comisión de transacción: + Send to multiple recipients at once Enviar a múltiples destinatarios de una vez @@ -1428,10 +1439,6 @@ Copy change Copiar Cambio - - Total Amount %1 (= %2) - Cuantía Total %1 (=%2) - or o @@ -1519,6 +1526,10 @@ Remove this entry Eliminar esta transacción + + Message: + Mensaje: + Enter a label for this address to add it to the list of used addresses Introduce una etiqueta para esta dirección para añadirla a la lista de direcciones utilizadas @@ -2103,11 +2114,6 @@ Run in the background as a daemon and accept commands Ejecutar en segundo plano como daemon y aceptar comandos - - - - Use the test network - Usar la red de pruebas @@ -2126,10 +2132,6 @@ This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Esta es una versión de pre-prueba - utilícela bajo su propio riesgo. No la utilice para usos comerciales o de minería. - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Aviso: ¡-paytxfee tiene un valor muy alto! Esta es la comisión que pagará si envía una transacción. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Atención: ¡Parece que la red no está totalmente de acuerdo! Algunos mineros están presentando inconvenientes. @@ -2138,10 +2140,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Atención: ¡Parece que no estamos completamente de acuerdo con nuestros pares! Podría necesitar una actualización, u otros nodos podrían necesitarla. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Aviso: ¡Error al leer wallet.dat! Todas las claves se han leído correctamente, pero podrían faltar o ser incorrectos los datos de transacciones o las entradas de la libreta de direcciones. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Aviso: ¡Recuperados datos de wallet.dat corrupto! El wallet.dat original se ha guardado como wallet.{timestamp}.bak en %s; si hubiera errores en su saldo o transacciones, deberá restaurar una copia de seguridad. @@ -2150,10 +2148,6 @@ <category> can be: <category> puede ser: - - Attempt to recover private keys from a corrupt wallet.dat - Intento de recuperar claves privadas de un wallet.dat corrupto - Block creation options: Opciones de creación de bloques: @@ -2194,10 +2188,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Ha fallado la escucha en todos los puertos. Use -listen=0 si desea esto. - - If <category> is not supplied, output all debugging information. - Si no se proporciona <category>, mostrar toda la depuración - Incorrect or no genesis block found. Wrong datadir for network? Incorrecto o bloque de génesis no encontrado. Datadir equivocada para la red? @@ -2234,10 +2224,6 @@ You need to rebuild the database using -reindex to change -txindex Usted necesita reconstruir la base de datos utilizando -reindex para cambiar -txindex - - Imports blocks from external blk000??.dat file - Importa los bloques desde un archivo blk000??.dat externo - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Ejecutar un comando cuando se reciba una alerta importante o cuando veamos un fork demasiado largo (%s en cmd se reemplazará por el mensaje) @@ -2247,13 +2233,17 @@ Establecer tamaño máximo de las transacciones de alta prioridad/comisión baja en bytes (por defecto: %d) - Choose data directory on startup (default: 0) - Elegir directorio de datos al iniciar (predeterminado: 0) + Cannot resolve -whitebind address: '%s' + No se puede resolver la dirección de -whitebind: '%s' Information Información + + Invalid amount for -maxtxfee=<amount>: '%s' + Inválido por el monto -maxtxfee=<amount>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' Inválido por el monto -minrelaytxfee=<amount>: '%s' @@ -2262,10 +2252,6 @@ Invalid amount for -mintxfee=<amount>: '%s' Inválido por el monto -mintxfee=<amount>: '%s' - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Opciones RPC SSL: (Vea la Wiki de Bitcoin para las instrucciones de la configuración de SSL) - RPC server options: Opciones del sservidor RPC: @@ -2274,18 +2260,10 @@ Send trace/debug info to console instead of debug.log file Enviar información de trazas/depuración a la consola en lugar de al archivo debug.log - - Set language, for example "de_DE" (default: system locale) - Establecer el idioma, por ejemplo, "es_ES" (predeterminado: configuración regional del sistema) - Show all debugging options (usage: --help -help-debug) Mostrar todas las opciones de depuración (uso: --help -help-debug) - - Show splash screen on startup (default: 1) - Mostrar pantalla de bienvenida en el inicio (predeterminado: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Reducir el archivo debug.log al iniciar el cliente (predeterminado: 1 sin -debug) @@ -2294,10 +2272,6 @@ Signing transaction failed Transacción falló - - Start minimized - Arrancar minimizado - Transaction amount too small Monto de la transacción muy pequeño @@ -2310,10 +2284,6 @@ Transaction too large Transacción demasiado grande - - Use UPnP to map the listening port (default: 1 when listening) - Usar UPnP para asignar el puerto de escucha (predeterminado: 1 al escuchar) - Username for JSON-RPC connections Nombre de usuario para las conexiones JSON-RPC @@ -2323,10 +2293,6 @@ Warning Aviso - - on startup - al iniciar - wallet.dat corrupt, salvage failed wallet.dat corrupto. Ha fallado la recuperación. @@ -2340,19 +2306,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Ejecutar un comando cuando cambia el mejor bloque (%s en cmd se sustituye por el hash de bloque) - - Upgrade wallet to latest format - Actualizar el monedero al último formato - - - Rescan the block chain for missing wallet transactions - Volver a examinar la cadena de bloques en busca de transacciones del monedero perdidas - - - Use OpenSSL (https) for JSON-RPC connections - Usar OpenSSL (https) para las conexiones JSON-RPC - - This help message Este mensaje de ayuda diff --git a/src/qt/locale/bitcoin_es_ES.ts b/src/qt/locale/bitcoin_es_ES.ts new file mode 100644 index 000000000..bdbfed4ec --- /dev/null +++ b/src/qt/locale/bitcoin_es_ES.ts @@ -0,0 +1,481 @@ + + + AddressBookPage + + Right-click to edit address or label + Haz clic derecho para editar la dirección o la etiqueta + + + Create a new address + Crea una nueva direccióon + + + &New + &Nuevo + + + Copy the currently selected address to the system clipboard + Copia la direccón seleccionada al portapapeles del sistema + + + &Copy + &Copiar + + + C&lose + C&errar + + + &Copy Address + &Copiar Direccón + + + Delete the currently selected address from the list + Elimina la dirección seleccionada de la lista + + + Export the data in the current tab to a file + Exporta los datos de la pestaña actual a un archivo + + + &Export + &Exportar + + + &Delete + &Eliminar + + + Choose the address to send coins to + Elige la dirección a la que enviar las monedas + + + Choose the address to receive coins with + Elige la direccón con la que recibir monedas + + + C&hoose + E&legir + + + Sending addresses + Enviando direcciones + + + Receiving addresses + Recibiendo direcciones + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Estas son tus direcciones de Bitcoin para enviar pagos. Comprueba siempre la cantidad y la dirección receptora antes de enviar monedas. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Estas son tus direcciones de Bitcoin para recibir pagos. Se recomienda usar una nueva dirección receptora para cada transacción + + + Copy &Label + Copiar &Etiqueta + + + &Edit + &Editar + + + Export Address List + Exportar Lista de Direcciones + + + Comma separated file (*.csv) + Archivo separado por comas (*.csv) + + + Exporting Failed + Exportacón Fallida + + + There was an error trying to save the address list to %1. Please try again. + Ha ocurrido un error intentando guardar la lista de direcciones en %1. Por favor intentalo de nuevo. + + + + AddressTableModel + + Label + Etiqueta + + + Address + Dirección + + + (no label) + (sin etiqueta) + + + + AskPassphraseDialog + + Passphrase Dialog + Dialogo de Contraseña + + + Enter passphrase + Introduzca la contraseña + + + New passphrase + Nueva contraseña + + + Repeat new passphrase + Repite la nueva contraseña + + + Encrypt wallet + Encriptar cartera + + + This operation needs your wallet passphrase to unlock the wallet. + Esta operacón necesita tu contraseña de la cartera para desbloquear la cartera. + + + Unlock wallet + Desbloquear cartera + + + This operation needs your wallet passphrase to decrypt the wallet. + Esta operación requiere tu contraseña de la cartera para desencriptar la cartera. + + + Decrypt wallet + Desencriptar cartera + + + Change passphrase + Cambiar contraseña + + + Confirm wallet encryption + Confirmar encriptación de la cartera + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Advertencia: Si encriptas tu cartera y pierdes tu contraseña, <b>PERDERÁS TODOS TUS BITCOINS</B> + + + Are you sure you wish to encrypt your wallet? + Estás seguro ue deseas encriptar tu cartera? + + + Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + Bitcoin Core se cerrará ahora para finalizar el proceso de encriptación. Recuerda que encriptar tu cartera no protege completamente tus bitcoins de ser robados por malware infectando tu ordenador. + + + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + IMPORTANTE: Cualquier copia de seguridad anterior del archivo de tu cartera debería ser remplazado con el nuevo archivo encriptado. Por motivos de seguridad, las copias de seguridad anteriores de la cartera desencriptada quedaran inusables tan pronto como empieces a usar la nueva cartera encriptada. + + + Warning: The Caps Lock key is on! + Advertencia: La Tecla de Bloqueo de Mayusculas esta activada! + + + Wallet encrypted + Cartera encriptada + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + Introduzca la nueva contraseña de la cartera. <br/>Por favor utilice una contraseña de <b>diez o mas caracteres aleatorios</b>, o <b>ocho o mas palabras</b>. + + + Enter the old passphrase and new passphrase to the wallet. + Introduzca la antigua contraseña y la nueva contraseña en la cartera. + + + Wallet encryption failed + Encriptación de la cartera fallida + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + La encriptación de la cartera ha fallado debido a un error interno. Tu cartera no ha sido encriptada. + + + The supplied passphrases do not match. + Las contraseñas proporcianadas no se corresponden. + + + Wallet unlock failed + Desbloqueo de la cartera fallido + + + The passphrase entered for the wallet decryption was incorrect. + La contraseña introducida para desencriptar la cartera es incorrecta. + + + Wallet decryption failed + Desencriptación de la cartera fallida + + + Wallet passphrase was successfully changed. + Contraseña de la cartera cambiada correctamente + + + + BanTableModel + + + BitcoinGUI + + Sign &message... + Firmar &mensaje... + + + Synchronizing with network... + Sincronizando con la red... + + + &Overview + &Vista general + + + Node + Nodo + + + Show general overview of wallet + Mostrar vista general de la cartera + + + &Transactions + &Transacciones + + + Browse transaction history + Navegar historial de transacciones + + + E&xit + S&alir + + + Quit application + Salir de la aplicación + + + About &Qt + Acerca de &Qt + + + Show information about Qt + Muestra información acerca de Qt + + + &Options... + &Opciones... + + + &Encrypt Wallet... + &Encriptar Cartera... + + + &Backup Wallet... + &Hacer copia de seguridad de la cartera... + + + &Change Passphrase... + &Cambiar contraseña... + + + &Sending addresses... + &Enviando direcciones... + + + &Receiving addresses... + &Recibiendo direcciones.. + + + Open &URI... + Abrir &URI... + + + Bitcoin Core client + Cliente Bitcoin Core + + + Importing blocks from disk... + Importando bloques desde disco... + + + Reindexing blocks on disk... + Reindexando bloques en el disco... + + + Send coins to a Bitcoin address + Envia monedas a una dirección Bitcoin + + + Backup wallet to another location + Crea una copia de seguridad de tu cartera en otra ubicación + + + + ClientModel + + + CoinControlDialog + + (no label) + (sin etiqueta) + + + + EditAddressDialog + + &Label + Etiqueta + + + &Address + Dirección + + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + Copy &Address + &Copiar Direccón + + + Address + Dirección + + + Label + Etiqueta + + + + RecentRequestsTableModel + + Label + Etiqueta + + + (no label) + (sin etiqueta) + + + + SendCoinsDialog + + (no label) + (sin etiqueta) + + + + SendCoinsEntry + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + Label + Etiqueta + + + + TransactionView + + Exporting Failed + Exportacón Fallida + + + Comma separated file (*.csv) + Archivo separado por comas (*.csv) + + + Label + Etiqueta + + + Address + Dirección + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + &Export + &Exportar + + + Export the data in the current tab to a file + Exporta los datos de la pestaña actual a un archivo + + + + bitcoin-core + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_es_MX.ts b/src/qt/locale/bitcoin_es_MX.ts index 258308598..fa2b3c062 100644 --- a/src/qt/locale/bitcoin_es_MX.ts +++ b/src/qt/locale/bitcoin_es_MX.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -11,7 +11,7 @@ Copy the currently selected address to the system clipboard - Copiar el domicilio seleccionado al portapapeles del sistema + Copiar la dirección seleccionada al portapapeles del sistema &Copy @@ -83,7 +83,7 @@ Comma separated file (*.csv) - Arhchivo separado por comas (*.CSV) + Archivo separado por comas (*.CSV) Exporting Failed @@ -98,7 +98,7 @@ Address - Domicilio + Dirección (no label) @@ -165,7 +165,7 @@ Wallet encryption failed - Encriptación de la cartera fallida + La encriptación de la cartera fallo Wallet encryption failed due to an internal error. Your wallet was not encrypted. @@ -181,7 +181,7 @@ The passphrase entered for the wallet decryption was incorrect. - La contraseña ingresada para la desencriptación de la cartera es incorrecto + La contraseña ingresada para la desencriptación de la cartera es incorrecta Wallet decryption failed @@ -192,11 +192,14 @@ La contraseña de la cartera ha sido exitosamente cambiada. + + BanTableModel + BitcoinGUI Sign &message... - Sign &mensaje + Firmar &mensaje Synchronizing with network... @@ -256,16 +259,20 @@ &Sending addresses... - &Enviando direcciones... + Direcciones de &envío... &Receiving addresses... - &Recibiendo direcciones... + Direcciones de &recepción... Open &URI... Abrir &URL... + + Bitcoin Core client + cliente Bitcoin Core + Importing blocks from disk... Importando bloques desde el disco... @@ -292,12 +299,28 @@ Open debugging and diagnostic console - Abrir la consola de depuración y disgnostico + Abrir consola de depuración y diagnostico &Verify message... &Verificar mensaje... + + Bitcoin + Bitcoin + + + Wallet + Cartera + + + &Send + &Enviar + + + &Receive + &Recibir + &File &Archivo @@ -318,6 +341,10 @@ Bitcoin Core nucleo Bitcoin + + &About Bitcoin Core + Acerca de Bitcoin Core + &Command-line options opciones de la &Linea de comandos @@ -332,7 +359,7 @@ Catching up... - Resiviendo... + Recibiendo... Sent transaction @@ -384,41 +411,45 @@ Confirmed Confirmado + + Priority + Prioridad + Copy address Copiar dirección Copy label - Copiar capa + Copiar etiqueta Copy amount - copiar monto + Copiar monto Copy quantity - copiar cantidad + Copiar cantidad Copy fee - copiar cuota + Copiar cuota Copy after fee - copiar despues de cuota + Copiar después de cuota Copy bytes - copiar bytes + Copiar bytes Copy priority - copiar prioridad + Copiar prioridad Copy change - copiar cambio + Copiar cambio (no label) @@ -441,23 +472,23 @@ New receiving address - Nueva dirección de entregas + Nueva dirección de recepción New sending address - Nueva dirección de entregas + Nueva dirección de envío Edit receiving address - Editar dirección de entregas + Editar dirección de recepción Edit sending address - Editar dirección de envios + Editar dirección de envío The entered address "%1" is already in the address book. - El domicilio ingresado "%1" ya existe en la libreta de direcciones + La dirección ingresada "%1" ya existe en la libreta de direcciones Could not unlock wallet. @@ -479,7 +510,7 @@ version - Versión + versión (%1-bit) @@ -489,6 +520,10 @@ About Bitcoin Core Acerca de Bitcoin Core + + Command-line options + opciones de la Linea de comandos + Usage: Uso: @@ -497,7 +532,7 @@ command-line options Opciones de comando de lineas - + Intro @@ -518,6 +553,10 @@ Active command-line options that override above options: Activar las opciones de linea de comando que sobre escriben las siguientes opciones: + + W&allet + Cartera + OverviewPage @@ -544,13 +583,25 @@ RPCConsole + + Debug window + Depurar ventana + ReceiveCoinsDialog + + &Amount: + Monto: + &Label: &Etiqueta + + &Message: + Mensaje: + An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network. Mensaje opcional para agregar a la solicitud de pago, el cual será mostrado cuando la solicitud este abierta. Nota: El mensaje no se manda con el pago a travéz de la red de Bitcoin. @@ -565,18 +616,22 @@ Copy label - Copiar capa + Copiar etiqueta Copy amount - copiar monto + Copiar monto ReceiveRequestDialog + + Copy &Address + &Copiar dirección + Address - Domicilio + Dirección Amount @@ -586,6 +641,10 @@ Label Etiqueta + + Message + Mensaje + RecentRequestsTableModel @@ -597,6 +656,10 @@ Label Etiqueta + + Message + Mensaje + Amount Monto @@ -610,7 +673,7 @@ SendCoinsDialog Send Coins - Mandar monedas + Enviar monedas Bytes: @@ -628,6 +691,10 @@ Fee: Cuota: + + fast + rápido + Send to multiple recipients at once Enviar a múltiples receptores a la vez @@ -642,39 +709,35 @@ Confirm send coins - Confirme para mandar monedas + Confirme para enviar monedas Copy quantity - copiar cantidad + Copiar cantidad Copy amount - copiar monto + Copiar monto Copy fee - copiar cuota + Copiar cuota Copy after fee - copiar despues de cuota + Copiar después de cuota Copy bytes - copiar bytes + Copiar bytes Copy priority - copiar prioridad + Copiar prioridad Copy change - copiar cambio - - - Total Amount %1 (= %2) - Monto total %1(=%2) + Copiar cambio or @@ -686,7 +749,7 @@ Transaction creation failed! - ¡La creación de transacion falló! + ¡La creación de la transación falló! The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -777,12 +840,16 @@ Alt+P Alt+P + + Signature + Firma + SplashScreen Bitcoin Core - nucleo Bitcoin + Bitcoin Core The Bitcoin Core developers @@ -806,14 +873,42 @@ %1 confirmations %1 confirmaciones + + Status + Estado + Date Fecha + + From + De + + + To + Para + + + label + etiqueta + + + Message + Mensaje + + + Comment + Comentario + Transaction ID ID + + Transaction + Transacción + Amount Monto @@ -870,7 +965,7 @@ Received with - Recivido con + Recibido con Sent to @@ -929,7 +1024,7 @@ Received with - Recivido con + Recibido con Sent to @@ -987,6 +1082,10 @@ Exporting Successful Exportacion satisfactoria + + The transaction history was successfully saved to %1. + el historial de transaciones ha sido guardado exitosamente en %1 + Comma separated file (*.csv) Arhchivo separado por comas (*.CSV) @@ -1051,33 +1150,33 @@ There was an error trying to save the wallet data to %1. Ocurrio un error tratando de guardar la información de la cartera %1 + + The wallet data was successfully saved to %1. + La información de la cartera fué guardada exitosamente a %1 + bitcoin-core + + Options: + Opciones: + <category> can be: <categoria> puede ser: + + Verifying blocks... + Verificando bloques... + + + Verifying wallet... + Verificando cartera... + Wallet options: Opciones de cartera: - - Choose data directory on startup (default: 0) - Escojer el directorio de información al iniciar (por defecto : 0) - - - Set language, for example "de_DE" (default: system locale) - Definir idioma, por ejemplo "de_DE" (por defecto: Sistema local) - - - Show splash screen on startup (default: 1) - Mostrar pantalla de arraque al iniciar (por defecto: 1) - - - Start minimized - Iniciar minimizado - Loading addresses... Cargando direcciones... diff --git a/src/qt/locale/bitcoin_es_UY.ts b/src/qt/locale/bitcoin_es_UY.ts index bb9946661..32d433d6e 100644 --- a/src/qt/locale/bitcoin_es_UY.ts +++ b/src/qt/locale/bitcoin_es_UY.ts @@ -1,22 +1,71 @@ - + AddressBookPage + + Right-click to edit address or label + Clic derecho para editar dirección o etiqueta + Create a new address Crear una nueva dirección + + &New + Nuevo + Copy the currently selected address to the system clipboard Copia la dirección seleccionada al portapapeles del sistema + + &Copy + Copiar + + + C&lose + Cerrar + + + &Copy Address + Copiar Dirección + + + &Export + Exportar + &Delete &Borrar + + Choose the address to send coins to + Elige una dirección donde enviar monedas a + + + Sending addresses + Enviando direcciones + + + Receiving addresses + Recibiendo direcciones + + + + &Edit + Editar + + + Export Address List + Exportar Lista de Direcciones + Comma separated file (*.csv) Archivos separados por coma (*.csv) + + Exporting Failed + Exportación fallida + AddressTableModel @@ -75,6 +124,14 @@ Confirm wallet encryption Confirme el cifrado del monedero + + Are you sure you wish to encrypt your wallet? + Estas seguro que deseas encriptar tu billetera? + + + Warning: The Caps Lock key is on! + Atención: la tecla Mayusculas esta activa! + Wallet encrypted Monedero cifrado @@ -104,6 +161,9 @@ Fallo en el descifrado del monedero + + BanTableModel + BitcoinGUI @@ -126,18 +186,58 @@ Browse transaction history Buscar en el historial de transacciones + + E&xit + Salida + Quit application Salir de la aplicacion + + Show information about Qt + Mostrar informacioón sobre + &Options... &Opciones... + + &Backup Wallet... + Respaldar Billetera + + + &Change Passphrase... + Cambiar contraseña + + + &Sending addresses... + Enviando direcciones + + + &Receiving addresses... + Recibiendo direcciones + + + Send coins to a Bitcoin address + Enviar monedas a una dirección BItCoin + Change the passphrase used for wallet encryption Cambie la clave utilizada para el cifrado del monedero + + Bitcoin + Bitcoin + + + Wallet + Billetera + + + &Show / Hide + Mostrar / Ocultar + &File &Archivo @@ -154,6 +254,18 @@ Tabs toolbar Barra de herramientas + + Error + Error + + + Warning + Alerta + + + Information + Información + Up to date A la fecha @@ -162,6 +274,17 @@ Catching up... Ponerse al dia... + + Type: %1 + + Tipo: %1 + + + + Address: %1 + + Dirección: %1 + Sent transaction Transaccion enviada @@ -184,10 +307,38 @@ CoinControlDialog + + Quantity: + Cantidad: + + + Bytes: + Bytes: + + + Amount: + AMonto: + + + Priority: + Prioridad: + + + Change: + Cambio: + Date Fecha + + Confirmed + Confirmado + + + Priority + Prioridad + (no label) (Sin etiqueta) @@ -223,6 +374,10 @@ Edit sending address Editar dirección de envío + + The entered address "%1" is already in the address book. + La dirección introducida "%1" ya está en la libreta de direcciones. + Could not unlock wallet. No se puede abrir el monedero. @@ -240,6 +395,10 @@ Intro + + Error + Error + OpenURIDialog @@ -250,6 +409,10 @@ Options Opciones + + W&allet + Billetera + OverviewPage @@ -272,6 +435,10 @@ RPCConsole + + &Information + Información + ReceiveCoinsDialog @@ -282,6 +449,10 @@ ReceiveRequestDialog + + Copy &Address + Copiar Dirección + Address Direccion @@ -312,6 +483,26 @@ Send Coins Enviar monedas + + Quantity: + Cantidad: + + + Bytes: + Bytes: + + + Amount: + AMonto: + + + Priority: + Prioridad: + + + Change: + Cambio: + Send to multiple recipients at once Enviar a varios destinatarios a la vez @@ -367,6 +558,10 @@ Alt+P Alt+P + + Pay To: + Pagar A: + ShutdownWindow @@ -406,6 +601,10 @@ Date Fecha + + Transaction + Transaccion + unknown desconocido @@ -431,10 +630,18 @@ TransactionView + + Exporting Failed + Exportación fallida + Comma separated file (*.csv) Archivos separados por coma (*.csv) + + Confirmed + Confirmado + Date Fecha @@ -463,8 +670,28 @@ WalletView + + &Export + Exportar + bitcoin-core - + + Options: + Opciones: + + + Information + Información + + + Warning + Alerta + + + Error + Error + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_es_VE.ts b/src/qt/locale/bitcoin_es_VE.ts new file mode 100644 index 000000000..582e72884 --- /dev/null +++ b/src/qt/locale/bitcoin_es_VE.ts @@ -0,0 +1,1133 @@ + + + AddressBookPage + + Right-click to edit address or label + Click derecho para editar la dirección o etiqueta + + + Create a new address + Crear una nueva dirección + + + &New + &Nuevo + + + Copy the currently selected address to the system clipboard + Copie las direcciones seleccionadas actualmente al portapapeles del sistema + + + &Copy + &Copiar + + + &Copy Address + &Copiar Dirección + + + Delete the currently selected address from the list + Borrar las direcciones seleccionadas recientemente de la lista + + + Export the data in the current tab to a file + Exportar los datos en la pestaña actual a un archivo + + + &Export + &Exportar + + + &Delete + &Borrar + + + Choose the address to send coins to + Elige la dirección para enviar monedas + + + Choose the address to receive coins with + Elige la dirección para recibir monedas + + + Sending addresses + Envío de direcciones + + + Receiving addresses + Recepción de direcciones + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Estas son tus direcciones Bitcoin para realizar pagos. Siempre checa el monto y la dirección de recepción antes de enviar monedas. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Estas son tus direcciones Bitcoin para recibir pagos. Es recomendable usar una nueva dirección para cada transacción. + + + Copy &Label + Copiar &Etiqueta + + + &Edit + &Editar + + + Export Address List + Exportar lista de direcciones + + + Comma separated file (*.csv) + Archivo separado por comas (*.csv) + + + Exporting Failed + Exportación fallida + + + There was an error trying to save the address list to %1. Please try again. + Hubo un error intentando guardar la lista de direcciones al %1. Por favor intente nuevamente. + + + + AddressTableModel + + Label + Etiqueta + + + Address + Dirección + + + (no label) + (sin etiqueta) + + + + AskPassphraseDialog + + Passphrase Dialog + Diálogo contraseña + + + Enter passphrase + Ingresa frase de contraseña + + + New passphrase + Nueva frase de contraseña + + + Repeat new passphrase + Repetir nueva frase de contraseña + + + Encrypt wallet + Encriptar billetera + + + This operation needs your wallet passphrase to unlock the wallet. + Esta operación necesita tu frase de contraseña de la billetera para desbloquearla. + + + Unlock wallet + Desbloquear billetera + + + This operation needs your wallet passphrase to decrypt the wallet. + Esta operacción necesita tu frase de contraseña para desepcriptar la billetera + + + Decrypt wallet + Desencriptar billetera + + + Change passphrase + Cambiar frase secreta + + + Confirm wallet encryption + Confirmar encriptación de billetera + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Aviso: Si encriptas tu billetera y pierdes tu frase secreta, ¡PERDERÁS TODOS TUS BITCOINS! + + + Are you sure you wish to encrypt your wallet? + ¿Está seguro que desea encriptar su billetera? + + + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + IMPORTANTE: Algunas copias de seguridad que hayas hecho de tu archivo de billetera deberían ser reemplazadas con la billetera encriptada generada recientemente. Por razones de seguridad, las copias de seguridad previas del archivo de billetera sin cifrar serán inútiles tan pronto uses la nueva billetera encriptada. + + + Warning: The Caps Lock key is on! + Aviso: El bloqueo de mayúsculas está activado. + + + Wallet encrypted + Billetera encriptada + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + Introduce la nueva frase secreta a la billetera. Por favor use una frase secreta de diez o más caracteres aleatorios, u ocho o más palabras. + + + Wallet encryption failed + Encriptación de billetera fallida + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Encriptación de billetera fallida debido a un error interno. Tu billetera no fue encriptada. + + + The supplied passphrases do not match. + Las frases secretas introducidas no concuerdan. + + + Wallet unlock failed + Desbloqueo de billetera fallido + + + The passphrase entered for the wallet decryption was incorrect. + La frase secreta introducida para la desencriptación de la billetera fué incorrecta. + + + Wallet decryption failed + Desencriptación de billetera fallida + + + Wallet passphrase was successfully changed. + La frase secreta de la billetera fué cambiada exitosamente. + + + + BanTableModel + + + BitcoinGUI + + Sign &message... + Firmar &mensaje... + + + Synchronizing with network... + Sincronizando con la red... + + + Node + Nodo + + + Show general overview of wallet + Mostrar visión general de la billetera + + + &Transactions + &Transacciones + + + Browse transaction history + Buscar historial de transacciones + + + Quit application + Quitar aplicación + + + &Receiving addresses... + Recepción de direcciones + + + Bitcoin Core client + Cliente Bitcoin Core + + + Importing blocks from disk... + Importando bloques desde el disco... + + + Reindexing blocks on disk... + Reindexando bloques en el disco... + + + Send coins to a Bitcoin address + Enviar monedas a una dirección Bitcoin + + + Backup wallet to another location + Respaldar billetera en otra ubicación + + + Change the passphrase used for wallet encryption + Cambiar frase secreta usada para la encriptación de la billetera + + + Open debugging and diagnostic console + Abre la consola de depuración y diágnostico + + + Bitcoin + Bitcoin + + + Wallet + Billetera + + + &Send + &Enviar + + + &Receive + &Recibir + + + Show information about Bitcoin Core + Mostrar información acerca de Bitcoin Core + + + &Show / Hide + &Mostar / Ocultar + + + Show or hide the main Window + Mostar u ocultar la ventana principal + + + Encrypt the private keys that belong to your wallet + Encriptar las llaves privadas que pertenecen a tu billetera + + + Sign messages with your Bitcoin addresses to prove you own them + Firma mensajes con tus direcciones Bitcoin para probar que eres dueño de ellas + + + Verify messages to ensure they were signed with specified Bitcoin addresses + Verificar mensajes para asegurar que estaban firmados con direcciones Bitcoin especificas + + + &File + &Archivo + + + &Settings + &Configuración + + + Bitcoin Core + Bitcoin Core + + + &About Bitcoin Core + Acerca de Bitcoin Core + + + &Command-line options + Opciones de línea de comandos + + + %1 and %2 + %1 y %2 + + + %1 behind + %1 detrás + + + Last received block was generated %1 ago. + El último bloque recibido fue generado hace %1 hora(s). + + + Transactions after this will not yet be visible. + Transacciones después de esta no serán visibles todavía. + + + Error + Error + + + Warning + Advertencia + + + Information + Información + + + Up to date + Al día + + + Catching up... + Alcanzando... + + + Sent transaction + Transacción enviada + + + Incoming transaction + Transacción entrante + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + La billetera está encriptada y desbloqueada recientemente + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + La billetera está encriptada y bloqueada recientemente + + + + ClientModel + + Network Alert + Alerta de red + + + + CoinControlDialog + + Coin Selection + Selección de moneda + + + Quantity: + Cantidad: + + + Bytes: + Bytes: + + + Amount: + Monto: + + + Priority: + Prioridad: + + + Fee: + Comisión: + + + Dust: + Polvo: + + + Change: + Cambio: + + + (un)select all + (de)seleccionar todo + + + Tree mode + Modo de árbol + + + List mode + Modo de lista + + + Amount + Monto + + + Received with label + Recibido con etiqueta + + + Received with address + Recibido con dirección + + + Date + Fecha + + + Confirmations + Confirmaciones + + + Confirmed + Confirmado + + + Priority + Prioridad + + + Copy address + Copiar dirección + + + Copy label + Copiar etiqueta + + + Copy amount + Copiar monto + + + Copy transaction ID + Copiar ID de la transacción + + + Lock unspent + Bloqueo no gastado + + + Unlock unspent + Desbloqueo no gastado + + + Copy quantity + Copiar cantidad + + + Copy fee + Copiar comisión + + + Copy bytes + Copiar bytes + + + Copy priority + Copiar prioridad + + + Copy dust + Copiar dust + + + Copy change + Copiar cambio + + + highest + Más alto + + + higher + superior + + + high + alto + + + medium-high + medio-alto + + + medium + medio + + + low-medium + bajo-medio + + + low + bajo + + + lower + inferior + + + lowest + más bajo + + + (%1 locked) + (%1 bloqueado) + + + none + ninguno + + + Can vary +/- %1 satoshi(s) per input. + Puede variar +/- %1 satoshi(s) por entrada. + + + yes + si + + + no + no + + + This means a fee of at least %1 per kB is required. + Esto significa que se requiere al menos de una comisión de %1 por kB + + + Can vary +/- 1 byte per input. + Puede variar +/- 1 byte por entrada. + + + Transactions with higher priority are more likely to get included into a block. + Transacciones con mayor prioridad son más probables de ser incluidas en un bloque. + + + (no label) + (sin etiqueta) + + + change from %1 (%2) + Cambio desde %1 (%2) + + + (change) + (cambio) + + + + EditAddressDialog + + Edit Address + Editar dirección + + + &Label + &Etiqueta + + + The label associated with this address list entry + La etiqueta asociada con esta entrada de la lista de direcciones + + + The address associated with this address list entry. This can only be modified for sending addresses. + La dirección asociada con esta entrada de la lista de direcciones. Esta puede ser modificada solo para el envío de direcciones. + + + &Address + &Dirección + + + New receiving address + Nueva dirección de recibo + + + New sending address + Nueva dirección de envío + + + Edit receiving address + Editar dirección de envío + + + Edit sending address + Editar dirección de envío + + + The entered address "%1" is already in the address book. + La dirección introducida "%1" ya está en el libro de direcciones. + + + The entered address "%1" is not a valid Bitcoin address. + La dirección introducida "%1" no es una dirección Bitcoin válida. + + + Could not unlock wallet. + No se pudo desbloquear la billetera. + + + New key generation failed. + Creación de la nueva llave fallida + + + + FreespaceChecker + + A new data directory will be created. + Un nuevo directorio de datos será creado. + + + name + nombre + + + Directory already exists. Add %1 if you intend to create a new directory here. + El directorio ya existe. Agrega %1 si tiene la intención de crear un nuevo directorio aquí. + + + Path already exists, and is not a directory. + La ruta ya existe, y no es un directorio. + + + Cannot create data directory here. + No puede crear directorio de datos aquí. + + + + HelpMessageDialog + + Bitcoin Core + Bitcoin Core + + + version + versión + + + (%1-bit) + (%1-bit) + + + About Bitcoin Core + Acerca de Bitcoin Core + + + Command-line options + Opciones de línea de comandos + + + Usage: + Uso: + + + command-line options + opciones de línea de comandos + + + + Intro + + Bitcoin Core will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. + Bitcoin Core descargará y almacenará una copia de la cadena de bloques Bitcoin. Al menos %1GB de datos serán almacenados en este directorio, y crecerá con el tiempo. La billetera será también almacenada en este directorio. + + + Use the default data directory + Usar el directorio de datos por defecto + + + Use a custom data directory: + Usa un directorio de datos personalizado: + + + Bitcoin Core + Bitcoin Core + + + Error: Specified data directory "%1" cannot be created. + Error: Directorio de datos especificado "%1" no puede ser creado. + + + Error + Error + + + + OpenURIDialog + + Open URI + Abrir URI + + + Open payment request from URI or file + Abrir solicitud de pago desde URI o archivo + + + URI: + URI: + + + Select payment request file + Seleccionar archivo de solicitud de pago + + + Select payment request file to open + Seleccionar archivo de solicitud de pago para abrir + + + + OptionsDialog + + Options + Opciones + + + &Main + &Main + + + W&allet + Billetera + + + none + ninguno + + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + Amount + Monto + + + + QRImageWidget + + + RPCConsole + + &Information + Información + + + + ReceiveCoinsDialog + + &Amount: + Monto: + + + &Label: + &Etiqueta: + + + Copy label + Copiar etiqueta + + + Copy amount + Copiar monto + + + + ReceiveRequestDialog + + Copy &Address + &Copiar Dirección + + + Address + Dirección + + + Amount + Monto + + + Label + Etiqueta + + + + RecentRequestsTableModel + + Date + Fecha + + + Label + Etiqueta + + + Amount + Monto + + + (no label) + (sin etiqueta) + + + + SendCoinsDialog + + Quantity: + Cantidad: + + + Bytes: + Bytes: + + + Amount: + Monto: + + + Priority: + Prioridad: + + + Fee: + Comisión: + + + Change: + Cambio: + + + Dust: + Polvo: + + + Copy quantity + Copiar cantidad + + + Copy amount + Copiar monto + + + Copy fee + Copiar comisión + + + Copy bytes + Copiar bytes + + + Copy priority + Copiar prioridad + + + Copy change + Copiar cambio + + + (no label) + (sin etiqueta) + + + Copy dust + Copiar dust + + + + SendCoinsEntry + + A&mount: + Monto: + + + &Label: + &Etiqueta: + + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + Bitcoin Core + Bitcoin Core + + + + TrafficGraphWidget + + + TransactionDesc + + Date + Fecha + + + Transaction + Transacción + + + Amount + Monto + + + + TransactionDescDialog + + + TransactionTableModel + + Date + Fecha + + + Label + Etiqueta + + + + TransactionView + + Copy address + Copiar dirección + + + Copy label + Copiar etiqueta + + + Copy amount + Copiar monto + + + Copy transaction ID + Copiar ID de la transacción + + + Exporting Failed + Exportación fallida + + + Comma separated file (*.csv) + Archivo separado por comas (*.csv) + + + Confirmed + Confirmado + + + Date + Fecha + + + Label + Etiqueta + + + Address + Dirección + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + &Export + &Exportar + + + Export the data in the current tab to a file + Exportar los datos en la pestaña actual a un archivo + + + Backup Failed + Copia de seguridad fallida + + + There was an error trying to save the wallet data to %1. + Hubo un error intentando guardar los datos de la billetera al %1 + + + The wallet data was successfully saved to %1. + Los datos de la billetera fueron guardados exitosamente al %1 + + + Backup Successful + Copia de seguridad completada + + + + bitcoin-core + + Options: + Opciones: + + + Specify data directory + Especifique directorio de datos + + + Connect to a node to retrieve peer addresses, and disconnect + Conecte un nodo para recuperar direcciones pares, y desconecte + + + Specify your own public address + Especifique su propia dirección pública + + + Accept command line and JSON-RPC commands + Aceptar linea de comando y comandos JSON-RPC + + + Run in the background as a daemon and accept commands + Correr en segundo plano como daemon y aceptar comandos + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Enlazar dirección dada y siempre escuchar en ella. Usar [host]:port notación para IPv6 + + + Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup + Borrar todas las transacciones de la billetera y solo recuperar aquellas partes de la cadena de bloques a través de -rescan en el inicio del sistema. + + + Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. + Distribuido bajo la licensia de software MIT, ver el archivo adjunto COPYING o <http://www.opensource.org/licenses/mit-license.php>. + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Ejecutar comando cuando una transacción de la billetera cambia (%s en cmd es reemplazado por TxID) + + + Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) + Fija el número de verificación de hilos de script (%u a %d, 0 = auto, <0 = leave that many cores free, default: %d) + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Esta es una compilación de prueba pre-lanzamiento - use bajo su propio riesgo - no utilizar para aplicaciones de minería o mercantes + + + Unable to bind to %s on this computer. Bitcoin Core is probably already running. + Deshabilitar para enlezar a %s en esta computadora. Bitcoin Core probablemente ya está ejecutándose. + + + Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. + Aviso: ¡La red no parece estar totalmente de acuerdo! Algunos mineros parecen estar teniendo inconvenientes. + + + Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. + Aviso: ¡No parecen estar totalmente de acuerdo con nuestros compañeros! Puede que tengas que actualizar, u otros nodos tengan que actualizarce. + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Aviso: wallet.dat está corrupto, ¡datos salvados! wallet.dat original guardado como wallet.{timestamp}.bak en %s; si tus transacciones o balance está incorrecto deberías restaurarlo desde una copia de seguridad. + + + Information + Información + + + Warning + Advertencia + + + Error + Error + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts index c746107bc..945e4cfa5 100644 --- a/src/qt/locale/bitcoin_et.ts +++ b/src/qt/locale/bitcoin_et.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -176,6 +176,9 @@ Rahakoti salafraasi muutmine õnnestus. + + BanTableModel + BitcoinGUI @@ -326,6 +329,14 @@ Bitcoin Core Bitcoini tuumik + + &About Bitcoin Core + Kirjeldus Bitcoini Tuumast + + + &Command-line options + Käsurea valikud + %n hour(s) %n tund%n tundi @@ -603,7 +614,7 @@ command-line options käsurea valikud - + Intro @@ -636,6 +647,10 @@ Options Valikud + + &Main + &Peamine + MB MB @@ -806,6 +821,10 @@ &Information &Informatsioon + + Debug window + Debugimise aken + General Üldine @@ -944,6 +963,10 @@ ReceiveRequestDialog + + Copy &Address + &Kopeeri Aadress + Address Aadress @@ -1006,6 +1029,10 @@ Send Coins Müntide saatmine + + Insufficient funds! + Liiga suur summa + Quantity: Kogus: @@ -1018,6 +1045,10 @@ Fee: Tasu: + + Transaction Fee: + Tehingu tasu: + Choose... Vali... @@ -1129,6 +1160,10 @@ Message: Sõnum: + + Pay To: + Maksa : + ShutdownWindow @@ -1280,6 +1315,10 @@ Open until %1 Avatud kuni %1 + + %1/offline + %1/offline'is + %1/unconfirmed %1/kinnitamata @@ -1656,10 +1695,6 @@ Run in the background as a daemon and accept commands Tööta taustal ning aktsepteeri käsklusi - - Use the test network - Testvõrgu kasutamine - Accept connections from outside (default: 1 if no -proxy or -connect) Luba välisühendusi (vaikeväärtus: 1 kui puudub -proxy või -connect) @@ -1676,22 +1711,10 @@ This is a pre-release test build - use at your own risk - do not use for mining or merchant applications See on test-versioon - kasutamine omal riisikol - ära kasuta mining'uks ega kaupmeeste programmides - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Hoiatus: -paytxfee on seatud väga kõrgeks! See on sinu poolt makstav tehingu lisatasu. - - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Hoiatus: ilmnes tõrge wallet.dat faili lugemisel! Võtmed on terved, kuid tehingu andmed või aadressiraamatu kirjed võivad olla kadunud või vigased. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Hoiatus: toimus wallet.dat faili andmete päästmine! Originaal wallet.dat nimetati kaustas %s ümber wallet.{ajatempel}.bak'iks, jäägi või tehingute ebakõlade puhul tuleks teha backup'ist taastamine. - - Attempt to recover private keys from a corrupt wallet.dat - Püüa vigasest wallet.dat failist taastada turvavõtmed - Block creation options: Blokeeri loomise valikud: @@ -1745,13 +1768,29 @@ Rahakoti valikud: - Imports blocks from external blk000??.dat file - Impordi blokid välisest blk000??.dat failist + (default: %u) + (vaikimisi: %u) + + + Cannot resolve -whitebind address: '%s' + Tundmatu -whitebind aadress: '%s' Information Informatsioon + + Invalid amount for -maxtxfee=<amount>: '%s' + -maxtxfee=<amount> jaoks vigane kogus: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + -minrelaytxfee=<amount> jaoks vigane kogus: '%s' + + + Invalid amount for -mintxfee=<amount>: '%s' + -mintxfee=<amount> jaoks vigane kogus: '%s' + RPC server options: RPC serveri valikud: @@ -1760,14 +1799,6 @@ Send trace/debug info to console instead of debug.log file Saada jälitus/debug, debug.log faili asemel, konsooli - - Set language, for example "de_DE" (default: system locale) - Keele valik, nt "ee_ET" (vaikeväärtus: system locale) - - - Show splash screen on startup (default: 1) - Käivitamisel teabeakna kuvamine (vaikeväärtus: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Kahanda programmi käivitamisel debug.log faili (vaikeväärtus: 1, kui ei ole -debug) @@ -1776,10 +1807,6 @@ Signing transaction failed Tehingu allkirjastamine ebaõnnestus - - Start minimized - Käivitu tegumiribale - The transaction amount is too small to pay the fee Tehingu summa on tasu maksmiseks liiga väikene @@ -1792,14 +1819,6 @@ Transaction too large Tehing liiga suur - - UI Options: - UI Valikud: - - - Use UPnP to map the listening port (default: 1 when listening) - Kasuta kuulatava pordi määramiseks UPnP ühendust (vaikeväärtus: 1, kui kuulatakse) - Username for JSON-RPC connections JSON-RPC ühenduste kasutajatunnus @@ -1808,10 +1827,6 @@ Warning Hoiatus - - on startup - käivitamisel - wallet.dat corrupt, salvage failed wallet.dat fail on katki, päästmine ebaõnnestus @@ -1824,18 +1839,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Käivita käsklus, kui parim plokk muutub (käskluse %s asendatakse ploki hash'iga) - - Upgrade wallet to latest format - Uuenda rahakott uusimasse vormingusse - - - Rescan the block chain for missing wallet transactions - Otsi ploki jadast rahakoti kadunud tehinguid - - - Use OpenSSL (https) for JSON-RPC connections - Kasuta JSON-RPC ühenduste jaoks OpenSSL'i (https) - This help message Käesolev abitekst diff --git a/src/qt/locale/bitcoin_eu_ES.ts b/src/qt/locale/bitcoin_eu_ES.ts index 3de9ad5a2..ca6b6489d 100644 --- a/src/qt/locale/bitcoin_eu_ES.ts +++ b/src/qt/locale/bitcoin_eu_ES.ts @@ -1,23 +1,103 @@ - + AddressBookPage + + Right-click to edit address or label + Eskuin-klika helbidea edo etiketa editatzeko + Create a new address Sortu helbide berria + + &New + &Berria + Copy the currently selected address to the system clipboard Kopiatu hautatutako helbidea sistemaren arbelera + + &Copy + &Kopiatu + + + C&lose + &Itxi + + + &Copy Address + &Kopiatu helbidea + + + Delete the currently selected address from the list + Ezabatu aukeratutako helbideak listatik + + + Export the data in the current tab to a file + Esportatu datuak uneko fitxategian + + + &Export + &Esportatu + &Delete &Ezabatu + + Choose the address to send coins to + Aukeratu helbidea txanponak bidaltzeko + + + Choose the address to receive coins with + Aukeratu helbidea txanponak jasotzeko + + + C&hoose + &Aukeratu + + + Sending addresses + Helbideak bidaltzen + + + Receiving addresses + Helbideak jasotzen + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Hauek dira zure Bitcoin helbideak dirua bidaltzeko. Beti egiaztatu diru-kantitatea eta jasotzeko helbidea bidali baino lehen. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Hauek dira zure Bitcoin helbideak dirua jasotzeko. Gomendagarria da erabiltzea jasotzeko helbide berri bat operazio bakoitzeko. + + + Copy &Label + Kopiatu &Etiketa + + + &Edit + &Editatu + + + Export Address List + Esportatu helbide lista + Comma separated file (*.csv) Komaz bereizitako artxiboa (*.csv) - + + Exporting Failed + Esportatua okerra + + + There was an error trying to save the address list to %1. Please try again. + Errakuntza bat egon da gordetzen %1 helbide listan. Mesedez, saiatu berriro. + + AddressTableModel @@ -35,6 +115,10 @@ AskPassphraseDialog + + Passphrase Dialog + Pasahitza dialogoa + Enter passphrase Sartu pasahitza @@ -75,6 +159,22 @@ Confirm wallet encryption Berretsi zorroaren enkriptazioa + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Abisua: Zuk enkriptatzen baduzu zure diruzorroa eta zure pasahitza galtzen baduzu, <b>BITCOIN GUZTIAK GALDUKO DITUZU</b>! + + + Are you sure you wish to encrypt your wallet? + Seguru zaude nahi duzula zure diruzorroa enkriptatu? + + + Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + Bitcoin Core orain itxiko da enkriptazio prozezua amaitzeko. Gogoratu enkriptatzean zure diruzorroa ez duzula guztiz babesten zure Bitcoinak lapurretatik infektatzen zure ordenagailua Malwareekin. + + + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + GARRANTZITSUA: Aurreko seguritate-kopiak ordeztuko dire berriekin, enkriptatutak. Segurtasun arrazoigaitik, aurreko kopiak ezin dira erabili hasiko zarenean zure diruzorro enkriptatu berriarekin. + Wallet encrypted Zorroa enkriptatuta @@ -104,6 +204,9 @@ Zorroaren desenkriptazioak huts egin du + + BanTableModel + BitcoinGUI @@ -146,6 +249,10 @@ &Options... &Aukerak... + + &Receiving addresses... + Helbideak jasotzen + Change the passphrase used for wallet encryption Aldatu zorroa enkriptatzeko erabilitako pasahitza @@ -311,10 +418,18 @@ ReceiveCoinsDialog + + &Amount: + Kopurua + &Label: &Etiketa: + + &Message: + Mezua + Copy label Kopiatu etiketa @@ -322,6 +437,10 @@ ReceiveRequestDialog + + Copy &Address + &Kopiatu helbidea + Address Helbidea @@ -334,6 +453,10 @@ Label Etiketa + + Message + Mezua + RecentRequestsTableModel @@ -345,6 +468,10 @@ Label Etiketa + + Message + Mezua + Amount Kopurua @@ -423,6 +550,10 @@ Message: Mezua + + Pay To: + Ordaindu honi: + ShutdownWindow @@ -470,6 +601,14 @@ Date Data + + Message + Mezua + + + Transaction + Transakzioaren + Amount Kopurua @@ -627,6 +766,10 @@ Copy label Kopiatu etiketa + + Exporting Failed + Esportatua okerra + Comma separated file (*.csv) Komaz bereizitako artxiboa (*.csv) @@ -663,6 +806,14 @@ WalletView + + &Export + &Esportatu + + + Export the data in the current tab to a file + Esportatu datuak uneko fitxategian + bitcoin-core diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index 5eeea0468..7ab3b77da 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -216,6 +216,9 @@ گذرواژهٔ کیف پول با موفقیت عوض شد. + + BanTableModel + BitcoinGUI @@ -394,6 +397,10 @@ Show the list of used receiving addresses and labels نمایش لیست آدرس های دریافت و لیبل ها + + &Command-line options + گزینه‌های خط‌فرمان + %n active connection(s) to Bitcoin network %n ارتباط فعال با شبکهٔ بیت‌کوین @@ -414,6 +421,14 @@ %n week(s) %n هفته + + %1 and %2 + %1 و %2 + + + %n year(s) + %n سال + %1 behind %1 عقب‌تر @@ -709,7 +724,7 @@ command-line options گزینه‌های خط فرمان - + Intro @@ -740,6 +755,10 @@ Error خطا + + %n GB of free space available + %n گیگابایت فضا موجود است + OpenURIDialog @@ -766,6 +785,10 @@ &Network &شبکه + + W&allet + کیف پول + Expert استخراج @@ -972,6 +995,10 @@ &Information &اطلاعات + + Debug window + پنجرهٔ اشکالزدایی + Using OpenSSL version نسخهٔ OpenSSL استفاده شده @@ -1060,13 +1087,21 @@ Unknown ناشناخته - + ReceiveCoinsDialog + + &Amount: + مبلغ: + &Label: &برچسب: + + &Message: + پیام: + Show نمایش @@ -1090,6 +1125,10 @@ QR Code کد QR + + Copy &Address + &کپی نشانی + Address نشانی @@ -1144,6 +1183,10 @@ Send Coins ارسال سکه + + Insufficient funds! + بود جه نا کافی + Quantity: تعداد: @@ -1172,6 +1215,10 @@ Change: پول خورد: + + Transaction Fee: + هزینهٔ تراکنش: + fast سریع @@ -1287,6 +1334,10 @@ Message: پیام: + + Pay To: + پرداخت به: + ShutdownWindow @@ -1612,10 +1663,18 @@ Generated but not accepted تولید شده ولی قبول نشده + + Offline + آفلاین + Label برچسب + + Unconfirmed + تایید نشده + Received with دریافت‌شده با @@ -1850,10 +1909,6 @@ Run in the background as a daemon and accept commands اجرا در پشت زمینه به‌صورت یک سرویس و پذیرش دستورات - - Use the test network - استفاده از شبکهٔ آزمایش - Accept connections from outside (default: 1 if no -proxy or -connect) پذیرش اتصالات از بیرون (پیش فرض:1 بدون پراکسی یا اتصال) @@ -1870,10 +1925,6 @@ This is a pre-release test build - use at your own risk - do not use for mining or merchant applications این یک نسخه ی آزمایشی است - با مسئولیت خودتان از آن استفاده کنید - آن را در معدن و بازرگانی بکار نگیرید. - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - هشدار: مبلغ paytxfee بسیار بالایی تنظیم شده است! این مبلغ هزینه‌ای است که شما برای تراکنش‌ها پرداخت می‌کنید. - Block creation options: بستن گزینه ایجاد @@ -1902,10 +1953,6 @@ Error opening block database خطا در بازگشایی پایگاه داده ی بلوک - - Error: A fatal internal error occured, see debug.log for details - خطا: یک خطای داخلی مهلک روی داد، debug.log را برای جزئیات ببینید - Error: Disk space is low! خطا: فضای دیسک کم است! @@ -1926,46 +1973,30 @@ Verifying wallet... در حال بازبینی کیف پول... - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - هشدار: تاریخ و ساعت کامپیوتر خود را بررسی کنید. اگر ساعت درست نباشد هسته بیت‌کوین به درستی کار نخواهد کرد. - - - Choose data directory on startup (default: 0) - انتخاب مسیر داده‌ها در ابتدای اجرای برنامه (پیش‌فرض: 0) - Information اطلاعات + + Invalid amount for -maxtxfee=<amount>: '%s' + میزان وجه اشتباه برای maxtxfee=<میزان وجه>: %s + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + میزان وجه اشتباه برای minrelaytxfee=<میزان وجه>: %s + + + Invalid amount for -mintxfee=<amount>: '%s' + میزان وجه اشتباه برای mintxfee=<میزان وجه>: %s + Send trace/debug info to console instead of debug.log file اطلاعات ردگیری/اشکال‌زدایی را به جای فایل لاگ اشکال‌زدایی به کنسول بفرستید - - Set language, for example "de_DE" (default: system locale) - زبان را تنظیم کنید؛ برای مثال «de_DE» (زبان پیش‌فرض محلی) - - - Show splash screen on startup (default: 1) - نمایش پنجرهٔ خوشامدگویی در ابتدای اجرای برنامه (پیش‌فرض: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) فایل debug.log را در startup مشتری کوچک کن (پیش فرض:1 اگر اشکال زدایی روی نداد) - - Start minimized - اجرای برنامه به صورت کوچک‌شده - - - UI Options: - گزینه‌های رابط کاربری: - - - Use UPnP to map the listening port (default: 1 when listening) - از UPnP برای شناسایی درگاه شنیداری استفاده کنید (پیش فرض:1 در زمان شنیدن) - Username for JSON-RPC connections JSON-RPC شناسه برای ارتباطات @@ -1982,18 +2013,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) زمانی که بهترین بلاک تغییر کرد، دستور را اجرا کن (%s در cmd با block hash جایگزین شده است) - - Upgrade wallet to latest format - wallet را به جدیدترین فرمت روزآمد کنید - - - Rescan the block chain for missing wallet transactions - اسکان مجدد زنجیر بلوکها برای گم والت معامله - - - Use OpenSSL (https) for JSON-RPC connections - JSON-RPCبرای ارتباطات استفاده کنید OpenSSL (https) - This help message پیام کمکی diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts index 1174e24b4..8bbfc7242 100644 --- a/src/qt/locale/bitcoin_fa_IR.ts +++ b/src/qt/locale/bitcoin_fa_IR.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -188,6 +188,9 @@ رمز عبور کیف پول با موفقیت تغییر کرد. + + BanTableModel + BitcoinGUI @@ -246,6 +249,10 @@ &Change Passphrase... تغییر رمز/پَس فرِیز + + &Receiving addresses... + دریافت آدرس ها + Backup wallet to another location گرفتن نسخه پیشتیبان در آدرسی دیگر @@ -388,6 +395,10 @@ Edit sending address ویرایش حساب ارسال کننده + + The entered address "%1" is already in the address book. + حساب وارد شده «%1» از پیش در دفترچه حساب ها موجود است. + The entered address "%1" is not a valid Bitcoin address. آدرس وارد شده "%1" یک آدرس صحیح برای bitcoin نسشت @@ -431,6 +442,14 @@ Options انتخاب/آپشن + + &Network + شبکه + + + W&allet + کیف پول + &OK و تایید @@ -500,10 +519,18 @@ ReceiveCoinsDialog + + &Amount: + میزان وجه: + &Label: و برچسب + + &Message: + پیام: + Copy label برچسب را کپی کنید @@ -515,6 +542,10 @@ ReceiveRequestDialog + + Copy &Address + کپی آدرس + Address حساب @@ -569,6 +600,10 @@ Send Coins سکه های ارسالی + + Insufficient funds! + وجوه ناکافی + Amount: میزان وجه: @@ -682,6 +717,10 @@ Alt+P Alt و P + + Sign &Message + و امضای پیام + SplashScreen @@ -992,14 +1031,22 @@ Run in the background as a daemon and accept commands به عنوان daemon بک گراند را اجرا کنید و دستورات را قبول نمایید - - Use the test network - از تستِ شبکه استفاده نمایید - The transaction amount is too small to send after the fee has been deducted مبلغ تراکنش کمتر از آن است که پس از کسر هزینه تراکنش قابل ارسال باشد + + Invalid amount for -maxtxfee=<amount>: '%s' + میزان اشتباه است for -maxtxfee=<amount>: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + میزان اشتباه است for -minrelaytxfee=<amount>: '%s' + + + Invalid amount for -mintxfee=<amount>: '%s' + میزان اشتباه است for -mintxfee=<amount>: '%s' + RPC server options: گزینه های سرویس دهنده RPC: @@ -1024,18 +1071,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) دستور را وقتی بهترین بلاک تغییر کرد اجرا کن (%s در دستور توسط block hash جایگزین شده است) - - Upgrade wallet to latest format - wallet را به جدیدترین نسخه روزآمد کنید - - - Rescan the block chain for missing wallet transactions - زنجیره بلاک را برای تراکنش جا افتاده در WALLET دوباره اسکن کنید - - - Use OpenSSL (https) for JSON-RPC connections - برای ارتباطاتِ JSON-RPC از OpenSSL (https) استفاده کنید - This help message این پیام راهنما diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts index eb90aa428..57987b26e 100644 --- a/src/qt/locale/bitcoin_fi.ts +++ b/src/qt/locale/bitcoin_fi.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,17 @@ Lompakon tunnuslause vaihdettiin onnistuneesti. + + BanTableModel + + IP/Netmask + IP/Verkon peite + + + Banned Until + Estetty kunnes + + BitcoinGUI @@ -871,6 +882,34 @@ command-line options komentorivi parametrit + + UI Options: + Käyttöliittymän asetukset: + + + Choose data directory on startup (default: %u) + Valitse datahakemisto käynnistyksen yhteydessä (oletus: %u) + + + Set language, for example "de_DE" (default: system locale) + Aseta kieli, esimerkiksi "de_DE" (oletus: järjestelmän kieli) + + + Start minimized + Käynnistä pienennettynä + + + Set SSL root certificates for payment request (default: -system-) + Aseta maksupyynnöille SSL-juurivarmenteet (oletus: -system-) + + + Show splash screen on startup (default: %u) + Näytä aloitusruutu käynnistyksen yhteydessä (oletus: %u) + + + Reset all settings changes made over the GUI + Nollaa kaikki graafisen käyttöliittymän kautta tehdyt muutokset + Intro @@ -976,6 +1015,14 @@ IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) IP osoite proxille (esim. IPv4: 127.0.0.1 / IPv6: ::1) + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu. + Minimoi ikkuna ohjelman sulkemisen sijasta kun ikkuna suljetaan. Kun tämä asetus on käytössä, ohjelma suljetaan vain valittaessa valikosta Poistu. + + + The user interface language can be set here. This setting will take effect after restarting Bitcoin Core. + Käyttöliittymän kieli voidaan asettaa tässä. Tämä asetus tulee käyttöön vasta kun Bitcoin Core käynnistetään uudelleen. + Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. Ulkopuoliset URL-osoitteet (esim. block explorer,) jotka esiintyvät siirrot-välilehdellä valikossa. %s URL-osoitteessa korvataan siirtotunnuksella. Useampi URL-osoite on eroteltu pystyviivalla |. @@ -1060,6 +1107,34 @@ Port of the proxy (e.g. 9050) Proxyn Portti (esim. 9050) + + Used for reaching peers via: + Vertaisten saavuttamiseen käytettävät verkkotyypit: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Ilmoittaa, mikäli oletetettua SOCKS5-välityspalvelinta käytetään tämän verkkotyypin kautta vertaisten saavuttamiseen. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Yhdistä Bitcoin-verkkoon erillisen SOCKS5-välityspalvelimen kautta piilotettuja Tor-palveluja varten. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Käytä erillistä SOCKS5-välityspalvelinta saavuttaaksesi vertaisia piilotettujen Tor-palveluiden kautta: + &Window &Ikkuna @@ -1278,10 +1353,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Maksupyyntö %1 on liian suuri (%2 tavua, sallittu %3 tavua). - - Payment request DoS protection - Maksupyynnön DoS-suojaus - Error communicating with %1: %2 Virhe kommunikoidessa %1n kanssa: %2 @@ -1434,6 +1505,22 @@ Current number of blocks Nykyinen Lohkojen määrä + + Memory Pool + Muistiallas + + + Current number of transactions + Tämänhetkinen rahansiirtojen määrä + + + Memory usage + Muistin käyttö + + + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. + Avaa Bitcoin Coren debug-loki tämänhetkisestä datahakemistosta. Tämä voi viedä muutaman sekunnin suurille lokitiedostoille. + Received Vastaanotetut @@ -1446,10 +1533,18 @@ &Peers &Vertaiset + + Banned peers + Estetyt vertaiset + Select a peer to view detailed information. Valitse vertainen eriteltyjä tietoja varten. + + Whitelisted + Sallittu + Direction Suunta @@ -1458,6 +1553,18 @@ Version Versio + + Starting Block + Alkaen lohkosta + + + Synced Headers + Synkronoidut ylätunnisteet + + + Synced Blocks + Synkronoidut lohkot + User Agent Käyttöliittymä @@ -1466,14 +1573,6 @@ Services Palvelut - - Starting Height - Aloituskorkeus - - - Sync Height - Synkronointikorkeus - Ban Score Panna-pisteytys @@ -1490,18 +1589,18 @@ Last Receive Viimeisin vastaanotettu - - Bytes Sent - Tavua lähetetty - - - Bytes Received - Tavua vastaanotettu - Ping Time Vasteaika + + The duration of a currently outstanding ping. + Tämänhetkisen merkittävän yhteyskokeilun kesto. + + + Ping Wait + Yhteyskokeilun odotus + Time Offset Ajan poikkeama @@ -1550,6 +1649,34 @@ Clear console Tyhjennä konsoli + + &Disconnect Node + &Katkaise yhteys solmukohtaan + + + Ban Node for + Estä solmukohta + + + 1 &hour + 1 &tunti + + + 1 &day + 1 &päivä + + + 1 &week + 1 &viikko + + + 1 &year + 1 &vuosi + + + &Unban Node + &Poista solmukohdan esto + Welcome to the Bitcoin Core RPC console. Tervetuloa Bitcoin Coren RPC-konsoliin. @@ -1578,6 +1705,10 @@ %1 GB %1 GB + + (node id: %1) + (solmukohdan id: %1) + via %1 %1 kautta @@ -1595,12 +1726,16 @@ Ulosmenevä - Unknown - Tuntematon + Yes + Kyllä - Fetching... - Hankitaan... + No + Ei + + + Unknown + Tuntematon @@ -1955,8 +2090,8 @@ Kopioi vaihtoraha - Total Amount %1 (= %2) - Yhteensä %1 (= %2) + Total Amount %1 + Kokonaismäärä %1 or @@ -1991,13 +2126,21 @@ Maksupyyntö on vanhentunut. - Pay only the minimum fee of %1 - Maksa vain vähimmäiskulu %1 + Pay only the required fee of %1 + Maksa vain vaadittu kulu kooltaan %1 + + + Estimated to begin confirmation within %n block(s). + Vahvistuminen alkaa arviolta %n lohkon päästä.Vahvistuminen alkaa arviolta %n lohkon päästä. The recipient address is not valid. Please recheck. Vastaanottajan osoite ei ole kelvollinen. Tarkistathan uudelleen. + + Duplicate address found: addresses should only be used once each. + Duplikaattiosoite löytyi: kutakin osoitetta pitäisi käyttää vain kerran. + Warning: Invalid Bitcoin address Varoitus: Virheellinen Bitcoin osoite @@ -2526,6 +2669,10 @@ Whether or not a watch-only address is involved in this transaction. Onko rahansiirrossa mukana ainoastaan katseltava osoite vai ei. + + User-defined intent/purpose of the transaction. + Käyttäjän määrittämä käyttötarkoitus rahansiirrolle. + Amount removed from or added to balance. Saldoon lisätty tai siitä vähennetty määrä. @@ -2605,6 +2752,10 @@ Copy transaction ID Kopioi siirtotunnus + + Copy raw transaction + Kopioi rahansiirron raakavedos + Edit label Muokkaa nimeä @@ -2752,13 +2903,21 @@ Accept command line and JSON-RPC commands Hyväksy merkkipohjaiset- ja JSON-RPC-käskyt + + If <category> is not supplied or if <category> = 1, output all debugging information. + Jos <category> on toimittamatta tai jos <category> = 1, tulosta kaikki debug-tieto. + + + Error: A fatal internal error occurred, see debug.log for details + Virhe: Kriittinen sisäinen virhe kohdattiin, katso debug.log lisätietoja varten + Run in the background as a daemon and accept commands Aja taustalla daemonina ja hyväksy komennot - Use the test network - Käytä test -verkkoa + Unable to start HTTP server. See debug log for details. + HTTP-palvelinta ei voitu käynnistää. Katso debug-lokista lisätietoja. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2785,8 +2944,16 @@ Ei voida yhdistää %s tässä tietokoneessa. Bitcoin Core on luultavasti jo käynnissä. - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Varoitus: -paytxfee on asetettu erittäin korkeaksi! Tämä on maksukulu jonka tulet maksamaan kun lähetät siirron. + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + Käytä UPnP:ta kuuntelevan portin kartoitukseen (oletus: 1 kun kuunnellaan ja -proxy ei käytössä) + + + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) + VAROITUS: epätavallisen monta lohkoa generoitu, vastaanotettu %d lohkoa viimeisen %d tunnin aikana (odotettavissa %d) + + + WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) + VAROITUS: tarkista verkkoyhteytesi, vastaanotettu %d lohkoa viimeisen %d tunnin aikana (odotettavissa %d) Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. @@ -2796,26 +2963,18 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Varoitus: Olemme vertaisverkon kanssa ristiriidassa! Sinun tulee päivittää tai toisten solmujen tulee päivitää. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Varoitus: virhe luettaessa wallet.dat-lompakkotiedostoa. Kaikki avaimet luettiin onnistuneesti, mutta siirtohistoria tai osoitekirja saattavat olla kadonneet tai virheellisiä. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Varoitus: wallet.dat -lompakkotiedosto on korruptoitunut, tiedot pelastettu. Alkuperäinen wallet.dat -lompakkotiedosto on tallennettu wallet.{timestamp}.bak kansioon %s; jos balanssisi tai siirtohistoria on virheellinen, sinun tulisi palauttaa lompakkotiedosto varmuuskopiosta. - (default: 1) - (oletus: 1) + -maxmempool must be at least %d MB + -maxmempool on oltava vähintään %d MB <category> can be: <category> voi olla: - - Attempt to recover private keys from a corrupt wallet.dat - Yritetään palauttaa privaattiavaimia korruptoituneesta wallet.dat -lompakkotiedostosta - Block creation options: Lohkon luonnin asetukset: @@ -2844,6 +3003,10 @@ Do you want to rebuild the block database now? Haluatko uudelleenrakentaa lohkotietokannan nyt? + + Enable publish raw transaction in <address> + Ota rahansiirtojen raakavedosten julkaisu käyttöön osoitteessa <address> + Error initializing block database Virhe alustaessa lohkotietokantaa @@ -2860,10 +3023,6 @@ Error opening block database Virhe avattaessa lohkoindeksiä - - Error: A fatal internal error occured, see debug.log for details - Virhe: Sisäinen kriittinen virhe kohdattiin, katso debug.log:sta lisätietoja - Error: Disk space is low! Varoitus: Levytila on vähissä! @@ -2872,10 +3031,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Ei onnistuttu kuuntelemaan missään portissa. Käytä -listen=0 jos haluat tätä. - - If <category> is not supplied, output all debugging information. - Jos <kategoria> ei annettu, tulosta kaikki debuggaustieto. - Importing... Tuodaan... @@ -2940,10 +3095,6 @@ You need to rebuild the database using -reindex to change -txindex Sinun tulee uudelleenrakentaa tietokanta käyttäen -reindex vaihtaen -txindex - - Imports blocks from external blk000??.dat file - Tuodaan lohkoja ulkoisesta blk000??.dat tiedostosta - Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running. Ei voida lukita data-hakemistoa %s. Bitcoin Core on luultavasti jo käynnissä. @@ -2973,17 +3124,13 @@ Aktivoidaan parhainta ketjua... - Can't run with a wallet in prune mode. - Lompakkoa ei voida ajaa karsitussa tilassa. + Attempt to recover private keys from a corrupt wallet.dat on startup + Yritä palauttaa yksityiset avaimet korruptoituneesta wallet.dat-tiedostosta käynnistyksen yhteydessä Cannot resolve -whitebind address: '%s' -whitebind -osoitetta '%s' ei voida jäsentää - - Choose data directory on startup (default: 0) - Valitse data-hakemisto käynnistyksessä (oletus: 0) - Connect through SOCKS5 proxy Yhdistä SOCKS5 proxin kautta @@ -3004,6 +3151,10 @@ Information Tietoa + + Invalid amount for -maxtxfee=<amount>: '%s' + Virheellinen määrä -maxtxfee=<amount>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' Virheellinen määrä -minrelaytxfee=<amount>: '%s' @@ -3016,42 +3167,26 @@ Node relay options: Välityssolmukohdan asetukset: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - RPC SSL valinnat: (katso Bitcoin Wikistä SSL-asennuksen ohjeet) - RPC server options: RPC-palvelimen valinnat: - - RPC support for HTTP persistent connections (default: %d) - RPC-tuki pysyville HTTP-yhteyksille (oletus: %d) - Receive and display P2P network alerts (default: %u) Vastaanota ja näytä P2P-verkon hälytyksiä (oletus: %u) + + Rescan the block chain for missing wallet transactions on startup + Uudelleenskannaa lohkoketju käynnistyksen yhteydessä puuttuvien lompakon rahansiirtojen vuoksi + Send trace/debug info to console instead of debug.log file Lähetä jäljitys/debug-tieto konsoliin, debug.log-tiedoston sijaan - - Set SSL root certificates for payment request (default: -system-) - Aseta SSL root varmenne maksupyynnöille (oletus: -system-) - - - Set language, for example "de_DE" (default: system locale) - Set language, for example "de_DE" (default: system locale) - Show all debugging options (usage: --help -help-debug) Näytä kaikki debuggaus valinnat: (käyttö: --help -help-debug) - - Show splash screen on startup (default: 1) - Näytä aloitusruutu käynnistettäessä (oletus: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Pienennä debug.log tiedosto käynnistyksen yhteydessä (vakioasetus: 1 kun ei -debug) @@ -3061,13 +3196,21 @@ Siirron vahvistus epäonnistui - Start minimized - Käynnistä pienennettynä + The transaction amount is too small to pay the fee + Rahansiirron määrä on liian pieni kattaakseen maksukulun This is experimental software. Tämä on ohjelmistoa kokeelliseen käyttöön. + + Tor control port password (default: empty) + Tor-hallintaportin salasana (oletus: tyhjä) + + + Tor control port to use if onion listening enabled (default: %s) + Tor-hallintaportti jota käytetään jos onion-kuuntelu on käytössä (oletus: %s) + Transaction amount too small Siirtosumma liian pieni @@ -3076,17 +3219,17 @@ Transaction amounts must be positive Siirtosumman tulee olla positiivinen + + Transaction too large for fee policy + Rahansiirto on liian suuri maksukulukäytännölle + Transaction too large Siirtosumma liian iso - UI Options: - Ulkoasun asetukset: - - - Use UPnP to map the listening port (default: 1 when listening) - Käytä UPnP:tä kuunneltavan portin avaamiseen (vakioasetus: 1 kun kuuntelemassa) + Upgrade wallet to latest format on startup + Päivitä lompakko viimeisimpään formaattiin käynnistyksen yhteydessä Username for JSON-RPC connections @@ -3100,13 +3243,17 @@ Warning Varoitus + + Whether to operate in a blocks only mode (default: %u) + Toimitaanko tilassa jossa ainoastaan lohkot sallitaan (oletus: %u) + Zapping all transactions from wallet... Tyhjennetään kaikki rahansiirrot lompakosta.... - on startup - käynnistyksessä + ZeroMQ notification options: + ZeroMQ-ilmoitusasetukset: wallet.dat corrupt, salvage failed @@ -3120,18 +3267,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Suorita käsky kun paras lohko muuttuu (%s cmd on vaihdettu block hashin kanssa) - - Upgrade wallet to latest format - Päivitä lompakko uusimpaan formaattiin - - - Rescan the block chain for missing wallet transactions - Skannaa uudelleen lohkoketju lompakon puuttuvien rahasiirtojen vuoksi - - - Use OpenSSL (https) for JSON-RPC connections - Käytä OpenSSL:ää (https) JSON-RPC-yhteyksille - This help message Tämä ohjeviesti @@ -3148,6 +3283,14 @@ Error loading wallet.dat: Wallet corrupted Virhe ladattaessa wallet.dat-tiedostoa: Lompakko vioittunut + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + Älä pidä rahansiirtoja muistivarannoissa kauemmin kuin <n> tuntia (oletus: %u) + + + How thorough the block verification of -checkblocks is (0-4, default: %u) + Kuinka läpikäyvä lohkojen -checkblocks -todennus on (0-4, oletus: %u) + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) Käytä erillistä SOCKS5-proxyä tavoittaaksesi vertaisia Tor-piilopalveluiden kautta (oletus: %s) @@ -3156,10 +3299,6 @@ (default: %s) (oletus: %s) - - Acceptable ciphers (default: %s) - Hyväksyttävät salaukset (oletus: %s) - Error loading wallet.dat Virhe ladattaessa wallet.dat-tiedostoa @@ -3180,6 +3319,10 @@ Invalid -proxy address: '%s' Virheellinen proxy-osoite '%s' + + Listen for JSON-RPC connections on <port> (default: %u or testnet: %u) + Kuuntele JSON-RPC-yhteyksiä portissa <port> (oletus: %u tai testnet: %u) + Listen for connections on <port> (default: %u or testnet: %u) Kuuntele yhteyksiä portissa <port> (oletus: %u tai testnet: %u) @@ -3188,18 +3331,22 @@ Make the wallet broadcast transactions Aseta lompakko kuuluttamaan rahansiirtoja + + Maximum per-connection receive buffer, <n>*1000 bytes (default: %u) + Maksimi yhteyttä kohden käytettävä vastaanottopuskurin koko, <n>*1000 tavua (oletus: %u) + + + Maximum per-connection send buffer, <n>*1000 bytes (default: %u) + Maksimi yhteyttä kohden käytettävä lähetyspuskurin koko, <n>*1000 tavua (oletus: %u) + + + Relay and mine data carrier transactions (default: %u) + Välitä ja louhi dataa kantavia rahansiirtoja (oletus: %u) + Relay non-P2SH multisig (default: %u) Välitä ei-P2SH-multisig (oletus: %u) - - Server certificate file (default: %s) - Palvelimen sertifikaattitiedosto (oletus: %s) - - - Server private key (default: %s) - Palvelimen private key (oletus: %s) - Set key pool size to <n> (default: %u) Aseta avainaltaan kooksi <n> (oletus: %u) diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index fe140634e..a0b9feb9a 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,17 @@ La phrase de passe du portefeuille a été modifiée avec succès. + + BanTableModel + + IP/Netmask + IP/masque réseau + + + Banned Until + Banni jusqu'au + + BitcoinGUI @@ -722,6 +733,10 @@ This label turns red if the priority is smaller than "medium". Cette étiquette devient rouge si la priorité est plus basse que « moyenne ». + + This label turns red if any recipient receives an amount smaller than %1. + Cette étiquette devient rouge si un destinataire reçoit un montant inférieur à %1. + Can vary +/- %1 satoshi(s) per input. Peut varier +/- %1 satoshi(s) par entrée. @@ -867,6 +882,34 @@ command-line options options de ligne de commande + + UI Options: + Options de l'IU : + + + Choose data directory on startup (default: %u) + Choisir un répertoire de données au démarrage (par défaut : %u) + + + Set language, for example "de_DE" (default: system locale) + Définir la langue, par exemple « fr_CA » (par défaut : la langue du système) + + + Start minimized + Démarrer minimisé + + + Set SSL root certificates for payment request (default: -system-) + Définir les certificats SSL racine pour les requêtes de paiement (par défaut : -system-) + + + Show splash screen on startup (default: %u) + Afficher l'écran d'accueil au démarrage (par défaut : %u) + + + Reset all settings changes made over the GUI + Réinitialiser tous les changements de paramètres appliqués à l'IUG + Intro @@ -910,7 +953,11 @@ %n GB of free space available %n Go d'espace libre disponible%n Go d'espace libre disponibles - + + (of %n GB needed) + (sur %n Go nécessaire)(sur %n Go nécessaires) + + OpenURIDialog @@ -1060,6 +1107,34 @@ Port of the proxy (e.g. 9050) Port du serveur mandataire (par ex. 9050) + + Used for reaching peers via: + Utilisé pour rejoindre les pairs par : + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + S'affiche, si le mandataire SOCKS5 par défaut fourni est utilisé pour atteindre les pairs par ce type de réseau. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Se connecter au réseau Bitcoin au travers d'un mandataire SOCKS5 séparé pour les services cachés de Tor. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Utiliser un mandataire SOCKS5 séparé pour atteindre les pairs grâce aux services cachés de Tor : + &Window &Fenêtre @@ -1278,10 +1353,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). La demande de paiement %1 est trop grande (%2 octets, %3 octets permis). - - Payment request DoS protection - Protection DdS des demandes de paiement - Error communicating with %1: %2 Erreur de communication avec %1 : %2 @@ -1330,7 +1401,7 @@ %1 d - %1 d + %1 j %1 h @@ -1434,6 +1505,18 @@ Current number of blocks Nombre actuel de blocs + + Memory Pool + Réserve de mémoire + + + Current number of transactions + Nombre actuel de transactions + + + Memory usage + Utilisation de la mémoire + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. Ouvrir le journal de débogage du répertoire de données actuel. Ceci pourrait prendre quelques secondes pour les gros fichiers de journalisation. @@ -1450,10 +1533,18 @@ &Peers &Pairs + + Banned peers + Pairs bannis + Select a peer to view detailed information. Choisir un pair pour voir l'information détaillée. + + Whitelisted + Dans la liste blanche + Direction Direction @@ -1462,6 +1553,18 @@ Version Version + + Starting Block + Bloc de départ + + + Synced Headers + En-têtes synchronisés + + + Synced Blocks + Blocs synchronisés + User Agent Agent utilisateur @@ -1470,14 +1573,6 @@ Services Services - - Starting Height - Hauteur de démarrage - - - Sync Height - Hauteur de synchro - Ban Score Pointage des bannissements @@ -1494,18 +1589,18 @@ Last Receive Dernière réception - - Bytes Sent - Octets envoyés - - - Bytes Received - Octets reçus - Ping Time Temps de ping + + The duration of a currently outstanding ping. + La durée d'un ping actuellement en cours. + + + Ping Wait + Attente du ping + Time Offset Décalage temporel @@ -1554,6 +1649,34 @@ Clear console Nettoyer la console + + &Disconnect Node + &Déconnecter le nœud + + + Ban Node for + Bannir le nœud pendant + + + 1 &hour + 1 &heure + + + 1 &day + 1 &jour + + + 1 &week + 1 &semaine + + + 1 &year + 1 &an + + + &Unban Node + &Réhabiliter le nœud + Welcome to the Bitcoin Core RPC console. Bienvenue dans le console RPC de Bitcoin Core. @@ -1582,6 +1705,10 @@ %1 GB %1 Go + + (node id: %1) + (ID de nœud : %1) + via %1 par %1 @@ -1599,12 +1726,16 @@ Sortant - Unknown - Inconnu + Yes + Oui - Fetching... - Récupération... + No + Non + + + Unknown + Inconnu @@ -1971,8 +2102,8 @@ Copier la monnaie - Total Amount %1 (= %2) - Montant total %1 (= %2) + Total Amount %1 + Montant total %1 or @@ -2006,14 +2137,14 @@ Payment request expired. Demande de paiement expirée. + + Pay only the required fee of %1 + Payer seulement les frais exigés de %1 + Estimated to begin confirmation within %n block(s). Il est estimé que la confirmation commencera dans %n bloc.Il est estimé que la confirmation commencera dans %n blocs. - - Pay only the minimum fee of %1 - Payer seulement les frais minimum de %1 - The recipient address is not valid. Please recheck. L'adresse du destinataire est invalide. Veuillez la vérifier. @@ -2645,6 +2776,10 @@ Copy transaction ID Copier l'ID de la transaction + + Copy raw transaction + Copier la transaction brute + Edit label Modifier l’étiquette @@ -2792,13 +2927,53 @@ Accept command line and JSON-RPC commands Accepter les commandes de JSON-RPC et de la ligne de commande + + If <category> is not supplied or if <category> = 1, output all debugging information. + Si <category> n'est pas indiqué ou si <category> = 1, extraire toutes les données de débogage. + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Frais totaux maximaux (en %s) à utiliser en une seule transaction de portefeuille. Les définir trop bas pourrait interrompre les grosses transactions (par défaut : %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + Veuillez vérifier que l'heure et la date de votre ordinateur sont justes ! Si votre horloge n'est pas à l'heure, Bitcoin Core ne fonctionnera pas correctement. + + + Prune configured below the minimum of %d MiB. Please use a higher number. + L'élagage est configuré au-dessous du minimum de %d Mio. Veuillez utiliser un nombre plus élevé. + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + Élagage : la dernière synchronisation de portefeuille va par-delà les données élaguées. Vous devez -reindex (réindexer, télécharger de nouveau toute la chaîne de blocs en cas de nœud élagué) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + Réduire les exigences de stockage en élaguant (supprimant) les anciens blocs. Ce mode est incompatible avec -txindex et -rescan. Avertissement : ramener ce paramètre à sa valeur antérieure exige un nouveau téléchargement de la chaîne de blocs en entier (par défaut : 0 = désactiver l'élagage des blocs, >%u = taille cible en Mio à utiliser pour les fichiers de blocs). + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + Les rebalayages sont impossibles en mode élagage. Vous devrez utiliser -reindex, ce qui téléchargera de nouveau la chaîne de blocs en entier. + + + Error: A fatal internal error occurred, see debug.log for details + Erreur : une erreur interne fatale s'est produite. Voir debug.log pour plus de détails + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Les frais (en %s/ko) à ajouter aux transactions que vous envoyez (par défaut : %s) + + + Pruning blockstore... + Élagage du magasin de blocs... + Run in the background as a daemon and accept commands Fonctionner en arrière-plan en tant que démon et accepter les commandes - Use the test network - Utiliser le réseau de test + Unable to start HTTP server. See debug log for details. + Impossible de démarrer le serveur HTTP. Voir le journal de débogage pour plus de détails. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2810,7 +2985,7 @@ Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup - Supprimer toutes les transactions du portefeuille et ne récupérer que ces parties de la chaîne de bloc avec -rescan au démarrage + Supprimer toutes les transactions du portefeuille et ne récupérer que ces parties de la chaîne de blocs avec -rescan au démarrage Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. @@ -2820,18 +2995,14 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Exécuter la commande lorsqu'une transaction de portefeuille change (%s dans la commande est remplacée par TxID) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Total maximal des frais à utiliser en une seule transaction de portefeuille. Le définir trop bas pourrait interrompre les grosses transactions (par défaut : %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Réduire les exigences de stockage en élaguant (supprimant) les anciens blocs. Ce mode désactive la prise en charge de portefeuilles et n'est pas compatible avec -txindex. Avertissement : configurer ce paramètre à sa valeur antérieure retéléchargera complètement la chaîne de blocs (par défaut : 0 = désactiver l'élagage des blocs, >%u = taille cible en Mo à utiliser pour les fichiers de blocs). - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Définir le nombre d'exétrons de vérification des scripts (%u à %d, 0 = auto, < 0 = laisser ce nombre de cœurs inutilisés, par défaut : %d) + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + La base de données de blocs contient un bloc qui semble provenir du futur. Cela pourrait être causé par la date et l'heure erronées de votre ordinateur. Ne reconstruisez la base de données de blocs que si vous êtes certain que la date et l'heure de votre ordinateur sont justes. + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Ceci est une pré-version de test - l'utiliser à vos risques et périls - ne pas l'utiliser pour miner ou pour des applications marchandes @@ -2840,6 +3011,10 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. Impossible de se lier à %s sur cet ordinateur. Bitcoin Core fonctionne probablement déjà. + + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + Utiliser l'UPnP pour mapper le port d'écoute (par défaut : 1 lors de l'écoute et pas de mandataire -proxy) + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) AVERTISSEMENT : un nombre anormalement élevé de blocs a été généré, %d blocs reçus durant les %d dernières heures (%d attendus) @@ -2848,10 +3023,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) AVERTISSEMENT : vérifiez votre connexion réseau, %d blocs reçus durant les %d dernières heures (%d attendus) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Avertissement : -paytxfee est réglé sur un montant très élevé ! Il s'agit des frais de transaction que vous payerez si vous envoyez une transaction. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Avertissement : le réseau ne semble pas totalement d'accord ! Quelques mineurs semblent éprouver des difficultés. @@ -2860,10 +3031,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Avertissement : nous ne semblons pas être en accord complet avec nos pairs ! Vous pourriez avoir besoin d'effectuer une mise à niveau, ou d'autres nœuds du réseau pourraient avoir besoin d'effectuer une mise à niveau. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Avertissement : une erreur est survenue lors de la lecture de wallet.dat ! Toutes les clefs ont été lues correctement mais les données de transaction ou les entrées du carnet d'adresses sont peut-être incorrectes ou manquantes. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Avertissement : wallet.dat corrompu, données récupérées ! Le fichier wallet.dat original a été enregistré en tant que wallet.{timestamp}.bak dans %s ; si votre solde ou transactions sont incorrects vous devriez effectuer une restauration depuis une sauvegarde. @@ -2873,17 +3040,13 @@ Pairs de la liste blanche se connectant à partir du masque réseau ou de l'IP donné. Peut être spécifié plusieurs fois. - (default: 1) - (par défaut : 1) + -maxmempool must be at least %d MB + -maxmempool doit être d'au moins %d Mo <category> can be: <category> peut être : - - Attempt to recover private keys from a corrupt wallet.dat - Tenter de récupérer les clefs privées d'un wallet.dat corrompu - Block creation options: Options de création de bloc : @@ -2912,6 +3075,22 @@ Do you want to rebuild the block database now? Voulez-vous reconstruire la base de données des blocs maintenant ? + + Enable publish hash block in <address> + Activer la publication du bloc de hachage dans <address> + + + Enable publish hash transaction in <address> + Activer la publication de la transaction de hachage dans <address> + + + Enable publish raw block in <address> + Activer la publication du bloc brut dans <address> + + + Enable publish raw transaction in <address> + Activer la publication de la transaction brute dans <address> + Error initializing block database Erreur lors de l'initialisation de la base de données des blocs @@ -2928,10 +3107,6 @@ Error opening block database Erreur lors de l'ouverture de la base de données des blocs - - Error: A fatal internal error occured, see debug.log for details - Erreur : une erreur interne fatale s'est produite. Voir debug.log pour des détails - Error: Disk space is low! Erreur : l'espace disque est faible ! @@ -2940,10 +3115,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Échec de l'écoute sur un port quelconque. Utilisez -listen=0 si vous voulez ceci. - - If <category> is not supplied, output all debugging information. - Si <category> n'est pas indiqué, extraire toutes les données de débogage. - Importing... Importation... @@ -2956,6 +3127,10 @@ Invalid -onion address: '%s' Adresse -onion invalide : « %s » + + Keep the transaction memory pool below <n> megabytes (default: %u) + Garder la réserve de mémoire transactionnelle sous <n> mégaoctets (par défaut : %u) + Not enough file descriptors available. Pas assez de descripteurs de fichiers proposés. @@ -2984,10 +3159,26 @@ Specify wallet file (within data directory) Spécifiez le fichier de portefeuille (dans le répertoire de données) + + Unsupported argument -benchmark ignored, use -debug=bench. + Argument non pris en charge -benchmark ignoré, utiliser -debug=bench. + + + Unsupported argument -debugnet ignored, use -debug=net. + Argument non pris en charge -debugnet ignoré, utiliser -debug=net. + + + Unsupported argument -tor found, use -onion. + Argument non pris en charge -tor trouvé, utiliser -onion + Use UPnP to map the listening port (default: %u) Utiliser l'UPnP pour mapper le port d'écoute (par défaut : %u) + + User Agent comment (%s) contains unsafe characters. + Le commentaire d'agent utilisateur (%s) contient des caractères dangereux. + Verifying blocks... Vérification des blocs en cours... @@ -3012,18 +3203,10 @@ You need to rebuild the database using -reindex to change -txindex Vous devez reconstruire la base de données en utilisant -reindex afin de modifier -txindex - - Imports blocks from external blk000??.dat file - Importe des blocs depuis un fichier blk000??.dat externe - 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 Permettre les connexions JSON-RPC de sources spécifiques. Valide pour <ip> qui sont une IP simple (p. ex. 1.2.3.4), un réseau/masque réseau (p. ex. 1.2.3.4/255.255.255.0) ou un réseau/CIDR (p. ex. 1.2.3.4/24). Cette option peut être être spécifiée plusieurs fois - - An error occurred while setting up the RPC address %s port %u for listening: %s - Une erreur est survenue lors de la mise en place de l'adresse %s port %u d'écoute RPC : %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Se lier à l'adresse donnée et aux pairs s'y connectant. Utiliser la notation [host]:port pour l'IPv6 @@ -3048,17 +3231,13 @@ Error: Listening for incoming connections failed (listen returned error %s) Erreur : l'écoute des connexions entrantes a échoué (l'écoute a retourné l'erreur %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Erreur : l'argument non pris en charge -socks a été trouvé. Il n'est plus possible de définir la version de SOCKS, seuls les serveurs mandataires SOCKS5 sont pris en charge. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Exécuter une commande lorsqu'une alerte pertinente est reçue ou si nous voyons une bifurcation vraiment étendue (%s dans la commande est remplacé par le message) - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Les frais (en BTC/Ko) inférieurs à ce seuil sont considérés comme étant nuls pour le relayage (par défaut : %s) + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + Les frais (en %s/Ko) inférieurs à ce seuil sont considérés comme étant nuls pour le relais, le minage et la création de transactions (par défaut : %s) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -3072,10 +3251,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) Quantité maximale de données dans les transactions du porteur de données que nous relayons et minons (par défaut : %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - L'élagage est configuré au-dessous du minimum de %d Mo. Veuillez utiliser un nombre plus élevé. - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Demander les adresses des pairs par recherche DNS si l'on manque d'adresses (par défaut : 1 sauf si -connect) @@ -3100,38 +3275,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Ce produit comprend des logiciels développés par le projet OpenSSL pour être utilisés dans la boîte à outils OpenSSL <https://www.openssl.org/> et un logiciel cryptographique écrit par Eric Young, ainsi qu'un logiciel UPnP écrit par Thomas Bernard. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - Pour utiliser bitcoind, ou l'option -server de bitcoin-qt, vous devez définir un mot de passe rpc dans le fichier de configuration : -%s -Il est recommandé d'utiliser le mot de passe aléatoire suivant : -rpcuser=bitcoinrpc -rpcpassword=%s -(vous n'avez pas à mémoriser ce mot de passe) -Le nom d'utilisateur et le mot de passe NE DOIVENT PAS être identiques. -Si le fichier n'existe pas, créez-le avec la permission lecture-seule-par-le-propriétaire. -Il est aussi recommandé de définir alertnotify afin que les problèmes vous soient signalés ; -par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Avertissement :-maxtxfee est défini très haut ! Des frais aussi élevés pourraient être payés sur une seule transaction. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Avertissement : veuillez vérifier que l'heure et la date de votre ordinateur sont correctes ! Si votre horloge n'est pas à l'heure, Bitcoin Core ne fonctionnera pas correctement. - 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 Les pairs de la liste blanche ne peuvent pas être bannis DoS et leurs transactions sont toujours relayées, même si elles sont déjà dans le mempool, utile p. ex. pour une passerelle @@ -3153,17 +3296,21 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com Activation de la meilleure chaîne... - Can't run with a wallet in prune mode. - L'exécution est impossible quand le portefeuille est en mode élagage. + Always relay transactions received from whitelisted peers (default: %d) + Toujours relayer les transactions reçues des pairs de la liste blanche (par défaut : %d) + + + Attempt to recover private keys from a corrupt wallet.dat on startup + Tenter de récupérer les clefs privées d'un wallet.dat corrompu lors du démarrage + + + Automatically create Tor hidden service (default: %d) + Créer automatiquement un service caché Tor (par défaut : %d) Cannot resolve -whitebind address: '%s' Impossible de résoudre l'adresse -whitebind : « %s » - - Choose data directory on startup (default: 0) - Choisir un répertoire de données au démarrage (par défaut : 0) - Connect through SOCKS5 proxy Se connecter par un mandataire SOCKS5 @@ -3172,10 +3319,6 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com Copyright (C) 2009-%i The Bitcoin Core Developers Copyright © 2009-%i Les développeurs de Bitcoin Core - - Could not parse -rpcbind value %s as network address - Impossible d'analyser la valeur -rpcbind %s comme adresse réseau - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Erreur lors du chargement de wallet.dat : le portefeuille exige une version plus récente de Bitcoin Core @@ -3185,12 +3328,8 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com Erreur de lecture de la base de données, fermeture en cours. - Error: Unsupported argument -tor found, use -onion. - Erreur : argument non pris en charge -tor trouvé, utiliser -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Les frais (en BTC/ko) à ajouter aux transactions que vous envoyez (par défaut : %s) + Imports blocks from external blk000??.dat file on startup + Importe des blocs depuis un fichier blk000??.dat externe lors du démarrage Information @@ -3232,18 +3371,10 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com Node relay options: Options de relais du nœud : - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Options RPC SSL : (voir le wiki Bitcoin pour les instructions de configuration de SSL) - RPC server options: Options du serveur RPC : - - RPC support for HTTP persistent connections (default: %d) - Prise en charge de RPC pour les connexions persistantes HTTP (par défaut : %d) - Rebuild block chain index from current blk000??.dat files on startup Reconstruire au démarrage l'index de la chaîne de blocs à partir des fichiers blk000??.dat actuels @@ -3252,6 +3383,14 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com Receive and display P2P network alerts (default: %u) Recevoir et afficher les alertes du réseau poste à poste (%u par défaut) + + Reducing -maxconnections from %d to %d, because of system limitations. + Réduction de -maxconnections de %d à %d, due aux restrictions du système + + + Rescan the block chain for missing wallet transactions on startup + Réanalyser la chaîne de blocs au démarrage, à la recherche de transactions de portefeuille manquantes + Send trace/debug info to console instead of debug.log file Envoyer les informations de débogage/trace à la console au lieu du fichier debug.log @@ -3260,22 +3399,10 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com Send transactions as zero-fee transactions if possible (default: %u) Envoyer si possible les transactions comme étant sans frais (par défaut : %u) - - Set SSL root certificates for payment request (default: -system-) - Définir les certificats racine SSL pour les demandes de paiement (par défaut : -système-) - - - Set language, for example "de_DE" (default: system locale) - Définir la langue, par exemple « fr_CA » (par défaut : la langue du système) - Show all debugging options (usage: --help -help-debug) Montrer toutes les options de débogage (utilisation : --help --help-debug) - - Show splash screen on startup (default: 1) - Afficher la page de garde au démarrage (par défaut : 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Réduire le fichier debug.log lors du démarrage du client (par défaut : 1 lorsque -debug n'est pas présent) @@ -3284,10 +3411,6 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com Signing transaction failed La signature de la transaction a échoué - - Start minimized - Démarrer minimisé - The transaction amount is too small to pay the fee Le montant de la transaction est trop bas pour que les frais soient payés @@ -3296,6 +3419,14 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com This is experimental software. Ceci est un logiciel expérimental. + + Tor control port password (default: empty) + Mot de passe du port de contrôle Tor (par défaut : vide) + + + Tor control port to use if onion listening enabled (default: %s) + Port de contrôle Tor à utiliser si l'écoute onion est activée (par défaut :%s) + Transaction amount too small Montant de la transaction trop bas @@ -3312,17 +3443,13 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com Transaction too large Transaction trop volumineuse - - UI Options: - Options de l'IU : - Unable to bind to %s on this computer (bind returned error %s) Impossible de se lier à %s sur cet ordinateur (bind a retourné l'erreur %s) - Use UPnP to map the listening port (default: 1 when listening) - Utiliser l'UPnP pour mapper le port d'écoute (par défaut : 1 lors de l'écoute) + Upgrade wallet to latest format on startup + Mettre à niveau le portefeuille au démarrage vers le format le plus récent Username for JSON-RPC connections @@ -3337,20 +3464,16 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com Avertissement - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Avertissement : l'argument -benchmark non pris en charge a été ignoré, utiliser -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Avertissement : l'argument -debugnet non pris en charge a été ignoré, utiliser -debug=net. + Whether to operate in a blocks only mode (default: %u) + Faut-il fonctionner en mode blocs seulement (par défaut : %u) Zapping all transactions from wallet... Supprimer toutes les transactions du portefeuille... - on startup - au démarrage + ZeroMQ notification options: + Options de notification ZeroMQ wallet.dat corrupt, salvage failed @@ -3364,18 +3487,6 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com Execute command when the best block changes (%s in cmd is replaced by block hash) Exécuter la commande lorsque le meilleur bloc change (%s dans cmd est remplacé par le hachage du bloc) - - Upgrade wallet to latest format - Mettre à niveau le portefeuille vers le format le plus récent - - - Rescan the block chain for missing wallet transactions - Réanalyser la chaîne de blocs pour les transactions de portefeuille manquantes - - - Use OpenSSL (https) for JSON-RPC connections - Utiliser OpenSSL (https) pour les connexions JSON-RPC - This help message Ce message d'aide @@ -3396,6 +3507,26 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = conserver les métadonnées de transmission, par ex. les informations du propriétaire du compte et de la demande de paiement, 2 = abandonner les métadonnées de transmission) + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + -maxtxfee est défini très haut ! Des frais aussi élevés pourraient être payés en une seule transaction. + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + -paytxfee est réglé sur un montant très élevé ! Il s'agit des frais de transaction que vous payerez si vous envoyez une transaction. + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + Ne pas conserver de transactions dans la réserve de mémoire plus de <n> heures (par défaut : %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Une erreur est survenue lors de la lecture de wallet.dat ! Toutes les clefs ont été lues correctement, mais les données transactionnelles ou les entrées du carnet d'adresses sont peut-être manquantes ou incorrectes. + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + Les frais (en %s/Ko) inférieurs à ce seuil sont considérés comme étant nuls pour la création de transactions (par défaut : %s) + How thorough the block verification of -checkblocks is (0-4, default: %u) Degré de profondeur de la vérification des blocs -checkblocks (0-4, par défaut : %u) @@ -3412,17 +3543,33 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com Output debugging information (default: %u, supplying <category> is optional) Extraire les informations de débogage (par défaut : %u, fournir <category> est optionnel) + + Support filtering of blocks and transaction with bloom filters (default: %u) + Prendre en charge le filtrage des blocs et des transactions avec les filtres bloom (par défaut : %u) + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + La taille totale de la chaîne de version de réseau (%i) dépasse la longueur maximale (%i). Réduire le nombre ou la taille des commentaires uacomments. + + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + Tente de garder le trafic sortant sous la cible donnée (en Mio par 24 h), 0 = sans limite (par défaut : %d) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + L'argument non pris en charge -socks a été trouvé. Il n'est plus possible de définir la version de SOCKS, seuls les mandataires SOCKS5 sont pris en charge. + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) Utiliser un serveur mandataire SOCKS5 séparé pour atteindre les pairs par les services cachés de Tor (par défaut : %s) - (default: %s) - (par défaut : %s) + 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. This option can be specified multiple times + Nom d'utilisateur et mot de passe haché pour les connexions JSON-RPC. Le champ <userpw> vient au format : <USERNAME>:<SALT>$<HASH>. Un script python canonique est inclus dans share/rpcuser. Cette option peut être spécifiée plusieurs fois. - Acceptable ciphers (default: %s) - Chiffrements acceptables (par défaut : %s) + (default: %s) + (par défaut : %s) Always query for peer addresses via DNS lookup (default: %u) @@ -3492,6 +3639,10 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com Set minimum block size in bytes (default: %u) Définir la taille de bloc minimale en octets (par défaut : %u) + + Set the number of threads to service RPC calls (default: %d) + Définir le nombre d'exétrons pour desservir les appels RPC (par défaut : %d) + Specify configuration file (default: %s) Spécifier le fichier de configuration (par défaut : %s) diff --git a/src/qt/locale/bitcoin_fr_CA.ts b/src/qt/locale/bitcoin_fr_CA.ts index f4fe7d659..7e6925f96 100644 --- a/src/qt/locale/bitcoin_fr_CA.ts +++ b/src/qt/locale/bitcoin_fr_CA.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -13,6 +13,10 @@ &Delete &Supprimer + + Sending addresses + envoyer adresse de reception + Comma separated file (*.csv) Fichier séparé par une virgule (*.csv) @@ -64,6 +68,9 @@ Cette opération nécessite le mot de passe de votre porte-feuille pour le décrypter. + + BanTableModel + BitcoinGUI @@ -72,6 +79,14 @@ CoinControlDialog + + (un)select all + Toute sélectionner + + + Copy address + copier l'adresse + (no label) (pas de record) @@ -79,6 +94,14 @@ EditAddressDialog + + &Label + Record + + + &Address + Addresse + FreespaceChecker @@ -88,6 +111,10 @@ Intro + + Welcome + Bienvenue + OpenURIDialog @@ -175,6 +202,10 @@ TransactionView + + Copy address + copier l'adresse + Comma separated file (*.csv) Fichier séparé par une virgule (*.csv) diff --git a/src/qt/locale/bitcoin_fr_FR.ts b/src/qt/locale/bitcoin_fr_FR.ts new file mode 100644 index 000000000..df6324335 --- /dev/null +++ b/src/qt/locale/bitcoin_fr_FR.ts @@ -0,0 +1,897 @@ + + + AddressBookPage + + Create a new address + Créer une nouvelle adresse + + + Copy the currently selected address to the system clipboard + Copier l'adresse surlignée dans votre presse-papiers + + + Export the data in the current tab to a file + Exporter les données de l'onglet courant vers un fichier + + + &Delete + &Supprimer + + + Comma separated file (*.csv) + Valeurs séparées par des virgules (*.csv) + + + + AddressTableModel + + Label + Étiquette + + + Address + Adresse + + + (no label) + (aucune étiquette) + + + + AskPassphraseDialog + + Enter passphrase + Entrez la phrase de passe + + + New passphrase + Nouvelle phrase de passe + + + Repeat new passphrase + Répétez la phrase de passe + + + Encrypt wallet + Chiffrer le porte-monnaie + + + This operation needs your wallet passphrase to unlock the wallet. + Cette opération nécessite votre phrase de passe pour déverrouiller le porte-monnaie. + + + Unlock wallet + Déverrouiller le porte-monnaie + + + This operation needs your wallet passphrase to decrypt the wallet. + Cette opération nécessite votre phrase de passe pour décrypter le porte-monnaie. + + + Decrypt wallet + Décrypter le porte-monnaie + + + Change passphrase + Changer la phrase de passe + + + Confirm wallet encryption + Confirmer le chiffrement du porte-monnaie + + + Wallet encrypted + Porte-monnaie chiffré + + + Wallet encryption failed + Le chiffrement du porte-monnaie a échoué + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Le chiffrement du porte-monnaie a échoué en raison d'une erreur interne. Votre porte-monnaie n'a pas été chiffré. + + + The supplied passphrases do not match. + Les phrases de passe entrées ne correspondent pas. + + + Wallet unlock failed + Le déverrouillage du porte-monnaie a échoué + + + The passphrase entered for the wallet decryption was incorrect. + La phrase de passe entrée pour décrypter le porte-monnaie était erronée. + + + Wallet decryption failed + Le décryptage du porte-monnaie a échoué + + + + BanTableModel + + + BitcoinGUI + + Synchronizing with network... + Synchronisation avec le réseau... + + + &Overview + &Vue d'ensemble + + + Show general overview of wallet + Affiche une vue d'ensemble du porte-monnaie + + + &Transactions + &Transactions + + + Browse transaction history + Permet de parcourir l'historique des transactions + + + E&xit + Qui&tter + + + Quit application + Quitter l'application + + + About &Qt + À propos de &Qt + + + Show information about Qt + Afficher des informations sur Qt + + + &Options... + &Options... + + + Backup wallet to another location + Sauvegarder le porte-monnaie à un autre emplacement + + + Change the passphrase used for wallet encryption + Modifier la phrase de passe utilisée pour le cryptage du porte-monnaie + + + Bitcoin + Bitcoin + + + &Send + &Envoyer + + + &File + &Fichier + + + &Settings + &Réglages + + + &Help + &Aide + + + Tabs toolbar + Barre d'outils des onglets + + + Up to date + À jour + + + Catching up... + Rattrapage... + + + Sent transaction + Transaction envoyée + + + Incoming transaction + Transaction entrante + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + Le porte-monnaie est <b>chiffré</b> et est actuellement <b>déverrouillé</b> + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + Le porte-monnaie est <b>chiffré</b> et est actuellement <b>verrouillé</b> + + + + ClientModel + + + CoinControlDialog + + Amount: + Montant : + + + Amount + Montant + + + Date + Date + + + Confirmed + Confirmée + + + Copy address + Copier l'adresse + + + Copy label + Copier l'étiquette + + + Copy amount + Copier le montant + + + (no label) + (aucune étiquette) + + + + EditAddressDialog + + Edit Address + Éditer l'adresse + + + &Label + &Étiquette + + + &Address + &Adresse + + + New receiving address + Nouvelle adresse de réception + + + New sending address + Nouvelle adresse d'envoi + + + Edit receiving address + Éditer l'adresse de réception + + + Edit sending address + Éditer l'adresse d'envoi + + + The entered address "%1" is already in the address book. + L'adresse fournie « %1 » est déjà présente dans le carnet d'adresses. + + + Could not unlock wallet. + Impossible de déverrouiller le porte-monnaie. + + + New key generation failed. + Échec de la génération de la nouvelle clef. + + + + FreespaceChecker + + + HelpMessageDialog + + Usage: + Utilisation : + + + + Intro + + + OpenURIDialog + + + OptionsDialog + + Options + Options + + + Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. + Ouvrir le port du client Bitcoin automatiquement sur le routeur. Cela ne fonctionne que si votre routeur supporte l'UPnP et si la fonctionnalité est activée. + + + Map port using &UPnP + Ouvrir le port avec l'&UPnP + + + &Minimize to the tray instead of the taskbar + &Minimiser dans la barre système au lieu de la barre des tâches + + + M&inimize on close + Mi&nimiser lors de la fermeture + + + + OverviewPage + + Form + Formulaire + + + + PaymentServer + + + PeerTableModel + + + QObject + + Amount + Montant + + + + QRImageWidget + + + RPCConsole + + Name + Nom + + + + ReceiveCoinsDialog + + &Amount: + Montant : + + + &Label: + &Étiquette : + + + &Message: + Message : + + + Copy label + Copier l'étiquette + + + Copy amount + Copier le montant + + + + ReceiveRequestDialog + + QR Code + QR Code + + + Address + Adresse + + + Amount + Montant + + + Label + Étiquette + + + Message + Message + + + + RecentRequestsTableModel + + Date + Date + + + Label + Étiquette + + + Message + Message + + + Amount + Montant + + + (no label) + (aucune étiquette) + + + + SendCoinsDialog + + Send Coins + Envoyer des pièces + + + Insufficient funds! + Fonds insuffisants + + + Amount: + Montant : + + + Send to multiple recipients at once + Envoyer des pièces à plusieurs destinataires à la fois + + + Balance: + Solde : + + + Confirm the send action + Confirmer l'action d'envoi + + + Confirm send coins + Confirmer l'envoi des pièces + + + Copy amount + Copier le montant + + + The amount to pay must be larger than 0. + Le montant à payer doit être supérieur à 0. + + + (no label) + (aucune étiquette) + + + + SendCoinsEntry + + A&mount: + &Montant : + + + Pay &To: + Payer &à : + + + Enter a label for this address to add it to your address book + Entrez une étiquette pour cette adresse afin de l'ajouter à votre carnet d'adresses + + + &Label: + &Étiquette : + + + Alt+A + Alt+A + + + Paste address from clipboard + Coller une adresse depuis le presse-papiers + + + Alt+P + Alt+P + + + Message: + Message : + + + Pay To: + Payer à : + + + + ShutdownWindow + + + SignVerifyMessageDialog + + &Sign Message + &Signer le message + + + Alt+A + Alt+A + + + Paste address from clipboard + Coller une adresse depuis le presse-papiers + + + Alt+P + Alt+P + + + Enter the message you want to sign here + Entrez ici le message que vous désirez signer + + + Sign &Message + &Signer le message + + + + SplashScreen + + [testnet] + [testnet] + + + + TrafficGraphWidget + + + TransactionDesc + + Open until %1 + Ouvert jusqu'à %1 + + + %1/unconfirmed + %1/non confirmée + + + %1 confirmations + %1 confirmations + + + Status + État + + + Date + Date + + + Generated + Généré + + + Credit + Crédit + + + Debit + Débit + + + Message + Message + + + Amount + Montant + + + , has not been successfully broadcast yet + , n'a pas encore été diffusée avec succès + + + unknown + inconnue + + + + TransactionDescDialog + + Transaction details + Détails de la transaction + + + This pane shows a detailed description of the transaction + Ce panneau affiche une description détaillée de la transaction + + + + TransactionTableModel + + Date + Date + + + Type + Type + + + Open until %1 + Ouvert jusqu'à %1 + + + Confirmed (%1 confirmations) + Confirmée (%1 confirmations) + + + This block was not received by any other nodes and will probably not be accepted! + Ce bloc n'a été reçu par aucun autre nœud et ne sera probablement pas accepté ! + + + Generated but not accepted + Généré mais pas accepté + + + Label + Étiquette + + + Received with + Reçues avec + + + Received from + Reçue de + + + Sent to + Envoyées à + + + Payment to yourself + Paiement à vous-même + + + Mined + Extraction + + + (n/a) + (indisponible) + + + Transaction status. Hover over this field to show number of confirmations. + État de la transaction. Laissez le pointeur de la souris sur ce champ pour voir le nombre de confirmations. + + + Date and time that the transaction was received. + Date et heure de réception de la transaction. + + + Type of transaction. + Type de transaction. + + + Amount removed from or added to balance. + Montant ajouté au ou enlevé du solde. + + + + TransactionView + + All + Toutes + + + Today + Aujourd'hui + + + This week + Cette semaine + + + This month + Ce mois + + + Last month + Mois dernier + + + This year + Cette année + + + Range... + Intervalle... + + + Received with + Reçues avec + + + Sent to + Envoyées à + + + To yourself + À vous-même + + + Mined + Extraction + + + Other + Autres + + + Enter address or label to search + Entrez une adresse ou une étiquette à rechercher + + + Min amount + Montant min + + + Copy address + Copier l'adresse + + + Copy label + Copier l'étiquette + + + Copy amount + Copier le montant + + + Edit label + Éditer l'étiquette + + + Comma separated file (*.csv) + Valeurs séparées par des virgules (*.csv) + + + Confirmed + Confirmée + + + Date + Date + + + Type + Type + + + Label + Étiquette + + + Address + Adresse + + + ID + ID + + + Range: + Intervalle : + + + to + à + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + Send Coins + Envoyer des pièces + + + + WalletView + + Export the data in the current tab to a file + Exporter les données de l'onglet courant vers un fichier + + + Backup Wallet + Sauvegarder le porte-monnaie + + + Wallet Data (*.dat) + Données de porte-monnaie (*.dat) + + + Backup Failed + La sauvegarde a échoué + + + + bitcoin-core + + Options: + Options : + + + Specify data directory + Spécifier le répertoire de données + + + Accept command line and JSON-RPC commands + Accepter les commandes de JSON-RPC et de la ligne de commande + + + Run in the background as a daemon and accept commands + Fonctionner en arrière-plan en tant que démon et accepter les commandes + + + Send trace/debug info to console instead of debug.log file + Envoyer les informations de débogage/trace à la console au lieu du fichier debug.log + + + Username for JSON-RPC connections + Nom d'utilisateur pour les connexions JSON-RPC + + + Password for JSON-RPC connections + Mot de passe pour les connexions JSON-RPC + + + This help message + Ce message d'aide + + + Loading addresses... + Chargement des adresses... + + + Error loading wallet.dat: Wallet corrupted + Erreur lors du chargement de wallet.dat : porte-monnaie corrompu + + + Error loading wallet.dat + Erreur lors du chargement de wallet.dat + + + Insufficient funds + Fonds insuffisants + + + Loading block index... + Chargement de l'index des blocs... + + + Loading wallet... + Chargement du porte-monnaie... + + + Rescanning... + Nouvelle analyse... + + + Done loading + Chargement terminé + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_gl.ts b/src/qt/locale/bitcoin_gl.ts index 709b17e2f..96d4adeba 100644 --- a/src/qt/locale/bitcoin_gl.ts +++ b/src/qt/locale/bitcoin_gl.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -200,6 +200,9 @@ Cambiouse con éxito o contrasinal do moedeiro. + + BanTableModel + BitcoinGUI @@ -258,6 +261,10 @@ &Change Passphrase... &Cambiar contrasinal... + + &Receiving addresses... + Direccións para recibir + Importing blocks from disk... Importando bloques de disco... @@ -366,6 +373,10 @@ Open a bitcoin: URI or payment request Abrir un bitcoin: URI ou solicitude de pago + + &Command-line options + Opcións da liña de comandos + No block source available... Non hai orixe de bloques dispoñible... @@ -693,7 +704,7 @@ command-line options opcións da liña de comandos - + Intro @@ -762,6 +773,10 @@ &Network &Rede + + W&allet + Moedeiro + Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. Abrir automáticamente o porto do cliente Bitcoin no router. Esto so funciona se o teu router soporta UPnP e está habilitado. @@ -964,6 +979,10 @@ &Information &Información + + Debug window + Ventana de Depuración + Using OpenSSL version Usar versión OpenSSL @@ -1184,6 +1203,10 @@ Send Coins Moedas Enviadas + + Insufficient funds! + Fondos insuficientes + Quantity: Cantidade: @@ -1208,6 +1231,10 @@ Change: Cambiar: + + Transaction Fee: + Tarifa de transacción: + Send to multiple recipients at once Enviar a múltiples receptores á vez @@ -1347,6 +1374,10 @@ Remove this entry Eliminar esta entrada + + Message: + Mensaxe: + Enter a label for this address to add it to the list of used addresses Introduce unha etiqueta para esta dirección para engadila á listaxe de direccións empregadas @@ -1930,10 +1961,6 @@ Run in the background as a daemon and accept commands Executar no fondo como un demo e aceptar comandos - - Use the test network - Empregar a rede de proba - Accept connections from outside (default: 1 if no -proxy or -connect) Aceptar conexións de fóra (por defecto: 1 se non -proxy ou -connect) @@ -1950,10 +1977,6 @@ This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Esta é unha build de test pre-lanzamento - emprégaa baixo o teu propio risco - non empregar para minado ou aplicacións de comerciantes - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Precaución: -paytxfee está posto moi algo! Esta é a tarifa de transacción que ti pagarás se envías unha transacción. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Precaución: A rede non parece estar totalmente de acordo! Algúns mineitos parecen estar experimentando problemas. @@ -1962,10 +1985,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Precaución: Non parece que esteamos totalmente de acordo cos nosos pares! Pode que precises actualizar, ou outros nodos poden precisar actualizarse. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Precaución: erro lendo wallet.dat! Tódalas claves lidas correctamente, pero os datos de transacción ou as entradas do libro de direccións podrían estar ausentes ou incorrectos. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Precaución: wallet.dat corrupto, datos salvagardados! O wallet.dat orixinal foi gardado como wallet.{timestamp}.bak en %s; se o teu balance ou transaccións son incorrectas deberías restauralas dende unha copia de seguridade. @@ -1974,10 +1993,6 @@ <category> can be: <categoría> pode ser: - - Attempt to recover private keys from a corrupt wallet.dat - Tentar recuperar claves privadas dende un wallet.dat corrupto - Block creation options: Opcións de creación de bloque: @@ -2050,22 +2065,22 @@ You need to rebuild the database using -reindex to change -txindex Precisas reconstruír a base de datos empregando -reindex para cambiar -txindex - - Imports blocks from external blk000??.dat file - Importa bloques dende arquivos blk000??.dat externos - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Executar comando cando se recibe unha alerta relevante ou vemos un fork realmente longo (%s no cmd é substituído pola mensaxe) - Choose data directory on startup (default: 0) - Escolle directorio de datos ao arrancar (por defecto: 0) + Cannot resolve -whitebind address: '%s' + Non se pode resolver dirección -whitebind: '%s' Information Información + + Invalid amount for -maxtxfee=<amount>: '%s' + Cantidade inválida para -maxtxfee=<cantidade>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' Cantidade inválida para -minrelaytxfee=<cantidade>: '%s' @@ -2078,14 +2093,6 @@ Send trace/debug info to console instead of debug.log file Enviar traza/información de depuración á consola en lugar de ao arquivo debug.log - - Set language, for example "de_DE" (default: system locale) - Fixar idioma, por exemplo "de_DE" (por defecto: locale del sistema) - - - Show splash screen on startup (default: 1) - Amosar pantalla splash no arranque (por defecto: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Recortar o arquivo debug.log ao arrancar o cliente (por defecto: 1 cando no-debug) @@ -2094,10 +2101,6 @@ Signing transaction failed Fallou a sinatura da transacción - - Start minimized - Comezar minimizado - Transaction amount too small A cantidade da transacción é demasiado pequena @@ -2110,10 +2113,6 @@ Transaction too large A transacción é demasiado grande - - Use UPnP to map the listening port (default: 1 when listening) - Usar UPnP para mapear o porto de escoita (por defecto: 1 se á escoita) - Username for JSON-RPC connections Nome de usuario para conexións JSON-RPC @@ -2134,18 +2133,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Executar comando cando o mellor bloque cambie (%s no comando é sustituído polo hash do bloque) - - Upgrade wallet to latest format - Actualizar moedeiro ao formato máis recente - - - Rescan the block chain for missing wallet transactions - Rescanear transaccións ausentes na cadea de bloques - - - Use OpenSSL (https) for JSON-RPC connections - Empregar OpenSSL (https) para conexións JSON-RPC - This help message Esta mensaxe de axuda diff --git a/src/qt/locale/bitcoin_gu_IN.ts b/src/qt/locale/bitcoin_gu_IN.ts deleted file mode 100644 index ef99b0dd3..000000000 --- a/src/qt/locale/bitcoin_gu_IN.ts +++ /dev/null @@ -1,110 +0,0 @@ - - - AddressBookPage - - - AddressTableModel - - - AskPassphraseDialog - - - BitcoinGUI - - - ClientModel - - - CoinControlDialog - - - EditAddressDialog - - - FreespaceChecker - - - HelpMessageDialog - - - Intro - - - OpenURIDialog - - - OptionsDialog - - - OverviewPage - - - PaymentServer - - - PeerTableModel - - - QObject - - - QRImageWidget - - - RPCConsole - - - ReceiveCoinsDialog - - - ReceiveRequestDialog - - - RecentRequestsTableModel - - - SendCoinsDialog - - - SendCoinsEntry - - - ShutdownWindow - - - SignVerifyMessageDialog - - - SplashScreen - - - TrafficGraphWidget - - - TransactionDesc - - - TransactionDescDialog - - - TransactionTableModel - - - TransactionView - - - UnitDisplayStatusBarControl - - - WalletFrame - - - WalletModel - - - WalletView - - - bitcoin-core - - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts index 9c1863de8..926d20620 100644 --- a/src/qt/locale/bitcoin_he.ts +++ b/src/qt/locale/bitcoin_he.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -208,6 +208,9 @@ מילת הצופן של הארנק שונתה בהצלחה. + + BanTableModel + BitcoinGUI @@ -414,6 +417,10 @@ %1 and %2 %1 ו%2 + + %1 behind + %1 מאחור + Last received block was generated %1 ago. המקטע האחרון שהתקבל נוצר לפני %1. @@ -620,6 +627,10 @@ lowest הנמוך ביותר + + (%1 locked) + (%1 נעול) + none ללא @@ -769,7 +780,7 @@ command-line options אפשרויות שורת פקודה - + Intro @@ -1312,14 +1323,6 @@ Services שירותים - - Starting Height - גובה התחלתי - - - Sync Height - גובה הסנכרון - Ban Score דירוג חסימה @@ -1336,14 +1339,6 @@ Last Receive קבלה אחרונה - - Bytes Sent - בתים שנשלחו - - - Bytes Received - בתים שהתקבלו - Ping Time זמן המענה @@ -1433,12 +1428,16 @@ תעבורה יוצאת - Unknown - לא ידוע + Yes + כן - Fetching... - מתקבל… + No + לא + + + Unknown + לא ידוע @@ -1668,6 +1667,10 @@ Custom change address כתובת לעודף מותאמת אישית + + Transaction Fee: + עמלת העברה: + Send to multiple recipients at once שליחה למספר מוטבים בו־זמנית @@ -1736,10 +1739,6 @@ Copy change העתקת עודף - - Total Amount %1 (= %2) - הסכום הכולל %1 (= %2) - or או @@ -2494,10 +2493,6 @@ Run in the background as a daemon and accept commands ריצה כסוכן ברקע וקבלת פקודות - - Use the test network - שימוש ברשת הבדיקה - Accept connections from outside (default: 1 if no -proxy or -connect) קבלת חיבורים מבחוץ (בררת מחדל: 1 ללא ‎-proxy או ‎-connect) @@ -2522,10 +2517,6 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. לא ניתן להתאגד אל %s במחשב זה. כנראה שליבת ביטקוין כבר פועלת. - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - אזהרה: ‎-paytxfee נקבע לערך מאד גבוה! זוהי עמלת הפעולה שתשולם בעת העברת שליחה. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. אזהרה: נראה שלא כל הרשת מסכימה! נראה שישנם כורים שנתקלים בבעיות. @@ -2534,26 +2525,14 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. אזהרה: נראה שישנה אי־הסכמה בינינו לבין שאר העמיתים שלנו! יתכן שעדיף לשדרג או שכל שאר העמיתים צריכים לשדרג. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - אזהרה: שגיאה בקריאת wallet.dat! כל המפתחות נקראו באופן תקין, אך נתוני ההעברות או ספר הכתובות עלולים להיות חסרים או שגויים. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. אזהרה: הקובץ wallet.dat הושחת, המידע חולץ! קובץ ה־wallet.dat המקורי נשמר בשם wallet.{timestamp}.bak במיקום %s; אם המאזן או ההעברות שגויים עליך לשחזר גיבוי. - - (default: 1) - (בררת מחדל: 1) - <category> can be: <קטגוריה> יכולה להיות: - - Attempt to recover private keys from a corrupt wallet.dat - נסה לשחזר מפתחות פרטיים מקובץ wallet.dat מושחת. - Block creation options: אפשרויות יצירת מקטע: @@ -2606,10 +2585,6 @@ Failed to listen on any port. Use -listen=0 if you want this. האזנה נכשלה בכל פורט. השתמש ב- -listen=0 אם ברצונך בכך. - - If <category> is not supplied, output all debugging information. - אם לא סופקה <קטגוריה> יש לייצא את כל פרטי הניפוי. - Importing... מתבצע יבוא… @@ -2662,26 +2637,14 @@ You need to rebuild the database using -reindex to change -txindex עליך לבנות מחדש את מסד הנתונים תוך שימוש ב־‎-reindex על מנת לשנות את ‎-txindex - - Imports blocks from external blk000??.dat file - מיובאים מקטעים מקובצי blk000??.dat חיצוניים - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) הרץ פקודה כאשר ההתראה הרלוונטית מתקבלת או כשאנחנו עדים לפיצול ארוך מאוד (%s בשורת הפקודה יוחלף ע"י ההודעה) - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - אזהרה: נא לבדוק שהתאריך והשעה של המחשב שלך נכונים! אם השעון שלך שגוי ליבת ביטקוין לא תעבוד כראוי. - Cannot resolve -whitebind address: '%s' לא ניתן לפתור את הכתובת ‎-whitebind:‏ '%s' - - Choose data directory on startup (default: 0) - בחירת תיקיית נתונים עם ההפעלה (בררת מחדל: 0) - Connect through SOCKS5 proxy התחברות דרך מתווך SOCKS5 @@ -2690,22 +2653,10 @@ Copyright (C) 2009-%i The Bitcoin Core Developers כל הזכויות שמורות (C)‏ 2009‏-%i מתכנתי ליבת ביטקוין - - Could not parse -rpcbind value %s as network address - לא ניתן לנתח את הערך של ‎-rpcbind שצוין בתור %s ככתובת רשת - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core אירעה שגיאה בטעינת wallet.dat: הארנק דורש גרסה חדשה יותר של ליבת ביטקוין - - Error: Unsupported argument -tor found, use -onion. - שגיאה: נמצא ארגומנט בלתי נתמך ‎-tor, יש להשתמש ב־‎-onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - עמלה (ב־BTC/ק״ב) להוספה להעברות שנשלחות ממך (בררת מחדל: %s) - Information מידע @@ -2714,6 +2665,10 @@ Initialization sanity check failed. Bitcoin Core is shutting down. בדיקת התקינות ההתחלתית נכשלה. ליבת ביטקוין תיסגר כעת. + + Invalid amount for -maxtxfee=<amount>: '%s' + כמות לא תקינה עבור -maxtxfee=<amount>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' כמות לא תקינה עבור -paytxfee=<amount>: '%s' @@ -2738,10 +2693,6 @@ Node relay options: אפשרויות ממסר מפרק: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - אפשרויות RPC SSL: (נא לעיין בוויקי של ביטקוין לקבלת הנחיות על הגדרת SSL) - RPC server options: הגדרות שרת RPC @@ -2750,22 +2701,10 @@ Send trace/debug info to console instead of debug.log file שלח מידע דיבאג ועקבה לקונסולה במקום לקובץ debug.log - - Set SSL root certificates for payment request (default: -system-) - הגדרות אישורי בסיס של SSL לבקשות תשלום (בררת המחדל: -מערכת-) - - - Set language, for example "de_DE" (default: system locale) - הגדרת שפה, למשל „he_il“ (בררת מחדל: שפת המערכת) - Show all debugging options (usage: --help -help-debug) הצגת כל אפשרויות הניפוי (שימוש: ‎--help -help-debug) - - Show splash screen on startup (default: 1) - הצגת מסך פתיחה בעת הפעלה (בררת מחדל: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) כיווץ הקובץ debug.log בהפעלת הלקוח (בררת מחדל: 1 ללא ‎-debug) @@ -2774,10 +2713,6 @@ Signing transaction failed החתימה על ההעברה נכשלה - - Start minimized - התחלה במצב ממוזער - This is experimental software. זוהי תכנית נסיונית. @@ -2798,10 +2733,6 @@ Unable to bind to %s on this computer (bind returned error %s) לא ניתן להתאגד עם הפתחה %s במחשב זה (פעולת האיגוד החזירה את השגיאה %s) - - Use UPnP to map the listening port (default: 1 when listening) - יש להשתמש ב־UPnP כדי למפות את הפתחה להאזנה (בררת מחדל: 1 בעת האזנה) - Username for JSON-RPC connections שם משתמש לחיבורי JSON-RPC @@ -2814,18 +2745,6 @@ Warning אזהרה - - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - אזהרה: הארגומנט שאינו נתמך עוד ‎-benchmark לא הופעל, נא להשתמש ב־‎-debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - אזהרה: הארגומנט שאינו נתמך עוד ‎-debugnet לא הופעל, נא להשתמש ב־‎-debug=net. - - - on startup - עם ההפעלה - wallet.dat corrupt, salvage failed קובץ wallet.dat מושחת, החילוץ נכשל @@ -2838,18 +2757,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) יש לבצע פקודה זו כשהמקטע הטוב ביותר משתנה (%s בפקודה יוחלף בגיבוב המקטע) - - Upgrade wallet to latest format - שדרוג הארנק למבנה העדכני - - - Rescan the block chain for missing wallet transactions - יש לסרוק מחדש את שרשרת המקטעים למציאת העברות חסרות בארנק - - - Use OpenSSL (https) for JSON-RPC connections - שימוש ב־OpenSSL (https)‎ עבור חיבורי JSON-RPC - This help message הודעת העזרה הזו diff --git a/src/qt/locale/bitcoin_hi_IN.ts b/src/qt/locale/bitcoin_hi_IN.ts index 01e074ffc..377ff3a3f 100644 --- a/src/qt/locale/bitcoin_hi_IN.ts +++ b/src/qt/locale/bitcoin_hi_IN.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -116,6 +116,9 @@ वॉलेट का डीक्रिप्ट-ष्ण असफल ! + + BanTableModel + BitcoinGUI @@ -331,6 +334,10 @@ Options विकल्प + + W&allet + वॉलेट + &OK &ओके @@ -382,6 +389,10 @@ ReceiveCoinsDialog + + &Amount: + राशि : + &Label: लेबल: @@ -397,6 +408,10 @@ ReceiveRequestDialog + + Copy &Address + &पता कॉपी करे + Address पता @@ -498,6 +513,10 @@ Alt+P Alt-P + + Pay To: + प्राप्तकर्ता: + ShutdownWindow @@ -813,10 +832,6 @@ Run in the background as a daemon and accept commands बैकग्राउंड में डेमॉन बन कर रन करे तथा कमांड्स स्वीकार करें - - Use the test network - टेस्ट नेटवर्क का इस्तेमाल करे - Verifying blocks... ब्लॉक्स जाँचे जा रहा है... diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts index 74d380ec2..413dc2185 100644 --- a/src/qt/locale/bitcoin_hr.ts +++ b/src/qt/locale/bitcoin_hr.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -216,6 +216,9 @@ Lozinka novčanika je uspješno promijenjena. + + BanTableModel + BitcoinGUI @@ -771,7 +774,7 @@ command-line options opcije programa u naredbenoj liniji - + Intro @@ -1010,6 +1013,10 @@ &Information &Informacije + + Debug window + Konzola za dijagnostiku + Using OpenSSL version OpenSSL verzija u upotrebi @@ -1054,14 +1061,6 @@ Connection Time Trajanje veze - - Bytes Sent - Bajtova poslano - - - Bytes Received - Bajtova primljeno - Last block time Posljednje vrijeme bloka @@ -1098,7 +1097,7 @@ Unknown Nepoznato - + ReceiveCoinsDialog @@ -1218,6 +1217,10 @@ Send Coins Slanje novca + + Insufficient funds! + Nedovoljna sredstva + Quantity: Količina: @@ -1242,6 +1245,10 @@ Change: Vraćeno: + + Transaction Fee: + Naknada za transakciju: + Send to multiple recipients at once Pošalji novce većem broju primatelja u jednoj transakciji @@ -1371,6 +1378,10 @@ Signature Potpis + + Sign &Message + &Potpišite poruku + Clear &All Obriši &sve @@ -1379,6 +1390,10 @@ &Verify Message &Potvrdite poruku + + Verify &Message + &Potvrdite poruku + Wallet unlock was cancelled. Otključavanje novčanika je otkazano. @@ -1768,14 +1783,6 @@ Run in the background as a daemon and accept commands Izvršavaj u pozadini kao uslužnik i prihvaćaj komande - - Use the test network - Koristi test mrežu - - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Upozorenje: -paytxfee je podešen na preveliki iznos. To je iznos koji ćete platiti za obradu transakcije. - Block creation options: Opcije za kreiranje bloka: @@ -1788,26 +1795,26 @@ Error: Disk space is low! Pogreška: Nema dovoljno prostora na disku! - - Imports blocks from external blk000??.dat file - Uvozi blokove sa vanjske blk000??.dat datoteke - Information Informacija + + Invalid amount for -maxtxfee=<amount>: '%s' + Nevaljali iznos za opciju -maxtxfee=<iznos>: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Nevaljali iznos za opciju -minrelaytxfee=<iznos>: '%s' + + + Invalid amount for -mintxfee=<amount>: '%s' + Nevaljali iznos za opciju -mintxfee=<iznos>: '%s' + Send trace/debug info to console instead of debug.log file Šalji trace/debug informacije na konzolu umjesto u debug.log datoteku - - Start minimized - Pokreni minimiziran - - - Use UPnP to map the listening port (default: 1 when listening) - Pokušaj koristiti UPnP da otvoriš port za uslugu (default: 1 when listening) - Username for JSON-RPC connections Korisničko ime za JSON-RPC veze @@ -1824,18 +1831,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Izvršite naredbu kada se najbolji blok promjeni (%s u cmd je zamjenjen sa block hash) - - Upgrade wallet to latest format - Nadogradite novčanik u posljednji format. - - - Rescan the block chain for missing wallet transactions - Ponovno pretraži lanac blokova za transakcije koje nedostaju - - - Use OpenSSL (https) for JSON-RPC connections - Koristi OpenSSL (https) za JSON-RPC povezivanje - This help message Ova poruka za pomoć diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts index fd476611e..ab4517ccf 100644 --- a/src/qt/locale/bitcoin_hu.ts +++ b/src/qt/locale/bitcoin_hu.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -183,6 +183,10 @@ Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. Add meg a tárca új jelszavát.<br/>Olyan jelszót válassz, ami <b>legalább tíz véletlenszerű karakterből</b> vagy <b>legalább 8 véletlenszerű szóból</b> áll. + + Enter the old passphrase and new passphrase to the wallet. + Add meg a tárcához a régi jelszavad és az új jelszavad. + Wallet encryption failed A tárca titkosítása sikertelen. @@ -212,6 +216,9 @@ Jelszó megváltoztatva. + + BanTableModel + BitcoinGUI @@ -390,6 +397,10 @@ &About Bitcoin Core &A Bitcoin Core-ról + + Modify configuration options for Bitcoin Core + Konfigurációs opciók módosítása a Bitcoin Core-hoz + Show the list of used sending addresses and labels A használt küldési címek és címkék megtekintése @@ -410,18 +421,38 @@ Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options A Bitcoin Core súgóüzenet megjelenítése a Bitcoin lehetséges parancssori kapcsolóival. + + %n active connection(s) to Bitcoin network + %n aktív kapcsolat a Bitcoin hálózathoz%n aktív kapcsolat a Bitcoin hálózathoz + No block source available... Blokk forrása ismeretlen... + + Processed %n block(s) of transaction history. + %n blokk feldolgozva a tranzakció előzményből.%n blokk feldolgozva a tranzakció előzményből. + %n hour(s) %n óra%n óra + + %n day(s) + %n nap%n nap + + + %n week(s) + %n hét%n hét + %1 and %2 %1 és %2 + + %n year(s) + %n év%n év + %1 behind %1 lemaradás @@ -458,12 +489,30 @@ Date: %1 Dátum: %1 + + + + Amount: %1 + + Összeg: %1 Type: %1 Típus: %1 + + + + Label: %1 + + Címke: %1 + + + + Address: %1 + + Cím: %1 @@ -492,6 +541,10 @@ CoinControlDialog + + Coin Selection + Érme Választás + Quantity: Mennyiség: @@ -510,7 +563,7 @@ Fee: - Díjak: + Díj: Dust: @@ -540,6 +593,14 @@ Amount Összeg + + Received with label + Címkével érkezett + + + Received with address + Címmel érkezett + Date Dátum @@ -652,6 +713,18 @@ none semmi + + This label turns red if the transaction size is greater than 1000 bytes. + Ez a címke pirosra változik, ha a tranzakció mérete nagyobb mint 1000 bájt. + + + This label turns red if the priority is smaller than "medium". + Ez a címke pirosra változik, ha a prioritás kisebb mint "közepes". + + + This label turns red if any recipient receives an amount smaller than %1. + Ez a címke pirosra változik, ha bármely fogadónak %1-nál kevesebb összeg érkezik. + Can vary +/- %1 satoshi(s) per input. Bemenetenként +/- %1 satoshi-val változhat @@ -793,7 +866,7 @@ command-line options parancssoros opciók - + Intro @@ -828,6 +901,10 @@ Error Hiba + + %n GB of free space available + %n GB elérhető szabad hely%n GB elérhető szabad hely + OpenURIDialog @@ -862,6 +939,10 @@ &Main &Fő + + Size of &database cache + A&datbázis gyorsítótár mérete + MB MB @@ -878,6 +959,10 @@ IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) A proxy IP címe (pl.: IPv4: 127.0.0.1 / IPv6: ::1) + + The user interface language can be set here. This setting will take effect after restarting Bitcoin Core. + Itt beállíthatod a kezelőfelület nyelvét. A beállítás a Bitcoin újraindítása után lép érvénybe. + Reset all client options to default. Minden kliensbeállítás alapértelmezettre állítása. @@ -894,9 +979,13 @@ &Start Bitcoin Core on system login A Bitcoin elindítása bejelentkezéskor + + W&allet + T&árca + Expert - szakértő + Szakértő Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. @@ -922,6 +1011,18 @@ Port of the proxy (e.g. 9050) Proxy portja (pl.: 9050) + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + &Window &Ablak @@ -993,6 +1094,10 @@ The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet. A kijelzett információ lehet, hogy elavult. A pénztárcája automatikusan szinkronizálja magát a Bitcoin hálózattal miután a kapcsolat létrejön, de ez e folyamat még nem fejeződött be. + + Watch-only: + Csak megfigyelés + Available: Elérhető: @@ -1017,6 +1122,10 @@ Mined balance that has not yet matured Bányászott egyenleg amely még nem érett be. + + Balances + Egyenlegek + Total: Összesen: @@ -1044,6 +1153,14 @@ Cannot start bitcoin: click-to-pay handler A bitcoint nem lehet elindítani: click-to-pay handler + + Payment request expired. + A fizetési kérelem lejárt + + + Invalid payment request. + Érvénytelen fizetési kérelem + PeerTableModel @@ -1062,6 +1179,10 @@ Amount Összeg + + Enter a Bitcoin address (e.g. %1) + Ad meg egy Bitcoin címet (pl: %1) + %1 d %1 n @@ -1078,11 +1199,19 @@ %1 s %1 mp + + None + Semmi + N/A Nem elérhető - + + %1 ms + %1 ms + + QRImageWidget @@ -1132,6 +1261,10 @@ Using OpenSSL version Használt OpenSSL verzió + + Using BerkeleyDB version + Használt BerkeleyDB verzió + Startup time Bekapcsolás ideje @@ -1156,6 +1289,10 @@ Current number of blocks Aktuális blokkok száma + + Memory usage + Memóriahasználat + Received Fogadott @@ -1168,6 +1305,10 @@ &Peers &Peerek + + Select a peer to view detailed information. + Peer kijelölése a részletes információkért + Version Verzió @@ -1180,6 +1321,10 @@ Services Szolgáltatások + + Connection Time + Csatlakozás ideje + Last Send Legutóbbi küldés @@ -1188,14 +1333,6 @@ Last Receive Legutóbbi fogadás - - Bytes Sent - Küldött bájtok - - - Bytes Received - Fogadott bájtok - Ping Time Ping idő @@ -1216,6 +1353,10 @@ &Network Traffic &Hálózati forgalom + + &Clear + &Törlés + Totals Összesen: @@ -1240,6 +1381,22 @@ Clear console Konzol törlése + + 1 &hour + 1 &óra + + + 1 &day + 1 &nap + + + 1 &week + 1 &hét + + + 1 &year + 1 &év + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. Navigálhat a fel és le nyilakkal, és <b>Ctrl-L</b> -vel törölheti a képernyőt. @@ -1264,17 +1421,41 @@ %1 GB %1 GB + + via %1 + %1 által + never soha + + Inbound + Bejövő + + + Outbound + Kimenő + + + Yes + Igen + + + No + Nem + Unknown Ismeretlen - + ReceiveCoinsDialog + + &Amount: + &Összeg: + &Label: Címke: @@ -1283,14 +1464,30 @@ &Message: &Üzenet: + + Clear all fields of the form. + Minden mező törlése + Clear Törlés + + Requested payments history + A kért kifizetések története + + + &Request payment + &Fizetés kérése + Show Mutat + + Remove the selected entries from the list + A kijelölt elemek törlése a listáról + Remove Eltávolítás @@ -1326,6 +1523,14 @@ &Save Image... &Kép mentése + + Request payment to %1 + Fizetés kérése a %1-hez + + + Payment information + Kifizetés információ + URI URI: @@ -1377,7 +1582,15 @@ (no label) (nincs címke) - + + (no message) + (nincs üzenet) + + + (no amount) + (nincs összeg) + + SendCoinsDialog @@ -1388,6 +1601,14 @@ Inputs... Bemenetek... + + automatically selected + automatikusan kiválasztva + + + Insufficient funds! + Fedezethiány! + Quantity: Mennyiség: @@ -1420,10 +1641,34 @@ Transaction Fee: Tranzakciós díj + + Choose... + Válassz... + + + per kilobyte + kilobájtonként + Hide Elrejtés + + Recommended: + Ajánlott: + + + Custom: + Egyéni: + + + normal + normál + + + fast + gyors + Send to multiple recipients at once Küldés több címzettnek egyszerre @@ -1432,6 +1677,10 @@ Add &Recipient &Címzett hozzáadása + + Clear all fields of the form. + Minden mező törlése + Dust: Por-határ: @@ -1500,6 +1749,14 @@ The total exceeds your balance when the %1 transaction fee is included. A küldeni kívánt összeg és a %1 tranzakciós díj együtt meghaladja az egyenlegeden rendelkezésedre álló összeget. + + Payment request expired. + A fizetési kérelem lejárt + + + Warning: Invalid Bitcoin address + Figyelmeztetés: Érvénytelen Bitcoin cím + (no label) (nincs címke) @@ -1508,6 +1765,10 @@ Copy dust Visszajáró másolása + + Are you sure you want to send? + Biztos, hogy el akarod küldeni? + SendCoinsEntry @@ -1528,6 +1789,10 @@ &Label: Címke: + + Choose previously used address + Válassz egy korábban már használt címet + Alt+A Alt+A @@ -1540,10 +1805,18 @@ Alt+P Alt+P + + Remove this entry + Ez a bejegyzés eltávolítása + Message: Üzenet: + + Pay To: + Címzett: + Memo: Jegyzet: @@ -1555,7 +1828,11 @@ Bitcoin Core is shutting down... A Bitcoin Core leáll... - + + Do not shut down the computer until this window disappears. + Ne állítsd le a számítógépet amíg ez az ablak el nem tűnik. + + SignVerifyMessageDialog @@ -1566,6 +1843,10 @@ &Sign Message Üzenet aláírása... + + Choose previously used address + Válassz egy korábban már használt címet + Alt+A Alt+A @@ -1606,6 +1887,10 @@ &Verify Message Üzenet ellenőrzése + + Verify &Message + Üzenet ellenőrzése + The entered address is invalid. A megadott cím nem érvényes. @@ -1948,6 +2233,10 @@ Show transaction details Tranzakciós részletek megjelenítése + + Watch-only + Csak megfigyelés + Exporting Failed Az exportálás sikertelen volt @@ -2061,11 +2350,6 @@ Run in the background as a daemon and accept commands Háttérben futtatás daemonként és parancsok elfogadása - - - - Use the test network - Teszthálózat használata @@ -2076,10 +2360,6 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Parancs, amit akkor hajt végre, amikor egy tárca-tranzakció megváltozik (%s a parancsban lecserélődik a blokk TxID-re) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Figyelem: a -paytxfee nagyon magas. Ennyi tranzakciós díjat fogsz fizetni, ha elküldöd a tranzakciót. - Connect only to the specified node(s) Csatlakozás csak a megadott csomóponthoz @@ -2145,8 +2425,8 @@ Az adatbázist újra kell építeni -reindex használatával (módosítás -tindex). - Choose data directory on startup (default: 0) - Adatkönyvtár kiválasztása induláskor (alapbeállítás: 0) + Cannot resolve -whitebind address: '%s' + Külső cím (-whitebind address) feloldása nem sikerült: '%s' Copyright (C) 2009-%i The Bitcoin Core Developers @@ -2160,6 +2440,10 @@ Information Információ + + Invalid amount for -maxtxfee=<amount>: '%s' + Érvénytelen -maxtxfee=<amount>: '%s' összeg + Invalid amount for -minrelaytxfee=<amount>: '%s' Érvénytelen -minrelaytxfee=<amount>: '%s' összeg @@ -2172,27 +2456,10 @@ Send trace/debug info to console instead of debug.log file trace/debug információ küldése a konzolra a debog.log fájl helyett - - Set SSL root certificates for payment request (default: -system-) - SLL gyökér-igazolások megadása fizetési kérelmekhez (alapértelmezett: -system-) - - - Set language, for example "de_DE" (default: system locale) - Nyelvbeállítás, például "de_DE" (alapértelmezett: rendszer nyelve) - - - Show splash screen on startup (default: 1) - Indítóképernyő mutatása induláskor (alapértelmezett: 1) - Signing transaction failed Tranzakció aláírása sikertelen - - Start minimized - Indítás lekicsinyítve - - This is experimental software. Ez egy kísérleti szoftver. @@ -2209,10 +2476,6 @@ Transaction too large Túl nagy tranzakció - - Use UPnP to map the listening port (default: 1 when listening) - UPnP-használat engedélyezése a figyelő port feltérképezésénél (default: 1 when listening) - Username for JSON-RPC connections Felhasználói név JSON-RPC csatlakozásokhoz @@ -2231,20 +2494,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Parancs, amit akkor hajt végre, amikor a legjobb blokk megváltozik (%s a cmd-ban lecserélődik a blokk hash-re) - - Upgrade wallet to latest format - A Tárca frissítése a legfrissebb formátumra - - - Rescan the block chain for missing wallet transactions - Blokklánc újraszkennelése hiányzó tárca-tranzakciók után - - - - Use OpenSSL (https) for JSON-RPC connections - OpenSSL (https) használata JSON-RPC csatalkozásokhoz - - This help message Ez a súgó-üzenet diff --git a/src/qt/locale/bitcoin_id_ID.ts b/src/qt/locale/bitcoin_id_ID.ts index 6855d11c8..1b626fbf2 100644 --- a/src/qt/locale/bitcoin_id_ID.ts +++ b/src/qt/locale/bitcoin_id_ID.ts @@ -1,6 +1,10 @@ - + AddressBookPage + + Right-click to edit address or label + Klik-kanan untuk mengubah alamat atau label + Create a new address Buat alamat baru @@ -196,6 +200,9 @@ Kata kunci untuk dompet berubah berhasil. + + BanTableModel + BitcoinGUI @@ -246,6 +253,10 @@ &Options... &Pilihan... + + &Encrypt Wallet... + &Enkripsi Dompet... + &Backup Wallet... &Cadangkan Dompet... @@ -450,6 +461,36 @@ Catching up... Menyusul... + + Date: %1 + + Tanggal: %1 + + + + Amount: %1 + + Jumlah: %1 + + + + Type: %1 + + Tipe: %1 + + + + Label: %1 + + Label: %1 + + + + Address: %1 + + Alamat: %1 + + Sent transaction Transaksi terkirim @@ -476,6 +517,10 @@ CoinControlDialog + + Coin Selection + Pemilihan Koin + Quantity: Kuantitas: @@ -753,6 +798,10 @@ About Bitcoin Core Mengenai Bitcoin Core + + Command-line options + pilihan Perintah-baris + Usage: Penggunaan: @@ -761,7 +810,7 @@ command-line options pilihan perintah-baris - + Intro @@ -894,6 +943,18 @@ Port of the proxy (e.g. 9050) Port proxy (cth. 9050) + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + &Window &Jendela @@ -954,6 +1015,10 @@ Client restart required to activate changes. Restart klien diperlukan untuk mengaktifkan perubahan. + + Client will be shut down. Do you want to proceed? + Klien akan dimatikan, apakah anda hendak melanjutkan? + This change would require a client restart. Perubahan ini akan memerlukan restart klien @@ -997,6 +1062,10 @@ Mined balance that has not yet matured Saldo ditambang yang masih terlalu muda + + Balances + Saldo: + Total: Jumlah: @@ -1016,6 +1085,10 @@ Invalid payment address %1 Alamat pembayaran salah %1 + + Payment request rejected + Permintaan pembayaran ditolak + Requested payment amount of %1 is too small (considered dust). Nilai pembayaran %1 yang diminta oleh Anda terlalu sedikit (dianggap debu). @@ -1024,6 +1097,10 @@ Payment request error Gagalan permintaan pembayaran + + Payment request expired. + Permintaan pembayaran telah kadaluarsa + Refund from %1 Pembayaran kembali dari %1 @@ -1047,6 +1124,10 @@ PeerTableModel + + User Agent + Agen Pengguna + QObject @@ -1054,6 +1135,10 @@ Amount Nilai + + Enter a Bitcoin address (e.g. %1) + Masukkan alamat Bitcoin (contoh %1) + %1 h %1 Jam @@ -1140,6 +1225,24 @@ Current number of blocks Jumlah blok terkini + + Sent + Terkirim + + + Version + Versi + + + User Agent + Agen Pengguna + + + + + Services + Layanan + Last block time Waktu blok terakhir @@ -1184,6 +1287,26 @@ Clear console Bersihkan konsol + + 1 &hour + 1 &jam + + + 1 &day + 1 &hari + + + 1 &week + 1 &minggu + + + 1 &year + 1 &tahun + + + Welcome to the Bitcoin Core RPC console. + Selamat datang di konsol RPC Bitcoin. + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. Gunakan panah keatas dan kebawah untuk menampilkan sejarah, dan <b>Ctrl-L</b> untuk bersihkan layar. @@ -1208,7 +1331,19 @@ %1 GB %1 GB - + + Yes + Ya + + + No + Tidak + + + Unknown + Tidak diketahui + + ReceiveCoinsDialog @@ -1428,6 +1563,26 @@ Custom change address Alamat uang kembali yang kustom + + Transaction Fee: + Biaya Transaksi: + + + Recommended: + Disarankan + + + Confirmation time: + Waktu konfirmasi: + + + normal + normal + + + fast + cepat + Send to multiple recipients at once Kirim ke beberapa penerima sekaligus @@ -1440,6 +1595,10 @@ Clear all fields of the form. Hapus informasi dari form. + + Clear &All + Hapus &Semua + Balance: Saldo: @@ -1489,8 +1648,8 @@ Salin uang kembali - Total Amount %1 (= %2) - Jumlah Nilai %1 (= %2) + Total Amount %1 + Jumlah Total %1 or @@ -1516,6 +1675,14 @@ The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. Gagal: Transaksi ditolak. Ini mungkin terjadi jika beberapa dari koin dalam dompet Anda telah digunakan, seperti ketika Anda menggunakan salinan wallet.dat dan beberapa koin telah dibelanjakan dalam salinan tersebut tetapi disini tidak tertandai sebagai terpakai. + + A fee higher than %1 is considered an absurdly high fee. + Biaya yang lebih tinggi dari %1 dianggap biaya tak masuk akal. + + + Payment request expired. + Permintaan pembayaran telah kadaluarsa + Warning: Invalid Bitcoin address Awas: Alamat Bitcoin tidak sah @@ -1653,6 +1820,10 @@ Reset all sign message fields Hapus semua bidang penanda pesan + + Clear &All + Hapus &Semua + &Verify Message &Verifikasi Pesan @@ -2190,10 +2361,6 @@ Run in the background as a daemon and accept commands Berjalan dibelakang sebagai daemin dan menerima perintah - - Use the test network - Gunakan jaringan uji - Accept connections from outside (default: 1 if no -proxy or -connect) Terima hubungan dari luar (standar: 1 kalau -proxy atau -connect tidak dipilih) @@ -2206,10 +2373,6 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. Tidak bisa mengikat dengan %s di computer ini. Kemungkinan Bitcoin Core sudah mulai. - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Peringatan: -paytxfee sangat besar! Ini adalah biaya pengiriman yang akan dibayar oleh Anda jika transaksi terkirim. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Peringatan: Jaringan tidak semua bersetuju! Beberapa penambang dapat persoalan. @@ -2218,18 +2381,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Peringatan: Kami tidak bersetujuh dengan peer-peer kami! Kemungkinan Anda harus upgrade, atau node-node lain yang harus diupgrade. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Awas: wallet.dat tidak bisa dibaca! Berhasil periksakan kunci-kunci dalam arsipnya, tetapi ada kemungkinan informasi tentang transaksi atau isi-isi buku alamat salah atau terhilang. - - - (default: 1) - (pengaturan awal: 1) - - - Attempt to recover private keys from a corrupt wallet.dat - Coba memulihkan kunci-kunci pribadi dari wallet.dat yang rusak - Block creation options: Pilihan pembuatan blok: @@ -2318,18 +2469,26 @@ You need to rebuild the database using -reindex to change -txindex Harus membangun ulang database menggunakan -reindex supaya mengubah -txindex - - Imports blocks from external blk000??.dat file - Impor blok dari eksternal berkas blk000???.dat - Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running. Tidak bisa mengunci data directory %s. Kemungkinan Bitcoin Core sudah mulai. + + Cannot resolve -whitebind address: '%s' + Tidak dapat menyelesaikan alamat -whitebind: '%s' + + + Connect through SOCKS5 proxy + Hubungkan melalui proxy SOCKS5 + Information Informasi + + Invalid amount for -maxtxfee=<amount>: '%s' + Nilai salah untuk -maxtxfee=<amount>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' Nilai yang salah untuk -minrelaytxfee=<amount>: '%s' @@ -2346,14 +2505,6 @@ Send trace/debug info to console instead of debug.log file Kirim info jejak/debug ke konsol bukan berkas debug.log - - Set language, for example "de_DE" (default: system locale) - Atur bahasa, sebagai contoh "id_ID" (standar: system locale) - - - Show splash screen on startup (default: 1) - Tampilkan layar pembuka saat nyala (standar: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Mengecilkan berkas debug.log saat klien berjalan (Standar: 1 jika tidak -debug) @@ -2362,10 +2513,6 @@ Signing transaction failed Tandatangani transaksi tergagal - - Start minimized - Memulai terminimalisi - Transaction amount too small Nilai transaksi terlalu kecil @@ -2402,18 +2549,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Menjalankan perintah ketika perubahan blok terbaik (%s dalam cmd digantikan oleh hash blok) - - Upgrade wallet to latest format - Perbarui dompet ke format terbaru - - - Rescan the block chain for missing wallet transactions - Pindai ulang rantai-blok untuk transaksi dompet yang hilang - - - Use OpenSSL (https) for JSON-RPC connections - Gunakan OpenSSL (https) untuk hubungan JSON-RPC - This help message Pesan bantuan ini diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts index d3cc57697..d510b1063 100644 --- a/src/qt/locale/bitcoin_it.ts +++ b/src/qt/locale/bitcoin_it.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,17 @@ Passphrase del portamonete modificata con successo. + + BanTableModel + + IP/Netmask + IP/Netmask + + + Banned Until + Bannato fino a + + BitcoinGUI @@ -871,6 +882,34 @@ command-line options opzioni della riga di comando + + UI Options: + Opzioni interfaccia: + + + Choose data directory on startup (default: %u) + Seleziona la directory dei dati all'avvio (default: %u) + + + Set language, for example "de_DE" (default: system locale) + Imposta la lingua, ad esempio "it_IT" (default: locale di sistema) + + + Start minimized + Avvia ridotto a icona + + + Set SSL root certificates for payment request (default: -system-) + Imposta un certificato SSL root per le richieste di pagamento (default: -system-) + + + Show splash screen on startup (default: %u) + Mostra schermata iniziale all'avvio (default: %u) + + + Reset all settings changes made over the GUI + Reset di tutte le modifiche alle impostazioni eseguite da interfaccia grafica + Intro @@ -910,7 +949,11 @@ Error Errore - + + (of %n GB needed) + (di %nGB richiesti)(%n GB richiesti) + + OpenURIDialog @@ -1061,6 +1104,34 @@ Per specificare più URL separarli con una barra verticale "|". Port of the proxy (e.g. 9050) Porta del proxy (ad es. 9050) + + Used for reaching peers via: + Utilizzata per connettersi attraverso: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Mostra se la proxy SOCKS5 fornita viene utilizzata per raggiungere i peers attraverso questo tipo di rete. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Connette alla rete Bitcoin attraverso un proxy SOCKS5 separato per Tor. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Usa un proxy SOCKS5 separato per connettersi ai peers attraverso Tor: + &Window &Finestra @@ -1279,10 +1350,6 @@ Per specificare più URL separarli con una barra verticale "|". Payment request %1 is too large (%2 bytes, allowed %3 bytes). La richiesta di pagamento %1 (%2 byte) supera la dimensione massima di %3 byte. - - Payment request DoS protection - Protezione DoS per la richiesta di pagamento - Error communicating with %1: %2 Errore di comunicazione con %1: %2 @@ -1435,6 +1502,18 @@ Per specificare più URL separarli con una barra verticale "|". Current number of blocks Numero attuale di blocchi + + Memory Pool + Memory Pool + + + Current number of transactions + Numero attuale di transazioni + + + Memory usage + Utilizzo memoria + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. Apre il file log di debug di Bitcoin Core dalla cartella dati attuale. Questa azione può richiedere alcuni secondi per file log di grandi dimensioni. @@ -1451,10 +1530,18 @@ Per specificare più URL separarli con una barra verticale "|". &Peers &Peer + + Banned peers + Peers bannati + Select a peer to view detailed information. Seleziona un peer per visualizzare informazioni più dettagliate. + + Whitelisted + Whitelisted/sicuri + Direction Direzione @@ -1463,6 +1550,18 @@ Per specificare più URL separarli con una barra verticale "|". Version Versione + + Starting Block + Blocco di partenza + + + Synced Headers + Headers sincronizzati + + + Synced Blocks + Blocchi sincronizzati + User Agent User Agent @@ -1471,14 +1570,6 @@ Per specificare più URL separarli con una barra verticale "|". Services Servizi - - Starting Height - Nr. Blocco Iniziale - - - Sync Height - Nr. Blocco Sincronizzato - Ban Score Punteggio di Ban @@ -1495,18 +1586,18 @@ Per specificare più URL separarli con una barra verticale "|". Last Receive Ultima Ricezione - - Bytes Sent - Byte Inviati - - - Bytes Received - Byte Ricevuti - Ping Time Tempo di Ping + + The duration of a currently outstanding ping. + La durata di un ping attualmente in corso. + + + Ping Wait + Attesa ping + Time Offset Scarto Temporale @@ -1555,6 +1646,34 @@ Per specificare più URL separarli con una barra verticale "|". Clear console Cancella console + + &Disconnect Node + &Nodo Disconnesso + + + Ban Node for + Nodo Bannato perché + + + 1 &hour + 1 &ora + + + 1 &day + 1 &giorno + + + 1 &week + 1 &settimana + + + 1 &year + 1 &anno + + + &Unban Node + &Elimina Ban Nodo + Welcome to the Bitcoin Core RPC console. Benvenuto nella console RPC di Bitcoin Core. @@ -1583,6 +1702,10 @@ Per specificare più URL separarli con una barra verticale "|". %1 GB %1 GB + + (node id: %1) + (id nodo: %1) + via %1 via %1 @@ -1600,12 +1723,16 @@ Per specificare più URL separarli con una barra verticale "|". In uscita - Unknown - Sconosciuto + Yes + Si - Fetching... - Recuperando... + No + No + + + Unknown + Sconosciuto @@ -1972,8 +2099,8 @@ Per specificare più URL separarli con una barra verticale "|". Copia resto - Total Amount %1 (= %2) - Importo Totale %1 (= %2) + Total Amount %1 + Ammontare Totale %1 or @@ -2008,8 +2135,12 @@ Per specificare più URL separarli con una barra verticale "|". Richiesta di pagamento scaduta. - Pay only the minimum fee of %1 - Paga solamente la commissione minima di %1 + Pay only the required fee of %1 + Paga solamente la commissione richiesta di %1 + + + Estimated to begin confirmation within %n block(s). + Inizio delle conferme stimato entro %n blocco.Inizio delle conferme stimato entro %n blocchi. The recipient address is not valid. Please recheck. @@ -2642,6 +2773,10 @@ Per specificare più URL separarli con una barra verticale "|". Copy transaction ID Copia l'ID transazione + + Copy raw transaction + Copia la transazione raw + Edit label Modifica l'etichetta @@ -2789,13 +2924,53 @@ Per specificare più URL separarli con una barra verticale "|". Accept command line and JSON-RPC commands Accetta comandi da riga di comando e JSON-RPC + + If <category> is not supplied or if <category> = 1, output all debugging information. + Se <category> non è specificato oppure se <category> = 1, mostra tutte le informazioni di debug. + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Totale massimo di commissioni (in %s) da usare in una singola transazione del wallet; valori troppo bassi possono abortire grandi transazioni (default: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + Per favore controllate che la data del computer e l'ora siano corrette. Se il vostro orologio è sbagliato Bitcoin non funzionerà correttamente. + + + Prune configured below the minimum of %d MiB. Please use a higher number. + La modalità prune è configurata al di sotto del minimo di %d MB. Si prega di utilizzare un valore più elevato. + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + Prune: l'ultima sincronizzazione del wallet risulta essere oltre la riduzione dei dati. È necessario eseguire un -reindex (scaricare nuovamente la blockchain in caso di nodo pruned) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + Riduce i requisiti di spazio di archiviazione attraverso la rimozione dei vecchi blocchi (pruning). Questa modalità è incompatibile con l'opzione -txindex e -rescan. Attenzione: ripristinando questa opzione l'intera blockchain dovrà essere riscaricata. (default: 0 = disabilita il pruning, >%u = dimensione desiderata in MiB per i file dei blocchi) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + Non è possibile un Rescan in modalità pruned. Sarà necessario utilizzare -reindex che farà scaricare nuovamente tutta la blockchain. + + + Error: A fatal internal error occurred, see debug.log for details + Errore: si è presentato un errore interno fatale, consulta il file debug.log per maggiori dettagli + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Commissione (in %s/kB) da aggiungere alle transazioni inviate (default: %s) + + + Pruning blockstore... + Pruning del blockstore... + Run in the background as a daemon and accept commands Esegui in background come demone ed accetta i comandi - Use the test network - Utilizza la rete di prova + Unable to start HTTP server. See debug log for details. + Impossibile avviare il server HTTP. Dettagli nel log di debug. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2817,18 +2992,14 @@ Per specificare più URL separarli con una barra verticale "|". Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Esegue un comando quando lo stato di una transazione del portamonete cambia (%s in cmd è sostituito da TxID) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Commissioni massime totali da includere in una singola transazione dal portamonete. Un'impostazione troppo bassa potrebbe provocare l'annullamento di transazioni di grosse dimensioni (predefinito: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Riduce i requisiti di spazio di archiviazione attraverso la rimozione dei vecchi blocchi (pruning). Questa modalità disabilita le funzionalità di portamonete ed è incompatibile con l'opzione -txindex. Attenzione: il ripristinando questa opzione l'intera blockchain dovrà essere riscaricata. (predefinito: 0 = disabilita il pruning, >%u = dimensione desiderata in MiB per i file dei blocchi) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Imposta il numero di thread per la verifica degli script (da %u a %d, 0 = automatico, <0 = lascia questo numero di core liberi, predefinito: %d) + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + Il database dei blocchi contiene un blocco che sembra provenire dal futuro. Questo può essere dovuto alla data e ora del tuo computer impostate in modo scorretto. Ricostruisci il database dei blocchi se sei certo che la data e l'ora sul tuo computer siano corrette + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Questa versione è una compilazione pre-rilascio - usala a tuo rischio - non utilizzarla per la generazione o per applicazioni di commercio @@ -2837,6 +3008,10 @@ Per specificare più URL separarli con una barra verticale "|". Unable to bind to %s on this computer. Bitcoin Core is probably already running. Impossibile associarsi a %s su questo computer. Probabilmente Bitcoin Core è già in esecuzione. + + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + Utilizza UPnP per mappare la porta in ascolto (default: 1 quando in ascolto e -proxy non è specificato) + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) ATTENZIONE, il numero di blocchi generati è insolitamente elevato: %d blocchi ricevuti nelle ultime %d ore (%d previsti) @@ -2845,10 +3020,6 @@ Per specificare più URL separarli con una barra verticale "|". WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) ATTENZIONE, si consiglia di verificare la connessione di rete: %d blocchi ricevuti nelle ultime %d ore (%d previsti) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Attenzione: -paytxfee è impostato su un valore molto elevato. Questa è la commissione che si paga quando si invia una transazione. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Attenzione: La rete non sembra trovarsi in pieno consenso! Alcuni minatori sembrano riscontrare problemi. @@ -2857,10 +3028,6 @@ Per specificare più URL separarli con una barra verticale "|". Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Attenzione: Sembra che non vi sia pieno consenso con i nostri peer! Un aggiornamento da parte tua o degli altri nodi potrebbe essere necessario. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Attenzione: errore di lettura di wallet.dat! Tutte le chiavi sono state lette correttamente, ma i dati delle transazioni o della rubrica potrebbero essere mancanti o non corretti. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Attenzione: wallet.dat corrotto, dati recuperati! Il wallet.dat originale è stato salvato come wallet.{timestamp}.bak in %s. Se i dati relativi a saldo o transazioni non dovessero risultare corretti si consiglia di procedere al ripristino da un backup. @@ -2870,17 +3037,13 @@ Per specificare più URL separarli con una barra verticale "|". Inserisce in whitelist i peer che si connettono da un dato indirizzo IP o netmask. Può essere specificato più volte. - (default: 1) - (predefinito: 1) + -maxmempool must be at least %d MB + -maxmempool deve essere almeno %d MB <category> can be: Valori possibili per <category>: - - Attempt to recover private keys from a corrupt wallet.dat - Tenta di recuperare le chiavi private da un wallet.dat corrotto - Block creation options: Opzioni creazione blocco: @@ -2909,6 +3072,22 @@ Per specificare più URL separarli con una barra verticale "|". Do you want to rebuild the block database now? Vuoi ricostruire ora il database dei blocchi? + + Enable publish hash block in <address> + Abilita pubblicazione hash blocco in <address> + + + Enable publish hash transaction in <address> + Abilità pubblicazione hash transazione in <address> + + + Enable publish raw block in <address> + Abilita pubblicazione blocchi raw in <address> + + + Enable publish raw transaction in <address> + Abilita pubblicazione transazione raw in <address> + Error initializing block database Errore durante l'inizializzazione del database dei blocchi @@ -2925,10 +3104,6 @@ Per specificare più URL separarli con una barra verticale "|". Error opening block database Errore durante l'apertura del database blocchi - - Error: A fatal internal error occured, see debug.log for details - Errore: si è verificato un errore interno fatale. Consulta il file debug.log for maggiori dettagli. - Error: Disk space is low! Errore: la spazio libero sul disco è insufficiente! @@ -2937,10 +3112,6 @@ Per specificare più URL separarli con una barra verticale "|". Failed to listen on any port. Use -listen=0 if you want this. Nessuna porta disponibile per l'ascolto. Usa -listen=0 se vuoi procedere comunque. - - If <category> is not supplied, output all debugging information. - Se <category> non è specificata, mostra tutte le informazioni di debug. - Importing... Importazione... @@ -2953,6 +3124,10 @@ Per specificare più URL separarli con una barra verticale "|". Invalid -onion address: '%s' Indirizzo -onion non valido: '%s' + + Keep the transaction memory pool below <n> megabytes (default: %u) + Mantieni la memory pool delle transazioni al di sotto di <n> megabytes (default: %u) + Not enough file descriptors available. Non ci sono abbastanza descrittori di file disponibili. @@ -2981,10 +3156,26 @@ Per specificare più URL separarli con una barra verticale "|". Specify wallet file (within data directory) Specifica il file del portamonete (all'interno della cartella dati) + + Unsupported argument -benchmark ignored, use -debug=bench. + Ignorata opzione -benchmark non supportata, utilizzare -debug=bench. + + + Unsupported argument -debugnet ignored, use -debug=net. + Argomento -debugnet ignorato in quanto non supportato, usare -debug=net. + + + Unsupported argument -tor found, use -onion. + Rilevato argomento -tor non supportato, utilizzare -onion. + Use UPnP to map the listening port (default: %u) Usa UPnP per mappare la porta di ascolto (predefinito: %u) + + User Agent comment (%s) contains unsafe characters. + Il commento del User Agent (%s) contiene caratteri non sicuri. + Verifying blocks... Verifica blocchi... @@ -3009,10 +3200,6 @@ Per specificare più URL separarli con una barra verticale "|". You need to rebuild the database using -reindex to change -txindex È necessario ricostruire il database usando -reindex per cambiare -txindex - - Imports blocks from external blk000??.dat file - Importa blocchi da un file blk000??.dat esterno - 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 Permette connessioni JSON-RPC dall'origine specificata. I valori validi per <ip> sono un singolo IP (ad es. 1.2.3.4), una network/netmask (ad es. 1.2.3.4/255.255.255.0) oppure una network/CIDR (ad es. 1.2.3.4/24). Questa opzione può essere specificata più volte. @@ -3041,17 +3228,13 @@ Per specificare più URL separarli con una barra verticale "|". Error: Listening for incoming connections failed (listen returned error %s) Errore: attesa per connessioni in arrivo fallita (errore riportato %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Errore: individuato argomento -socks non supportato. Non è più possibile impostare la versione SOCKS, solamente i proxy SOCKS5 sono supportati. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Esegue un comando in caso di ricezione di un allarme pertinente o se si rileva un fork molto lungo (%s in cmd è sostituito dal messaggio) - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Le commissioni (in BTC/kB) inferiori a questo valore sono considerate pari a zero relativamente alla trasmissione (predefinito: %s) + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + Le commissioni (in %s/kB) inferiori a questo valore sono considerate pari a zero per trasmissione, mining e creazione della transazione (default: %s) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -3065,10 +3248,6 @@ Per specificare più URL separarli con una barra verticale "|". Maximum size of data in data carrier transactions we relay and mine (default: %u) Dimensione massima dei dati in transazioni di trasporto dati che saranno trasmesse ed incluse nei blocchi (predefinito: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - La modalità prune è configurata al di sotto del minimo di %d MB. Si prega di utilizzare un valore più elevato. - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Ottiene gli indirizzi dei peer attraverso interrogazioni DNS, in caso di scarsa disponibilità (predefinito: 1 a meno che -connect non sia specificato) @@ -3093,37 +3272,6 @@ Per specificare più URL separarli con una barra verticale "|". This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso del Toolkit OpenSSL <https://www.openssl.org/>, software crittografico scritto da Eric Young e software UPnP scritto da Thomas Bernard. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - Per utilizzare bitcoind o l'opzione -server in Bitcoin Core è necessario specificare una rpcpassword nel file di configurazione: -%s -Si raccomanda di utilizzare la seguente password casuale: -rpcuser=bitcoinrpc -rpcpassword=%s -(non è necessario ricordare questa password) -Il nome utente e la password NON DEVONO corrispondere. -Se il file non esiste si raccomanda di crearlo con permessi di lettura per il solo proprietario. -Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche di eventuali problemi, ad es. alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Attenzione: -maxtxfee è impostato su un valore molto elevato. Tali commissioni potrebbero essere pagate anche in una singola transazione. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Attenzione: Si prega di verificare che data ed ora del computer siano corrette! Una configurazione errata dell'orologio di sistema potrebbe impedire a Bitcoin Core di funzionare regolarmente. - 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 I peer inclusi in whitelist non possono subire ban per DoS e le loro transazioni saranno sempre trasmesse, anche nel caso in cui si trovino già nel mempool. Ciò è utile ad es. per i gateway @@ -3145,17 +3293,21 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d Attivazione della blockchain migliore... - Can't run with a wallet in prune mode. - Impossibile operare con un portamonete in modalità prune. + Always relay transactions received from whitelisted peers (default: %d) + Trasmetti sempre le transazioni ricevute da peers whitelisted (default: %d) + + + Attempt to recover private keys from a corrupt wallet.dat on startup + Prova a recuperare le chiavi private da un wallet corrotto all'avvio + + + Automatically create Tor hidden service (default: %d) + Crea automaticamente il servizio Tor (default: %d) Cannot resolve -whitebind address: '%s' Impossibile risolvere indirizzo -whitebind: '%s' - - Choose data directory on startup (default: 0) - Seleziona la cartella dati all'avvio (predefinito: 0) - Connect through SOCKS5 proxy Connessione attraverso un proxy SOCKS5 @@ -3164,10 +3316,6 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d Copyright (C) 2009-%i The Bitcoin Core Developers Copyright (C) 2009-%i Gli sviluppatori di Bitcoin Core - - Could not parse -rpcbind value %s as network address - Non è stato possibile riconoscere il valore %s di -rpcbind come indirizzo di rete - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Errore durante il caricamento del file wallet.dat: il portamonete richiede una versione di Bitcoin Core più recente @@ -3177,12 +3325,8 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d Errore durante lalettura del database. Arresto in corso. - Error: Unsupported argument -tor found, use -onion. - Errore: Rilevato argomento -tor non supportato, utilizzare -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Commissione (in BTC/kB) da aggiungere alle transazioni che invii (predefinito: %s) + Imports blocks from external blk000??.dat file on startup + Importa blocchi da un file blk000??.dat esterno all'avvio Information @@ -3224,18 +3368,10 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d Node relay options: Opzioni trasmissione nodo: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Opzioni RPC SSL: (consulta la Bitcoin Wiki per le istruzioni relative alla configurazione SSL) - RPC server options: Opzioni server RPC: - - RPC support for HTTP persistent connections (default: %d) - Supporto RPC per le connessioni HTTP persistenti (predefinito: %d) - Rebuild block chain index from current blk000??.dat files on startup Ricostruzione dell'indice della block chain dai file blk000??.dat correnti all'avvio @@ -3244,6 +3380,14 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d Receive and display P2P network alerts (default: %u) Ricevi e visualizza gli alerts della rete P2P (default: %u) + + Reducing -maxconnections from %d to %d, because of system limitations. + Riduzione -maxconnections da %d a %d a causa di limitazioni di sistema. + + + Rescan the block chain for missing wallet transactions on startup + Ripete la scansione della block chain per individuare le transazioni che mancano dal wallet all'avvio + Send trace/debug info to console instead of debug.log file Invia le informazioni di trace/debug alla console invece che al file debug.log @@ -3252,22 +3396,10 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d Send transactions as zero-fee transactions if possible (default: %u) Invia transazioni a zero commissioni se possibile (predefinito: %u) - - Set SSL root certificates for payment request (default: -system-) - Imposta i certificati radice SSL per le richieste di pagamento (predefinito: -system-) - - - Set language, for example "de_DE" (default: system locale) - Imposta lingua, ad esempio "it_IT" (predefinito: lingua di sistema) - Show all debugging options (usage: --help -help-debug) Mostra tutte le opzioni di debug (utilizzo: --help -help-debug) - - Show splash screen on startup (default: 1) - Mostra finestra di presentazione all'avvio (predefinito: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Riduce il file debug.log all'avvio del client (predefinito: 1 se -debug non è impostato) @@ -3276,10 +3408,6 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d Signing transaction failed Firma transazione fallita - - Start minimized - Avvia ridotto a icona - The transaction amount is too small to pay the fee L'importo della transazione è troppo basso per pagare la commissione @@ -3288,6 +3416,14 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d This is experimental software. Questo è un software sperimentale. + + Tor control port password (default: empty) + Password porta controllo Tor (default: empty) + + + Tor control port to use if onion listening enabled (default: %s) + Porta di controllo Tor da usare se in ascolto su onion (default: %s) + Transaction amount too small Importo transazione troppo piccolo @@ -3304,17 +3440,13 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d Transaction too large Transazione troppo grande - - UI Options: - Opzioni Interfaccia Utente: - Unable to bind to %s on this computer (bind returned error %s) Impossibile associarsi a %s su questo computer (l'associazione ha restituito l'errore %s) - Use UPnP to map the listening port (default: 1 when listening) - Usa UPnP per mappare la porta in ascolto (predefinito: 1 quando in ascolto) + Upgrade wallet to latest format on startup + Aggiorna il wallet all'ultimo formato all'avvio Username for JSON-RPC connections @@ -3329,20 +3461,16 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d Attenzione - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Attenzione: Argomento -benchmark ignorato in quanto non supportato, usare -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Attenzione: Argomento -debugnet ignorato in quanto non supportato, usare -debug=net. + Whether to operate in a blocks only mode (default: %u) + Imposta se operare in modalità solo blocchi (default: %u) Zapping all transactions from wallet... Eliminazione dal portamonete di tutte le transazioni... - on startup - all'avvio + ZeroMQ notification options: + Opzioni di notifica ZeroMQ wallet.dat corrupt, salvage failed @@ -3356,18 +3484,6 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d Execute command when the best block changes (%s in cmd is replaced by block hash) Esegue un comando quando il miglior blocco cambia (%s nel cmd è sostituito dall'hash del blocco) - - Upgrade wallet to latest format - Aggiorna il wallet all'ultimo formato - - - Rescan the block chain for missing wallet transactions - Ripete la scansione della block chain per individuare le transazioni che mancano dal portamonete - - - Use OpenSSL (https) for JSON-RPC connections - Utilizza OpenSSL (https) per le connessioni JSON-RPC - This help message Questo messaggio di aiuto @@ -3388,6 +3504,26 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = mantiene metadati tx, ad es. proprietario account ed informazioni di richiesta di pagamento, 2 = scarta metadati tx) + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + -maxtxfee è impostato molto alto! Commissioni così alte possono venir pagate anche su una singola transazione. + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + -paytxfee è impostato su un valore molto elevato. Questa è la commissione che si paga quando si invia una transazione. + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + Non mantenere le transazioni nella mempool più a lungo di <n> ore (default: %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Errore di lettura di wallet.dat! Tutte le chiavi sono state lette correttamente, ma i dati delle transazioni o della rubrica potrebbero essere mancanti o non corretti. + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + Le commissioni (in %s/kB) inferiori a questo valore sono considerate pari a zero per la creazione della transazione (default: %s) + How thorough the block verification of -checkblocks is (0-4, default: %u) Determina quanto sarà approfondita la verifica da parte di -checkblocks (0-4, predefinito: %u) @@ -3404,17 +3540,33 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d Output debugging information (default: %u, supplying <category> is optional) Emette informazioni di debug (predefinito: %u, fornire <category> è opzionale) + + Support filtering of blocks and transaction with bloom filters (default: %u) + Supporta filtraggio di blocchi e transazioni con filtri bloom (default: %u) + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + La lunghezza totale della stringa di network version (%i) eccede la lunghezza massima (%i). Ridurre il numero o la dimensione di uacomments. + + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + Cerca di mantenere il traffico in uscita al di sotto della soglia scelta (in MiB ogni 24h), 0 = nessun limite (default: %d) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Argomento -socks non supportato. Non è più possibile impostare la versione SOCKS, solamente i proxy SOCKS5 sono supportati. + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) Usa un proxy SOCKS5 a parte per raggiungere i peer attraverso gli hidden services di Tor (predefinito: %s) - (default: %s) - (predefinito: %s) + 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. This option can be specified multiple times + Username e hash password per connessioni JSON-RPC. Il campo <userpw> utilizza il formato: <USERNAME>:<SALT>$<HASH>. Uno script python standard è incluso in share/rpcuser. Questa opzione può essere specificata più volte - Acceptable ciphers (default: %s) - Cifrari accettabili (predefinito: %s) + (default: %s) + (predefinito: %s) Always query for peer addresses via DNS lookup (default: %u) @@ -3476,14 +3628,6 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d Relay non-P2SH multisig (default: %u) Trasmette transazioni non-P2SH multisig (predefinito: %u) - - Server certificate file (default: %s) - File del certificato del server (predefinito: %s) - - - Server private key (default: %s) - Chiave privata del server (predefinito: %s) - Set key pool size to <n> (default: %u) Imposta la dimensione del pool di chiavi a <n> (predefinito: %u) diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts index e2c22f7f6..4344fd043 100644 --- a/src/qt/locale/bitcoin_ja.ts +++ b/src/qt/locale/bitcoin_ja.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,17 @@ ウォレットのパスフレーズの変更が成功しました。 + + BanTableModel + + IP/Netmask + IPアドレス/ネットマスク + + + Banned Until + 以下の時間までbanする: + + BitcoinGUI @@ -340,11 +351,11 @@ &Send - 送る (&S) + 送金 (&S) &Receive - 受信 (&R) + 入金 (&R) Show information about Bitcoin Core @@ -787,7 +798,7 @@ New receiving address - 新しい受信アドレス + 新しい入金アドレス New sending address @@ -795,7 +806,7 @@ Edit receiving address - 受信アドレスを編集 + 入金アドレスを編集 Edit sending address @@ -871,6 +882,34 @@ command-line options コマンドライン オプション + + UI Options: + UIオプション: + + + Choose data directory on startup (default: %u) + 起動時にデータ ディレクトリを選ぶ (初期値: %u) + + + Set language, for example "de_DE" (default: system locale) + 言語設定 例: "de_DE" (初期値: システムの言語) + + + Start minimized + 最小化された状態で起動する + + + Set SSL root certificates for payment request (default: -system-) + 支払いリクエスト用にSSLルート証明書を設定する (デフォルト:-system-) + + + Show splash screen on startup (default: %u) + 起動時にスプラッシュ画面を表示する (初期値: %u) + + + Reset all settings changes made over the GUI + GUI 経由で行われた設定の変更を全てリセット + Intro @@ -1068,6 +1107,34 @@ Port of the proxy (e.g. 9050) プロキシのポート番号 (例 9050) + + Used for reaching peers via: + ピアへ到達するために使われた方法: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + このネットワークタイプ経由で、与えられたデフォルトのSOCKS5プロキシを使用してピアに到達した場合に表示する。 + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Tor秘匿サービスを利用するため、独立なSOCKS5プロキシ経由でBitcoinネットワークに接続する + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Tor秘匿サービス経由でピアに到達するため、独立なSOCKS5プロキシを利用する: + &Window ウインドウ (&W) @@ -1286,10 +1353,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). 支払リクエスト %1 は大きすぎます(%2バイトですが、%3バイトまでが許されています)。 - - Payment request DoS protection - 支払リクエストDoS保護 - Error communicating with %1: %2 %1: %2とコミュニケーション・エラーです @@ -1442,6 +1505,18 @@ Current number of blocks 現在のブロック数 + + Memory Pool + メモリ・プール + + + Current number of transactions + 現在のトランザクション数 + + + Memory usage + メモリ使用量 + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. 現在のデータディレクトリからBitcoin Coreのデバッグ用ログファイルを開きます。ログファイルが巨大な場合、数秒かかることがあります。 @@ -1458,10 +1533,18 @@ &Peers ピア (&P) + + Banned peers + Banされたピア + Select a peer to view detailed information. 詳しい情報を見たいピアを選択してください。 + + Whitelisted + ホワイトリスト + Direction 方向 @@ -1470,6 +1553,18 @@ Version バージョン + + Starting Block + 開始ブロック + + + Synced Headers + 同期済みヘッダ + + + Synced Blocks + 同期済みブロック + User Agent ユーザエージェント @@ -1478,14 +1573,6 @@ Services サービス - - Starting Height - 開始時のブロック高 - - - Sync Height - 同期済みブロック高 - Ban Score Banスコア @@ -1502,18 +1589,18 @@ Last Receive 最終受信 - - Bytes Sent - 送信済バイト数 - - - Bytes Received - 受信済バイト数 - Ping Time Ping時間 + + The duration of a currently outstanding ping. + 現在実行中のpingにかかっている時間。 + + + Ping Wait + Ping待ち + Time Offset 時間オフセット @@ -1562,6 +1649,34 @@ Clear console コンソールをクリア + + &Disconnect Node + ノードを切断する (&D) + + + Ban Node for + ノードをbanする: + + + 1 &hour + 1時間 (&H) + + + 1 &day + 1日 (&D) + + + 1 &week + 1週間 (&W) + + + 1 &year + 1年 (&Y) + + + &Unban Node + ノードのbanを解除する (&U) + Welcome to the Bitcoin Core RPC console. Bitcoin CoreのRPCコンソールへようこそ。 @@ -1590,6 +1705,10 @@ %1 GB %1 GB + + (node id: %1) + (ノードID: %1) + via %1 %1経由 @@ -1607,12 +1726,16 @@ 外向き - Unknown - 未知 + Yes + はい - Fetching... - 取得中…… + No + いいえ + + + Unknown + 未知 @@ -1940,7 +2063,7 @@ S&end - 送る (&e) + 送金 (&E) Confirm send coins @@ -1979,8 +2102,8 @@ 釣り銭をコピー - Total Amount %1 (= %2) - 総送金額 %1 (= %2) + Total Amount %1 + 合計: %1 or @@ -2014,14 +2137,14 @@ Payment request expired. 支払いリクエストの期限が切れました。 + + Pay only the required fee of %1 + 要求手数料 %1 のみを支払う + Estimated to begin confirmation within %n block(s). %n ブロック以内に検証が開始されると予想されます。 - - Pay only the minimum fee of %1 - 最小手数料 %1 のみを支払う - The recipient address is not valid. Please recheck. 受取アドレスが不正です。再チェックしてください。 @@ -2528,7 +2651,7 @@ Received with - 受信元 + 受け取り Received from @@ -2653,6 +2776,10 @@ Copy transaction ID 取引 ID をコピー + + Copy raw transaction + 生トランザクションをコピー + Edit label ラベルの編集 @@ -2800,13 +2927,53 @@ Accept command line and JSON-RPC commands コマンドラインと JSON-RPC コマンドを許可 + + If <category> is not supplied or if <category> = 1, output all debugging information. + <category> が与えられなかった場合や <category> = 1 の場合には、すべてのデバッグ情報が出力されます。 + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + ひとつのウォレットトランザクションで使用する合計手数料 (%s 単位) の最大値。低すぎる値を指定すると巨大なトランザクションの作成ができなくなります (規定値: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + あなたのPCの日付と時刻が正しいことを確認して下さい! もしあなたの時計が正しくなければBitcoin Coreが正確に動作しません。 + + + Prune configured below the minimum of %d MiB. Please use a higher number. + 剪定が最小値の %d MiB以下に設定されています。もっと大きな値を使用してください。 + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + 剪定: 最後のウォレット同期ポイントは、選定されたデータよりも過去のものとなっています。-reindexをする必要があります (剪定されたノードの場合、ブロックチェイン全体をダウンロードします) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + 古いブロックを剪定する (削除する) ことで記憶容量の必要量を削減する。このモードを有効にすると-txindexや-rescanと互換性がなくなります。警告: この設定の再有効化には全ブロックチェインの再ダウンロードが必要となります。(規定値: 0 = ブロックの剪定無効、>%u = ブロックファイルに使用するMiB単位の目標サイズ) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + 剪定モードでは再スキャンを行うことはできません。-reindexを指定し、ブロックチェイン全体を再ダウンロードする必要があります。 + + + Error: A fatal internal error occurred, see debug.log for details + エラー:致命的な内部エラーが発生しました。詳細はdebug.logを参照してください + + + Fee (in %s/kB) to add to transactions you send (default: %s) + 送信するトランザクションに付加する手数料 (%s/kB単位) (初期値: %s) + + + Pruning blockstore... + ブロックデータを剪定しています…… + Run in the background as a daemon and accept commands デーモンとしてバックグランドで実行しコマンドを許可 - Use the test network - テストのためのネットワークを使用 + Unable to start HTTP server. See debug log for details. + HTTPサーバを開始できませんでした。詳細はデバッグログをご確認ください。 Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2828,18 +2995,14 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) ウォレットの取引を変更する際にコマンドを実行 (cmd の %s は TxID に置換される) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - ひとつのウォレットトランザクションで使用する合計手数料の最大値。低すぎる値を指定すると巨大なトランザクションの作成ができなくなります (規定値: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - 古いブロックを剪定する(削除する)ことで記憶容量の必要量を削減する。このモードを有効にするとウォレット機能のサポートは無効になり、-txindexとも互換性がなくなります。警告: この設定の再有効化には全ブロックチェインの再ダウンロードが必要となります。(規定値: 0 = ブロックの剪定無効、>%u = ブロックファイルに使用するMiB単位の目標サイズ) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) スクリプト検証スレッドを設定 (%uから%dの間, 0 = 自動, <0 = たくさんのコアを自由にしておく, 初期値: %d) + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + ブロックのデータベースに未来の時刻のブロックが含まれています。これはおそらくお使いのコンピュータに設定されている日時が間違っていることを示しています。お使いのコンピュータの日時が本当に正しい場合にのみ、ブロックのデータベースの再構築を行ってください。 + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications これはリリース前のテストビルドです - 各自の責任で利用すること - 採掘や商取引に使用しないでください @@ -2848,6 +3011,10 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. このコンピュータの %s にバインドすることができません。おそらく Bitcoin Core は既に実行されています。 + + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + リスン ポートの割当に UPnP を使用 (初期値: リスン中および-proxyが指定されていない場合は1) + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) 警告:異常に多くの数のブロックが生成されています。%d ブロックが最近 %d 時間以内に受け取られました。(期待値: %d) @@ -2856,10 +3023,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) 警告:ネットワーク接続を確認してください。%d ブロックが最近 %d 時間以内にに受け取られました。(期待値: %d) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - 警告: -paytxfee が非常に高く設定されています! これは取引を送信する場合に支払う取引手数料です。 - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. 警告: ネットワークは完全に同意しないみたいです。マイナーは何かの問題を経験してるみたいなんです。 @@ -2868,10 +3031,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. 警告: ピアーと完全に同意しないみたいです!アップグレードは必要かもしれません、それとも他のノードはアップグレードは必要かもしれません。 - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - 警告: wallet.dat の読み込みエラー! すべてのキーは正しく読み取れますが、取引データやアドレス帳のエントリが失われたか、正しくない可能性があります。 - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. 警告: wallet.dat が壊れたのでデータを復旧しました! オリジナルの wallet.dat は wallet.{timestamp}.bak として %s に保存されました; もしもあなたの残高や取引が正しくないならバックアップから復元してください。 @@ -2881,17 +3040,13 @@ 与えられたネットマスクやIPアドレスから接続を行う、ホワイトリストのピア。複数回指定できます。 - (default: 1) - (デフォルト: 1) + -maxmempool must be at least %d MB + -maxmempoolは最低でも %d MB必要です <category> can be: <category>は以下の値を指定できます: - - Attempt to recover private keys from a corrupt wallet.dat - 壊れた wallet.dat から秘密鍵を復旧することを試す - Block creation options: ブロック作成オプション: @@ -2921,6 +3076,22 @@ Do you want to rebuild the block database now? ブロック データベースを今すぐ再構築しますか? + + Enable publish hash block in <address> + <address>に対し、ハッシュブロックの公開を有効にする + + + Enable publish hash transaction in <address> + <address> に対し、ハッシュトランザクションの公開を有効にする + + + Enable publish raw block in <address> + <address> に対し、生ブロックの公開を有効にする + + + Enable publish raw transaction in <address> + <address> に対し、生トランザクションの公開を有効にする + Error initializing block database ブロック データベースの初期化中にエラー @@ -2937,10 +3108,6 @@ Error opening block database ブロック データベースの開始エラー - - Error: A fatal internal error occured, see debug.log for details - エラー:致命的な内部エラーが発生しました。詳細はdebug.logを参照してください - Error: Disk space is low! エラー: ディスク容量不足! @@ -2949,10 +3116,6 @@ Failed to listen on any port. Use -listen=0 if you want this. ポートのリスンに失敗しました。必要であれば -listen=0 を使用してください。 - - If <category> is not supplied, output all debugging information. - <category> が与えられなかった場合には、すべてのデバッグ情報が出力されます。 - Importing... インポートしています…… @@ -2965,6 +3128,10 @@ Invalid -onion address: '%s' 無効な -onion アドレス:'%s' + + Keep the transaction memory pool below <n> megabytes (default: %u) + トランザクションのメモリ・プールの総量を <n> メガバイト以下に維持する (初期値: %u) + Not enough file descriptors available. 使用可能なファイルディスクリプタが不足しています。 @@ -2993,10 +3160,26 @@ Specify wallet file (within data directory) ウォレットのファイルを指定 (データ・ディレクトリの中に) + + Unsupported argument -benchmark ignored, use -debug=bench. + サポートされていない引数 -benchmark は無視されました。-debug=bench を使用してください。 + + + Unsupported argument -debugnet ignored, use -debug=net. + サポートされていない引数 -debugnet は無視されました。-debug=net を使用してください。 + + + Unsupported argument -tor found, use -onion. + サポートされていない引数 -tor が見つかりました。-onion を使用してください。 + Use UPnP to map the listening port (default: %u) リッスンポートの割当に UPnP を使用 (初期値: %u) + + User Agent comment (%s) contains unsafe characters. + ユーザエージェントのコメント (%s) には安全でない文字が含まれています。 + Verifying blocks... ブロックの検証中... @@ -3021,18 +3204,10 @@ You need to rebuild the database using -reindex to change -txindex -txindex を変更するには -reindex を使用してデータベースを再構築する必要があります - - Imports blocks from external blk000??.dat file - 外部の blk000??.dat ファイルからブロックをインポート - 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 指定したアクセス元からのJSON-RPC接続を許可する。有効な<ip>は、単一のIP (例 1.2.3.4)、ネットワーク/ネットマスク (1.2.3.4/255.255.255.0)、またはネットワーク/CIDR (1.2.3.4/24)です。このオプションは複数回指定できます。 - - An error occurred while setting up the RPC address %s port %u for listening: %s - リッスンする RPC アドレス %s、ポート %u の設定中にエラーが発生しました: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 指定されたアドレスおよび、そこに接続を行ってきたホワイトリストのピアに対してバインドを行います。IPv6の場合には [host]:port 表記を使用してください @@ -3057,17 +3232,13 @@ Error: Listening for incoming connections failed (listen returned error %s) エラー: 内向きの接続をリッスンするのに失敗しました (エラー %s が返却されました) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - エラー: サポートされていない引数 -socks が見つかりました。SOCKSバージョンの設定はできないようになりました。SOCKS5プロキシのみがサポートされています。 - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) 関連のアラートをもらってもすごく長いのフォークを見てもコマンドを実行 (コマンドの中にあるの%sはメッセージから置き換えさせる) - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - 中継の際、この値未満の手数料 (BTC/Kb単位) はゼロであるとみなす (デフォルト: %s) + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + トランザクションの中継、採掘および作成の際には、この値未満の手数料 (%s/kB単位) はゼロであるとみなす (デフォルト: %s) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -3081,10 +3252,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) 中継および採掘を行う際の、データ運送トランザクションの中のデータの最大サイズ (初期値: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - 剪定が最小値の %d MB以下に設定されています。もっと大きな値を使用してください。 - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) 保有するピアアドレスが少ない場合、DNS ルックアップによりピアアドレスを問い合わせる (-connect を使っていない場合の初期値: 1) @@ -3109,38 +3276,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. この製品はOpenSSLプロジェクトにより開発されたソフトウェアをOpenSSLツールキットとして利用しています <https://www.openssl.org/>。また、Eric Young氏により開発された暗号ソフトウェア、Thomas Bernard氏により書かれたUPnPソフトウェアを用いています。 - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - bitcoindを用いる場合や、-server オプションをbitcoin-qtに指定する場合には、設定ファイルにrpcpasswordを設定しなければなりません: -%s -以下のランダムなパスワードを用いることが推奨されます: -rpcuser=bitcoinrpc -rpcpassword=%s -(このパスワードを暗記する必要はありません) -ユーザ名とパスワードは一致してはいけません。 -ファイルが存在しない場合には、所有者のみ読み込み可能なファイルパーミッションでファイルを作成してください。 -またalertnotifyを設定し、問題発生時に通知が行くようにすることをおすすめします; -例: alertnotify=echo %%s | mail -s "Bitcoinアラート" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - 警告: -maxtxfee が非常に高く設定されています!ひとつのトランザクションでこの量の手数料が支払われてしまうことがあります。 - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - 警告: あなたのPCの日付と時刻が正しいことを確認して下さい! もしあなたの時計が正しくなければBitcoin Coreが正確に動作しません。 - 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 ホワイトリストのピアはDoSによるアクセス禁止処理が無効化され、トランザクションは例えmempool内に既に存在していたとしても常にリレーされます。これは例えばゲートウェイに対して有用です @@ -3162,17 +3297,21 @@ rpcpassword=%s 最優良のチェインを有効化しています... - Can't run with a wallet in prune mode. - 剪定モードではウォレット機能付きで起動できません。 + Always relay transactions received from whitelisted peers (default: %d) + ホワイトリストにあるピアから受け取ったトランザクションを常にリレーする (初期値: %d) + + + Attempt to recover private keys from a corrupt wallet.dat on startup + 起動時に壊れた wallet.dat から秘密鍵を復旧することを試す + + + Automatically create Tor hidden service (default: %d) + Tor秘匿サービスを自動的に作成する (初期値: %d) Cannot resolve -whitebind address: '%s' -whitebind アドレス '%s' を解決できません - - Choose data directory on startup (default: 0) - 起動時にデータ ディレクトリを選ぶ (初期値: 0) - Connect through SOCKS5 proxy SOCKS5 プロキシ経由で接続する @@ -3181,10 +3320,6 @@ rpcpassword=%s Copyright (C) 2009-%i The Bitcoin Core Developers Copyright (C) 2009-%i Bitcoin Core 開発者 - - Could not parse -rpcbind value %s as network address - -rpcbind の値 %s をネットワークアドレスとして解釈できませんでした - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core wallet.dat の読み込みに失敗しました: ウォレットの読み込みにはより新しいバージョンの Bitcoin Core が必要です @@ -3194,12 +3329,8 @@ rpcpassword=%s データベースの読み込みエラー。シャットダウンします。 - Error: Unsupported argument -tor found, use -onion. - エラー: サポートされていない引数 -tor が見つかりました。-onion を使用してください。 - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - 送信するトランザクションに付加する手数料 (BTC/kB単位) (初期値: %s) + Imports blocks from external blk000??.dat file on startup + 起動時に外部の blk000??.dat ファイルからブロックをインポート Information @@ -3241,18 +3372,10 @@ rpcpassword=%s Node relay options: ノード中継オプション: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - RPC SSL オプション: (SSLのセットアップ手順はビットコインWikiを参照してください) - RPC server options: RPCサーバのオプション: - - RPC support for HTTP persistent connections (default: %d) - RPCにおけるHTTPの持続的接続のサポート (初期値: %d) - Rebuild block chain index from current blk000??.dat files on startup 起動時に現在の blk000??.dat ファイルからブロック チェーンのインデックスを再構築 @@ -3261,6 +3384,14 @@ rpcpassword=%s Receive and display P2P network alerts (default: %u) P2Pネットワークのアラートの受け取りと表示を行う (デフォルト: %u) + + Reducing -maxconnections from %d to %d, because of system limitations. + システム上の制約から、-maxconnections を %d から %d に削減しました。 + + + Rescan the block chain for missing wallet transactions on startup + 起動時に失ったウォレットの取引のブロック チェーンを再スキャン + Send trace/debug info to console instead of debug.log file トレース/デバッグ情報を debug.log ファイルの代わりにコンソールへ送る @@ -3269,22 +3400,10 @@ rpcpassword=%s Send transactions as zero-fee transactions if possible (default: %u) 可能な場合には手数料ゼロのトランザクションとしてトランザクションを送信する (初期値: %u) - - Set SSL root certificates for payment request (default: -system-) - 支払いリクエスト用にSSLルート証明書を設定する(デフォルト:-system-) - - - Set language, for example "de_DE" (default: system locale) - 言語設定 例: "de_DE" (初期値: システムの言語) - Show all debugging options (usage: --help -help-debug) すべてのデバッグオプションを表示する (使い方: --help -help-debug) - - Show splash screen on startup (default: 1) - 起動時にスプラッシュ画面を表示する (初期値: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) クライアント起動時に debug.log ファイルを縮小 (初期値: -debug オプションを指定しない場合は1) @@ -3293,10 +3412,6 @@ rpcpassword=%s Signing transaction failed 取引の署名に失敗しました - - Start minimized - 最小化された状態で起動する - The transaction amount is too small to pay the fee トランザクションの金額が小さすぎて手数料を支払えません @@ -3305,6 +3420,14 @@ rpcpassword=%s This is experimental software. これは実験的なソフトウェアです。 + + Tor control port password (default: empty) + Tor管理ポートのパスワード (初期値: 空文字) + + + Tor control port to use if onion listening enabled (default: %s) + Onion のリッスンが有効になっている場合に使用するTor管理ポート (初期値: %s) + Transaction amount too small 取引の額が小さ過ぎます @@ -3321,17 +3444,13 @@ rpcpassword=%s Transaction too large 取引が大き過ぎます - - UI Options: - UIオプション: - Unable to bind to %s on this computer (bind returned error %s) このコンピュータの %s にバインドすることができません (バインドが返したエラーは %s) - Use UPnP to map the listening port (default: 1 when listening) - リスン ポートの割当に UPnP を使用 (初期値: リスン中は1) + Upgrade wallet to latest format on startup + 起動時にウォレットを最新のフォーマットにアップグレード Username for JSON-RPC connections @@ -3346,20 +3465,16 @@ rpcpassword=%s 警告 - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - 警告: サポートされていない引数 -benchmark は無視されました。-debug=bench を使用してください。 - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - 警告: サポートされていない引数 -debugnet は無視されました。-debug=net を使用してください。 + Whether to operate in a blocks only mode (default: %u) + ブロック限定モードにおいて動作を行うかどうか (初期値: %u) Zapping all transactions from wallet... ウォレットからすべてのトランザクションを消去しています... - on startup - 起動時 + ZeroMQ notification options: + ZeroMQ通知オプション: wallet.dat corrupt, salvage failed @@ -3373,18 +3488,6 @@ rpcpassword=%s Execute command when the best block changes (%s in cmd is replaced by block hash) 最良のブロックに変更する際にコマンドを実行 (cmd の %s はブロック ハッシュに置換される) - - Upgrade wallet to latest format - ウォレットを最新のフォーマットにアップグレード - - - Rescan the block chain for missing wallet transactions - 失ったウォレットの取引のブロック チェーンを再スキャン - - - Use OpenSSL (https) for JSON-RPC connections - JSON-RPC 接続に OpenSSL (https) を使用 - This help message このヘルプ メッセージ @@ -3405,6 +3508,26 @@ rpcpassword=%s (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = トランザクションのメタデータ、例えばアカウントの所有者や支払リクエストの内容を保持する, 2 = トランザクションのメタデータを破棄する) + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + -maxtxfee が非常に高く設定されています!ひとつのトランザクションでこの量の手数料が支払われてしまうことがあります。 + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + -paytxfee が非常に高く設定されています! これは取引を送信する場合に支払う取引手数料です。 + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + mempool内でトランザクションを <n> 時間以上保持しない (初期値: %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + wallet.dat の読み込みエラー! すべてのキーは正しく読み取れますが、取引データやアドレス帳のエントリが失われたか、正しくない可能性があります。 + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + トランザクション作成の際、この値未満の手数料 (%s/kB単位) はゼロであるとみなす (デフォルト: %s) + How thorough the block verification of -checkblocks is (0-4, default: %u) -checkblocks のブロックの検証レベル (0-4, 初期値: %u) @@ -3421,17 +3544,33 @@ rpcpassword=%s Output debugging information (default: %u, supplying <category> is optional) デバッグ情報を出力する (初期値: %u, <category> の指定は任意です) + + Support filtering of blocks and transaction with bloom filters (default: %u) + Bloomフィルタによる、ブロックおよびトランザクションのフィルタリングを有効化する (初期値: %u) + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + ネットワークバージョン文字 (%i) の長さが最大の長さ (%i) を超えています。UAコメントの数や長さを削減してください。 + + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + 送信転送量を与えられた目標値以下に維持するようにする (24時間あたり何MiBかで指定)。0 の場合は無制限 (初期値: %d) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + サポートされていない引数 -socks が見つかりました。SOCKSバージョンの設定はできないようになりました。SOCKS5プロキシのみがサポートされています。 + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) Tor 秘匿サービスを通し、別々の SOCKS5 プロキシを用いることでピアに到達する (初期値: %s) - (default: %s) - (デフォルト: %s) + 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. This option can be specified multiple times + JSON-RPC接続時のユーザ名とハッシュ化されたパスワード。<userpw> フィールドのフォーマットは <USERNAME>:<SALT>$<HASH>。標準的な Python スクリプトが share/rpcuser 内に含まれています。このオプションは複数回指定できます。 - Acceptable ciphers (default: %s) - 受付可能な暗号化方式 (初期値: %s) + (default: %s) + (デフォルト: %s) Always query for peer addresses via DNS lookup (default: %u) @@ -3493,14 +3632,6 @@ rpcpassword=%s Relay non-P2SH multisig (default: %u) P2SHでないマルチシグトランザクションをリレーする (初期値: %u) - - Server certificate file (default: %s) - サーバ証明書ファイル (初期値: %s) - - - Server private key (default: %s) - サーバの秘密鍵 (初期値: %s) - Set key pool size to <n> (default: %u) key pool のサイズを <n> (初期値: %u) にセット diff --git a/src/qt/locale/bitcoin_ka.ts b/src/qt/locale/bitcoin_ka.ts index 4c6ce13ef..11c73ec76 100644 --- a/src/qt/locale/bitcoin_ka.ts +++ b/src/qt/locale/bitcoin_ka.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -200,6 +200,9 @@ საფულის ფრაზა-პაროლი შეცვლილია. + + BanTableModel + BitcoinGUI @@ -745,7 +748,7 @@ command-line options კომანდების ზოლის ოპციები - + Intro @@ -760,6 +763,10 @@ As this is the first time the program is launched, you can choose where Bitcoin Core will store its data. ეს პროგრამის პირველი გაშვებაა; შეგიძლიათ მიუთითოთ, სად შეინახოს მონაცემები Bitcoin Core-მ. + + Bitcoin Core will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. + Bitcoin Core გადმოტვირთავს და შეინახავს Bitcoin-ის ბლოკთა ჯაჭვს. მითითებულ კატალოგში დაგროვდება სულ ცოტა %1 გბ მონაცემები, და მომავალში უფრო გაიზრდება. საფულეც ამავე კატალოგში შეინახება. + Use the default data directory ნაგულისხმევი კატალოგის გამოყენება @@ -1428,6 +1435,10 @@ Custom change address ხურდის მისამართი + + Transaction Fee: + ტრანსაქციის საფასური - საკომისიო: + Send to multiple recipients at once გაგზავნა რამდენიმე რეციპიენტთან ერთდროულად @@ -1492,10 +1503,6 @@ Copy change ხურდის კოპირება - - Total Amount %1 (= %2) - ჯამური თანხა %1 (= %2) - or ან @@ -1508,6 +1515,10 @@ The amount exceeds your balance. თანხა აღემატება თქვენს ბალანსს + + The total exceeds your balance when the %1 transaction fee is included. + საკომისიო %1-ის დამატების შემდეგ თანხა აჭარბებს თქვენს ბალანსს + Transaction creation failed! შეცდომა ტრანსაქციის შექმნისას! @@ -2202,10 +2213,6 @@ Run in the background as a daemon and accept commands რეზიდენტულად გაშვება და კომანდების მიღება - - Use the test network - სატესტო ქსელის გამოყენება - Accept connections from outside (default: 1 if no -proxy or -connect) გარედან შეერთებების დაშვება (ნაგულისხმევი: 1 თუ არ გამოიყენება -proxy ან -connect) @@ -2222,10 +2229,6 @@ This is a pre-release test build - use at your own risk - do not use for mining or merchant applications ეს არის წინასწარი სატესტო ვერსია - გამოიყენეთ საკუთარი რისკით - არ გამოიყენოთ მოპოვებისა ან კომერციული მიზნებისათვის - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - ყურადღება: ძალიან მაღალია -paytxfee - საკომისო, რომელსაც თქვენ გადაიხდით ამ ტრანსაქციის გაგზავნის საფასურად. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. ყურადღება: ქსელში შეუთანხმებლობაა. შესაძლოა ცალკეულ მომპოვებლებს პრობლემები ექმნებათ! @@ -2234,10 +2237,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. ყურადღება: ჩვენ არ ვეთანხმებით ყველა პირს. შესაძლოა თქვენ ან სხვა კვანძებს განახლება გჭირდებათ. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - ყურადღება: არ იკითხება wallet.dat! ყველა გასაღები წაკითხულია, მაგრამ გამორჩენილი ან არასწორია ტრანსაქციის თარიღი ან ჩანაწერები მისამართების წიგნში. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. ყურადღება: wallet.dat დაზიანებულია! ორიგინალური wallet.dat შენახულია როგორც wallet.{timestamp}.bak %s-ში; თუ შეამჩნიეთ უზუსტობა ნაშთში ან ტრანსაქციებში, აღადგინეთ არქივიდან. @@ -2246,10 +2245,6 @@ <category> can be: <category> შეიძლება იყოს: - - Attempt to recover private keys from a corrupt wallet.dat - პირადი გასაღებების აღდგენის მცდელობა wallet.dat-იდან - Block creation options: ბლოკის შექმნის ოპციები: @@ -2294,10 +2289,6 @@ Failed to listen on any port. Use -listen=0 if you want this. ვერ ხერხდება პორტების მიყურადება. თუ გსურთ, გამოიყენეთ -listen=0. - - If <category> is not supplied, output all debugging information. - თუ <category> არ არის მითითებული, ნაჩვენები იქნება სრული დახვეწის ინფორმაცია. - Incorrect or no genesis block found. Wrong datadir for network? საწყისი ბლოკი არ არსებობს ან არასწორია. ქსელის მონაცემთა კატალოგი datadir ხომ არის არასწორი? @@ -2338,10 +2329,6 @@ You need to rebuild the database using -reindex to change -txindex საჭიროა ბაზის ხელახალი აგება, გამოიყენეთ -reindex რათა შეცვალოთ -txindex - - Imports blocks from external blk000??.dat file - ბლოკების იმპორტი გარე blk000??.dat ფაილიდან - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) ბრძანების შესრულება შესაბამისი უწყების მიღებისას ან როცა შეინიშნება საგრძნობი გახლეჩა (cmd-ში %s შეიცვლება მესიჯით) @@ -2351,13 +2338,17 @@ მაღალპრიორიტეტული/დაბალსაკომისიოიანი ტრანსაქციების მაქსიმალური ზომა ბაიტებში (ნაგულისხმევი: %d) - Choose data directory on startup (default: 0) - მონაცემთა კატალოგის მითითება ყოველი გაშვებისას (ნაგულისხმევი: 0) + Cannot resolve -whitebind address: '%s' + ვერ ხერხდება -whitebind მისამართის გარკვევა: '%s' Information ინფორმაცია + + Invalid amount for -maxtxfee=<amount>: '%s' + დაუშვებელი მნიშვნელობა -pmaxtxfee<amount>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' დაუშვებელი მნიშვნელობა -minrelaytxfee=<amount>: '%s' @@ -2370,14 +2361,6 @@ Send trace/debug info to console instead of debug.log file ტრასირების/დახვეწის ინფოს გაგზავნა კონსოლზე debug.log ფაილის ნაცვლად - - Set language, for example "de_DE" (default: system locale) - აირჩიეთ ენა, მაგალითად "de_DE" (ნაგულისხმევია სისტემური ლოკალი) - - - Show splash screen on startup (default: 1) - მისალმების ეკრანის ჩვენება გაშვებისას (ნაგულისხმევი:1) - Shrink debug.log file on client startup (default: 1 when no -debug) debug.log ფაილის შეკუმშვა გაშვებისას (ნაგულისხმევია: 1 როცა არ აყენია -debug) @@ -2386,10 +2369,6 @@ Signing transaction failed ტრანსაქციების ხელმოწერა ვერ მოხერხდა - - Start minimized - გაშვება მინიმიზებული ეკრანით - Transaction amount too small ტრანსაქციების რაოდენობა ძალიან ცოტაა @@ -2402,10 +2381,6 @@ Transaction too large ტრანსაქცია ძალიან დიდია - - Use UPnP to map the listening port (default: 1 when listening) - გამოიყენეთ UPnP მისაყურადებელი პორტის გადასამისამართებლად (ნაგულისხმევი: 1 როცა ჩართულია მიყურადება) - Username for JSON-RPC connections მომხმარებლის სახელი JSON-RPC-შეერთებისათვის @@ -2430,18 +2405,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) კომანდის შესრულება უკეთესი ბლოკის გამოჩენისას (%s კომანდაში ჩანაცვლდება ბლოკის ჰეშით) - - Upgrade wallet to latest format - საფულის ფორმატის განახლება - - - Rescan the block chain for missing wallet transactions - ბლოკების ჯაჭვის გადამოწმება საფულეში გამორჩენილ ტრანსაქციებზე - - - Use OpenSSL (https) for JSON-RPC connections - OpenSSL-ის (https) გამოყენება JSON-RPC-შეერთებებისათვის - This help message ეს ტექსტი diff --git a/src/qt/locale/bitcoin_kk_KZ.ts b/src/qt/locale/bitcoin_kk_KZ.ts index 5ee904063..cfa19d13f 100644 --- a/src/qt/locale/bitcoin_kk_KZ.ts +++ b/src/qt/locale/bitcoin_kk_KZ.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -84,6 +84,9 @@ Құпия сөзді өзгерту + + BanTableModel + BitcoinGUI @@ -227,6 +230,10 @@ EditAddressDialog + + &Label + таңба + &Address Адрес @@ -250,6 +257,10 @@ OptionsDialog + + W&allet + Әмиян + OverviewPage @@ -272,9 +283,17 @@ RPCConsole + + &Information + Информация + ReceiveCoinsDialog + + &Amount: + Саны + ReceiveRequestDialog @@ -339,6 +358,10 @@ SendCoinsEntry + + A&mount: + Саны + ShutdownWindow diff --git a/src/qt/locale/bitcoin_ko_KR.ts b/src/qt/locale/bitcoin_ko_KR.ts index 5126e53f8..ce48ce249 100644 --- a/src/qt/locale/bitcoin_ko_KR.ts +++ b/src/qt/locale/bitcoin_ko_KR.ts @@ -1,9 +1,9 @@ - + AddressBookPage Right-click to edit address or label - 지갑 주소나 이름을 수정하려면 우클릭하세요. + 지갑 주소나 라벨을 수정하려면 우클릭하세요. Create a new address @@ -27,7 +27,7 @@ &Copy Address - 계좌 복사(&C) + 주소 복사(&C) Delete the currently selected address from the list @@ -59,11 +59,11 @@ Sending addresses - 보내는 주소들 + 타인 계좌 주소목록 Receiving addresses - 받은 주소들 + 내 계좌 주소목록 These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. @@ -75,7 +75,7 @@ Copy &Label - 표 복사 + 라벨 복사 &Edit @@ -87,7 +87,7 @@ Comma separated file (*.csv) - 각각의 파일에 쉼표하기(*.csv) + 쉼표로 구분된 파일(*.csv) Exporting Failed @@ -95,14 +95,14 @@ There was an error trying to save the address list to %1. Please try again. - %1으로 주소 리스트를 저장하는 동안 오류가 발생했습니다. 다시 시도해주세요. + %1으로 주소 목록을 저장하는 동안 오류가 발생했습니다. 다시 시도해주세요. AddressTableModel Label - + 라벨 Address @@ -110,7 +110,7 @@ (no label) - (표 없음) + (라벨 없음) @@ -129,7 +129,7 @@ Repeat new passphrase - 새 암호 반복 + 새로운 암호 재확인 Encrypt wallet @@ -141,7 +141,7 @@ Unlock wallet - 지갑 열기 + 지갑 잠금해제 This operation needs your wallet passphrase to decrypt the wallet. @@ -157,11 +157,11 @@ Confirm wallet encryption - 지갑의 암호화를 확정 + 지갑 암호화 승인 Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! - 경고: 만약 암호화된 지갑의 비밀번호를 잃어버릴 경우, 모든 비트코인들을 잃어버릴 수 있습니다! + 경고: 만약 암호화 된 지갑의 비밀번호를 잃어버릴 경우, <b>모든 비트코인들을 잃어버릴 수 있습니다</b>! Are you sure you wish to encrypt your wallet? @@ -169,16 +169,20 @@ IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. - 중요: 본인 지갑파일에서 만든 예전 백업들은 새로 생성한 암화화된 지갑 파일로 교체됩니다. 보안상 이유로 이전에 암호화 하지 않은 지갑 파일 백업은 사용할 수 없게 되니 빠른 시일 내로 새로 암화화된 지갑을 사용하시기 바랍니다. + 중요: 본인 지갑파일에서 만든 예전 백업들은 새로 생성한 암호화 된 지갑 파일로 교체됩니다. 보안상 이유로 이전에 암호화 하지 않은 지갑 파일 백업은 사용할 수 없게 되니 빠른 시일 내로 새로 암호화 된 지갑을 사용하시기 바랍니다. Warning: The Caps Lock key is on! - 경고: 캡스록 키가 켜져있습니다! + 경고: Caps Lock키가 켜져있습니다! Wallet encrypted 지갑 암호화 완료 + + Enter the old passphrase and new passphrase to the wallet. + 지갑의 기존 암호와 새로운 암호를 입력해주세요. + Wallet encryption failed 지갑 암호화 실패 @@ -208,6 +212,9 @@ 지갑 비밀번호가 성공적으로 변경되었습니다. + + BanTableModel + BitcoinGUI @@ -344,11 +351,11 @@ Show or hide the main Window - 주 창 보이기 또는 숨기기 + 메인창 보이기 또는 숨기기 Encrypt the private keys that belong to your wallet - 소유 지갑 개인키 암호화 + 지갑에 포함된 개인키 암호화하기 Sign messages with your Bitcoin addresses to prove you own them @@ -396,7 +403,7 @@ Open a bitcoin: URI or payment request - 비트코인: URI 또는 지불요청 열기 + bitcoin: URI 또는 지불요청 열기 &Command-line options @@ -426,6 +433,10 @@ %1 and %2 %1 그리고 %2 + + %n year(s) + %n년 + %1 behind %1 뒤에 @@ -458,6 +469,36 @@ Catching up... 블록 따라잡기... + + Date: %1 + + 날짜: %1 + + + + Amount: %1 + + 금액: %1 + + + + Type: %1 + + 종류: %1 + + + + Label: %1 + + 라벨: %1 + + + + Address: %1 + + 주소: %1 + + Sent transaction 거래 보내기 @@ -498,7 +539,7 @@ Amount: - 거래량: + 금액: Priority: @@ -769,7 +810,7 @@ command-line options 명령줄 옵션 - + Intro @@ -926,6 +967,18 @@ Port of the proxy (e.g. 9050) 프록시의 포트번호입니다(예: 9050) + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + &Window 창(&W) @@ -1033,6 +1086,10 @@ Mined balance that has not yet matured 아직 사용 가능하지 않은 채굴된 잔액 + + Balances + 잔액 + Total: 총액: @@ -1045,6 +1102,10 @@ Your current balance in watch-only addresses 모니터링 지갑의 현재 잔액 + + Recent transactions + 최근 거래 + PaymentServer @@ -1114,11 +1175,27 @@ Enter a Bitcoin address (e.g. %1) 비트코인 주소를 입력하기 (예. %1) + + %1 h + %1 시간 + + + %1 m + %1 분 + + + %1 s + %1 초 + N/A 없음 - + + %1 ms + %1 ms + + QRImageWidget @@ -1166,7 +1243,11 @@ Using OpenSSL version - 오픈SSL 버전을 사용합니다 + 사용중인 OpenSSL 버전 + + + Using BerkeleyDB version + 사용중인 BerkeleyDB 버전 Startup time @@ -1192,6 +1273,22 @@ Current number of blocks 현재 블럭 수 + + Received + 받음 + + + Sent + 보냄 + + + &Peers + &피어 + + + Version + 버전 + Last block time 최종 블럭 시각 @@ -1244,6 +1341,22 @@ Type <b>help</b> for an overview of available commands. 사용할 수 있는 명령을 둘러보려면 <b>help</b>를 입력하십시오. + + %1 B + %1 바이트 + + + %1 KB + %1 킬로바이트 + + + %1 MB + %1 메가바이트 + + + %1 GB + %1 기가바이트 + ReceiveCoinsDialog @@ -1253,7 +1366,7 @@ &Label: - 표: + 라벨: &Message: @@ -1395,7 +1508,7 @@ (no label) - (표 없음) + (라벨 없음) (no message) @@ -1460,6 +1573,14 @@ Custom change address 주소변경 + + Transaction Fee: + 거래 수수료: + + + Recommended: + 권장: + Send to multiple recipients at once 다수의 수령인들에게 한번에 보내기 @@ -1524,10 +1645,6 @@ Copy priority 우선도 복사 - - Total Amount %1 (= %2) - 총 액수 %1(=%2) - or 또는 @@ -2107,6 +2224,10 @@ Export Transaction History 거래 기록 내보내기 + + Watch-only + 모니터링 지갑 + Exporting Failed 내보내기 실패 @@ -2238,10 +2359,6 @@ Run in the background as a daemon and accept commands 데몬으로 백그라운드에서 실행하고 명령을 허용 - - Use the test network - 테스트 네트워크 사용 - Accept connections from outside (default: 1 if no -proxy or -connect) 외부 접속을 승인합니다 @@ -2258,10 +2375,6 @@ This is a pre-release test build - use at your own risk - do not use for mining or merchant applications 이 빌드 버전은 정식 출시 전 테스트의 목적이며, 예기치 않은 위험과 오류가 발생할 수 있습니다. 채굴과 상점용 소프트웨어로 사용하는 것을 권하지 않습니다. - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - 경고: -paytxfee값이 너무 큽니다! 이 값은 송금할때 지불할 송금 수수료입니다. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. 경고 : 모든 네트워크가 동의해야 하나, 일부 채굴자들에게 문제가 있는 것으로 보입니다. @@ -2270,22 +2383,10 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. 경고: 현재 비트코인 버전이 다른 네트워크 참여자들과 동일하지 않는 것 같습니다. 당신 또는 다른 참여자들이 동일한 비트코인 버전으로 업그레이드 할 필요가 있습니다. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - 경고 : wallet.dat 파일을 읽는 중 에러가 발생했습니다. 주소 키는 모두 정확하게 로딩되었으나 거래 데이터와 주소록 필드에서 누락이나 오류가 존재할 수 있습니다. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. 경고 : wallet.dat가 손상되어 데이터가 복구되었습니다. 원래의 wallet.dat 파일은 %s 후에 wallet.{timestamp}.bak 이름으로 저장됩니다. 잔액과 거래 내역이 정확하지 않다면 백업 파일로 부터 복원해야 합니다. - - (default: 1) - (기본값: 1) - - - Attempt to recover private keys from a corrupt wallet.dat - 손상된 wallet.dat에서 개인키 복원을 시도합니다 - Block creation options: 블록 생성 옵션: @@ -2318,6 +2419,10 @@ Error initializing block database 블록 데이터베이스를 초기화하는데 오류 + + Error initializing wallet database environment %s! + 지갑 데이터베이스 환경 초기화하는데 오류 %s + Error loading block database 블록 데이터베이스를 불러오는데 오류 @@ -2334,10 +2439,6 @@ Failed to listen on any port. Use -listen=0 if you want this. 어떤 포트도 반응하지 않습니다. 사용자 반응=0 만약 원한다면 - - If <category> is not supplied, output all debugging information. - <카테고리>가 제공되지 않을 경우, 모든 디버깅 정보를 출력 - Importing... 들여오기 중... @@ -2386,10 +2487,6 @@ You need to rebuild the database using -reindex to change -txindex -txindex를 바꾸기 위해서는 -reindex를 사용해서 데이터베이스를 재구성해야 합니다. - - Imports blocks from external blk000??.dat file - 외부 blk000??.dat 파일에서 블록을 가져옵니다. - Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running. 데이터 디렉토리 %s에 락을 걸 수 없었습니다. 비트코인 코어가 이미 실행 중인 것으로 보입니다. @@ -2403,13 +2500,17 @@ 최대 크기를 최우선으로 설정 / 바이트당 최소 수수료로 거래(기본값: %d) - Choose data directory on startup (default: 0) - 파일목록을 선택하여 시작하시오(기본값: 0) + Cannot resolve -whitebind address: '%s' + -whitebind 주소를 확인할 수 없습니다: '%s' Information 정보 + + Invalid amount for -maxtxfee=<amount>: '%s' + -maxtxfee=<amount>에 대한 양이 잘못되었습니다: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' 노드로 전달하기 위한 최저 거래 수수료가 부족합니다. - minrelaytxfee=<amount>: '%s' - @@ -2418,10 +2519,6 @@ Invalid amount for -mintxfee=<amount>: '%s' 최저 거래 수수료가 부족합니다. -mintxfee=<amount>: '%s' - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - RPC SSL 옵션: (비트코인 위키의 SSL 설정 설명서 참고) - RPC server options: RPC 서버 설정 @@ -2430,22 +2527,10 @@ Send trace/debug info to console instead of debug.log file 추적오류 정보를 degug.log 자료로 보내는 대신 콘솔로 보내기 - - Set SSL root certificates for payment request (default: -system-) - 지불 요청을 위해 SSL 최상위 인증을 설정합니다. (기본값: -system-) - - - Set language, for example "de_DE" (default: system locale) - "de_DE"와 같이 언어를 설정하십시오 (기본값: 시스템 로캘) - Show all debugging options (usage: --help -help-debug) 모든 디버그 설정 보기(설정: --help -help-debug) - - Show splash screen on startup (default: 1) - 시작시 시작 화면 표시 (기본값: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) 클라이언트 시작시 debug.log 파일 비우기(기본값: 디버그 안할때 1) @@ -2454,10 +2539,6 @@ Signing transaction failed 거래를 서명하는것을 실패하였습니다. - - Start minimized - 최소화 상태에서 시작 - Transaction amount too small 거래량이 너무 적습니다 @@ -2470,10 +2551,6 @@ Transaction too large 너무 큰 거래 - - Use UPnP to map the listening port (default: 1 when listening) - UPnP사용하여 지도에서 포트 반응기다리는 중 (기본값: 1 반응이 생기면) - Username for JSON-RPC connections JSON-RPC 연결에 사용할 사용자 이름 @@ -2486,10 +2563,6 @@ Zapping all transactions from wallet... 지갑의 모든거래내역 건너뛰기... - - on startup - 구동 중 - wallet.dat corrupt, salvage failed wallet.dat 파일이 손상되었고 복구가 실패하였습니다. @@ -2502,18 +2575,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) 최고의 블럭이 변하면 명령을 실행(cmd 에 있는 %s 는 블럭 해시에 의해 대체되어 짐) - - Upgrade wallet to latest format - 지갑을 최근 형식으로 개선하시오 - - - Rescan the block chain for missing wallet transactions - 누락된 지갑 송금에 대한 블록 체인 다시 검색 - - - Use OpenSSL (https) for JSON-RPC connections - JSON-RPC 연결에 OpenSSL(https) 사용 - This help message 도움말 메시지입니다 diff --git a/src/qt/locale/bitcoin_ky.ts b/src/qt/locale/bitcoin_ky.ts index 442d7c5d5..51efd519c 100644 --- a/src/qt/locale/bitcoin_ky.ts +++ b/src/qt/locale/bitcoin_ky.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -24,6 +24,9 @@ AskPassphraseDialog + + BanTableModel + BitcoinGUI @@ -122,6 +125,10 @@ &Network &Тармак + + W&allet + Капчык + &Port: &Порт: @@ -172,6 +179,10 @@ General Жалпы + + Network + &Тармак + Name Аты @@ -191,6 +202,10 @@ ReceiveCoinsDialog + + &Message: + Билдирүү: + ReceiveRequestDialog diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts index b1a69c9a9..e3dcd505f 100644 --- a/src/qt/locale/bitcoin_la.ts +++ b/src/qt/locale/bitcoin_la.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -156,6 +156,9 @@ Tessera cassidilis successa est in mutando. + + BanTableModel + BitcoinGUI @@ -302,6 +305,10 @@ Bitcoin Core Bitcoin Nucleus + + &Command-line options + Optiones mandati initiantis + No block source available... Nulla fons frustorum absens... @@ -473,7 +480,7 @@ command-line options Optiones mandati intiantis - + Intro @@ -510,6 +517,10 @@ &Network &Rete + + W&allet + Cassidile + Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. Aperi per se portam clientis Bitcoin in itineratore. Hoc tantum effectivum est si itineratrum tuum supportat UPnP et id activum est. @@ -652,6 +663,10 @@ &Information &Informatio + + Debug window + Fenestra Debug + Using OpenSSL version Utens OpenSSL versione @@ -711,10 +726,18 @@ ReceiveCoinsDialog + + &Amount: + Quantitas: + &Label: &Titulus: + + &Message: + Nuntius: + Copy label Copia titulum @@ -726,6 +749,10 @@ ReceiveRequestDialog + + Copy &Address + &Copia Inscriptionem + Address Inscriptio @@ -780,10 +807,18 @@ Send Coins Mitte Nummos + + Insufficient funds! + Inopia nummorum + Amount: Quantitas: + + Transaction Fee: + Transactionis merces: + Send to multiple recipients at once Mitte pluribus accipientibus simul @@ -867,6 +902,10 @@ Message: Nuntius: + + Pay To: + Pensa Ad: + ShutdownWindow @@ -1386,10 +1425,6 @@ Run in the background as a daemon and accept commands Operare infere sicut daemon et mandata accipe - - Use the test network - Utere rete experimentale - Accept connections from outside (default: 1 if no -proxy or -connect) Accipe conexiones externas (praedefinitum: 1 nisi -proxy neque -connect) @@ -1406,22 +1441,10 @@ This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Hoc est prae-dimittum experimentala aedes - utere eo periculo tuo proprio - nolite utere fodendo vel applicationibus mercatoriis - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Monitio: -paytxfee constitutum valde magnum! Hoc est merces transactionis solves si mittis transactionem. - - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Monitio: error legendo wallet.dat! Omnes claves recte lectae, sed data transactionum vel libri inscriptionum fortasse desint vel prava sint. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Monitio: wallet.data corrupta, data salvata! Originalis wallet.dat salvata ut wallet.{timestamp}.bak in %s; si pendendum tuum vel transactiones pravae sunt, oportet ab conservato restituere. - - Attempt to recover private keys from a corrupt wallet.dat - Conare recipere claves privatas de corrupto wallet.dat - Block creation options: Optiones creandi frustorum: @@ -1475,13 +1498,17 @@ Verificante cassidilem... - Imports blocks from external blk000??.dat file - Importat frusta ab externa plica blk000??.dat + Cannot resolve -whitebind address: '%s' + Non posse resolvere -whitebind inscriptionem: '%s' Information Informatio + + Invalid amount for -maxtxfee=<amount>: '%s' + Quantitas non valida pro -maxtxfee=<amount>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' Quantitas non valida pro -minrelaytxfee=<amount>: '%s' @@ -1494,14 +1521,6 @@ Send trace/debug info to console instead of debug.log file Mitte informationem vestigii/debug ad terminale potius quam plicam debug.log - - Set language, for example "de_DE" (default: system locale) - Constitue linguam, exempli gratia "de_DE" (praedefinitum: lingua systematis) - - - Show splash screen on startup (default: 1) - Monstra principem imaginem ad initium (praedefinitum: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Diminue plicam debug.log ad initium clientis (praedefinitum: 1 nisi -debug) @@ -1510,10 +1529,6 @@ Signing transaction failed Signandum transactionis abortum est - - Start minimized - Incipe minifactum ut icon - Transaction amount too small Magnitudo transactionis nimis parva @@ -1526,10 +1541,6 @@ Transaction too large Transactio nimis magna - - Use UPnP to map the listening port (default: 1 when listening) - Utere UPnP designare portam auscultandi (praedefinitum: 1 quando auscultans) - Username for JSON-RPC connections Nomen utentis pro conexionibus JSON-RPC @@ -1550,18 +1561,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Pelle mandatum quando optissimum frustum mutat (%s in mandato substituitur ab hash frusti) - - Upgrade wallet to latest format - Progredere cassidile ad formam recentissimam - - - Rescan the block chain for missing wallet transactions - Iterum perlege catenam frustorum propter absentes cassidilis transactiones - - - Use OpenSSL (https) for JSON-RPC connections - Utere OpenSSL (https) pro conexionibus JSON-RPC - This help message Hic nuntius auxilii diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index 4e468911d..b98976dfe 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -188,6 +188,13 @@ Piniginės slaptažodis sėkmingai pakeistas. + + BanTableModel + + Banned Until + Užblokuotas iki + + BitcoinGUI @@ -354,6 +361,10 @@ &About Bitcoin Core &Apie Bitcoin Core + + &Command-line options + Komandinės eilutės parametrai + Error Klaida @@ -548,7 +559,11 @@ (no label) (nėra žymės) - + + (change) + (Graža) + + EditAddressDialog @@ -629,7 +644,7 @@ command-line options komandinės eilutės parametrai - + Intro @@ -662,10 +677,26 @@ &Main &Pagrindinės + + MB + MB + + + IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) + Proxy IP adresas (Pvz. IPv4: 127.0.0.1 / IPv6: ::1) + + + &Reset Options + &Atstatyti Parinktis + &Network &Tinklas + + W&allet + Piniginė + Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. Automatiškai atidaryti Bitcoin kliento prievadą maršrutizatoriuje. Tai veikia tik tada, kai jūsų maršrutizatorius palaiko UPnP ir ji įjungta. @@ -686,6 +717,18 @@ Port of the proxy (e.g. 9050) Tarpinio serverio preivadas (pvz, 9050) + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + &Window &Langas @@ -738,6 +781,14 @@ Confirm options reset Patvirtinti nustatymų atstatymą + + Client restart required to activate changes. + Kliento perkrovimas reikalingas nustatymų aktyvavimui + + + This change would require a client restart. + Šis pakeitimas reikalautų kliento perkrovimo + The supplied proxy address is invalid. Nurodytas tarpinio serverio adresas negalioja. @@ -753,6 +804,10 @@ Available: Galimi: + + Your current spendable balance + Jūsų dabartinis išleidžiamas balansas + Pending: Laukiantys: @@ -776,10 +831,18 @@ URI handling URI apdorojimas + + Invalid payment address %1 + Neteisingas mokėjimo adresas %1 + Payment request rejected Mokėjimo siuntimas atmestas + + Payment request expired. + Mokėjimo siuntimas pasibaigė + Network request error Tinklo užklausos klaida @@ -809,11 +872,19 @@ QRImageWidget + + &Copy Image + Kopijuoti nuotrauką + Save QR Code Įrašyti QR kodą - + + PNG Image (*.png) + PNG paveikslėlis (*.png) + + RPCConsole @@ -832,6 +903,10 @@ &Information &Informacija + + Debug window + Derinimo langas + Using OpenSSL version Naudojama OpenSSL versija @@ -844,6 +919,10 @@ Network Tinklas + + Name + Pavadinimas + Number of connections Prisijungimų kiekis @@ -868,14 +947,6 @@ Version Versija - - Bytes Sent - Nusiųsti baitai - - - Bytes Received - Gauti baitai - Last block time Paskutinio bloko laikas @@ -888,6 +959,10 @@ &Console &Konsolė + + &Clear + Išvalyti + Totals Viso: @@ -924,13 +999,29 @@ never Niekada + + Yes + Taip + + + No + Ne + ReceiveCoinsDialog + + &Amount: + Suma: + &Label: Ž&ymė: + + &Message: + Žinutė: + Clear Išvalyti @@ -950,6 +1041,10 @@ QR Code QR kodas + + Copy &Address + &Kopijuoti adresą + Payment information Mokėjimo informacija @@ -1004,6 +1099,10 @@ Send Coins Siųsti monetas + + Insufficient funds! + Nepakanka lėšų + Quantity: Kiekis: @@ -1032,6 +1131,10 @@ Change: Graža: + + Transaction Fee: + Sandorio mokestis: + Send to multiple recipients at once Siųsti keliems gavėjams vienu metu @@ -1096,6 +1199,10 @@ The total exceeds your balance when the %1 transaction fee is included. Jei pridedame sandorio mokestį %1 bendra suma viršija jūsų balansą. + + Payment request expired. + Mokėjimo siuntimas pasibaigė + (no label) (nėra žymės) @@ -1135,6 +1242,10 @@ Message: Žinutė: + + Pay To: + Mokėti gavėjui: + ShutdownWindow @@ -1181,6 +1292,10 @@ Verify the message to ensure it was signed with the specified Bitcoin address Patikrinkite žinutę, jog įsitikintumėte, kad ją pasirašė nurodytas Bitcoin adresas + + Verify &Message + &Patikrinti žinutę + Click "Sign Message" to generate signature Spragtelėkite "Registruotis žinutę" tam, kad gauti parašą @@ -1614,14 +1729,6 @@ Run in the background as a daemon and accept commands Dirbti fone kaip šešėlyje ir priimti komandas - - Use the test network - Naudoti testavimo tinklą - - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Įspėjimas: -paytxfee yra nustatytas per didelis. Tai sandorio mokestis, kurį turėsite mokėti, jei siųsite sandorį. - Connect only to the specified node(s) Prisijungti tik prie nurodyto mazgo @@ -1642,22 +1749,22 @@ Information Informacija + + Invalid amount for -maxtxfee=<amount>: '%s' + Neteisinga suma -maxtxfee=<amount>: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Neteisinga suma -minrelaytxfee=<amount>: '%s' + + + Invalid amount for -mintxfee=<amount>: '%s' + Neteisinga suma -mintxfee=<amount>: '%s' + Send trace/debug info to console instead of debug.log file Siųsti atsekimo/derinimo info į konsolę vietoj debug.log failo - - Set language, for example "de_DE" (default: system locale) - Nustatyti kalbą, pavyzdžiui "lt_LT" (numatyta: sistemos kalba) - - - Start minimized - Paleisti sumažintą - - - Use UPnP to map the listening port (default: 1 when listening) - Bandymas naudoti UPnP struktūra klausymosi prievadui (default: 1 when listening) - Username for JSON-RPC connections Vartotojo vardas JSON-RPC jungimuisi @@ -1670,18 +1777,6 @@ Password for JSON-RPC connections Slaptažodis JSON-RPC sujungimams - - Upgrade wallet to latest format - Atnaujinti piniginę į naujausią formatą - - - Rescan the block chain for missing wallet transactions - Ieškoti prarastų piniginės sandorių blokų grandinėje - - - Use OpenSSL (https) for JSON-RPC connections - Naudoti OpenSSL (https) jungimuisi JSON-RPC - This help message Pagelbos žinutė diff --git a/src/qt/locale/bitcoin_lv_LV.ts b/src/qt/locale/bitcoin_lv_LV.ts index 23b846bd4..e01d4c812 100644 --- a/src/qt/locale/bitcoin_lv_LV.ts +++ b/src/qt/locale/bitcoin_lv_LV.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -61,6 +61,14 @@ Receiving addresses Saņemšanas adreses + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Šīs ir jūsu Bitcoin adreses maksājumu sūtīšanai. Vienmēr pārbaudiet summu un saņēmēja adresi pirms monētu sūtīšanas. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Šīs ir jūsu Bitcoin adreses maksājumu saņemšanai. Ir ieteicams katram darījumam izmantot jaunu saņemšanas adresi. + Copy &Label Kopēt &Nosaukumu @@ -81,7 +89,11 @@ Exporting Failed Eksportēšana Neizdevās - + + There was an error trying to save the address list to %1. Please try again. + Radās kļūda, saglabājot adrešu sarakstu %1. Lūdzu, mēģiniet vēlreiz! + + AddressTableModel @@ -151,6 +163,14 @@ Are you sure you wish to encrypt your wallet? Vai tu tiešām vēlies šifrēt savu maciņu? + + Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + Bitcoin Core tiks aizvērts, lai pabeigtu šifrēšansa procesu. Atcerieties, ka jūsu maka šifrēšana nevar pilnībā pasargāt jūsu monētas no to nozagašanas, inficējot datoru ar ļaunprātīgām programmām. + + + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + SVARĪGI: Iepriekšējie maka faila dublējumi ir jāaizvieto ar jauno, šifrēto maka failu. Drošības apsvērumu dēļ iepriekšējie nešifrētā maka dublējumi vairs nebūs derīgi, tiklīdz sāksiet izmantot jauno, šifrēto maku. + Warning: The Caps Lock key is on! Brīdinājums: Caps Lock ir ieslēgts! @@ -159,6 +179,10 @@ Wallet encrypted Maciņš nošifrēts + + Enter the old passphrase and new passphrase to the wallet. + Ievadiet veco un jauno maka paroli. + Wallet encryption failed Maciņa šifrēšana neizdevās @@ -188,6 +212,9 @@ Maciņa parole tika veiksmīgi nomainīta. + + BanTableModel + BitcoinGUI @@ -693,6 +720,10 @@ About Bitcoin Core Par Bitcoin Core + + Command-line options + Komandrindas iespējas + Usage: Lietojums: @@ -701,7 +732,7 @@ command-line options komandrindas izvēles - + Intro @@ -774,10 +805,18 @@ Number of script &verification threads Skriptu &pārbaudes pavedienu skaits + + Allow incoming connections + Atļaut ienākošos savienojumus + IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) Starpniekservera IP adrese (piem. IPv4: 127.0.0.1 / IPv6: ::1) + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu. + Minimizēt nevis aizvērt aplikāciju, kad logs tiek aizvērts. Kad šī iespēja ir ieslēgta, aplikācija tiks aizvērta, izvēloties Aizvērt izvēlnē. + Third party transaction URLs Trešo personu transakciju URLs @@ -944,6 +983,14 @@ Invalid payment address %1 Nederīga maksājuma adrese %1 + + Payment request rejected + Maksājuma pieprasījums noraidīts + + + Payment request network doesn't match client network. + Maksājuma pieprasījuma tīkls neatbilst klienta tīklam. + Payment request error Maksājumu pieprasījuma kļūda @@ -1332,6 +1379,10 @@ Custom change address Pielāgota atlikuma adrese + + Transaction Fee: + Transakcijas maksa: + Send to multiple recipients at once Sūtīt vairākiem saņēmējiem uzreiz @@ -1396,10 +1447,6 @@ Copy change Kopēt atlikumu - - Total Amount %1 (= %2) - Kopējā Summa %1 (= %2) - or vai @@ -2074,22 +2121,10 @@ Run in the background as a daemon and accept commands Darbināt fonā kā servisu un pieņemt komandas - - Use the test network - Izmantot testa tīklu - - - (default: 1) - (noklusējums: 1) - <category> can be: <category> var būt: - - Attempt to recover private keys from a corrupt wallet.dat - Mēģināt atgūt privātās atslēgas no bojāta wallet.dat - Block creation options: Bloka izveidošanas iestatījumi: @@ -2114,10 +2149,6 @@ Error: Disk space is low! Kļūda: Zema diska vieta! - - If <category> is not supplied, output all debugging information. - Ja <category> nav norādīta, izvadīt visu atkļūdošanas informāciju. - Importing... Importē... @@ -2135,13 +2166,25 @@ Maciņa iespējas: - Imports blocks from external blk000??.dat file - Importēt blokus no ārējās blk000??.dat datnes + Cannot resolve -whitebind address: '%s' + Nevar atrisināt -whitebind adresi: '%s' Information Informācija + + Invalid amount for -maxtxfee=<amount>: '%s' + Nederīgs daudzums priekš -maxtxfee=<amount>: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Nederīgs daudzums priekš -minrelaytxfee=<amount>: '%s' + + + Invalid amount for -mintxfee=<amount>: '%s' + Nederīgs daudzums priekš -mintxfee=<amount>: '%s' + RPC server options: RPC servera iestatījumi: @@ -2150,22 +2193,10 @@ Send trace/debug info to console instead of debug.log file Debug/trace informāciju izvadīt konsolē, nevis debug.log failā - - Set language, for example "de_DE" (default: system locale) - Uzstādiet valodu, piemēram "de_DE" (pēc noklusēšanas: sistēmas lokāle) - - - Show splash screen on startup (default: 1) - Uzsākot, parādīt programmas informācijas logu (pēc noklusēšanas: 1) - Signing transaction failed Transakcijas parakstīšana neizdevās - - Start minimized - Sākt minimizētu - Transaction amount too small Transakcijas summa ir pārāk maza @@ -2186,10 +2217,6 @@ Warning Brīdinājums - - on startup - startēšanas laikā - wallet.dat corrupt, salvage failed wallet.dat ir bojāts, glābšana neizdevās @@ -2202,18 +2229,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Izpildīt komandu, kad labāk atbilstošais bloks izmainās (%s cmd aizvieto ar bloka hešu) - - Upgrade wallet to latest format - Atjaunot maciņa formātu uz jaunāko - - - Rescan the block chain for missing wallet transactions - Atkārtoti skanēt bloku virkni, meklējot trūkstošās maciņa transakcijas - - - Use OpenSSL (https) for JSON-RPC connections - JSON-RPC savienojumiem izmantot OpenSSL (https) - This help message Šis palīdzības paziņojums diff --git a/src/qt/locale/bitcoin_mk_MK.ts b/src/qt/locale/bitcoin_mk_MK.ts new file mode 100644 index 000000000..b7797063b --- /dev/null +++ b/src/qt/locale/bitcoin_mk_MK.ts @@ -0,0 +1,1039 @@ + + + AddressBookPage + + Right-click to edit address or label + Десен клик за уредување на адреса или етикета + + + Create a new address + Креирај нова адреса + + + &New + &Нова + + + Copy the currently selected address to the system clipboard + Копирај ја избраната адреса на системскиот клипборд + + + &Copy + &Копирај + + + C&lose + З&атвори + + + &Copy Address + &Копирај Адреса + + + Delete the currently selected address from the list + Избриши ја избраната адреса од листата + + + Export the data in the current tab to a file + Експортирај ги податоците од активното јазиче во датотека + + + &Export + &Експорт + + + &Delete + &Избриши + + + Choose the address to send coins to + Изберете адресата за да пратите биткоини + + + Choose the address to receive coins with + Изберете адресата за да примите биткоини + + + C&hoose + И&збери + + + Sending addresses + Адреси за праќање + + + Receiving addresses + Адреси за примање + + + Copy &Label + Копирај &Етикета + + + &Edit + &Уреди + + + Export Address List + Експортирај Листа со Адреси + + + Exporting Failed + Експортирањето не Успеа + + + + AddressTableModel + + Label + Етикета + + + Address + Адреса + + + (no label) + (без етикета) + + + + AskPassphraseDialog + + Enter passphrase + Внеси тајна фраза + + + New passphrase + Нова тајна фраза + + + Repeat new passphrase + Повторете ја новата тајна фраза + + + Encrypt wallet + Криптирање на паричник + + + Unlock wallet + Отклучи паричник + + + Decrypt wallet + Декриптирање на паричник + + + Change passphrase + Измени тајна фраза + + + Confirm wallet encryption + Потврдете го криптирањето на паричникот + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Предупредување: Ако го шифрирате вашиот паричник и ја изгубите вашата тајна фраза, ќе <b>ГИ ИЗГУБИТЕ СИТЕ ВАШИ БИТКОИНИ</b>! + + + Are you sure you wish to encrypt your wallet? + Дали сте сигурни дека сакате да криптирате вашиот паричник? + + + Warning: The Caps Lock key is on! + Предупредување: Caps Lock копчето е активно! + + + Wallet encrypted + Паричникот е криптиран + + + Wallet encryption failed + Криптирањето на паричникот е неуспешно + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Криптирањето на паричникот не успеа поради интерна грешка. Вашиот паричник не е криптиран. + + + The supplied passphrases do not match. + Приложените тајни фрази не се поклопуваат + + + Wallet unlock failed + Отклучувањето на паричникот е неуспешно + + + The passphrase entered for the wallet decryption was incorrect. + Тајната фраза која што ја внесовте за декриптирање на паричникот е неточна. + + + Wallet decryption failed + Декриптирањето на паричникот е неуспешно + + + Wallet passphrase was successfully changed. + Тајната фраза е успешно променета. + + + + BanTableModel + + + BitcoinGUI + + Sign &message... + Потпиши &порака... + + + Synchronizing with network... + Синхронизација со мрежата... + + + &Overview + &Преглед + + + Node + Јазол + + + &Transactions + &Трансакции + + + Browse transaction history + Преглед на историјата на трансакции + + + E&xit + И&злез + + + Quit application + Напушти ја апликацијата + + + About &Qt + За &Qt + + + Show information about Qt + Прикажи информации за Qt + + + &Options... + &Опции... + + + &Encrypt Wallet... + &Криптирање на Паричник... + + + &Backup Wallet... + &Бекап на Паричник... + + + &Change Passphrase... + &Измени Тајна Фраза... + + + &Sending addresses... + &Адреси за Испраќање... + + + &Receiving addresses... + &Адреси за Примање... + + + Open &URI... + Отвори &URI... + + + Bitcoin Core client + Биткоин Core софтверот + + + Importing blocks from disk... + Внесување на блокови од дискот... + + + Reindexing blocks on disk... + Повторно индексирање на блокови од дискот... + + + Send coins to a Bitcoin address + Испрати биткоини на Биткоин адреса + + + &Verify message... + &Потврди порака... + + + Bitcoin + Биткоин + + + Wallet + Паричник + + + &Send + &Испрати + + + &Receive + &Прими + + + Show information about Bitcoin Core + Прикажи информации за Биткоин Core + + + &Show / Hide + &Прикажи / Сокриј + + + Encrypt the private keys that belong to your wallet + Криптирај ги приватните клучеви кои припаѓаат на твојот паричник + + + &Settings + &Подесувања + + + &Help + &Помош + + + Bitcoin Core + Биткоин Core + + + &About Bitcoin Core + &За Биткоин Core + + + Processed %n block(s) of transaction history. + Обработен %n блок од историјата на трансакции.Обработени %n блокови од историјата на трансакции. + + + %n hour(s) + %n час%n часови + + + %n day(s) + %n ден%n денови + + + %n week(s) + %n недела%n недели + + + %1 and %2 + %1 и %2 + + + %n year(s) + %n година%n години + + + %1 behind + %1 позади + + + Error + Грешка + + + Warning + Предупредување + + + Up to date + Во тек + + + Date: %1 + + Дата: %1 + + + + Amount: %1 + + Сума: %1 + + + + Type: %1 + + Тип: %1 + + + + Label: %1 + + Етикета: %1 + + + + Address: %1 + + Адреса: %1 + + + + + ClientModel + + + CoinControlDialog + + Bytes: + Бајти: + + + Amount: + Сума: + + + Priority: + Приоритет: + + + Fee: + Провизија: + + + Dust: + Прашина: + + + After Fee: + После Провизија: + + + Change: + Кусур: + + + Amount + Сума + + + Date + Дата + + + Priority + Приоритет + + + Copy address + Копирај адреса + + + Copy label + Копирај етикета + + + Copy amount + Копирај сума + + + Lock unspent + Заклучи непотрошени + + + Unlock unspent + Отклучи непотрошени + + + Copy quantity + Копирај количина + + + Copy fee + Копирај провизија + + + Copy after fee + Копирај после провизија + + + Copy bytes + Копирај бајти + + + Copy priority + Копирај приоритет + + + Copy dust + Копирај прашина + + + Copy change + Копирај кусур + + + highest + највисок + + + higher + повисок + + + high + висок + + + medium-high + средно-висок + + + medium + среден + + + low-medium + ниско-среден + + + low + низок + + + lower + понизок + + + lowest + најнизок + + + none + нема + + + This label turns red if the transaction size is greater than 1000 bytes. + Оваа етикета станува црвена ако големината на трансакцијата е поголема од 1000 бајти. + + + This label turns red if the priority is smaller than "medium". + Оваа етикета станува црвена ако приоритетот е помал од "среден". + + + This label turns red if any recipient receives an amount smaller than %1. + Оваа етикета станува црвена ако примачот прими сума помала од %1. + + + yes + да + + + no + не + + + Transactions with higher priority are more likely to get included into a block. + Трансакциите со повисок приоритет имаат поголеми шанси да бидат вклучени во блок. + + + (no label) + (без етикета) + + + (change) + (кусур) + + + + EditAddressDialog + + Edit Address + Измени Адреса + + + &Label + &Етикета + + + &Address + &Адреса + + + + FreespaceChecker + + name + име + + + + HelpMessageDialog + + Bitcoin Core + Биткоин Core + + + version + верзија + + + (%1-bit) + (%1-бит) + + + About Bitcoin Core + За Биткоин Core + + + + Intro + + Bitcoin Core + Биткоин Core + + + Error + Грешка + + + + OpenURIDialog + + Open URI + Отвори URI + + + URI: + URI: + + + + OptionsDialog + + Options + Опции + + + MB + МБ + + + &Network + &Мрежа + + + W&allet + П&аричник + + + &Window + &Прозорец + + + &OK + &ОК + + + &Cancel + &Откажи + + + none + нема + + + + OverviewPage + + Total: + Вкупно: + + + + PaymentServer + + + PeerTableModel + + + QObject + + Amount + Сума + + + %1 d + %1 д + + + %1 h + %1 ч + + + %1 m + %1 м + + + %1 s + %1 с + + + %1 ms + %1 мс + + + + QRImageWidget + + &Save Image... + &Сними Слика... + + + Save QR Code + Сними QR Код + + + PNG Image (*.png) + PNG Слика (*.png) + + + + RPCConsole + + Network + Мрежа + + + Name + Име + + + Number of connections + Број на конекции + + + Block chain + Block chain + + + Sent + Испратени + + + Version + Верзија + + + &Console + &Конзола + + + %1 B + %1 Б + + + %1 KB + %1 КБ + + + %1 MB + %1 МБ + + + %1 GB + %1 ГБ + + + + ReceiveCoinsDialog + + &Amount: + &Сума: + + + &Label: + &Етикета: + + + &Message: + &Порака: + + + Show + Прикажи + + + Copy label + Копирај етикета + + + Copy message + Копирај порака + + + Copy amount + Копирај сума + + + + ReceiveRequestDialog + + QR Code + QR Код + + + Copy &URI + Копирај &URI + + + Copy &Address + Копирај &Адреса + + + &Save Image... + &Сними Слика... + + + URI + URI + + + Address + Адреса + + + Amount + Сума + + + Label + Етикета + + + Message + Порака + + + + RecentRequestsTableModel + + Date + Дата + + + Label + Етикета + + + Message + Порака + + + Amount + Сума + + + (no label) + (без етикета) + + + + SendCoinsDialog + + Bytes: + Бајти: + + + Amount: + Сума: + + + Priority: + Приоритет: + + + Fee: + Провизија: + + + After Fee: + После Провизија: + + + Change: + Кусур: + + + Dust: + Прашина: + + + Copy quantity + Копирај количина + + + Copy amount + Копирај сума + + + Copy fee + Копирај провизија + + + Copy after fee + Копирај после провизија + + + Copy bytes + Копирај бајти + + + Copy priority + Копирај приоритет + + + Copy change + Копирај кусур + + + (no label) + (без етикета) + + + Copy dust + Копирај прашина + + + + SendCoinsEntry + + A&mount: + Сума: + + + &Label: + &Етикета: + + + Message: + Порака: + + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + Bitcoin Core + Биткоин Core + + + + TrafficGraphWidget + + + TransactionDesc + + Date + Дата + + + Message + Порака + + + Amount + Сума + + + + TransactionDescDialog + + + TransactionTableModel + + Date + Дата + + + Label + Етикета + + + + TransactionView + + Copy address + Копирај Адреса + + + Copy label + Копирај етикета + + + Copy amount + Копирај сума + + + Exporting Failed + Експортирањето не Успеа + + + Date + Дата + + + Label + Етикета + + + Address + Адреса + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + &Export + &Експорт + + + Export the data in the current tab to a file + Експортирај ги податоците од активното јазиче во датотека + + + + bitcoin-core + + Options: + Опции: + + + Warning + Предупредување + + + Error + Грешка + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_mn.ts b/src/qt/locale/bitcoin_mn.ts index 73793482d..b79001006 100644 --- a/src/qt/locale/bitcoin_mn.ts +++ b/src/qt/locale/bitcoin_mn.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -49,6 +49,10 @@ Choose the address to receive coins with Зооснуудыг хүлээн авах хаягийг сонгоно уу + + C&hoose + С&онго + Sending addresses Илгээх хаягууд @@ -172,6 +176,9 @@ Түрүйвчийн нууц үг амжилттай ѳѳр + + BanTableModel + BitcoinGUI @@ -226,6 +233,10 @@ &Change Passphrase... &Нууц Үгийг Солих... + + &Receiving addresses... + Хүлээн авах хаяг + Change the passphrase used for wallet encryption Түрүйвчийг цоожлох нууц үгийг солих @@ -262,6 +273,10 @@ Error Алдаа + + Information + Мэдээллэл + Up to date Шинэчлэгдсэн @@ -414,6 +429,14 @@ IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) проксигийн IP хаяг (жишээ нь: IPv4: 127.0.0.1 / IPv6: ::1) + + &Network + Сүлжээ + + + W&allet + Түрүйвч + Client restart required to activate changes. Ѳѳрчлѳлтүүдийг идэвхижүүлхийн тулд клиентийг ахин эхлүүлэх шаардлагтай @@ -515,10 +538,18 @@ ReceiveCoinsDialog + + &Amount: + Хэмжээ: + &Label: &Шошго: + + &Message: + Зурвас: + Show Харуул @@ -546,6 +577,10 @@ ReceiveRequestDialog + + Copy &Address + Хаягийг &Хуулбарлах + Address Хаяг @@ -648,10 +683,6 @@ Copy change Ѳѳрчлѳлтийг санах - - Total Amount %1 (= %2) - Нийт дүн %1 (= %2) - or эсвэл @@ -711,6 +742,10 @@ Message: Зурвас: + + Pay To: + Тѳлѳх хаяг: + ShutdownWindow @@ -1031,8 +1066,8 @@ Түрүйвчийн сонголтууд: - Upgrade wallet to latest format - Түрүйвчийг хамгийн сүүлийн үеийн форматруу шинэчлэх + Information + Мэдээллэл Loading addresses... diff --git a/src/qt/locale/bitcoin_ms_MY.ts b/src/qt/locale/bitcoin_ms_MY.ts index 5e10c80af..df98dd839 100644 --- a/src/qt/locale/bitcoin_ms_MY.ts +++ b/src/qt/locale/bitcoin_ms_MY.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -56,6 +56,9 @@ AskPassphraseDialog + + BanTableModel + BitcoinGUI @@ -118,6 +121,10 @@ ReceiveRequestDialog + + Copy &Address + &Salin Alamat + Address Alamat diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts index 385f038d4..9236ac86f 100644 --- a/src/qt/locale/bitcoin_nb.ts +++ b/src/qt/locale/bitcoin_nb.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,17 @@ Adgangsfrase for lommebok endret. + + BanTableModel + + IP/Netmask + IP/Nettmaske + + + Banned Until + Utestengt til + + BitcoinGUI @@ -871,6 +882,34 @@ command-line options kommandolinjevalg + + UI Options: + Grensesnittvalg: + + + Choose data directory on startup (default: %u) + Velg datakatalog for oppstart (default: %u) + + + Set language, for example "de_DE" (default: system locale) + Sett språk, for eksempel "nb_NO" (default: system-«locale») + + + Start minimized + Begynn minimert + + + Set SSL root certificates for payment request (default: -system-) + Sett SSL-rootsertifikat for betalingshenvendelser (default: -system-) + + + Show splash screen on startup (default: %u) + Vis velkomstbilde ved oppstart (default: %u) + + + Reset all settings changes made over the GUI + Nullstill alle oppsettendringer gjort via det grafiske grensesnittet + Intro @@ -1068,6 +1107,34 @@ Port of the proxy (e.g. 9050) Proxyens port (f.eks. 9050) + + Used for reaching peers via: + Brukt for å nå noder via: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Viser om angitt SOCKS5 mellomtjener blir brukt for å nå noder via denne nettverkstypen. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Koble til Bitcoin-nettverket gjennom en separat SOCKS5 mellomtjener for Tor skjulte tjenester. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Bruk separat SOCKS5 mellomtjener for å nå noder via Tor skjulte tjenester: + &Window &Vindu @@ -1286,10 +1353,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Betalingsforespørsel %1 er for stor (%2 bytes, tillatt %3 bytes). - - Payment request DoS protection - Betalingsforespørsel DoS-beskyttelse - Error communicating with %1: %2 Feil i kommunikasjonen med %1: %2 @@ -1442,6 +1505,18 @@ Current number of blocks Nåværende antall blokker + + Memory Pool + Minnepool + + + Current number of transactions + Nåværende antall transaksjoner + + + Memory usage + Minnebruk + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. Åpne Bitcoin Core sin loggfil for feilsøk fra gjeldende datamappe. Dette kan ta noen sekunder for store loggfiler. @@ -1458,10 +1533,18 @@ &Peers &Noder + + Banned peers + Utestengte noder + Select a peer to view detailed information. Velg en node for å vise detaljert informasjon. + + Whitelisted + Hvitelistet + Direction Retning @@ -1470,6 +1553,18 @@ Version Versjon + + Starting Block + Startblokk + + + Synced Headers + Synkroniserte Blokkhoder + + + Synced Blocks + Synkroniserte Blokker + User Agent Brukeragent @@ -1478,14 +1573,6 @@ Services Tjenester - - Starting Height - Starthøyde - - - Sync Height - Synkroniseringshøyde - Ban Score Ban Poengsum @@ -1502,18 +1589,18 @@ Last Receive Siste Mottatte - - Bytes Sent - Byte Sendt - - - Bytes Received - Byte Mottatt - Ping Time Ping-tid + + The duration of a currently outstanding ping. + Tidsforløp for utestående ping. + + + Ping Wait + Ping Tid + Time Offset Tidsforskyvning @@ -1562,6 +1649,34 @@ Clear console Tøm konsoll + + &Disconnect Node + &Koble fra node + + + Ban Node for + Steng node ute for + + + 1 &hour + 1 &time + + + 1 &day + 1 &dag + + + 1 &week + 1 &uke + + + 1 &year + 1 &år + + + &Unban Node + Fjern &Utestengning av Node + Welcome to the Bitcoin Core RPC console. Velkommen til Bitcoin Core sin RPC-konsoll. @@ -1590,6 +1705,10 @@ %1 GB %1 GB + + (node id: %1) + (node id: %1) + via %1 via %1 @@ -1607,12 +1726,16 @@ Utgående - Unknown - Ukjent + Yes + Ja - Fetching... - Henter … + No + Nei + + + Unknown + Ukjent @@ -1979,8 +2102,8 @@ Kopier veksel - Total Amount %1 (= %2) - Totalt Beløp %1 (= %2) + Total Amount %1 + Totalt Beløp %1 or @@ -2014,14 +2137,14 @@ Payment request expired. Betalingsetterspørringen har utløpt. + + Pay only the required fee of %1 + Betal kun påkrevd gebyr på %1 + Estimated to begin confirmation within %n block(s). Anslått til å begynne bekreftelse innen %n blokk.Anslått til å begynne bekreftelse innen %n blokker. - - Pay only the minimum fee of %1 - Betal kun minimumsgebyret på %1 - The recipient address is not valid. Please recheck. Mottakeradressen er ikke gyldig. Vennligst kontroller på nytt. @@ -2653,6 +2776,10 @@ Copy transaction ID Kopier transaksjons-ID + + Copy raw transaction + Kopier råtransaksjon + Edit label Rediger merkelapp @@ -2800,13 +2927,53 @@ Accept command line and JSON-RPC commands Ta imot kommandolinje- og JSON-RPC-kommandoer + + If <category> is not supplied or if <category> = 1, output all debugging information. + Hvis <category> ikke er oppgitt eller hvis <category> = 1, ta ut all informasjon for feilsøking. + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Maksimalt samlede gebyrer (i %s) til å bruke i en enkelt lommeboktransaksjon; settes dette for lavt kan store transaksjoner kanskje avbrytes (standardverdi: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + Vennligst undersøk at din datamaskin har riktig dato og klokkeslett! Hvis klokken er stilt feil vil ikke Bitcoin Core fungere riktig. + + + Prune configured below the minimum of %d MiB. Please use a higher number. + Beskjæringsmodus er konfigurert under minimum på %d MiB. Vennligst bruk et høyere nummer. + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + Beskjæring: siste lommeboksynkronisering går utenfor beskjærte data. Du må bruke -reindex (laster ned hele blokkjeden igjen for beskjærte noder) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + Reduser lagringsbehovet ved beskjæring (sletting) av gamle blokker. Denne modusen er ikke kompatibel med -txindex og -rescan. Advarsel: Tilbakestilling av denne innstillingen krever at hele blokkjeden må lastes ned på nytt. (Standardverdi: 0 = deaktiver beskjæring av blokker, >%u = mål for størrelse i MiB å bruke for blokkfiler) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + Omsøk er ikke mulig i beskjært modus. Du vil måtte bruke -reindex som vil laste nede hele blokkjeden på nytt. + + + Error: A fatal internal error occurred, see debug.log for details + Feil: En fatal intern feil oppstod, se debug.log for detaljer + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Gebyr (i %s/kB) for å legge til i transaksjoner du sender (standardverdi: %s) + + + Pruning blockstore... + Beskjærer blokklageret... + Run in the background as a daemon and accept commands Kjør i bakgrunnen som daemon og ta imot kommandoer - Use the test network - Bruk testnettverket + Unable to start HTTP server. See debug log for details. + Kunne ikke starte HTTP server. Se debug logg for detaljer. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2828,18 +2995,14 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Kjør kommando når en lommeboktransaksjon endres (%s i kommando er erstattet med TxID) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Maksimalt samlede gebyrer til å bruke i en enkelt lommeboktransaksjon; settes dette for lavt kan store transaksjoner kanskje avbrytes (standardverdi: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Reduser lagringsbehovet ved beskjæring (slette) gamle blokker. Denne modusen deaktiverer støtte for lommebok og er ikke kompatibel med -txindex. Advarsel: Tilbakestilling av denne innstillingen krever at hele blokkjeden må lastes ned på nytt. (Standardverdi: 0 = deaktiver beskjæringsblokker, >%u = mål for størrelse i MiB å bruke for blokkfiler) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Angi antall tråder for skriptverifisering (%u til %d, 0 = auto, <0 = la det antallet kjerner være ledig, standard: %d) + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + Blokkdatabasen inneholder en blokk som ser ut til å være fra fremtiden. Dette kan være fordi dato og tid på din datamaskin er satt feil. Gjenopprett kun blokkdatabasen når du er sikker på at dato og tid er satt riktig. + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Dette er en forhåndssluppet testversjon - bruk på egen risiko - ikke for bruk til blokkutvinning eller bedriftsapplikasjoner @@ -2848,6 +3011,10 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. Ute av stand til å binde til %s på denne datamaskinen. Bitcoin Core kjører sannsynligvis allerede. + + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + Bruk UPnP for lytteport (standardverdi: 1 ved lytting og uten -proxy) + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) ADVARSEL: unormalt høyt antall blokker generert, %d blokker mottatt de siste %d timene (%d forventet) @@ -2856,10 +3023,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) ADVARSEL: kontroller nettverkstilkoblingen, mottok %d blokker i de siste %d timene (%d forventet) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Advarsel: -paytxfee er satt veldig høyt! Dette er transaksjonsgebyret du betaler når du sender transaksjoner. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Advarsel: Nettverket ser ikke ut til å være enig! Noen minere ser ut til å ha problemer. @@ -2868,10 +3031,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Advarsel: Vi ser ikke ut til å være enige med våre noder! Du må oppgradere, eller andre noder må oppgradere. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Advarsel: Feil ved lesing av wallet.dat! Alle nøkler lest riktig, men transaksjonsdataene eller oppføringer i adresseboken mangler kanskje eller er feil. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Advarsel: wallet.dat korrupt, data reddet! Original wallet.dat lagret som wallet.{timestamp}.bak i %s; hvis din saldo eller dine transaksjoner ikke er korrekte bør du gjenopprette fra en backup. @@ -2881,17 +3040,13 @@ Hvitelist noder som kobler til fra den oppgitte nettmasken eller IP-adressen. Kan oppgis flere ganger. - (default: 1) - (standardverdi: 1) + -maxmempool must be at least %d MB + -maxmempool må være minst %d MB <category> can be: <category> kan være: - - Attempt to recover private keys from a corrupt wallet.dat - Forsøk å berge private nøkler fra en korrupt wallet.dat - Block creation options: Valg for opprettelse av blokker: @@ -2920,6 +3075,22 @@ Do you want to rebuild the block database now? Ønsker du å gjenopprette blokkdatabasen nå? + + Enable publish hash block in <address> + Slå på publish hash block i <address> + + + Enable publish hash transaction in <address> + Slå på publish hash transaction i <address> + + + Enable publish raw block in <address> + Slå på publisering av råblokk i <address> + + + Enable publish raw transaction in <address> + Slå på publisering av råtransaksjon i <address> + Error initializing block database Feil under initialisering av blokkdatabase @@ -2936,10 +3107,6 @@ Error opening block database Feil under åpning av blokkdatabase - - Error: A fatal internal error occured, see debug.log for details - Feil: En fatal intern feil oppstod, se debug.log for detaljer - Error: Disk space is low! Feil: Lite ledig lagringsplass! @@ -2948,10 +3115,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Kunne ikke lytte på noen port. Bruk -listen=0 hvis det er dette du vil. - - If <category> is not supplied, output all debugging information. - Hvis <category> ikke er oppgitt, ta ut all informasjon om feilsøking. - Importing... Importerer... @@ -2964,6 +3127,10 @@ Invalid -onion address: '%s' Ugyldig -onion adresse: '%s' + + Keep the transaction memory pool below <n> megabytes (default: %u) + Hold transaksjonsminnet under <n> megabytes (standard: %u) + Not enough file descriptors available. For få fildeskriptorer tilgjengelig. @@ -2992,10 +3159,26 @@ Specify wallet file (within data directory) Angi lommebokfil (inne i datamappe) + + Unsupported argument -benchmark ignored, use -debug=bench. + Ustøttet argument -benchmark ble ignorert, bruk -debug=bench. + + + Unsupported argument -debugnet ignored, use -debug=net. + Advarsel: Argumentet -debugnet er ikke støttet og ble ignorert, bruk -debug=net. + + + Unsupported argument -tor found, use -onion. + Feil: Argumentet -tor er ikke støttet, bruk -onion. + Use UPnP to map the listening port (default: %u) Bruk UPnP for å sette opp lytteport (standardverdi: %u) + + User Agent comment (%s) contains unsafe characters. + User Agent kommentar (%s) inneholder utrygge tegn. + Verifying blocks... Verifiserer blokker... @@ -3020,18 +3203,10 @@ You need to rebuild the database using -reindex to change -txindex Du må gjenoppbygge databasen med å bruke -reindex for å endre -txindex - - Imports blocks from external blk000??.dat file - Importerer blokker fra ekstern fil blk000??.dat - 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 Tillat JSON-RPC-tilkoblinger fra angitt kilde. Gyldig for <ip> er en enkelt IP (f. eks. 1.2.3.4), et nettverk/nettmaske (f. eks. 1.2.3.4/255.255.255.0) eller et nettverk/CIDR (f. eks. 1.2.3.4/24). Dette alternativet kan angis flere ganger - - An error occurred while setting up the RPC address %s port %u for listening: %s - En feil oppstod under oppsett av RPC-adressen %s port %u for lytting: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Bind til gitt adresse og hvitlist peers som kobler seg til den. Bruk [host]:port notasjon for IPv6 @@ -3056,17 +3231,13 @@ Error: Listening for incoming connections failed (listen returned error %s) Feil: Lytting etter innkommende tilkoblinger feilet (lytting returnerte feil %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Feil: Argumentet -socks er ikke støttet. Det er ikke lenger mulig å sette SOCKS-versjon; bare SOCKS5-proxyer er støttet. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Utfør kommando når et relevant varsel er mottatt eller vi ser en veldig lang gaffel (%s i kommando er erstattet med melding) - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Gebyrer (i BTC/Kb) mindre enn dette anses som null gebyr for videresending (standardverdi: %s) + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + Gebyrer (i %s/kB) mindre enn dette anses som null gebyr for videresending, graving og laging av transaksjoner (standardverdi: %s) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -3080,10 +3251,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) Maksimal størrelse på data i databærende transaksjoner vi videresender og ufører graving på (standardverdi: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - Beskjæringsmodus er konfigurert under minimum på %d MB. Vennligst bruk et høyere nummer. - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Søk etter nodeadresser via DNS-oppslag, hvis vi har få adresser å koble til (standard: 1 med mindre -connect) @@ -3108,38 +3275,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Dette produktet inneholder programvare utviklet av OpenSSL Project for bruk i OpenSSL Toolkit <https://www.openssl.org/> og kryptografisk programvare skrevet av Eric Young og UPnP-programvare skrevet av Thomas Bernard. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - For å bruke bitcoind, eller -server valget til bitcoin-qt, må du angi et rpcpassord i konfigurasjonsfilen: -%s -Det anbefales at du bruker det følgende tilfeldige passordet: -rpcuser=bitcoinrpc -rpcpassword=%s -(du behøver ikke å huske passordet) -Brukernavnet og passordet MÅ IKKE være like. -Om filen ikke eksisterer, opprett den med eier-kun-les filrettigheter. -Det er også anbefalt at å sette varselsmelding slik du får melding om problemer; -for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Advarsel: -paytxfee er satt veldig høyt! Så stort gebyr kan bli betalt ved en enkelt transaksjon. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Advarsel: Vennligst undersøk at din datamaskin har riktig dato og klokkeslett! Hvis klokken er stilt feil vil ikke Bitcoin Core fungere riktig. - 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 Hvitlistede noder kan ikke DoS-blokkeres, og deres transaksjoner videresendes alltid, selv om de allerede er i minnelageret. Nyttig f.eks. for en gateway. @@ -3161,17 +3296,21 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Aktiverer beste kjede... - Can't run with a wallet in prune mode. - Kan ikke kjøre med en lommebok i beskjæringsmodus. + Always relay transactions received from whitelisted peers (default: %d) + Alltid videresend transaksjoner mottatt fra hvitlistede noder (standardverdi: %d) + + + Attempt to recover private keys from a corrupt wallet.dat on startup + Forsøk å berge private nøkler fra en korrupt wallet.dat ved oppstart + + + Automatically create Tor hidden service (default: %d) + Automatisk opprette Tor skjult tjeneste (standardverdi: %d) Cannot resolve -whitebind address: '%s' Kan ikke løse -whitebind-adresse: '%s' - - Choose data directory on startup (default: 0) - Velg datamappe ved oppstart (standard: 0) - Connect through SOCKS5 proxy Koble til via SOCKS5-proxy @@ -3180,10 +3319,6 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Copyright (C) 2009-%i The Bitcoin Core Developers Copyright (C) 2009-%i utviklerne av Bitcoin Core - - Could not parse -rpcbind value %s as network address - Kunne ikke tolke -rpcbind-verdi %s som en nettverksadresse - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Feil ved lasting av wallet.dat: Lommeboken krever en nyere versjon av Bitcoin Core @@ -3193,12 +3328,8 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Feil ved lesing fra database, stenger ned. - Error: Unsupported argument -tor found, use -onion. - Feil: Argumentet -tor er ikke støttet, bruk -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Gebyr (i BTC/kB) for å legge til i transaksjoner du sender (standardverdi: %s) + Imports blocks from external blk000??.dat file on startup + Importerer blokker fra ekstern fil blk000??.dat ved oppstart Information @@ -3240,18 +3371,10 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Node relay options: Node alternativer for videresending: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - RPC SSL-valg: (se Bitcoin Wiki for oppsettsinstruksjoner for SSL) - RPC server options: Innstillinger for RPC-server: - - RPC support for HTTP persistent connections (default: %d) - RPC-støtte for persistente HTTP-forbindelser (standardverdi: %d) - Rebuild block chain index from current blk000??.dat files on startup Gjenopprett blokkjedeindeks fra gjeldende blk000??.dat filer ved oppstart @@ -3260,6 +3383,14 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Receive and display P2P network alerts (default: %u) Motta og vis P2P nettverksvarsler (standardvalg: %u) + + Reducing -maxconnections from %d to %d, because of system limitations. + Reduserer -maxconnections fra %d til %d, pga. systembegrensninger. + + + Rescan the block chain for missing wallet transactions on startup + Se gjennom blokkjeden etter manglende lommeboktransaksjoner ved oppstart + Send trace/debug info to console instead of debug.log file Send spor-/feilsøkingsinformasjon til konsollen istedenfor filen debug.log @@ -3268,22 +3399,10 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Send transactions as zero-fee transactions if possible (default: %u) Send transaksjoner uten transaksjonsgebyr hvis mulig (standardverdi: %u) - - Set SSL root certificates for payment request (default: -system-) - Sett SSL-rotsertifikat for betalingsetterspørring (standard: -system-) - - - Set language, for example "de_DE" (default: system locale) - Sett språk, for eksempel "nb_NO" (standardverdi: fra operativsystem) - Show all debugging options (usage: --help -help-debug) Vis alle feilsøkingsvalg (bruk: --help -help-debug) - - Show splash screen on startup (default: 1) - Vis splashskjerm ved oppstart (standardverdi: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Krymp filen debug.log når klienten starter (standardverdi: 1 hvis uten -debug) @@ -3292,10 +3411,6 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Signing transaction failed Signering av transaksjon feilet - - Start minimized - Start minimert - The transaction amount is too small to pay the fee Transaksjonsbeløpet er for lite til å betale gebyr @@ -3304,6 +3419,14 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com This is experimental software. Dette er eksperimentell programvare. + + Tor control port password (default: empty) + Passord for Tor-kontrollport (standardverdi: tom) + + + Tor control port to use if onion listening enabled (default: %s) + Tor-kontrollport å bruke hvis onion-lytting er aktivert (standardverdi: %s) + Transaction amount too small Transaksjonen er for liten @@ -3320,17 +3443,13 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Transaction too large Transaksjonen er for stor - - UI Options: - Innstillinger for Brukergrensesnitt: - Unable to bind to %s on this computer (bind returned error %s) Kan ikke binde til %s på denne datamaskinen (binding returnerte feilen %s) - Use UPnP to map the listening port (default: 1 when listening) - Bruk UPnP for lytteport (standardverdi: 1 ved lytting) + Upgrade wallet to latest format on startup + Oppgrader lommebok til nyeste format ved oppstart Username for JSON-RPC connections @@ -3345,20 +3464,16 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Advarsel - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Advarsel: Argumentet -benchmark er ikke støttet og ble ignorert, bruk -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Advarsel: Argumentet -debugnet er ikke støttet og ble ignorert, bruk -debug=net. + Whether to operate in a blocks only mode (default: %u) + Hvorvidt å operere i modus med kun blokker (standardverdi: %u) Zapping all transactions from wallet... Zapper alle transaksjoner fra lommeboken... - on startup - ved oppstart + ZeroMQ notification options: + Valg for ZeroMQ-meldinger: wallet.dat corrupt, salvage failed @@ -3372,18 +3487,6 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Execute command when the best block changes (%s in cmd is replaced by block hash) Utfør kommando når beste blokk endrer seg (%s i kommandoen erstattes med blokkens hash) - - Upgrade wallet to latest format - Oppgrader lommebok til nyeste format - - - Rescan the block chain for missing wallet transactions - Se gjennom blokkjeden etter manglende lommeboktransaksjoner - - - Use OpenSSL (https) for JSON-RPC connections - Bruk OpenSSL (https) for JSON-RPC forbindelser - This help message Denne hjelpemeldingen @@ -3404,6 +3507,26 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = behold metadata for transaksjon som f. eks. kontoeier og informasjon om betalingsanmodning, 2 = dropp metadata for transaksjon) + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + -maxtxfee er satt veldig høyt! Så stort gebyr kan bli betalt ved en enkelt transaksjon. + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + -paytxfee er satt veldig høyt! Dette er transaksjonsgebyret du betaler når du sender transaksjoner. + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + Ikke hold transaksjoner i minnet lenger enn <n> timer (standard: %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Feil ved lesing av wallet.dat! Alle nøkler lest riktig, men transaksjonsdataene eller oppføringer i adresseboken mangler kanskje eller er feil. + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + Gebyrer (i %s/Kb) mindre enn dette anses som null gebyr for laging av transaksjoner (standardverdi: %s) + How thorough the block verification of -checkblocks is (0-4, default: %u) Hvor grundig blokkverifiseringen til -checkblocks er (0-4, standardverdi: %u) @@ -3420,17 +3543,33 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Output debugging information (default: %u, supplying <category> is optional) Ta ut feilsøkingsinformasjon (standardverdi: %u, bruk av <category> er valgfritt) + + Support filtering of blocks and transaction with bloom filters (default: %u) + Støtte filtrering av blokker og transaksjoner med bloomfiltre (standardverdi: %u) + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + Total lengde av nettverks-versionstreng (%i) er over maks lengde (%i). Reduser tallet eller størrelsen av uacomments. + + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + Prøv å holde utgående trafikk under angitt mål (i MB per 24t), 0 = ingen grense (standard: %d) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Argumentet -socks er ikke støttet. Det er ikke lenger mulig å sette SOCKS-versjon; bare SOCKS5-proxyer er støttet. + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) Bruk separate SOCKS5 proxyer for å nå noder via Tor skjulte tjenester (standardverdi: %s) - (default: %s) - (standardverdi: %s) + 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. This option can be specified multiple times + Brukernavn og hashet passord for JSON-RPC tilkoblinger. Feltet <userpw> kommer i formatet: <USERNAME>:<SALT>$<HASH>. Et Python-skript er inkludert i share/rpcuser. Dette alternativet kan angis flere ganger - Acceptable ciphers (default: %s) - Akseptable sifre (standardverdi: %s) + (default: %s) + (standardverdi: %s) Always query for peer addresses via DNS lookup (default: %u) @@ -3492,14 +3631,6 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Relay non-P2SH multisig (default: %u) Videresend ikke-P2SH multisig (standardverdi: %u) - - Server certificate file (default: %s) - Fil for tjenersertifikat (standardverdi: %s) - - - Server private key (default: %s) - Privat nøkkel for tjener (standardverdi: %s) - Set key pool size to <n> (default: %u) Angi størrelse på nøkkel-lager til <n> (standardverdi: %u) diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index 7999e263e..8457a9ab5 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -59,7 +59,7 @@ Sending addresses - Verstuur adressen + Verstuuradressen Receiving addresses @@ -67,11 +67,11 @@ These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. - Dit zijn uw Bitcoinadressen om betalingen mee te verzenden. Controleer altijd het bedrag en het ontvang adres voordat u uw bitcoins verzendt. + Dit zijn uw Bitcoinadressen om betalingen mee te doen. Controleer altijd het bedrag en het ontvang adres voordat u uw bitcoins verstuurt. These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. - Dit zijn uw Bitcoin-adressen waarmee u kunt betalen. We raden u aan om een nieuw ontvangstadres voor elke transactie te gebruiken. + Dit zijn uw Bitcoinadressen waarmee u kunt betalen. We raden u aan om een nieuw ontvangstadres voor elke transactie te gebruiken. Copy &Label @@ -157,7 +157,7 @@ Confirm wallet encryption - Bevestig versleuteling van de portemonnee + Bevestig versleuteling van uw portemonnee Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! @@ -177,7 +177,7 @@ Warning: The Caps Lock key is on! - Waarschuwing: De Caps-Lock-toets staat aan! + Waarschuwing: De Caps Locktoets staat aan! Wallet encrypted @@ -220,6 +220,17 @@ Portemonneewachtwoord is met succes gewijzigd. + + BanTableModel + + IP/Netmask + IP/Netmasker + + + Banned Until + Geband tot + + BitcoinGUI @@ -248,11 +259,11 @@ Browse transaction history - Blader door transactieverleden + Blader door transactiegescheidenis E&xit - &Afsluiten + A&fsluiten Quit application @@ -268,7 +279,7 @@ &Options... - O&pties... + &Opties... &Encrypt Wallet... @@ -284,11 +295,11 @@ &Sending addresses... - V&erstuur adressen... + &Verstuuradressen... &Receiving addresses... - O&ntvang adressen... + &Ontvang adressen... Open &URI... @@ -296,7 +307,7 @@ Bitcoin Core client - Bitcoin Kern applicatie + Bitcoin Coreapplicatie Importing blocks from disk... @@ -340,7 +351,7 @@ &Send - &Versturen + &Verstuur &Receive @@ -348,7 +359,7 @@ Show information about Bitcoin Core - Toon informatie over bitcoin kern + Toon informatie over Bitcoin Core &Show / Hide @@ -388,11 +399,11 @@ Bitcoin Core - Bitcoin Kern + Bitcoin Core Request payments (generates QR codes and bitcoin: URIs) - Vraag betaling aan (genereert QR codes en bitcoin: URIs) + Vraag betaling aan (genereert QR-codes en bitcoin: URI's) &About Bitcoin Core @@ -404,7 +415,7 @@ Show the list of used sending addresses and labels - Toon de lijst met gebruikt verzend adressen en labels + Toon de lijst met gebruikte verstuuradressen en -labels Show the list of used receiving addresses and labels @@ -416,15 +427,15 @@ &Command-line options - &Commandoregel-opties + &Opdrachytregelopties Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options - Toon het Bitcoin Core hulpbericht om een lijst te krijgen met mogelijke Bitcoin commandoregelopties + Toon het Bitcoin Core hulpbericht om een lijst te krijgen met mogelijke Bitcoinopdrachtregelopties %n active connection(s) to Bitcoin network - %n actieve connectie naar Bitcoin netwerk%n actieve connecties naar Bitcoin netwerk + %n actieve verbinding met Bitcoinnetwerk%n actieve verbindingen met Bitcoinnetwerk No block source available... @@ -432,11 +443,11 @@ Processed %n block(s) of transaction history. - %n blok aan transactie geschiedenis verwerkt.%n blokken aan transactie geschiedenis verwerkt. + %n blok aan transactiegeschiedenis verwerkt.%n blokken aan transactiegeschiedenis verwerkt. %n hour(s) - %n uur%n uur + %n uur%n uren %n day(s) @@ -452,7 +463,7 @@ %n year(s) - %n jaar%n jaar + %n jaar%n jaren %1 behind @@ -518,7 +529,7 @@ Sent transaction - Verzonden transactie + Verstuurde transactie Incoming transaction @@ -564,7 +575,7 @@ Fee: - Vergoeding: + Transactiekosten: Dust: @@ -572,7 +583,7 @@ After Fee: - Na vergoeding: + Naheffing: Change: @@ -648,11 +659,11 @@ Copy fee - Kopieer vergoeding + Kopieerkosten Copy after fee - Kopieer na vergoeding + Kopieernaheffing Copy bytes @@ -740,15 +751,15 @@ This means a fee of at least %1 per kB is required. - Dit betekent dat een vergoeding van minimaal %1 per kB nodig is. + Dit betekent dat kosten van minimaal %1 per kB aan verbonden zijn. Can vary +/- 1 byte per input. - Kan +/- byte per invoer variëren. + Kan +/- 1 byte per invoer variëren. Transactions with higher priority are more likely to get included into a block. - Transacties met een hogere prioriteit zullen eerder in een block gezet worden. + Transacties met een hogere prioriteit zullen eerder in een blok gezet worden. (no label) @@ -779,7 +790,7 @@ The address associated with this address list entry. This can only be modified for sending addresses. - Het adres dat bij dit adres item hoort. Dit kan alleen bewerkt worden voor verstuur adressen. + Het adres dat bij dit adresitem hoort. Dit kan alleen bewerkt worden voor verstuuradressen. &Address @@ -791,7 +802,7 @@ New sending address - Nieuw adres om naar te verzenden + Nieuw adres om naar te versturen Edit receiving address @@ -799,7 +810,7 @@ Edit sending address - Bewerk adres om naar te verzenden + Bewerk adres om naar te versturen The entered address "%1" is already in the address book. @@ -834,7 +845,7 @@ Path already exists, and is not a directory. - Communicatiepad bestaat al, en is geen folder. + Communicatiepad bestaat al, en is geen map. Cannot create data directory here. @@ -845,7 +856,7 @@ HelpMessageDialog Bitcoin Core - Bitcoin Kern + Bitcoin Core version @@ -861,7 +872,7 @@ Command-line options - Commandoregel-opties + Opdrachtregelopties Usage: @@ -869,7 +880,35 @@ command-line options - commandoregel-opties + opdrachtregelopties + + + UI Options: + UI-opties: + + + Choose data directory on startup (default: %u) + Kies gegevensmap bij opstarten (standaard: %u) + + + Set language, for example "de_DE" (default: system locale) + Stel taal in, bijvoorbeeld "nl_NL" (standaard: systeemlocale) + + + Start minimized + Geminimaliseerd starten + + + Set SSL root certificates for payment request (default: -system-) + Zet SSL-rootcertificaat voor betalingsverzoeken (standaard: -systeem-) + + + Show splash screen on startup (default: %u) + Toon opstartscherm bij opstarten (standaard: %u) + + + Reset all settings changes made over the GUI + Reset alle wijzigingen aan instellingen gedaan met de GUI @@ -888,7 +927,7 @@ Bitcoin Core will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. - Bitcoin Core zal een kopie van de Bitcoin blokketen downloaden en opslaan. Tenminste %1 GB aan data wordt opgeslagen in deze map en het zal groeien in de tijd. De portemonnee wordt ook in deze map opgeslagen. + Bitcoin Core zal een kopie van de Bitcoinblokketen downloaden en opslaan. Tenminste %1 GB aan data wordt opgeslagen in deze map en het zal groeien in de tijd. De portemonnee wordt ook in deze map opgeslagen. Use the default data directory @@ -900,7 +939,7 @@ Bitcoin Core - Bitcoin Kern + Bitcoin Core Error: Specified data directory "%1" cannot be created. @@ -912,7 +951,7 @@ %n GB of free space available - %n GB aan vrije oplsagruimte beschikbaar%n GB aan vrije oplsagruimte beschikbaar + %n GB aan vrije opslagruimte beschikbaar%n GB aan vrije opslagruimte beschikbaar (of %n GB needed) @@ -954,7 +993,7 @@ Size of &database cache - Grootte van de &database cache + Grootte van de &databasecache MB @@ -986,7 +1025,7 @@ Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - Derde partijen URL's (bijvoorbeeld block explorer) dat in de transacties tab verschijnen als contextmenu elementen. %s in de URL is vervangen door transactie hash. Verscheidene URL's zijn gescheiden door een verticale streep |. + URL's van derden (bijvoorbeeld block explorer) die in de transacties tab verschijnen als contextmenuelementen. %s in de URL is vervangen door transactiehash. Verscheidene URL's zijn gescheiden door een verticale streep |. Third party transaction URLs @@ -994,7 +1033,7 @@ Active command-line options that override above options: - Actieve commandoregelopties die bovenstaande opties overschrijven: + Actieve opdrachtregelopties die bovenstaande opties overschrijven: Reset all client options to default. @@ -1010,11 +1049,11 @@ Automatically start Bitcoin Core after logging in to the system. - Bitcoin Kern automatisch starten bij inloggen. + Bitcoin Core automatisch starten bij inloggen. &Start Bitcoin Core on system login - &Start Bitcoin Kern tijdens login. + &Start Bitcoin Core tijdens login. (0 = auto, <0 = leave that many cores free) @@ -1042,7 +1081,7 @@ Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. - Open de Bitcoin-poort automatisch op de router. Dit werkt alleen als de router UPnP ondersteunt en het aanstaat. + Open de Bitcoinpoort automatisch op de router. Dit werkt alleen als de router UPnP ondersteunt en het aanstaat. Map port using &UPnP @@ -1050,7 +1089,7 @@ Connect to the Bitcoin network through a SOCKS5 proxy. - Verbind met het Bitcoin netwerk via een SOCKS5 proxy. + Verbind met het Bitcoinnetwerk via een SOCKS5 proxy. &Connect through SOCKS5 proxy (default proxy): @@ -1068,13 +1107,41 @@ Port of the proxy (e.g. 9050) Poort van de proxy (bijv. 9050) + + Used for reaching peers via: + Gebruikt om peers te bereiken via: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Vertoningen, als de opgegeven standaard SOCKS5-proxy is gebruikt om peers te benaderen via dit type netwerk. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Maak verbinding met Bitcoinnetwerk door een aparte SOCKS5-proxy voor verborgen diensten van Tor. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Gebruikt aparte SOCKS5-proxy om peers te bereiken via verborgen diensten van Tor: + &Window &Scherm Show only a tray icon after minimizing the window. - Laat alleen een systeemvak-icoon zien wanneer het venster geminimaliseerd is + Laat alleen een systeemvakicoon zien wanneer het venster geminimaliseerd is &Minimize to the tray instead of the taskbar @@ -1082,7 +1149,7 @@ M&inimize on close - Minimaliseer bij sluiten van het &venster + M&inimaliseer bij sluiten van het venster &Display @@ -1098,7 +1165,7 @@ Choose the default subdivision unit to show in the interface and when sending coins. - Kies de standaard onderverdelingseenheid om weer te geven in uw programma, en voor het versturen van munten + Kies de standaardonderverdelingseenheid om weer te geven in uw programma, en voor het versturen van munten Whether to show coin control features or not. @@ -1110,7 +1177,7 @@ &Cancel - Ann&uleren + &Annuleren default @@ -1256,7 +1323,7 @@ URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. - URI kan niet verwerkt worden! Dit kan het gevolg zijn van een ongeldig Bitcoin adres of misvormde URI parameters. + URI kan niet verwerkt worden! Dit kan het gevolg zijn van een ongeldig Bitcoinadres of misvormde URI-parameters. Payment request file handling @@ -1264,7 +1331,7 @@ Payment request file cannot be read! This can be caused by an invalid payment request file. - Betalingsverzoek-bestand kan niet gelezen of verwerkt worden! Dit kan veroorzaakt worden door een ongeldig betalingsverzoek-bestand. + Betalingsverzoekbestand kan niet gelezen of verwerkt worden! Dit kan veroorzaakt worden door een ongeldig betalingsverzoek-bestand. Payment request expired. @@ -1286,10 +1353,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Betalingsverzoek %1 is te groot (%2 bytes, toegestaan ​​%3 bytes). - - Payment request DoS protection - Betalingsaanvraag DoS bescherming - Error communicating with %1: %2 Fout bij communiceren met %1: %2 @@ -1317,6 +1380,10 @@ User Agent User Agent + + Node/Service + Node/Dienst + Ping Time Ping tijd @@ -1330,11 +1397,11 @@ Enter a Bitcoin address (e.g. %1) - Voer een Bitcoin-adres in (bijv. %1) + Voer een Bitcoinadres in (bijv. %1) %1 d - %1d + %1 d %1 h @@ -1346,7 +1413,7 @@ %1 s - %1s + %1 s None @@ -1438,9 +1505,21 @@ Current number of blocks Huidig aantal blokken + + Memory Pool + Geheugenpoel + + + Current number of transactions + Huidig aantal transacties + + + Memory usage + Geheugengebruik + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. - Open het Bitcoin Core debug logbestand van de huidige gegevens directory. Dit kan enkele seconden duren voor grote logbestanden. + Open het Bitcoin Core debuglogbestand van de huidige gegevensmap. Dit kan enkele seconden duren voor grote logbestanden. Received @@ -1454,10 +1533,18 @@ &Peers &Peers + + Banned peers + Gebande peers + Select a peer to view detailed information. Selecteer een peer om gedetailleerde informatie te bekijken. + + Whitelisted + Toegestaan + Direction Directie @@ -1466,21 +1553,25 @@ Version Versie + + Starting Block + Start Blok + + + Synced Headers + Gesynchroniseerde headers + + + Synced Blocks + Gesynchroniseerde blokken + User Agent User Agent Services - Services - - - Starting Height - Aanvangshoogte - - - Sync Height - Synchronisatiehoogte + Diensten Ban Score @@ -1498,18 +1589,22 @@ Last Receive Laatst ontvangen - - Bytes Sent - Bytes Verzonden - - - Bytes Received - Bytes Ontvangen - Ping Time Ping Tijd + + The duration of a currently outstanding ping. + De tijdsduur van een op het moment openstaande ping. + + + Ping Wait + Pingwachttijd + + + Time Offset + Tijdcompensatie + Last block time Tijd laatste blok @@ -1548,12 +1643,40 @@ Debug log file - Debug-logbestand + Debuglogbestand Clear console Maak console leeg + + &Disconnect Node + &Verbreek Verbinding Node + + + Ban Node for + Ban Node voor + + + 1 &hour + 1 &uur + + + 1 &day + 1 &dag + + + 1 &week + 1 &week + + + 1 &year + 1 &jaar + + + &Unban Node + &Maak Ban Ongedaan voor Node + Welcome to the Bitcoin Core RPC console. Welkom op de Bitcoin Core RPC console. @@ -1564,7 +1687,7 @@ Type <b>help</b> for an overview of available commands. - Typ <b>help</b> voor een overzicht van de beschikbare commando's. + Typ <b>help</b> voor een overzicht van de beschikbare opdrachten. %1 B @@ -1582,6 +1705,10 @@ %1 GB %1 Gb + + (node id: %1) + (node id: %1) + via %1 via %1 @@ -1599,12 +1726,16 @@ Uitgaand - Unknown - Onbekend + Yes + Ja - Fetching... - Ophalen... + No + Nee + + + Unknown + Onbekend @@ -1631,7 +1762,7 @@ An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network. - Een optioneel bericht om bij te voegen aan het betalingsverzoek, dewelke zal getoond worden wanneer het verzoek is geopend. Opermerking: Het bericht zal niet worden verzonden met de betaling over het Bitcoin netwerk. + Een optioneel bericht om bij te voegen aan het betalingsverzoek, welke zal getoond worden wanneer het verzoek is geopend. Opmerking: Het bericht zal niet worden verzonden met de betaling over het Bitcoinnetwerk. An optional label to associate with the new receiving address. @@ -1780,7 +1911,7 @@ SendCoinsDialog Send Coins - Verstuur munten + Verstuurde munten Coin Control Features @@ -1816,11 +1947,11 @@ Fee: - Vergoeding: + Kosten: After Fee: - Na vergoeding: + Naheffing: Change: @@ -1828,7 +1959,7 @@ If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. - Als dit is geactiveerd, maar het wisselgeldadres is leeg of ongeldig, dan wordt het wisselgeld verzonden naar een nieuw gegenereerd adres. + Als dit is geactiveerd, maar het wisselgeldadres is leeg of ongeldig, dan wordt het wisselgeld verstuurd naar een nieuw gegenereerd adres. Custom change address @@ -1844,7 +1975,7 @@ collapse fee-settings - Transactiekosteninstellingen verbergen + verberg kosteninstellingen per kilobyte @@ -1880,7 +2011,7 @@ (Smart fee not initialized yet. This usually takes a few blocks...) - (Slimme vergoeding is nog niet geïnitialiseerd. Dit duurt meestal een paar blokken...) + (Slimme transactiekosten is nog niet geïnitialiseerd. Dit duurt meestal een paar blokken...) Confirmation time: @@ -1896,7 +2027,7 @@ Send as zero-fee transaction if possible - Verstuur als transactie zonder verzendkosten indien mogelijk + Indien mogelijk, verstuur zonder transactiekosten (confirmation may take longer) @@ -1904,7 +2035,7 @@ Send to multiple recipients at once - Verstuur aan verschillende ontvangers ineens + Verstuur in een keer aan verschillende ontvangers Add &Recipient @@ -1932,7 +2063,7 @@ S&end - &Verstuur + V&erstuur Confirm send coins @@ -1952,11 +2083,11 @@ Copy fee - Kopieer vergoeding + Kopieerkosten Copy after fee - Kopieer na vergoeding + Kopieernaheffing Copy bytes @@ -1971,8 +2102,8 @@ Kopieer wijziging - Total Amount %1 (= %2) - Totaal bedrag %1 (= %2) + Total Amount %1 + Totaalbedrag %1 or @@ -1998,13 +2129,21 @@ The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. De transactie was afgewezen. Dit kan gebeuren als u eerder uitgegeven munten opnieuw wilt versturen, zoals wanneer u een kopie van uw wallet.dat heeft gebruikt en in de kopie deze munten zijn gemarkeerd als uitgegeven, maar in de huidige nog niet. + + A fee higher than %1 is considered an absurdly high fee. + Transactiekosten van meer dan %1 wordt beschouwd als een absurd hoge transactiekosten. + Payment request expired. Betalingsverzoek verlopen. - Pay only the minimum fee of %1 - Betaal alleen de minimale transactiekosten van %1 + Pay only the required fee of %1 + Betaal alleen de verplichte transactiekosten van %1 + + + Estimated to begin confirmation within %n block(s). + Schatting is dat bevestiging begint over %n blok.Schatting is dat bevestiging begint over %n blokken. The recipient address is not valid. Please recheck. @@ -2016,7 +2155,7 @@ Warning: Invalid Bitcoin address - Waarschuwing: Ongeldig Bitcoin adres + Waarschuwing: Ongeldig Bitcoinadres (no label) @@ -2032,7 +2171,7 @@ Are you sure you want to send? - Weet u zeker dat u wilt verzenden? + Weet u zeker dat u wilt versturen? added as transaction fee @@ -2043,7 +2182,7 @@ SendCoinsEntry A&mount: - Bedra&g: + B&edrag: Pay &To: @@ -2067,7 +2206,7 @@ The Bitcoin address to send the payment to - Het Bitcoin adres om betaling aan te voldoen + Het Bitcoinadres om betaling aan te versturen Alt+A @@ -2085,6 +2224,14 @@ Remove this entry Verwijder deze toevoeging + + The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally. + De transactiekosten zal worden afgetrokken van het bedrag dat verstuurd wordt. De ontvangers zullen minder bitcoins ontvangen dan ingevoerd is in het hoeveelheidsveld. Als er meerdere ontvangers geselecteerd zijn, dan worden de transactiekosten gelijk verdeeld. + + + S&ubtract fee from amount + Trek de transactiekosten a&f van het bedrag. + Message: Bericht: @@ -2103,7 +2250,7 @@ A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network. - Een bericht dat werd toegevoegd aan de bitcoin: URI dewelke wordt opgeslagen met de transactie ter referentie. Opmerking: Dit bericht zal niet worden verzonden over het Bitcoin netwerk. + Een bericht dat werd toegevoegd aan de bitcoin: URI welke wordt opgeslagen met de transactie ter referentie. Opmerking: Dit bericht zal niet worden verzonden over het Bitcoinnetwerk. Pay To: @@ -2129,19 +2276,19 @@ SignVerifyMessageDialog Signatures - Sign / Verify a Message - Handtekeningen - Onderteken een bericht / Verifiëer een handtekening + Handtekeningen – Onderteken een bericht / Verifiëer een handtekening &Sign Message - O&nderteken Bericht + &Onderteken Bericht You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. - U kunt berichten/overeenkomsten ondertekenen met uw adres om te bewijzen dat u Bitcoins kunt versturen. Wees voorzichtig met het ondertekenen van iets vaags of willekeurigs, omdat phishing-aanvallen u kunnen proberen te misleiden tot het ondertekenen van overeenkomsten om uw identiteit aan hen toe te vertrouwen. Onderteken alleen volledig gedetailleerde verklaringen voordat u akkoord gaat. + U kunt berichten/overeenkomsten ondertekenen met uw adres om te bewijzen dat u Bitcoins kunt versturen. Wees voorzichtig met het ondertekenen van iets vaags of willekeurigs, omdat phishingaanvallen u kunnen proberen te misleiden tot het ondertekenen van overeenkomsten om uw identiteit aan hen toe te vertrouwen. Onderteken alleen volledig gedetailleerde verklaringen voordat u akkoord gaat. The Bitcoin address to sign the message with - Het Bitcoin adres om bericht mee te ondertekenen + Het Bitcoinadres om bericht mee te ondertekenen Choose previously used address @@ -2191,9 +2338,13 @@ &Verify Message &Verifiëer Bericht + + Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction! + Voer het adres van de ontvanger in, bericht (zorg ervoor dat de regeleinden, spaties, tabs etc. precies kloppen) en onderteken onderaan om het bericht te verifiëren. Wees voorzicht om niet meer in de ondertekening te lezen dan in het getekende bericht zelf, om te voorkomen dat je wordt aangevallen met een man-in-the-middle attack. Houd er mee rekening dat dit alleen de ondertekende partij bewijst met het ontvangen adres, er kan niet bewezen worden dat er een transactie heeft plaatsgevonden! + The Bitcoin address the message was signed with - Het Bitcoin adres waarmee het bericht ondertekend is + Het Bitcoinadres waarmee het bericht ondertekend is Verify the message to ensure it was signed with the specified Bitcoin address @@ -2264,11 +2415,11 @@ SplashScreen Bitcoin Core - Bitcoin Kern + Bitcoin Core The Bitcoin Core developers - De Bitcoin Core ontwikkelaars + De Bitcoin Core-ontwikkelaars [testnet] @@ -2398,7 +2549,7 @@ Debug information - Debug-informatie + Debuginformatie Transaction @@ -2456,7 +2607,7 @@ Immature (%1 confirmations, will be available after %2) - immatuur (%1 bevestigingen, zal beschikbaar zijn na %2) + Premature (%1 bevestigingen, zal beschikbaar zijn na %2) Open for %n more block(s) @@ -2508,7 +2659,7 @@ Sent to - Verzonden aan + Verstuurd aan Payment to yourself @@ -2542,6 +2693,10 @@ Whether or not a watch-only address is involved in this transaction. Of er een alleen-bekijken adres is betrokken bij deze transactie. + + User-defined intent/purpose of the transaction. + Door gebruiker gedefinieerde intentie/doel van de transactie + Amount removed from or added to balance. Bedrag verwijderd van of toegevoegd aan saldo @@ -2583,7 +2738,7 @@ Sent to - Verzonden aan + Verstuurd aan To yourself @@ -2621,6 +2776,10 @@ Copy transaction ID Kopieer transactie-ID + + Copy raw transaction + Kopieer ruwe transactie + Edit label Bewerk label @@ -2631,7 +2790,7 @@ Export Transaction History - Exporteer Transactieverleden + Exporteer Transactiegeschiedenis Watch-only @@ -2643,7 +2802,7 @@ There was an error trying to save the transaction history to %1. - Er is een fout opgetreden bij het opslaan van het transactieverleden naar %1. + Er is een fout opgetreden bij het opslaan van het transactiegeschiedenis naar %1. Exporting Successful @@ -2651,7 +2810,7 @@ The transaction history was successfully saved to %1. - Het transactieverleden was succesvol bewaard in %1. + Het transactiegeschiedenis was succesvol bewaard in %1. Comma separated file (*.csv) @@ -2708,7 +2867,7 @@ WalletModel Send Coins - Verstuur munten + Verstuur Munten @@ -2727,7 +2886,7 @@ Wallet Data (*.dat) - Portemonnee-data (*.dat) + Portemonneedata (*.dat) Backup Failed @@ -2735,7 +2894,7 @@ There was an error trying to save the wallet data to %1. - Er is een fout opgetreden bij het wegschrijven van de portemonnee-data naar %1. + Er is een fout opgetreden bij het wegschrijven van de portemonneedata naar %1. The wallet data was successfully saved to %1. @@ -2766,15 +2925,55 @@ Accept command line and JSON-RPC commands - Aanvaard commandoregel- en JSON-RPC-commando's + Aanvaard opdrachtregel- en JSON-RPC-opdrachten + + + If <category> is not supplied or if <category> = 1, output all debugging information. + Als er geen <categorie> is opgegeven of als de <categorie> 1 is, laat dan alle debugginginformatie zien. + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Maximum totale transactiekosten (in %s) om te gebruiken voor een enkele portemonneetransactie; als dit te laag is ingesteld kan het grote transacties verhinderen (default: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + Check a.u.b. of de datum en tijd van uw computer correct zijn! Als uw klok verkeerd staat zal Bitcoin Core niet correct werken. + + + Prune configured below the minimum of %d MiB. Please use a higher number. + Snoeien is geconfigureerd on het minimum van %d MiB. Gebruik a.u.b. een hoger aantal. + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + Snoei: laatste portemoneesynchronisatie gaat verder dan de gesnoeide data. U moet -reindex gebruiken (download opnieuw de gehele blokketen voor een weggesnoeide node) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + Beperk benodigde opslag door snoeien (verwijderen) van oude blokken. Deze modus is niet-compatibele met -txindex en -rescan. Waarschuwing: Terugzetten van deze instellingen vereist opnieuw downloaden van gehele de blokketen. (standaard:0 = uitzetten snoeimodus, >%u = doelgrootte in MiB voor blokbestanden) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + Herscannen is niet mogelijk in de snoeimodus. U moet -reindex gebruiken dat de hele blokketen opnieuw zal downloaden. + + + Error: A fatal internal error occurred, see debug.log for details + Fout: er is een fout opgetreden, zie debug.log voor details + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Transactiekosten (in %s/kB) toevoegen aan transacties die u doet (standaard: %s) + + + Pruning blockstore... + Snoei blokopslag... Run in the background as a daemon and accept commands - Draai in de achtergrond als daemon en aanvaard commando's + Draai in de achtergrond als daemon en aanvaard opdrachten - Use the test network - Gebruik het testnetwerk + Unable to start HTTP server. See debug log for details. + Niet mogelijk ok HTTP-server te starten. Zie debuglogboek voor details. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2786,11 +2985,11 @@ Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup - Verwijder alle transacties van de portemonnee en herstel alleen de delen van de blockchain door -rescan tijdens het opstarten + Verwijder alle transacties van de portemonnee en herstel alleen de delen van de blokketen door -rescan tijdens het opstarten Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. - Uitgegeven onder de MIT software licentie, zie het bijgevoegde bestand COPYING of <http://www.opensource.org/licenses/mit-license.php>. + Uitgegeven onder de MIT-softwarelicentie, zie het bijgevoegde bestand COPYING of <http://www.opensource.org/licenses/mit-license.php>. Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) @@ -2798,23 +2997,31 @@ Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) - Kies het aantal script verificatie processen (%u tot %d, 0 = auto, <0 = laat dit aantal kernen vrij, standaard: %d) + Kies het aantal scriptverificatie processen (%u tot %d, 0 = auto, <0 = laat dit aantal kernen vrij, standaard: %d) + + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + De blokdatabase bevat een blok dat lijkt uit de toekomst te komen. Dit kan gebeuren omdat de datum en tijd van uw computer niet goed staat. Herbouw de blokdatabase pas nadat u de datum en tijd van uw computer correct heeft ingesteld. This is a pre-release test build - use at your own risk - do not use for mining or merchant applications - Dit is een pre-release testversie - gebruik op eigen risico! Gebruik deze niet voor het delven van munten of handelsdoeleinden + Dit is een prerelease testversie – gebruik op eigen risico! Gebruik deze niet voor het delven van munten of handelsdoeleinden Unable to bind to %s on this computer. Bitcoin Core is probably already running. Niet in staat om %s te verbinden op deze computer. Bitcoin Core draait waarschijnlijk al. - WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) - WAARSCHUWING: controleer uw netwerkverbinding, %d blokken ontvangen in de laatste %d uren (%d verwacht) + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + Gebruik UPnP om de luisterende poort te mappen (standaard: 1 als er geluisterd worden en geen -proxy is meegegeven) - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Waarschuwing: -paytxfee is zeer hoog ingesteld. Dit zijn de transactiekosten die u betaalt bij het versturen van een transactie. + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) + WAARSCHUWING: abnormaal hoog aantal blokken is gegenereerd, %d blokken ontvangen in de laatste %d uren (%d verwacht) + + + WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) + WAARSCHUWING: controleer uw netwerkverbinding, %d blokken ontvangen in de laatste %d uren (%d verwacht) Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. @@ -2824,10 +3031,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Waarschuwing: Het lijkt erop dat we geen consensus kunnen vinden met onze peers! Mogelijk dient u te upgraden, of andere nodes moeten wellicht upgraden. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Waarschuwing: Fout bij het lezen van wallet.dat! Alle sleutels zijn in goede orde uitgelezen, maar transactiedata of adresboeklemma's zouden kunnen ontbreken of fouten bevatten. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Waarschuwing: wallet.dat is corrupt, data is veiliggesteld! Originele wallet.dat is opgeslagen als wallet.{tijdstip}.bak in %s; als uw balans of transacties incorrect zijn dient u een backup terug te zetten. @@ -2837,16 +3040,12 @@ Goedgekeurde peers die verbinden van het ingegeven netmask of IP adres. Kan meerdere keren gespecificeerd worden. - (default: 1) - (standaard: 1) + -maxmempool must be at least %d MB + -maxmempool moet tenminste %d MB zijn <category> can be: - <category> kan zijn: - - - Attempt to recover private keys from a corrupt wallet.dat - Poog de geheime sleutels uit een corrupt wallet.dat bestand terug te halen + <categorie> kan zijn: Block creation options: @@ -2876,6 +3075,22 @@ Do you want to rebuild the block database now? Wilt u de blokkendatabase nu herbouwen? + + Enable publish hash block in <address> + Sta toe om hashblok te publiceren in <adres> + + + Enable publish hash transaction in <address> + Stat toe om hashtransactie te publiceren in <adres> + + + Enable publish raw block in <address> + Sta toe rauw blok te publiceren in <adres> + + + Enable publish raw transaction in <address> + Sta toe ruwe transacties te publiceren in <adres> + Error initializing block database Fout bij intialisatie blokkendatabase @@ -2892,10 +3107,6 @@ Error opening block database Fout bij openen blokkendatabase - - Error: A fatal internal error occured, see debug.log for details - Fout: Een fatale interne fout is opgetreden, zie debug.log voor details - Error: Disk space is low! Fout: Weinig vrije diskruimte! @@ -2904,22 +3115,22 @@ Failed to listen on any port. Use -listen=0 if you want this. Mislukt om op welke poort dan ook te luisteren. Gebruik -listen=0 as u dit wilt. - - If <category> is not supplied, output all debugging information. - Als er geen <category> is opgegeven, laat dan alle debugging informatie zien. - Importing... Importeren... Incorrect or no genesis block found. Wrong datadir for network? - Incorrect of geen genesis-blok gevonden. Verkeerde datamap voor het netwerk? + Incorrect of geen genesisblok gevonden. Verkeerde datamap voor het netwerk? Invalid -onion address: '%s' Ongeldig -onion adres '%s' + + Keep the transaction memory pool below <n> megabytes (default: %u) + De transactiegeheugenpool moet onder de <n> megabytes blijven (standaard: %u) + Not enough file descriptors available. Niet genoeg file descriptors beschikbaar. @@ -2928,6 +3139,14 @@ Only connect to nodes in network <net> (ipv4, ipv6 or onion) Verbind alleen met nodes in netwerk <net> (ipv4, ipv6 of onion) + + Prune cannot be configured with a negative value. + Snoeien kan niet worden geconfigureerd met een negatieve waarde. + + + Prune mode is incompatible with -txindex. + Snoeimodus is niet-compatibel met -txindex + Set database cache size in megabytes (%d to %d, default: %d) Zet database cache grootte in megabytes (%d tot %d, standaard: %d) @@ -2940,10 +3159,26 @@ Specify wallet file (within data directory) Specificeer het portemonnee bestand (vanuit de gegevensmap) + + Unsupported argument -benchmark ignored, use -debug=bench. + Niet-ondersteund argument -benchmark genegeerd, gebruik -debug=bench. + + + Unsupported argument -debugnet ignored, use -debug=net. + Niet-ondersteund argument -debugnet genegeerd, gebruik -debug=net + + + Unsupported argument -tor found, use -onion. + Niet-ondersteund argument -tor gevonden, gebruik -onion. + Use UPnP to map the listening port (default: %u) Gebruik UPnP om de luisterende poort te mappen (standaard: %u) + + User Agent comment (%s) contains unsafe characters. + User Agentcommentaar (%s) bevat onveilige karakters. + Verifying blocks... Blokken aan het controleren... @@ -2966,20 +3201,12 @@ You need to rebuild the database using -reindex to change -txindex - Om -txindex te kunnen veranderen dient u de database opnieuw te bouwen met gebruik van -reindex. - - - Imports blocks from external blk000??.dat file - Importeert blokken van extern blk000??.dat bestand + Om -txindex te kunnen veranderen dient u de database herbouwen met gebruik van -reindex. 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 Sta JSON-RPC verbindingen toe vanuit een gespecificeerde bron. Geldig voor <ip> zijn een enkel IP (bijv. 1.2.3.4), een netwerk/netmask (bijv. 1.2.3.4/255.255.255.0) of een netwerk/CIDR (bijv. 1.2.3.4/24). Deze optie kan meerdere keren gespecificeerd worden. - - An error occurred while setting up the RPC address %s port %u for listening: %s - Er is een fout opgetreden tijdens het opzetten van het RPC adres %s poort %u voor luisteren: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Bind aan opgegeven adres en keur peers die ermee verbinden goed. Gebruik [host]:poort notatie voor IPv6 @@ -2996,38 +3223,41 @@ Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality) Creër nieuwe bestanden met standaard systeem bestandsrechten in plaats van umask 077 (alleen effectief met uitgeschakelde portemonnee functionaliteit) + + Discover own IP addresses (default: 1 when listening and no -externalip or -proxy) + Ontdek eigen IP-adressen (standaard: 1 voor luisteren en geen -externalip of -proxy) + Error: Listening for incoming connections failed (listen returned error %s) Fout: luisteren naar binnenkomende verbindingen mislukt (luisteren gaf foutmelding %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Fout: er is een niet-ondersteund argument -socks aangetroffen. Het instellen van de SOCKS-versie is niet langer mogelijk. Alleen SOCKS5-proxy's worden ondersteund. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) - Voer commando uit zodra een waarschuwing is ontvangen of wanneer we een erg lange fork detecteren (%s in commando wordt vervangen door bericht) + Voer opdracht uit zodra een waarschuwing is ontvangen of wanneer we een erg lange fork detecteren (%s in opdracht wordt vervangen door bericht) - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Toeslagen (in BTC/Kb) kleiner dan dit worden beschouwd als geen vergoeding (voor doorgeven) (standaard: %s) + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + Transactiekosten (in %s/kB) kleiner dan dit worden beschouw dat geen transactiekosten in rekening worden gebracht voor doorgeven, mijnen en transactiecreatie (standaard: %s) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) - Als paytxfee niet is ingesteld, het pakket voldoende vergoeding zodat transacties beginnen bevestiging gemiddeld binnen in blokken (default: %u) + Als paytxfee niet is ingesteld, voeg voldoende transactiekosten toe zodat transacties starten met bevestigingen binnen in n blokken (standaard: %u) Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - ongeldig bedrag voor -maxtxfee=<amount>: '%s' (moet ten minste de minrelay vergoeding van %s het voorkomen geplakt transacties voorkomen) + ongeldig bedrag voor -maxtxfee=<bedrag>: '%s' (moet ten minste de minimale doorgeeftransactiekosten van %s het voorkomen geplakt transacties voorkomen) Maximum size of data in data carrier transactions we relay and mine (default: %u) - Maximale grootte va n de gegevens in gegevensdrager transacties we relais en de mijnen -(default: %u) + Maximale grootte va n de gegevens in gegevensdragertransacties die we doorgeven en mijnen (standaard: %u) Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) - Query voor peer- adressen via DNS- lookup , als laag op adressen (default: 1 unless -connect) + Query voor peeradressen via DNS- lookup , als laag op adressen (standaard: 1 unless -connect) + + + Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u) + Gebruik willekeurige inloggegevens voor elke proxyverbinding. Dit maakt streamislatie voor Tor mogelijk (standaard: %u) Set maximum size of high-priority/low-fee transactions in bytes (default: %d) @@ -3039,46 +3269,19 @@ The transaction amount is too small to send after the fee has been deducted - Het transactiebedrag is te klein om te versturen nadat de vergoeding in mindering is gebracht + Het transactiebedrag is te klein om te versturen nadat de transactiekosten in mindering zijn gebracht This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Dit product bevat software dat ontwikkeld is door het OpenSSL Project voor gebruik in de OpenSSL Toolkit <https://www.openssl.org/> en cryptografische software geschreven door Eric Young en UPnP software geschreven door Thomas Bernard. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - Om bitcoind of de -server optie naar bitcoin-gt te gebruiken, dient u een rpcwachtwoord in te stellen in het configuratiebestand: - %s -Wij raden u aan om het volgende wachtwoord willekeurig te gebruiken: -rpcuser=bitcoinrpc -rpcpassword=%s -(u hoeft dit wachtwoord niet te onthouden) -De gebruikersnaam en het wachtwoorden moeten NIET hetzelfde zijn. -Indien het bestand niet bestaat, maak het bestand aan met bestandsrechten: alleen lezen voor eigenaar. -Het is ook aan te raden om een alarmnotificatie in te stellen, zodat u op de hoogte bent van de problemen; -Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Let op: -maxtxfee is erg hoog ingesteld! Transactiekosten van dergelijke groottes kunnen in een enkele transactie worden betaald. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Waarschuwing: Controleer dat de datum en tijd van uw computer correct zijn ingesteld! Bij een onjuist ingestelde klok zal Bitcoin Core niet goed werken. - 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 - Goedgekeurde peers kunnen niet ge-DoS-banned worden en hun transacties worden altijd doorgestuurd, zelfs als ze reeds in de mempool aanwezig zijn, nuttig voor bijv. een gateway + Goedgekeurde peers kunnen niet ge-DoS-banned worden en hun transacties worden altijd doorgegeven, zelfs als ze reeds in de mempool aanwezig zijn, nuttig voor bijv. een gateway + + + You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain + U moet de database herbouwen met -reindex om terug te gaan naar de ongesnoeide modus. Dit zal de gehele blokkketen opnieuw downloaden. (default: %u) @@ -3086,19 +3289,27 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Accept public REST requests (default: %u) - Accepteer publieke REST-requests (standaard: %u) + Accepteer publieke REST-verzoeken (standaard: %u) Activating best chain... Beste reeks activeren... - Cannot resolve -whitebind address: '%s' - Kan -whitebind adres niet herleiden: '%s' + Always relay transactions received from whitelisted peers (default: %d) + Geef transacties altijd door aan goedgekeurde peers (standaard: %d) - Choose data directory on startup (default: 0) - Kies de gegevensmap tijdens het opstarten (standaard: 0) + Attempt to recover private keys from a corrupt wallet.dat on startup + Probeer privésleutels te herstellen van een corrupte wallet.dat bij opstarten + + + Automatically create Tor hidden service (default: %d) + Creëer automatisch verborgen dienst van Tor (standaard:%d) + + + Cannot resolve -whitebind address: '%s' + Kan -whitebind adres niet herleiden: '%s' Connect through SOCKS5 proxy @@ -3108,10 +3319,6 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.comCopyright (C) 2009-%i The Bitcoin Core Developers Auteursrecht (C) 2009-%i De Bitcoin Core Ontwikkelaars - - Could not parse -rpcbind value %s as network address - Niet mogelijk om -rpcbind waarde %s te verwerken als netwerk adres - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Fout bij laden wallet.dat: Portemonnee vereist een nieuwere versie van Bitcoin Core @@ -3121,12 +3328,8 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.comFout bij het lezen van de database, afsluiten. - Error: Unsupported argument -tor found, use -onion. - Fout: Niet ondersteund argument -tor gevonden, gebruik -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Transactiekosten (in BTC/kB) om toe te voegen aan transacties die u verstuurd (standaard: %s) + Imports blocks from external blk000??.dat file on startup + Importeer blokken van externe blk000??.dat-bestand bij opstarten Information @@ -3138,7 +3341,7 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Invalid amount for -maxtxfee=<amount>: '%s' - Ongeldig bedrag voor -maxtxfee=<amount>: '%s' + Ongeldig bedrag voor -maxtxfee=<bedrag>: '%s' Invalid amount for -minrelaytxfee=<amount>: '%s' @@ -3166,44 +3369,40 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Node relay options: - Node relay opties: - - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - RPC SSL opties: (zie de Bitcoin Wiki voor SSL installatie-instructies) + Nodedoorgeefopties: RPC server options: RPC server opties: - RPC support for HTTP persistent connections (default: %d) - RPC ondersteuning voor HTTP persisten verbindingen (default: %d) + Rebuild block chain index from current blk000??.dat files on startup + Herbouwen blokketenindex vanuit huidige blk000??.dat-bestanden bij opstarten? + + + Receive and display P2P network alerts (default: %u) + Ontvang en toon P2P-netwerkwaarschuwingen (standaard: %u) + + + Reducing -maxconnections from %d to %d, because of system limitations. + Verminder -maxconnections van %d naar %d, vanwege systeembeperkingen. + + + Rescan the block chain for missing wallet transactions on startup + Herscan de blokketen voor missende portemonneetransacties bij opstarten Send trace/debug info to console instead of debug.log file - Stuur trace/debug-info naar de console in plaats van het debug.log bestand + Verzend trace/debug-info naar de console in plaats van het debug.log-bestand Send transactions as zero-fee transactions if possible (default: %u) - Verstuur transacties zonder verzendkosten indien mogelijk (standaard: %u) - - - Set SSL root certificates for payment request (default: -system-) - Zet SSL root certificaten voor betalingsverzoek (standaard: -sytem-) - - - Set language, for example "de_DE" (default: system locale) - Stel taal in, bijvoorbeeld ''de_DE" (standaard: systeeminstellingen) + Indien mogelijk, verstuur zonder transactiekosten (standaard: %u) Show all debugging options (usage: --help -help-debug) Toon alle foutopsporingsopties (gebruik: --help -help-debug) - - Show splash screen on startup (default: 1) - Laat laadscherm zien bij het opstarten. (standaard: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Verklein debug.log-bestand bij het opstarten van de client (standaard: 1 als geen -debug) @@ -3212,18 +3411,22 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.comSigning transaction failed Ondertekenen van transactie mislukt - - Start minimized - Geminimaliseerd starten - The transaction amount is too small to pay the fee - Het transactiebedrag is te klein om de vergoeding te betalen + Het transactiebedrag is te klein om transactiekosten in rekening te brengen This is experimental software. Dit is experimentele software. + + Tor control port password (default: empty) + Tor bepaalt poortwachtwoord (standaard: empty) + + + Tor control port to use if onion listening enabled (default: %s) + Tor bepaalt welke poort te gebruiken als luisteren naar onion wordt gebruikt (standaard: %s) + Transaction amount too small Transactiebedrag te klein @@ -3234,23 +3437,19 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Transaction too large for fee policy - De transactie is te groot voor het toeslagenbeleid + De transactie is te groot voor het transactiekostenbeleid Transaction too large Transactie te groot - - UI Options: - UI Opties: - Unable to bind to %s on this computer (bind returned error %s) Niet in staat om aan %s te binden op deze computer (bind gaf error %s) - Use UPnP to map the listening port (default: 1 when listening) - Gebruik UPnP om de luisterende poort te mappen (standaard: 1 als er wordt geluisterd) + Upgrade wallet to latest format on startup + Upgrade portemonee naar laatste formaat bij opstarten Username for JSON-RPC connections @@ -3265,20 +3464,16 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.comWaarschuwing - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Waarschuwing: Niet ondersteund argument -benchmark genegeerd, gebruik -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Waarschuwing: Niet ondersteund argument -debugnet genegeerd, gebruik -debug=net. + Whether to operate in a blocks only mode (default: %u) + Om in alleen een blokmodus te opereren (standaard: %u) Zapping all transactions from wallet... Bezig met het zappen van alle transacties van de portemonnee... - on startup - bij opstarten + ZeroMQ notification options: + ZeroMQ notificatieopties: wallet.dat corrupt, salvage failed @@ -3290,19 +3485,7 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Execute command when the best block changes (%s in cmd is replaced by block hash) - Voer commando uit zodra het beste blok verandert (%s in cmd wordt vervangen door blockhash) - - - Upgrade wallet to latest format - Vernieuw portemonnee naar nieuwste versie - - - Rescan the block chain for missing wallet transactions - Doorzoek de blokketen op ontbrekende portemonnee-transacties - - - Use OpenSSL (https) for JSON-RPC connections - Gebruik OpenSSL (https) voor JSON-RPC-verbindingen + Voer opdracht uit zodra het beste blok verandert (%s in cmd wordt vervangen door blokhash) This help message @@ -3324,6 +3507,26 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = behoudt tx meta data bijv. account eigenaar en betalingsverzoek informatie, 2. sla tx meta data niet op) + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + -maxtxfee staat zeer hoog! Transactiekosten van de grootte kunnen worden gebruikt in een enkele transactie. + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + -paytxfee staat zeer hoog! Dit is de transactiekosten die u betaalt als u een transactie doet. + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + Bewaar transactie niet langer dan <n> uren in de geheugenpool (standaard: %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Fout tijdens lezen van wallet.dat! Alle sleutels zijn correct te lezen, maar de transactiondatabase of adresboekingangen zijn mogelijk verdwenen of incorrect. + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + Transactiekosten (in %s/kB) kleiner dan dit worden beschouwd dat geen transactiekosten in rekening worden gebracht voor transactiecreatie (standaard: %s) + How thorough the block verification of -checkblocks is (0-4, default: %u) Hoe grondig de blokverificatie van -checkblocks is (0-4, standaard: %u) @@ -3338,15 +3541,35 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Output debugging information (default: %u, supplying <category> is optional) - Output extra debugginginformatie (standaard: %u, het leveren van <category> is optioneel) + Output extra debugginginformatie (standaard: %u, het leveren van <categorie> is optioneel) + + + Support filtering of blocks and transaction with bloom filters (default: %u) + Ondersteun filtering van blokken en transacties met bloomfilters (standaard: %u) + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + Totale lengte van netwerkversiestring (%i) overschrijdt maximale lengte (%i). Verminder het aantal of grootte van uacomments. + + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + Pogingen om uitgaand verkeer onder een bepaald doel te houden (in MiB per 24u), 0 = geen limiet (standaard: %d) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Niet-ondersteund argument -socks gevonden. Instellen van SOCKS-versie is niet meer mogelijk, alleen SOCKS5-proxies worden ondersteund. Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) - Gebruik een aparte SOCKS5 proxy om 'Tor hidden services' te bereiken (standaard: %s) + Gebruik een aparte SOCKS5 proxy om verborgen diensten van Tor te bereiken (standaard: %s) - Acceptable ciphers (default: %s) - Geaccepteerde versleutelingen (standaard: %s) + 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. This option can be specified multiple times + Gebruikersnaam en gehasht wachtwoord voor JSON-RPC-verbindingen. De velden <userpw> is in het formaat: <GEBRUIKERSNAAM>:<SALT>$<HASH>. Een kanoniek Pythonscript is inbegrepen in de share/rpcuser. Deze optie kan meerdere keren worden meegegeven + + + (default: %s) + (standaard: %s) Always query for peer addresses via DNS lookup (default: %u) @@ -3374,7 +3597,7 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Listen for JSON-RPC connections on <port> (default: %u or testnet: %u) - Luister naar JSON-RPC-verbindingen op poort <port> (standaard: %u of testnet: %u) + Luister naar JSON-RPC-verbindingen op <poort> (standaard: %u of testnet: %u) Listen for connections on <port> (default: %u or testnet: %u) @@ -3394,7 +3617,7 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Maximum per-connection send buffer, <n>*1000 bytes (default: %u) - Maximum per-connectie zendbuffer, <n>*1000 bytes (standaard: %u) + Maximum per-connectie verstuurbuffer, <n>*1000 bytes (standaard: %u) Prepend debug output with timestamp (default: %u) @@ -3402,23 +3625,15 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Relay and mine data carrier transactions (default: %u) - Gegevensdrager transacties relay en de mijnen (default: %u) + Geef gegevensdragertransacties door en mijn ze ook (standaard: %u) Relay non-P2SH multisig (default: %u) - Relay non-P2SH multisig (default: %u) - - - Server certificate file (default: %s) - Certificaat-bestand voor server (standaard: %s) - - - Server private key (default: %s) - Geheime sleutel voor server (standaard: %s) + Geef non-P2SH multisig door (standaard: %u) Set key pool size to <n> (default: %u) - Stel sleutelpoelgrootte in op <&> (standaard: %u) + Stel sleutelpoelgrootte in op <n> (standaard: %u) Set minimum block size in bytes (default: %u) @@ -3430,7 +3645,7 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Specify configuration file (default: %s) - Specificeer configuratie bestand (standaard: %s) + Specificeer configuratiebestand (standaard: %s) Specify connection timeout in milliseconds (minimum: 1, default: %d) @@ -3442,7 +3657,7 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Spend unconfirmed change when sending transactions (default: %u) - Besteed onbevestigd wisselgeld bij het versturen van transacties (standaard: %u) + Besteed onbevestigd wisselgeld bij het doen van transacties (standaard: %u) Threshold for disconnecting misbehaving peers (default: %u) @@ -3490,7 +3705,7 @@ Voorbeeld: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Rescanning... - Blokketen aan het doorzoeken... + Blokketen aan het herscannen... Done loading diff --git a/src/qt/locale/bitcoin_pam.ts b/src/qt/locale/bitcoin_pam.ts index 4939dff4b..233918ff2 100644 --- a/src/qt/locale/bitcoin_pam.ts +++ b/src/qt/locale/bitcoin_pam.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -188,6 +188,9 @@ Mi-alilan ne ing passphrase na ning wallet. + + BanTableModel + BitcoinGUI @@ -246,6 +249,10 @@ &Change Passphrase... &Alilan ing Passphrase... + + &Receiving addresses... + Address king pamag-Tanggap + Send coins to a Bitcoin address Magpadalang barya king Bitcoin address @@ -306,6 +313,10 @@ Bitcoin Core Kapilubluban ning Bitcoin + + &Command-line options + Pipamilian command-line + Last received block was generated %1 ago. Ing tatauling block a metanggap, me-generate ya %1 ing milabas @@ -360,6 +371,10 @@ CoinControlDialog + + Amount: + Alaga: + Amount Alaga @@ -461,7 +476,7 @@ command-line options pipamilian command-line - + Intro @@ -636,6 +651,10 @@ &Information &Impormasion + + Debug window + I-Debug ing awang + Using OpenSSL version Gagamit bersion na ning OpenSSL @@ -714,6 +733,10 @@ ReceiveRequestDialog + + Copy &Address + &Kopyan ing address + Address Address @@ -760,6 +783,18 @@ Send Coins Magpadalang Barya + + Insufficient funds! + Kulang a pondo + + + Amount: + Alaga: + + + Transaction Fee: + Bayad king Transaksion: + Send to multiple recipients at once Misanang magpadala kareng alialiuang tumanggap @@ -839,6 +874,14 @@ Alt+P Alt+P + + Message: + Mensayi: + + + Pay To: + Ibayad kang: + ShutdownWindow @@ -1326,18 +1369,10 @@ Run in the background as a daemon and accept commands Gumana king gulut bilang daemon at tumanggap commands - - Use the test network - Gamitan ing test network - Accept connections from outside (default: 1 if no -proxy or -connect) Tumanggap koneksion menibat king kilwal (default: 1 if no -proxy or -connect) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Kapabaluan: Sobra ya katas ing makalage king -paytxfee. Ini ing maging bayad mu para king bayad na ning transaksion istung pepadala me ing transaksion a ini. - Block creation options: Pipamilian king pamag-gawang block: @@ -1370,26 +1405,30 @@ Failed to listen on any port. Use -listen=0 if you want this. Memali ya ing pamakiramdam kareng gang nanung port. Gamita me ini -listen=0 nung buri me ini. + + Cannot resolve -whitebind address: '%s' + Eya me-resolve ing -whitebind address: '%s' + Information &Impormasion + + Invalid amount for -maxtxfee=<amount>: '%s' + Eya maliari ing alaga keng -maxtxfee=<amount>: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Eya maliari ing alaga keng -minrelaytxfee=<amount>: '%s' + + + Invalid amount for -mintxfee=<amount>: '%s' + Eya maliari ing alaga keng -mintxfee=<amount>: '%s' + Send trace/debug info to console instead of debug.log file Magpadalang trace/debug info okeng console kesa keng debug.log file - - Set language, for example "de_DE" (default: system locale) - Mamiling Amanu, alimbawa "de_DE"(default: system locale) - - - Show splash screen on startup (default: 1) - Ipalto ing splash screen keng umpisa (default: 1) - - - Start minimized - Umpisan ing pamaglati - Transaction too large Maragul yang masiadu ing transaksion @@ -1410,18 +1449,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) I-execute ing command istung mialilan ya ing best block (%s in cmd is replaced by block hash) - - Upgrade wallet to latest format - I-upgrade ing wallet king pekabayung porma - - - Rescan the block chain for missing wallet transactions - I-scan pasibayu ing block chain para kareng mauaualang transaksion - - - Use OpenSSL (https) for JSON-RPC connections - Gumamit OpenSSL(https) para king JSON-RPC koneksion - This help message Ining saup a mensayi diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index 5bc7df0ac..8a8c37748 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,17 @@ Hasło portfela zostało pomyślnie zmienione. + + BanTableModel + + IP/Netmask + IP/Maska Sieci + + + Banned Until + Blokada do + + BitcoinGUI @@ -867,6 +878,34 @@ command-line options opcje konsoli + + UI Options: + Opcje interfejsu + + + Choose data directory on startup (default: %u) + Katalog danych używany podczas uruchamiania programu (domyślny: %u) + + + Set language, for example "de_DE" (default: system locale) + Wybierz język, na przykład "de_DE" (domyślnie: język systemowy) + + + Start minimized + Uruchom zminimalizowany + + + Set SSL root certificates for payment request (default: -system-) + Ustaw certyfikaty główne SSL dla żądań płatności (domyślnie: -system-) + + + Show splash screen on startup (default: %u) + Wyświetl okno powitalne podczas uruchamiania (domyślnie: %u) + + + Reset all settings changes made over the GUI + Ustaw jako domyślne wszystkie ustawienia interfejsu + Intro @@ -1064,6 +1103,26 @@ Port of the proxy (e.g. 9050) Port proxy (np. 9050) + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Pokazuje, czy wspierane domyślnie proxy SOCKS5 jest używane do łączenia się z peerami w tej sieci + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Użyj oddzielnego prozy SOCKS5 aby osiągnąć węzły w ukrytych usługach Tor: + &Window &Okno @@ -1282,10 +1341,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Żądanie płatności %1 jest zbyt duże (%2 bajtów, dozwolone %3 bajtów). - - Payment request DoS protection - Zabezpieczenie żądania płatności przed atakiem DoS - Error communicating with %1: %2 Błąd komunikacji z %1 : %2 @@ -1438,6 +1493,14 @@ Current number of blocks Aktualna liczba bloków + + Current number of transactions + Obecna liczba transakcji + + + Memory usage + Zużycie pamięci + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. Otwórz plik logowania debugowania Bitcoin Core z obecnego katalogu z danymi. Może to potrwać kilka sekund przy większych plikach. @@ -1454,10 +1517,18 @@ &Peers &Węzły + + Banned peers + Blokowane węzły + Select a peer to view detailed information. Wybierz węzeł żeby zobaczyć szczegóły. + + Whitelisted + Biała lista + Direction Kierunek @@ -1466,6 +1537,18 @@ Version Wersja + + Starting Block + Blok startowy + + + Synced Headers + Zsynchronizowane nagłówki + + + Synced Blocks + Zsynchronizowane bloki + User Agent Aplikacja kliencka @@ -1474,14 +1557,6 @@ Services Usługi - - Starting Height - Początkowa wysokość - - - Sync Height - Zsynchronizowana wysokość - Ban Score Punkty karne @@ -1498,18 +1573,14 @@ Last Receive Ostatnio odebrano - - Bytes Sent - Bajtów wysłano - - - Bytes Received - Bajtów pobrano - Ping Time Czas odpowiedzi + + Ping Wait + Czas odpowiedzi + Time Offset Przesunięcie czasu @@ -1558,6 +1629,14 @@ Clear console Wyczyść konsolę + + Ban Node for + Blokuj węzeł na okres + + + &Unban Node + Odblokuj węzeł + Welcome to the Bitcoin Core RPC console. Witaj w konsoli Bitcoin Core RPC. @@ -1586,6 +1665,10 @@ %1 GB %1 GB + + (node id: %1) + (id węzła: %1) + via %1 przez %1 @@ -1603,12 +1686,16 @@ Wyjściowy - Unknown - Nieznany + Yes + Tak - Fetching... - Pobieram... + No + Nie + + + Unknown + Nieznany @@ -1629,6 +1716,10 @@ Reuse one of the previously used receiving addresses. Reusing addresses has security and privacy issues. Do not use this unless re-generating a payment request made before. Użyj jednego z poprzednio użytych adresów odbiorczych. Podczas ponownego używania adresów występują problemy z bezpieczeństwem i prywatnością. Nie korzystaj z tej opcji, chyba że odtwarzasz żądanie płatności wykonane już wcześniej. + + R&euse an existing receiving address (not recommended) + U&żyj ponownie istniejącego adresu odbiorczego (niepolecane) + An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network. Opcjonalna wiadomość do dołączenia do żądania płatności, która będzie wyświetlana, gdy żądanie zostanie otwarte. Uwaga: wiadomość ta nie zostanie wysłana wraz z płatnością w sieci Bitcoin. @@ -1971,8 +2062,8 @@ Skopiuj resztę - Total Amount %1 (= %2) - Łączna kwota %1 (= %2) + Total Amount %1 + Łączna kwota %1 or @@ -2006,14 +2097,14 @@ Payment request expired. Żądanie płatności upłynęło. + + Pay only the required fee of %1 + Zapłać tylko wymaganą opłatę %1 + Estimated to begin confirmation within %n block(s). Przybliżony czas zatwierdzenia: %n bloków.Przybliżony czas zatwierdzenia: %n bloków.Przybliżony czas zatwierdzenia: %n bloków. - - Pay only the minimum fee of %1 - Płac tylko minimalna opłatę %1 - The recipient address is not valid. Please recheck. Adres odbiorcy jest nieprawidłowy, proszę sprawić ponownie. @@ -2641,6 +2732,10 @@ Copy transaction ID Skopiuj ID transakcji + + Copy raw transaction + Skopiuj surowe dane transakcji + Edit label Zmień etykietę @@ -2788,13 +2883,25 @@ Accept command line and JSON-RPC commands Akceptuj linię poleceń oraz polecenia JSON-RPC + + Error: A fatal internal error occurred, see debug.log for details + Błąd: Wystąpił fatalny błąd wewnętrzny, sprawdź szczegóły w debug.log + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Prowizja (w %s/kB) dodawana do wysyłanych transakcji (domyślnie: %s) + + + Pruning blockstore... + Przycinanie zapisu bloków... + Run in the background as a daemon and accept commands Uruchom w tle jako daemon i przyjmuj polecenia - Use the test network - Użyj sieci testowej + Unable to start HTTP server. See debug log for details. + Uruchomienie serwera HTTP nie powiodło się. Zobacz dziennik debugowania, aby uzyskać więcej szczegółów. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2829,8 +2936,12 @@ Nie można przywiązać z portem %s na tym komputerze. Bitcoin Core prawdopodobnie już działa. - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Ostrzeżenie: -paytxfee jest bardzo duże! Jest to prowizja za transakcje, którą płacisz, gdy wysyłasz monety. + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) + UWAGA: nienaturalnie duża liczba wygenerowanych bloków, %d bloków otrzymano w ostatnich %d godzinach (%d oczekiwanych) + + + WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) + UWAGA: sprawdź swoje połączenie sieciowe, %d bloków otrzymano w ostatnich %d godzinach (%d oczekiwanych) Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. @@ -2840,10 +2951,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Uwaga: Wygląda na to, że nie ma pełnej zgodności z naszymi peerami! Możliwe, że potrzebujesz aktualizacji bądź inne węzły jej potrzebują - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Ostrzeżenie: błąd odczytu wallet.dat! Wszystkie klucze zostały odczytane, ale może brakować pewnych danych transakcji lub wpisów w książce adresowej lub mogą one być nieprawidłowe. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Ostrzeżenie: Odtworzono dane z uszkodzonego pliku wallet.dat! Oryginalny wallet.dat został zapisany jako wallet.{timestamp}.bak w %s; jeśli twoje saldo lub transakcje są niepoprawne powinieneś odtworzyć kopię zapasową. @@ -2852,18 +2959,10 @@ Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. Dodawaj do białej listy węzły łączące się z podanej maski sieciowej lub adresu IP. Może być określona kilka razy. - - (default: 1) - (domyślnie: 1) - <category> can be: <category> mogą być: - - Attempt to recover private keys from a corrupt wallet.dat - Próbuj odzyskać klucze prywatne z uszkodzonego wallet.dat - Block creation options: Opcje tworzenia bloku: @@ -2908,10 +3007,6 @@ Error opening block database Błąd otwierania bazy bloków - - Error: A fatal internal error occured, see debug.log for details - Błąd: Wystąpił krytyczny błąd wewnętrzny, sprawdź w debug.log - Error: Disk space is low! Błąd: Mało miejsca na dysku! @@ -2920,10 +3015,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Próba nasłuchiwania na jakimkolwiek porcie nie powiodła się. Użyj -listen=0 jeśli tego chcesz. - - If <category> is not supplied, output all debugging information. - Jeżeli <category> nie zostanie określona, wyświetl wszystkie informacje debugowania. - Importing... Importowanie… @@ -2944,6 +3035,10 @@ Only connect to nodes in network <net> (ipv4, ipv6 or onion) Łącz z węzłami tylko w sieci <net> (ipv4, piv6 lub onion) + + Prune cannot be configured with a negative value. + Przycinanie nie może być skonfigurowane z negatywną wartością. + Prune mode is incompatible with -txindex. Tryb ograniczony jest niekompatybilny z -txindex. @@ -2960,6 +3055,14 @@ Specify wallet file (within data directory) Określ plik portfela (w obrębie folderu danych) + + Unsupported argument -benchmark ignored, use -debug=bench. + Niewspierany argument -benchmark zignorowany, użyj -debug=bench. + + + Unsupported argument -debugnet ignored, use -debug=net. + Niewspierany argument -debugnet zignorowany, użyj -debug=net. + Use UPnP to map the listening port (default: %u) Użyj UPnP do przekazania portu nasłuchu (domyślnie : %u) @@ -2988,18 +3091,10 @@ You need to rebuild the database using -reindex to change -txindex Musisz przebudować bazę używając parametru -reindex aby zmienić -txindex - - Imports blocks from external blk000??.dat file - Importuj bloki z zewnętrznego pliku blk000??.dat - 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 Pozwól na połączenia JSON-RPC z podanego źródła. Jako <ip> prawidłowe jest pojedyncze IP (np. 1.2.3.4), podsieć/maska (np. 1.2.3.4/255.255.255.0) lub sieć/CIDR (np. 1.2.3.4/24). Opcja ta może być użyta wiele razy. - - An error occurred while setting up the RPC address %s port %u for listening: %s - Napotkano błąd podczas ustawiania adres RPC %s port %u dla nasłuchiwania: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Podepnij się do podanego adresu i dodawaj do białej listy węzły łączące się z nim. Użyj notacji [host]:port dla IPv6 @@ -3016,22 +3111,18 @@ Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality) Twórz nowe pliki z domyślnymi dla systemu uprawnieniami, zamiast umask 077 (skuteczne tylko przy wyłączonej funkcjonalności portfela) + + Discover own IP addresses (default: 1 when listening and no -externalip or -proxy) + Odkryj własny adres IP (domyślnie: 1 kiedy w trybie nasłuchu i brak -externalip lub -proxy) + Error: Listening for incoming connections failed (listen returned error %s) Błąd: Nasłuchiwanie połączeń przychodzących nie powiodło się (nasłuch zwrócił błąd %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Błąd: Znaleziono niewspierany argument -socks . Ustawienie wersji SOCKS nie jest już możliwe, tylko serwery proxy SOCKS5 są wspierane. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Uruchom polecenie przy otrzymaniu odpowiedniego powiadomienia lub gdy zobaczymy naprawdę długie rozgałęzienie (%s w poleceniu jest podstawiane za komunikat) - - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Opłaty (w BTC/Kb) mniejsze niż ta będą traktowane jako bez opłaty przy propagowaniu (domyślnie: %s) - If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) Jeżeli nie ustawiono paytxfee, dołącz wystarczająca opłatę, aby transakcja mogła zostać zatwierdzona w ciągu średniej ilości n bloków (domyślnie: %u) @@ -3064,38 +3155,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Program ten zawiera oprogramowanie stworzone przez OpenSSL Project do użycia w OpensSSL Toolkit <https://www.openssl.org/>, oprogramowanie kryptograficzne napisane przez Eric Young oraz oprogramowanie UPnP napisane przez Thomas Bernard. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - Aby korzystać z bitcoind, lub opcji -server w bitcoin-qt, musisz ustawić opcję rpcpassword w pliku konfiguracyjnym: -%s -Zalecane jest użycie poniższego losowego hasła: -rpcuser=bitcoinrpc -rpcpassword=%s -(nie musisz pamiętać tego hasła) -Nazwa użytkownika i hasło NIE MOGĄ być takie same. -Jeżeli ten plik nie istnieje, utwórz go z uprawnieniami tylko-do-odczytu przez właściciela. -Zalecane jest także ustawienie opcji alertnotify, dzięki której będziesz powiadamiany o problemach; -na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Ostrzeżenie: -matxfee jest ustawione bardzo wysokie! Tak wysokie opłaty mogą być zapłacone w jednej transakcji. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Ostrzeżenie: Proszę sprawdzić czy data i czas na Twoim komputerze są poprawne! Jeżeli ustawienia zegara będą złe, Bitcoin Core nie będzie działał prawidłowo. - 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 Węzły z białej listy nie mogą zostać zbanowane za ataki DoS, a ich transakcje będą zawsze przekazywane, nawet jeżeli będą znajdywać się już w pamięci, przydatne np. dla bramek płatniczych @@ -3113,17 +3172,21 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com Aktywuje najlepszy łańcuch - Can't run with a wallet in prune mode. - Nie można uruchomić z portfela w trybie ograniczonym. + Always relay transactions received from whitelisted peers (default: %d) + Zawsze przekazuj informacje o transakcjach otrzymanych od osób z białej listy (domyślnie: %d) + + + Attempt to recover private keys from a corrupt wallet.dat on startup + Próbuj podczas uruchamiania programu odzyskać klucze prywatne z uszkodzonego pliku wallet.dat + + + Automatically create Tor hidden service (default: %d) + Stwórz automatycznie ukrytą usługę Tora (domyślnie: %d) Cannot resolve -whitebind address: '%s' Nie można rozwiązać adresu -whitebind: '%s' - - Choose data directory on startup (default: 0) - Wybierz folder danych przy starcie (domyślnie: 0) - Connect through SOCKS5 proxy Połącz przez SOCKS5 proxy @@ -3132,10 +3195,6 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com Copyright (C) 2009-%i The Bitcoin Core Developers Copyright (C) 2009-%i The Bitcoin Core Developers - - Could not parse -rpcbind value %s as network address - Nie można przetworzyć wartości -rpcbind %s jako adresu sieciowego - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Błąd ładowania wallet.dat: Portfel wymaga nowszej wersji Bitcoin Core @@ -3145,12 +3204,8 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com Błąd odczytu z bazy danych, wyłączam się. - Error: Unsupported argument -tor found, use -onion. - Błąd: Znaleziono nieprawidłowy argument -tor, użyj -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Prowizja (w BTC za kB) dodawana do wysyłanej transakcji (domyślnie: %s) + Imports blocks from external blk000??.dat file on startup + Importuj bloki z zewnętrznego pliku blk000??.dat podczas uruchamiania programu Information @@ -3184,22 +3239,18 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com Keep at most <n> unconnectable transactions in memory (default: %u) Przechowuj w pamięci maksymalnie <n> transakcji nie możliwych do połączenia (domyślnie: %u) + + Need to specify a port with -whitebind: '%s' + Musisz określić port z -whitebind: '%s' + Node relay options: Opcje przekaźnikowe węzła: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Opcje RPC SSL: (odwiedź Bitcoin Wiki w celu uzyskania instrukcji) - RPC server options: Opcje serwera RPC: - - RPC support for HTTP persistent connections (default: %d) - Wsparcie RPC dla ciągłych połączeń HTTP (domyślnie: %d) - Rebuild block chain index from current blk000??.dat files on startup Odbuduj indeks łańcucha bloków z obecnych plików blk000??.dat podczas ponownego uruchomienia @@ -3208,6 +3259,10 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com Receive and display P2P network alerts (default: %u) Odbieranie i wyświetlanie alertów sieci P2P (domyślnie: %u) + + Rescan the block chain for missing wallet transactions on startup + Przeskanuj podczas ładowania programu łańcuch bloków w poszukiwaniu zaginionych transakcji portfela + Send trace/debug info to console instead of debug.log file Wyślij informację/raport do konsoli zamiast do pliku debug.log. @@ -3216,22 +3271,10 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com Send transactions as zero-fee transactions if possible (default: %u) Wyślij bez opłaty jeżeli to możliwe (domyślnie: %u) - - Set SSL root certificates for payment request (default: -system-) - Ustaw certyfikaty główne SSL dla żądań płatności (domyślnie: -system-) - - - Set language, for example "de_DE" (default: system locale) - Ustaw Język, na przykład "pl_PL" (domyślnie: systemowy) - Show all debugging options (usage: --help -help-debug) Pokaż wszystkie opcje odpluskwiania (użycie: --help -help-debug) - - Show splash screen on startup (default: 1) - Pokazuj okno powitalne przy starcie (domyślnie: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Zmniejsz plik debug.log przy starcie programu (domyślnie: 1 jeśli nie użyto -debug) @@ -3240,10 +3283,6 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com Signing transaction failed Podpisywanie transakcji nie powiodło się - - Start minimized - Uruchom zminimalizowany - The transaction amount is too small to pay the fee Zbyt niska kwota transakcji by zapłacić opłatę @@ -3252,6 +3291,10 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com This is experimental software. To oprogramowanie eksperymentalne. + + Tor control port password (default: empty) + Hasło zabezpieczające portu kontrolnego Tora (domyślnie: puste) + Transaction amount too small Zbyt niska kwota transakcji @@ -3268,17 +3311,13 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com Transaction too large Transakcja zbyt duża - - UI Options: - Opcje UI - Unable to bind to %s on this computer (bind returned error %s) Nie można przywiązać do %s na tym komputerze (bind zwrócił błąd %s) - Use UPnP to map the listening port (default: 1 when listening) - Używaj UPnP do mapowania portu nasłuchu (domyślnie: 1 gdy nasłuchuje) + Upgrade wallet to latest format on startup + Zaktualizuj portfel do najnowszego formatu podczas ładowania programu Username for JSON-RPC connections @@ -3292,22 +3331,10 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com Warning Ostrzeżenie - - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Uwaga: Zignorowano nieprawidłowy argument -benchmark, użyj -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Uwaga: Zignorowano nieprawidłowy argument -debugnet , użyj -debug=net. - Zapping all transactions from wallet... Usuwam wszystkie transakcje z portfela... - - on startup - podczas uruchamiania - wallet.dat corrupt, salvage failed wallet.dat uszkodzony, odtworzenie się nie powiodło @@ -3320,18 +3347,6 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com Execute command when the best block changes (%s in cmd is replaced by block hash) Wykonaj polecenie kiedy najlepszy blok ulegnie zmianie (%s w komendzie zastanie zastąpione przez hash bloku) - - Upgrade wallet to latest format - Zaktualizuj portfel do najnowszego formatu. - - - Rescan the block chain for missing wallet transactions - Przeskanuj łańcuch bloków w poszukiwaniu zaginionych transakcji portfela - - - Use OpenSSL (https) for JSON-RPC connections - Użyj OpenSSL (https) do połączeń JSON-RPC - This help message Ta wiadomość pomocy @@ -3352,6 +3367,14 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = zachowaj wysłane metadane np. właściciel konta i informacje o żądaniach płatności, 2 = porzuć wysłane metadane) + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + Nie trzymaj w pamięci transakcji starszych niż <n> godzin (domyślnie: %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Ostrzeżenie: błąd odczytu wallet.dat! Wszystkie klucze zostały odczytane, ale może brakować pewnych danych transakcji lub wpisów w książce adresowej lub mogą one być nieprawidłowe. + How thorough the block verification of -checkblocks is (0-4, default: %u) Jak dokładna jest weryfikacja bloków przy -checkblocks (0-4, domyślnie: %u) @@ -3368,6 +3391,10 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com Output debugging information (default: %u, supplying <category> is optional) Wypuść informacje debugowania (domyślnie: %u, podanie <category> jest opcjonalne) + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Znaleziono niewspierany argument -socks. Wybieranie wersji SOCKS nie jest już możliwe, wsparcie programu obejmuje tylko proxy SOCKS5 + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) Użyj oddzielnego prozy SOCKS5 aby osiągnąć węzły w ukrytych usługach Tor (domyślnie: %s) @@ -3376,10 +3403,6 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com (default: %s) (domyślnie: %s) - - Acceptable ciphers (default: %s) - Akceptowane szyfry (domyślne: %s) - Always query for peer addresses via DNS lookup (default: %u) Zawsze wypytuj o adresy węzłów poprzez podejrzenie DNS (domyślnie: %u) @@ -3440,14 +3463,6 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo.com Relay non-P2SH multisig (default: %u) Przekazuj transakcje multisig inne niż P2SH (domyślnie: %u) - - Server certificate file (default: %s) - Plik certyfikatu serwera (domyślnie: %s) - - - Server private key (default: %s) - Klucz prywatny serwera (domyślnie: %s) - Set key pool size to <n> (default: %u) Ustaw rozmiar puli kluczy na <n> (domyślnie: %u) diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index cd2a5a632..5cea349fb 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -67,7 +67,7 @@ These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. - Esses são seus endereços Bitcoin para enviar pagamentos. Certifique-se sempre da quantia e do destinatário antes de enviar moedas. + Esses são seus endereços Bitcoin para enviar pagamentos. Confira sempre a quantia e o destinatário antes de enviar moedas. These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. @@ -220,6 +220,17 @@ A frase de segurança da carteira foi alterada com êxito. + + BanTableModel + + IP/Netmask + IP/Máscara + + + Banned Until + Banido até + + BitcoinGUI @@ -376,7 +387,7 @@ &Settings - &Configurações + &definições &Help @@ -430,6 +441,10 @@ No block source available... Nenhum servidor disponível... + + Processed %n block(s) of transaction history. + %n bloco processado do histórico de transações.%n blocos processados do histórico de transações. + %n hour(s) %n hora%n horas @@ -867,6 +882,34 @@ command-line options opções da linha de comando + + UI Options: + Opções de Interface: + + + Choose data directory on startup (default: %u) + Escolher diretório de dados na inicialização (padrão: %u) + + + Set language, for example "de_DE" (default: system locale) + Definir idioma, por exemplo "de_DE" (padrão: idioma do sistema) + + + Start minimized + Iniciar minimizado + + + Set SSL root certificates for payment request (default: -system-) + Definir certificados de root SSL para requisições de pagamento (padrão: -sistema-) + + + Show splash screen on startup (default: %u) + Exibir tela de abertura na inicialização (padrão: %u) + + + Reset all settings changes made over the GUI + Desfazer todas as mudanças de configuração feitas na interface + Intro @@ -1064,6 +1107,34 @@ Port of the proxy (e.g. 9050) Porta do serviço de proxy (ex. 9050) + + Used for reaching peers via: + Usado para alcançar participantes via: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Exibe, caso o proxy padrão SOCKS5 fornecido seja usado para se conectar a peers através deste tipo de rede. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Conecte-se à rede Bitcoin através de um proxy SOCKS5 separado para utilizar serviços ocultos Tor. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Use um proxy SOCKS5 separado para alcançar participantes da rede via serviços ocultos Tor: + &Window &Janela @@ -1226,6 +1297,10 @@ Payment request rejected Solicitação de pagamento rejeitada + + Payment request network doesn't match client network. + Rede de pedido de pagamento não corresponde rede do cliente. + Payment request is not initialized. Pedido de pagamento não é inicializado. @@ -1246,10 +1321,18 @@ Payment request fetch URL is invalid: %1 URL de cobrança é inválida: %1 + + URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. + URI não pode ser analisado ! Isto pode ser causado por um endereço Bitcoin inválido ou parâmetros URI informados incorretamente. + Payment request file handling Manipulação de arquivo de cobrança + + Payment request file cannot be read! This can be caused by an invalid payment request file. + Arquivo de pedido de pagamento não pode ser lido ! Isto pode ser causado por uma requisição de pagamento inválida. + Payment request expired. Pedido de pagamento expirado. @@ -1270,10 +1353,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Pedido de pagamento %1 é muito grande (%2 bytes, permitido %3 bytes). - - Payment request DoS protection - Pagamento requer proteção DoS - Error communicating with %1: %2 Erro na comunicação com %1: %2 @@ -1426,6 +1505,18 @@ Current number of blocks Quantidade atual de blocos + + Memory Pool + Pool de Memória + + + Current number of transactions + Número atual de transações + + + Memory usage + Uso de memória + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. Abrir o arquivo de log de depuração do Bitcoin na pasta de dados atual. Isso pode demorar para arquivos grandes. @@ -1442,10 +1533,18 @@ &Peers &Pares + + Banned peers + Nós banidos + Select a peer to view detailed information. Selecione um cliente para ver informações detalhadas. + + Whitelisted + Lista branca + Direction Direção @@ -1454,6 +1553,18 @@ Version Versão + + Starting Block + Bloco inicial + + + Synced Headers + Cabeçalhos Sincronizados + + + Synced Blocks + Blocos Sincronizados + User Agent User Agent @@ -1462,14 +1573,6 @@ Services Serviços - - Starting Height - Altura inicial - - - Sync Height - Altura sincronizada - Ban Score Banir pontuação @@ -1486,18 +1589,22 @@ Last Receive Ultimo Recebido - - Bytes Sent - Bytes Enviados - - - Bytes Received - Bytes recebidos - Ping Time Ping + + The duration of a currently outstanding ping. + A duração de um ping excepcional no momento. + + + Ping Wait + Espera de ping + + + Time Offset + Offset de tempo + Last block time Horário do último bloco @@ -1542,6 +1649,34 @@ Clear console Limpar console + + &Disconnect Node + &Desconectar Nó + + + Ban Node for + Banir nó por + + + 1 &hour + 1 &hora + + + 1 &day + 1 &dia + + + 1 &week + 1 &semana + + + 1 &year + 1 &ano + + + &Unban Node + &Desbanir nó + Welcome to the Bitcoin Core RPC console. Bem vindo ao console de RPC do Bitcoin. @@ -1570,6 +1705,10 @@ %1 GB %1 GB + + (node id: %1) + (id do nó: %1) + via %1 por %1 @@ -1587,12 +1726,16 @@ Saída - Unknown - Desconhecido + Yes + Sim - Fetching... - Buscando... + No + Não + + + Unknown + Desconhecido @@ -1816,7 +1959,7 @@ If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. - Se isso estiver ativo e o endereço de troco estiver vazio ou inválido, o troco será enviado a um novo endereço gerado na hora. + Se essa opção for ativada e o endereço de troco estiver vazio ou inválido, o troco será enviado a um novo endereço gerado na hora. Custom change address @@ -1959,8 +2102,8 @@ Copia alteração - Total Amount %1 (= %2) - Quantidade Total %1 (= %2) + Total Amount %1 + Quantia Total %1 or @@ -1994,14 +2137,14 @@ Payment request expired. Pedido de pagamento expirado. + + Pay only the required fee of %1 + Pagar somente a taxa requerida de %1 + Estimated to begin confirmation within %n block(s). Confirmação estimada em %n bloco.Confirmação estimada em %n blocos. - - Pay only the minimum fee of %1 - Pagar somente a taxa mínima de %1 - The recipient address is not valid. Please recheck. O endereço do destinatário é inválido. Favor confirmar. @@ -2083,7 +2226,7 @@ The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally. - A taxa será deduzida da quantia sendo enviada. O beneficiario receberá menos bitcoins do que você colocou no campo de quantidade. Se varios beneficiarios estão selecionados, a taxa é dividida igualmente. + A taxa será deduzida da quantia sendo enviada. O destinatário receberá menos bitcoins do que você colocou no campo de quantidade. Se varios destinatários estão selecionados, a taxa é dividida igualmente. S&ubtract fee from amount @@ -2122,7 +2265,7 @@ ShutdownWindow Bitcoin Core is shutting down... - Bitcoin está desligando... + Bitcoin está sendo encerrado... Do not shut down the computer until this window disappears. @@ -2139,6 +2282,10 @@ &Sign Message &Assinar mensagem + + You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Você pode assinar mensagens com seus endereços para provar que você pode receber bitcoins enviados por alguém. Cuidado para não assinar nada vago ou aleatório, pois ataques phishing podem tentar te enganar para assinar coisas para eles como se fosse você. Somente assine termos bem detalhados que você concorde. + The Bitcoin address to sign the message with O enderesso Bitcoin que assinará a mensagem @@ -2191,6 +2338,10 @@ &Verify Message &Verificar mensagem + + Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction! + Coloque o endereço do destinatário, a mensagem (certifique-se de copiar toda a mensagem, incluindo quebras de linha, espaços, tabulações, etc.) e a assinatura embaixo para verificar a mensagem. Cuidado para não ler mais da assinatura do que está assinado na mensagem, para evitar ser enganado pelo ataque man-in-the-middle. Note que isso somente prova a propriedade de um endereço, e não o remetende de qualquer transação. + The Bitcoin address the message was signed with O enderesso Bitcoin que assionou a mesnagem @@ -2542,6 +2693,10 @@ Whether or not a watch-only address is involved in this transaction. Mostrar ou não endereços Bitcoin na lista de transações. + + User-defined intent/purpose of the transaction. + Intenção/Propósito definido pelo usuário para a transação + Amount removed from or added to balance. Quantidade debitada ou creditada ao saldo. @@ -2621,6 +2776,10 @@ Copy transaction ID Copiar ID da transação + + Copy raw transaction + Copia os dados brutos da transação + Edit label Editar rótulo @@ -2768,13 +2927,53 @@ Accept command line and JSON-RPC commands Aceitar linha de comando e comandos JSON-RPC + + If <category> is not supplied or if <category> = 1, output all debugging information. + Se <category> não for suprida ou se <category> = 1, mostrar toda informação de depuração. + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Total máximo de comissão (em %s) que será usado em uma única transação; um valor muito baixo pode cancelar uma transação grande (padrão: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + Por favor verifique se a data e horário estão corretos no seu computador! Se o seu relógio estiver incorreto, a Carteira Bitcoin não irá funcionar corretamente. + + + Prune configured below the minimum of %d MiB. Please use a higher number. + Corte configurado abaixo do nível mínimo de %d de MiB. Por favor use um número mais alto. + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + Corte: a ultima sincronização da carteira foi além do dado comprimido. Você precisa reindexar ( -reindex , faça o download de toda a blockchain novamente) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + Reduza os requerimentos de armazenamento de dados (cortando) deletando blocos mais antigos. Esse modo é incompatível com -txindex e -rescan. Cuidado: Reverter essa configuração requer um novo download de toda a blockchain. (Padrão: 0 = desabilita o corte de blocos, >%u = tamanho alvo em MiB para o uso de blocos cortados) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + Rescans não são possíveis no modo de corte. Você precisa usar -reindex, que irá fazer o download de toda a blockchain novamente. + + + Error: A fatal internal error occurred, see debug.log for details + Erro: Um erro interno fatal ocorreu, veja debug.log para detalhes + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Taxa (em %s/kB) a ser adicionada às transações que você mandar (padrão: %s) + + + Pruning blockstore... + Prunando os blocos existentes... + Run in the background as a daemon and accept commands Rodar em segundo plano como serviço e aceitar comandos - Use the test network - Usar rede de teste + Unable to start HTTP server. See debug log for details. + Não foi possível iniciar o servidor HTTP. Veja o log para detaihes. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2796,14 +2995,14 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Executa um comando quando uma transação da carteira mudar (%s no comando será substituído por TxID) - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Reduz o armazenamento requerido prunando (apagando) blocos antigos. Este modo desativa o suporte a carteira e é incompatível com -txindex. Aviso: Reverter essa opção requer re-baixar o blockchain inteiro. (padrão: 0 = disativado, >%u = Tamanho em mega para os arquivos de bloco) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Define o número de threads de verificação de script (%u a %d, 0 = automático, <0 = número de cores deixados livres, padrão: %d) + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + O banco de dados de blocos contém um bloco que parece ser do futuro. Isso pode ser devido à data e hora do seu computador estarem configuradas incorretamente. Apenas reconstrua o banco de dados de blocos se você estiver certo de que a data e hora de seu computador estão corretas. + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Este pode ser um build de teste pré-lançamento - use por sua conta e risco - não use para mineração ou aplicações de comércio. @@ -2813,8 +3012,16 @@ Impossível ouvir em %s neste computador. Provavelmente o Bitcoin já está sendo executado. - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Atenção: valor de -paytxfee escolhido é muito alto! Este é o valor da taxa de transação que você irá pagar se enviar a transação. + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + Use UPnP para mapear a porta escutada (padrão: 1 quando escutando e sem -proxy) + + + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) + AVISO: números estranhamente altos de blocos gerados, %d blocos recebidos nas últimas %d horas (%d esperados) + + + WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) + ATENÇÃO: verifique sua conexão %d blocos recebidos nas últimas %d horas (%d tempo estimado) Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. @@ -2824,10 +3031,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Atenção: Nós não parecemos concordar plenamente com nossos colegas! Você pode precisar atualizar ou outros nós podem precisar atualizar. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Atenção: erro ao ler arquivo wallet.dat! Todas as chaves foram lidas corretamente, mas dados de transações e do catálogo de endereços podem estar faltando ou incorretos. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Atenção: wallet.dat corrompido, dados recuperados! Arquivo wallet.dat original salvo como wallet.{timestamp}.bak em %s; se seu saldo ou transações estiverem incorretos, você deve restaurar o backup. @@ -2837,17 +3040,13 @@ Lista Branca pares de ligação da máscara de rede dado ou o endereço IP . Pode ser especificado várias vezes. - (default: 1) - (padrão: 1) + -maxmempool must be at least %d MB + -maxmempool deve ser pelo menos %d MB <category> can be: <category> pode ser: - - Attempt to recover private keys from a corrupt wallet.dat - Tentar recuperar chaves privadas de um arquivo wallet.dat corrompido - Block creation options: Opções de criação de blocos: @@ -2876,6 +3075,22 @@ Do you want to rebuild the block database now? Você quer reconstruir o banco de dados de blocos agora? + + Enable publish hash block in <address> + Abilitar a publicação da hash do block em <endereço> + + + Enable publish hash transaction in <address> + Abilitar a publicação da hash da transação em <endereço> + + + Enable publish raw block in <address> + Abilitar a publicação dos dados brutos do block em <endereço> + + + Enable publish raw transaction in <address> + Abilitar a publicação dos dados brutos da transação em <endereço> + Error initializing block database Erro ao inicializar banco de dados de blocos @@ -2892,10 +3107,6 @@ Error opening block database Erro ao abrir banco de dados de blocos - - Error: A fatal internal error occured, see debug.log for details - Erro: Um erro interno fatal ocorreu, ver o debug.log para detalhes - Error: Disk space is low! Erro: Espaço em disco insuficiente! @@ -2904,10 +3115,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Falha ao escutar em qualquer porta. Use -listen=0 se você quiser isso. - - If <category> is not supplied, output all debugging information. - Se <category> não for informada, registrar toda informação de depuração. - Importing... Importando... @@ -2920,6 +3127,10 @@ Invalid -onion address: '%s' Endereço -onion inválido: '%s' + + Keep the transaction memory pool below <n> megabytes (default: %u) + Mantenha a mempool de transações abaixo de <n> megabytes (padrão: %u) + Not enough file descriptors available. Decriptadores de arquivos disponíveis insuficientes. @@ -2948,10 +3159,26 @@ Specify wallet file (within data directory) Especifique o arquivo da carteira (dentro do diretório de dados) + + Unsupported argument -benchmark ignored, use -debug=bench. + Argumento não suportado -benchmark ignorado, use -debug=bench. + + + Unsupported argument -debugnet ignored, use -debug=net. + Argumento não suportado -debugnet ignorado, use -debug=net + + + Unsupported argument -tor found, use -onion. + Argumento não suportador encontrado: -tor. Use -onion. + Use UPnP to map the listening port (default: %u) Use UPnP para mapear a porta de entrada (padrão: %u) + + User Agent comment (%s) contains unsafe characters. + Comentário do Agente de Usuário (%s) contém caracteres inseguros. + Verifying blocks... Verificando blocos... @@ -2976,26 +3203,26 @@ You need to rebuild the database using -reindex to change -txindex Você precisa reconstruir o banco de dados utilizando -reindex - - Imports blocks from external blk000??.dat file - Importar blocos de um arquivo externo blk000??.dat - 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 Permitir conexões JSON-RPC de uma fonte específica. Válido para um único ip (ex. 1.2.3.4), até uma rede/máscara (ex. 1.2.3.4/255.255.255.0) ou uma rede/CIDR (ex. 1.2.3.4/24). Esta opção pode ser usada múltiplas vezes - - An error occurred while setting up the RPC address %s port %u for listening: %s - Um erro ocorreu enquanto configurando o endereço RPC %s porta %u para escuta: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Vincular ao endereço fornecido e sempre escutar nele. Use a notação [host]:port para IPv6 + + Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces) + Conecte ao endereço dado para receber conecções JSON-RPC. Use a notação [destino]:porta para IPv6. Essa opção pode ser especificada várias vezes (padrão: conecte a todas as interfaces) + Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running. Não foi possível obter acesso exclusivo ao diretório de dados %s. Provavelmente Bitcoin já está sendo executado. + + Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality) + Criar novos arquivos com permissões padrão do sistema, em vez de umask 077 (apenas efetivo com funcionalidade de carteira desabilitada) + Discover own IP addresses (default: 1 when listening and no -externalip or -proxy) Descobrir o próprio IP (padrão: 1 enquanto aguardando conexões e sem -externalip ou -proxy) @@ -3009,40 +3236,48 @@ Executa um comando quando um alerta relevante é recebido ou vemos uma longa segregação (%s em cmd é substituído pela mensagem) - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Taxas (em BTC/Kb) menores do que este valor são consideradas inexistentes para divulgação (padrão: %s) + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + Comissões (em %s/kB) menores serão consideradas como zero para relaying, mineração e criação de transação (padrão %s) - Prune configured below the minimum of %d MB. Please use a higher number. - Prunagem configurada abaixo do mínimo de %d MB. Use um número maior. + If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) + Se paytxfee não estiver definida, incluir comissão suficiente para que as transações comecem a ter confirmações em média dentro de N blocos (padrão %u) + + + Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Valor inválido para -maxtxfee = <valor>: '%s'( precisa ser pelo menos a comissão mínima de %s para prevenir travamento de transações) + + + Maximum size of data in data carrier transactions we relay and mine (default: %u) + Tamanho máximo de dados em transações de dados de operadora (padrão %u) + + + Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) + Buscar por endereços de peers via busca DNS, se estiver baixo em endereços (padrão: 1 a não ser que -connect) + + + Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u) + Gerar credenciais aleatórias para cada conexão por proxy. Isto habilita o isolamento de stream do Tor (padrão: %u) Set maximum size of high-priority/low-fee transactions in bytes (default: %d) Define o tamanho máximo de alta-prioridade por taxa baixa nas transações em bytes (padrão: %d) - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - Para usar o bitcoind, ou a opção -server do bitcoin-qt, você deve definir rpcpassword no arquivo de configuração: -%s -É recomendado que use a seguinte senha randômica: -rpcuser=bitcoinrpc -rpcpassword=%s -(você não precisa lembrar esta senha) -O usuário e senha NÃO DEVEM ser os mesmos. -Se o arquivo não existir, crie com permissão de proprietário criador somente. -É também recomendado definir a opção alertnotify se deseja ser notificado de problemas; -por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br - + Set the number of threads for coin generation if enabled (-1 = all cores, default: %d) + Determina o número de núcleos para a geração de moedas se ativado (-1 = todos os núcleos, padrão: %d) + + + The transaction amount is too small to send after the fee has been deducted + A quantia da transação é muito pequena para mandar + + + This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. + Esse produto inclui software desenvolvido pelo Open SSL Project para uso na OpenSSL Toolkit<https://www.openssl.org/> e software criptográfico escrito por Eric Young e software UPnP escrito por Thomas Bernard. + + + 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 + Peers permitidos não podem ser banidos do DoS e suas transações sempre são transmitidas, até mesmo se eles já estão no pool de memória, útil, por exemplo, para um gateway You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain @@ -3052,17 +3287,29 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br (default: %u) (padrão: %u) + + Accept public REST requests (default: %u) + Aceitar pedidos restantes públicas (padrão: %u) + Activating best chain... Ativando a melhor sequência... - Cannot resolve -whitebind address: '%s' - Impossível resolver endereço -whitebind: '%s' + Always relay transactions received from whitelisted peers (default: %d) + Sempre transmitir transações recebidas de peers confiáveis (padrão: %d) - Choose data directory on startup (default: 0) - Escolha o diretório de dados na inicialização (padrão: 0) + Attempt to recover private keys from a corrupt wallet.dat on startup + Tentar recuperar na inicialização chaves privadas de um arquivo wallet.dat corrompido + + + Automatically create Tor hidden service (default: %d) + Criar automaticamente serviços ocultos do Tor (padrão: %d) + + + Cannot resolve -whitebind address: '%s' + Impossível resolver endereço -whitebind: '%s' Connect through SOCKS5 proxy @@ -3072,10 +3319,6 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br Copyright (C) 2009-%i The Bitcoin Core Developers Copyright (C) 2009-%i Desenvolvedores Bitcoin Core - - Could not parse -rpcbind value %s as network address - Impossível interpretar o valor -rpcbind %s como um endereço da rede - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Erro ao carregar wallet.dat: A carteira requer a nova versão do Bitcoin @@ -3085,17 +3328,17 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br Erro ao ler o banco de dados. Finalizando. - Error: Unsupported argument -tor found, use -onion. - Erro: Argumento não suportado -tor, use -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Taxa (em BTC/kB) a adicionar nas transações que você envia (padrão: %s) + Imports blocks from external blk000??.dat file on startup + Importar blocos a partir de arquivo externo blk000??.dat durante a inicialização Information Informação + + Initialization sanity check failed. Bitcoin Core is shutting down. + O teste de integridade da inicialização falhou. O Core do Bitcoin está sendo desligado. + Invalid amount for -maxtxfee=<amount>: '%s' Quantidade inválida para -maxtxfee=<quantidade>: '%s' @@ -3116,6 +3359,10 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br Invalid netmask specified in -whitelist: '%s' Máscara de rede especificada em -whitelist: '%s' é inválida + + Keep at most <n> unconnectable transactions in memory (default: %u) + Manter ao máximo <n> transações inconectáveis na memória (padrão: %u) + Need to specify a port with -whitebind: '%s' Necessário informar uma porta com -whitebind: '%s' @@ -3124,14 +3371,18 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br Node relay options: Opções de relé nó : - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Opções RPC SSL: (veja o Bitcoin Wiki para instruções de configuração SSL) - RPC server options: Opções do servidor RPC: + + Rebuild block chain index from current blk000??.dat files on startup + Reconstruir índice de cadeia de bloco a partir dos arquivos blk000??.dat atuais durante a inicialização + + + Receive and display P2P network alerts (default: %u) + Receba e mostre P2P alerta de rede (padrão: %u) + Send trace/debug info to console instead of debug.log file Mandar informação de trace/debug para o console em vez de para o arquivo debug.log @@ -3140,22 +3391,10 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br Send transactions as zero-fee transactions if possible (default: %u) Enviar transação sem taxa, se possível (padrão: %u) - - Set SSL root certificates for payment request (default: -system-) - Define certificados SSL root para requisição de pagamento (padrão: -system-) - - - Set language, for example "de_DE" (default: system locale) - Escolher língua, por exemplo "de_DE" (padrão: localização do sistema) - Show all debugging options (usage: --help -help-debug) Exibir todas opções de depuração (uso: --help -help-debug) - - Show splash screen on startup (default: 1) - Mostrar tela inicial ao ligar (padrão: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Encolher arquivo debug.log ao iniciar o cliente (padrão 1 se opção -debug não estiver presente) @@ -3165,8 +3404,8 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br Assinatura de transação falhou - Start minimized - Inicializar minimizado + The transaction amount is too small to pay the fee + A quantidade da transação é pequena demais para pagar a taxa This is experimental software. @@ -3188,18 +3427,10 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br Transaction too large Transação muito larga - - UI Options: - Opções da interface: - Unable to bind to %s on this computer (bind returned error %s) Impossível se ligar a %s neste computador (bind retornou erro %s) - - Use UPnP to map the listening port (default: 1 when listening) - Usar UPnP para mapear porta de escuta (padrão: 1 quando estiver escutando) - Username for JSON-RPC connections Nome de usuário para conexões JSON-RPC @@ -3216,10 +3447,6 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br Zapping all transactions from wallet... Aniquilando todas as transações da carteira... - - on startup - ao iniciar - wallet.dat corrupt, salvage failed wallet.dat corrompido, recuperação falhou @@ -3232,18 +3459,6 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br Execute command when the best block changes (%s in cmd is replaced by block hash) Executa um comando quando o melhor bloco mudar (%s no comando será substituído pelo hash do bloco) - - Upgrade wallet to latest format - Atualizar carteira para o formato mais recente - - - Rescan the block chain for missing wallet transactions - Re-escanear blocos procurando por transações perdidas da carteira - - - Use OpenSSL (https) for JSON-RPC connections - Usar OpenSSL (https) para conexões JSON-RPC - This help message Exibe esta mensagem de ajuda @@ -3260,13 +3475,21 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br Error loading wallet.dat: Wallet corrupted Erro ao carregar wallet.dat: Carteira corrompida + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + Comissões (em %s/kB) menores serão consideradas como zero para criação de transação (padrão %s) + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) + Use um proxy SOCKS5 separado para alcançar participantes da rede via serviços ocultos Tor (padrão: %s) + (default: %s) (padrão: %s) - Acceptable ciphers (default: %s) - Cífras aceitas (padrão: %s) + Always query for peer addresses via DNS lookup (default: %u) + Sempre pergunte pelo endereço de peer via pesquisa DNS (padrão: %u) Error loading wallet.dat @@ -3288,30 +3511,46 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br Invalid -proxy address: '%s' Endereço -proxy inválido: '%s' + + Listen for JSON-RPC connections on <port> (default: %u or testnet: %u) + Escutar por conexões JSON-RPC na porta <port> (padrão: %u ou testnet: %u) + Listen for connections on <port> (default: %u or testnet: %u) Aguardar por conexões na porta <port> (padrão: %u ou testnet: %u) + + Maintain at most <n> connections to peers (default: %u) + Manter, no máximo, <n> conexões com peers (padrão: %u) + + + Make the wallet broadcast transactions + Fazer a carteira transmitir transações + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: %u) + Buffer máximo de recebimento por conexão, <n>*1000 bytes (padrão: %u) + Prepend debug output with timestamp (default: %u) - Adiciona timestamp como prefixo no debug (default: %u) + Adiciona timestamp como prefixo no debug (padrão: %u) Relay non-P2SH multisig (default: %u) - Retransmitir P2SH não multisig (default: %u) + Retransmitir P2SH não multisig (padrão: %u) - Server certificate file (default: %s) - Arquivo de certificado do servidor (padrão: %s) - - - Server private key (default: %s) - Chave privada do servidor (padrão: %s) + Set key pool size to <n> (default: %u) + Defina o tamanho da chave para piscina<n> (padrão: %u) Set minimum block size in bytes (default: %u) Definir tamanho mínimo do bloco, em bytes (padrão: %u) + + Set the number of threads to service RPC calls (default: %d) + Defina o número de threads para chamadas do serviço RPC (padrão: %d) + Specify configuration file (default: %s) Especificar arquivo de configuração (padrão: %s) @@ -3322,7 +3561,11 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br Specify pid file (default: %s) - Especificar aqrquivo pid (default: %s) + Especificar aqrquivo pid (padrão: %s) + + + Spend unconfirmed change when sending transactions (default: %u) + Gastar troco não confirmado quando enviar transações (padrão: %u) Unknown network specified in -onlynet: '%s' diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts index 7ac0a4fa5..ffed44a61 100644 --- a/src/qt/locale/bitcoin_pt_PT.ts +++ b/src/qt/locale/bitcoin_pt_PT.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,9 @@ A frase de segurança da carteira foi alterada com êxito. + + BanTableModel + BitcoinGUI @@ -871,7 +874,7 @@ command-line options opções da linha de comandos - + Intro @@ -1287,10 +1290,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Pedido de pagamento %1 excede o tamanho (%2 bytes, permitido %3 bytes). - - Payment request DoS protection - Pedido de pagamento proteção DdS - Error communicating with %1: %2 Erro ao comunicar com %1: %2 @@ -1475,14 +1474,6 @@ Services Serviços - - Starting Height - Iniciando Altura - - - Sync Height - Sincronização da Altura - Ban Score Resultado da Suspensão @@ -1499,14 +1490,6 @@ Last Receive Ultimo Recebimento - - Bytes Sent - Bytes Enviados - - - Bytes Received - Bytes Recebidos - Ping Time Tempo de Latência @@ -1603,10 +1586,6 @@ Unknown Desconhecido - - Fetching... - Em busca... - ReceiveCoinsDialog @@ -1971,10 +1950,6 @@ Copy change Copiar alteração - - Total Amount %1 (= %2) - Quantia Total %1 (= %2) - or ou @@ -2003,10 +1978,6 @@ Payment request expired. Pedido de pagamento expirou. - - Pay only the minimum fee of %1 - Pagar somente a taxa minima de %1 - Warning: Invalid Bitcoin address Aviso: Endereço Bitcoin inválido @@ -2753,10 +2724,6 @@ Run in the background as a daemon and accept commands Correr o processo em segundo plano e aceitar comandos - - Use the test network - Utilizar a rede de testes - Accept connections from outside (default: 1 if no -proxy or -connect) Aceitar ligações externas (padrão: 1 sem -proxy ou -connect) @@ -2789,10 +2756,6 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. Incapaz de vincular à porta %s neste computador. O Bitcoin Core provavelmente já está a correr. - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Atenção: -paytxfee está definida com um valor muito alto! Esta é a taxa que irá pagar se enviar uma transação. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Aviso: A rede não parece estar completamente de acordo! Parece que alguns mineiros estão com dificuldades técnicas. @@ -2801,10 +2764,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Atenção: Parecemos não estar de acordo com os nossos pares! Poderá ter que atualizar o seu cliente, ou outros nós poderão ter que atualizar os seus clientes. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Atenção: erro ao ler wallet.dat! Todas as chaves foram lidas correctamente, mas dados de transação ou do livro de endereços podem estar em falta ou incorrectos. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Atenção: wallet.dat corrompido, dados recuperados! wallet.dat original salvo como wallet.{timestamp}.bak em %s; se o seu saldo ou transações estiverem incorrectos deverá recuperar uma cópia de segurança. @@ -2813,18 +2772,10 @@ Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. Ligações na lista branca conectam desde a seguinte netmask ou endereço IP. Posse ser especificado varias vezes. - - (default: 1) - (padrão: 1) - <category> can be: <categoria> pode ser: - - Attempt to recover private keys from a corrupt wallet.dat - Tentar recuperar chaves privadas de um wallet.dat corrupto - Block creation options: Opções de criação de bloco: @@ -2869,10 +2820,6 @@ Error opening block database Erro ao abrir a base de dados de blocos - - Error: A fatal internal error occured, see debug.log for details - Erro: Um erro fatal interno ocorreu, verificar debug.log para mais informação - Error: Disk space is low! Erro: Pouco espaço em disco! @@ -2881,10 +2828,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Falhou a escutar em qualquer porta. Use -listen=0 se quiser isto. - - If <category> is not supplied, output all debugging information. - Se uma <categoria> não é fornecida, imprimir toda a informação de depuração. - Importing... A importar... @@ -2945,22 +2888,18 @@ You need to rebuild the database using -reindex to change -txindex É necessário reconstruir as bases de dados usando -reindex para mudar o -txindex - - Imports blocks from external blk000??.dat file - Importar blocos de um ficheiro blk000??.dat externo - 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 Permitir conexções JSON-RPC de fontes especificas. Valido para <ip> um unico IP (ex. 1.2.3.4), uma rede/netmask (ex. 1.2.3.4/255.255.255.0) ou uma rede/CIDR (ex. 1.2.3.4/24). Esta opção pode ser especificada varias vezes - - An error occurred while setting up the RPC address %s port %u for listening: %s - Um erro ocorreu durante a definição do endereço RPC %s porto %u para escutar: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Vincualar o endereço dado e listar as ligações conectadas ao mesmo na lista branca. Use a notação [anfitrião]:porta para IPv6 + + Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces) + Vinculado para dar o endereço para atender as ligações JSON-RPC. Use [host]: Notação de porta para IPv6. Esta opção pode ser especificada várias vezes (padrão: ligam-se a todas as interfaces) + Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running. Impossível trancar a pasta de dados %s. Provavelmente o Bitcoin Core já está a ser executado. @@ -2973,17 +2912,13 @@ Set maximum size of high-priority/low-fee transactions in bytes (default: %d) Definir tamanho máximo de transações com alta-prioridade/baixa-taxa em bytes (por defeito: %d) - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Atenção: Por favor verifique que a data e hora do seu computador estão correctas! Se o seu relógio não estiver certo o Bitcoin Core não irá funcionar correctamente. - (default: %u) (por defeito: %u) - Choose data directory on startup (default: 0) - Escolha a pasta de dados ao iniciar (por defeito: 0) + Cannot resolve -whitebind address: '%s' + Não foi possível resolver o endereço -whitebind: '%s' Copyright (C) 2009-%i The Bitcoin Core Developers @@ -2997,6 +2932,10 @@ Information Informação + + Invalid amount for -maxtxfee=<amount>: '%s' + Quantia inválida para -maxtxfee=<quantidade>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' Quantia inválida para -minrelaytxfee=<quantidade>: '%s' @@ -3009,18 +2948,6 @@ Send trace/debug info to console instead of debug.log file Enviar informação de rastreio/depuração para a consola e não para o ficheiro debug.log - - Set SSL root certificates for payment request (default: -system-) - Configurar certificados SSL root para pedido de pagamento (default: -system-) - - - Set language, for example "de_DE" (default: system locale) - Definir linguagem, por exemplo "pt_PT" (por defeito: linguagem do sistema) - - - Show splash screen on startup (default: 1) - Mostrar imagem ao iniciar (por defeito: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Encolher ficheiro debug.log ao iniciar o cliente (por defeito: 1 sem -debug definido) @@ -3029,10 +2956,6 @@ Signing transaction failed Falhou assinatura da transação - - Start minimized - Iniciar minimizado - Transaction amount too small Quantia da transação é muito baixa @@ -3045,10 +2968,6 @@ Transaction too large Transação grande demais - - Use UPnP to map the listening port (default: 1 when listening) - Usar UPnP para mapear a porta de escuta (padrão: 1 ao escutar) - Username for JSON-RPC connections Nome de utilizador para ligações JSON-RPC @@ -3077,18 +2996,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Executar comando quando o melhor bloco mudar (no comando, %s é substituído pela hash do bloco) - - Upgrade wallet to latest format - Atualize a carteira para o formato mais recente - - - Rescan the block chain for missing wallet transactions - Procurar transações em falta na cadeia de blocos - - - Use OpenSSL (https) for JSON-RPC connections - Usar OpenSSL (https) para ligações JSON-RPC - This help message Esta mensagem de ajuda @@ -3105,6 +3012,10 @@ Error loading wallet.dat: Wallet corrupted Erro ao carregar wallet.dat: Carteira danificada + + (default: %s) + (por defeito: %s) + Error loading wallet.dat Erro ao carregar wallet.dat @@ -3137,14 +3048,6 @@ Prepend debug output with timestamp (default: %u) Adicionar data e hora à informação de depuração (por defeito: %u) - - Server certificate file (default: %s) - Ficheiro de certificado do servidor (por defeito: %s) - - - Server private key (default: %s) - Chave privada do servidor (por defeito: %s) - Set key pool size to <n> (default: %u) Definir o tamanho da memória de chaves para <n> (por defeito: %u) diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts index be2466853..8bccf037a 100644 --- a/src/qt/locale/bitcoin_ro_RO.ts +++ b/src/qt/locale/bitcoin_ro_RO.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,9 @@ Parola portofelului electronic a fost schimbată. + + BanTableModel + BitcoinGUI @@ -706,6 +709,10 @@ lowest cea mai scăzută + + (%1 locked) + (%1 blocat) + none nimic @@ -734,6 +741,10 @@ no nu + + This means a fee of at least %1 per kB is required. + Aceasta înseamnă o taxă de cel puţin %1 pe kB necesar. + Can vary +/- 1 byte per input. Poate varia +/- 1 octet pentru fiecare intrare. @@ -863,7 +874,7 @@ command-line options Opţiuni linie de comandă - + Intro @@ -878,6 +889,10 @@ As this is the first time the program is launched, you can choose where Bitcoin Core will store its data. Dacă aceasta este prima dată cînd programul este lansat, puteţi alege unde Nucleul Bitcoin va stoca datele. + + Bitcoin Core will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. + Nucleul Bitcoin se va descărca şi va stoca o copie a lanţului blocului Bitcoin. Cel puţin %1GB de date vor fi stocate în acest dosar şi se va mări în timp. Portofelul va fi, de asemenea, stocat în acest dosar. + Use the default data directory Foloseşte dosarul de date implicit @@ -1270,10 +1285,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Cererea de plată %1 este prea mare (%2 octeţi, permis %3 octeţi). - - Payment request DoS protection - Protecţie DoS cerere de plată - Error communicating with %1: %2 Eroare la comunicarea cu %1: %2 @@ -1466,14 +1477,6 @@ Last Receive Ultima primire - - Bytes Sent - Octeţi trimişi - - - Bytes Received - Octeţi primiţi - Ping Time Timp ping @@ -1570,10 +1573,6 @@ Unknown Necunoscut - - Fetching... - Preluare... - ReceiveCoinsDialog @@ -1918,10 +1917,6 @@ Copy change Copiază rest - - Total Amount %1 (= %2) - Suma totală %1 (= %2) - or sau @@ -1950,10 +1945,6 @@ Payment request expired. Cererea de plată a expirat. - - Pay only the minimum fee of %1 - Plăteşte doar taxa minimă de %1 - The recipient address is not valid. Please recheck. Adresa destinatarului nu este validă, vă rugăm să o verificaţi. @@ -2356,6 +2347,10 @@ , has not been successfully broadcast yet , nu s-a propagat încă + + Open for %n more block(s) + Deschis pentru încă %n blocDeschis pentru încă %n blocuriDeschis pentru încă %n de blocuri + unknown necunoscut @@ -2386,6 +2381,10 @@ Immature (%1 confirmations, will be available after %2) Imatur (%1 confirmări, va fi disponibil după %2) + + Open for %n more block(s) + Deschis pentru încă %n blocDeschis pentru încă %n blocuriDeschis pentru încă %n de blocuri + Open until %1 Deschis până la %1 @@ -2696,10 +2695,6 @@ Run in the background as a daemon and accept commands Rulează în fundal ca un demon şi acceptă comenzi - - Use the test network - Utilizează reţeaua de test - Accept connections from outside (default: 1 if no -proxy or -connect) Acceptă conexiuni din afară (implicit: 1 dacă nu se foloseşte -proxy sau -connect) @@ -2728,10 +2723,6 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. Nu se poate lega la %s pe acest calculator. Nucleul Bitcoin probabil deja rulează. - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Atenţie: setarea -paytxfee este foarte mare! Aceasta este taxa tranzacţiei pe care o veţi plăti dacă trimiteţi o tranzacţie. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Atenţie: Reţeaua nu pare să fie de acord în totalitate! Aparent nişte mineri au probleme. @@ -2740,26 +2731,14 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Atenţie: Aparent, nu sîntem de acord cu toţi partenerii noştri! Va trebui să faceţi o actualizare, sau alte noduri necesită actualizare. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Atenţie: eroare la citirea fişierului wallet.dat! Toate cheile sînt citite corect, dar datele tranzactiei sau anumite intrări din agenda sînt incorecte sau lipsesc. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Atenţie: fişierul wallet.dat este corupt, date salvate! Fişierul original wallet.dat a fost salvat ca wallet.{timestamp}.bak in %s; dacă balansul sau tranzactiile sînt incorecte ar trebui să restauraţi dintr-o copie de siguranţă. - - (default: 1) - (iniţial: 1) - <category> can be: <category> poate fi: - - Attempt to recover private keys from a corrupt wallet.dat - Încercare de recuperare a cheilor private dintr-un wallet.dat corupt - Block creation options: Opţiuni creare bloc: @@ -2812,10 +2791,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Nu s-a reuşit ascultarea pe orice port. Folosiţi -listen=0 dacă vreţi asta. - - If <category> is not supplied, output all debugging information. - Dacă <category> nu este furnizat, produce toate informaţiile de depanare. - Importing... Import... @@ -2872,18 +2847,10 @@ You need to rebuild the database using -reindex to change -txindex Trebuie să reconstruiţi baza de date folosind -reindex pentru a schimba -txindex - - Imports blocks from external blk000??.dat file - Importă blocuri dintr-un fişier extern blk000??.dat - 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 Permite conexiunile JSON-RPC din sursa specificată. Valid pentru <ip> sînt IP singulare (ex. 1.2.3.4), o reţea/mască-reţea (ex. 1.2.3.4/255.255.255.0) sau o reţea/CIDR (ex. 1.2.3.4/24). Această opţiune poate fi specificată de mai multe ori - - An error occurred while setting up the RPC address %s port %u for listening: %s - A apărut o eroare la setarea adresei RPC %s portul %u pentru ascultare: %s - Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running. Nu se poate obţine blocarea folderului cu date %s. Nucleul Bitcoin probabil deja rulează. @@ -2900,13 +2867,17 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Acest produs include programe dezvoltate de către Proiectul OpenSSL pentru a fi folosite în OpenSSL Toolkit <https://www.openssl.org/> şi programe criptografice scrise de către Eric Young şi programe UPnP scrise de către Thomas Bernard. + + (default: %u) + (implicit: %u) + Accept public REST requests (default: %u) Acceptă cererile publice REST (implicit: %u) - Choose data directory on startup (default: 0) - Alege dosarul de date la pornire (implicit: 0) + Cannot resolve -whitebind address: '%s' + Nu se poate rezolva adresa -whitebind: '%s' Connect through SOCKS5 proxy @@ -2920,14 +2891,6 @@ Error reading from database, shutting down. Eroare la citirea bazei de date. Oprire. - - Error: Unsupported argument -tor found, use -onion. - Eroare: Argument nesuportat -tor găsit, folosiţi -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Taxa (în BTC/kB) de adăugat la tranzacţiile pe care le trimiteţi(implicit: %s) - Information Informaţie @@ -2960,18 +2923,10 @@ Need to specify a port with -whitebind: '%s' Trebuie să specificaţi un port cu -whitebind: '%s' - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Opţiuni RPC SSL: (vedeţi Wiki Bitcoin pentru intrucţiunile de setare SSL) - RPC server options: Opţiuni server RPC: - - RPC support for HTTP persistent connections (default: %d) - RPC suportă pentru HTTP conexiuni persistente (implicit: %d) - Send trace/debug info to console instead of debug.log file Trimite informaţiile trace/debug la consolă în locul fişierului debug.log @@ -2980,22 +2935,10 @@ Send transactions as zero-fee transactions if possible (default: %u) Trimitere tranzacţii ca tranzacţii taxă-zero dacă este posibil (implicit: %u) - - Set SSL root certificates for payment request (default: -system-) - Setare rădăcină certificat SSL pentru cerere de plată (implicit: -sistem- ) - - - Set language, for example "de_DE" (default: system locale) - Setează limba, de exemplu: "de_DE" (implicit: sistem local) - Show all debugging options (usage: --help -help-debug) Arată toate opţiunile de depanare (uz: --help -help-debug) - - Show splash screen on startup (default: 1) - Afişează pe ecran splash la pornire (implicit: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Micşorează fişierul debug.log la pornirea clientului (implicit: 1 cînd nu se foloseşte -debug) @@ -3004,10 +2947,6 @@ Signing transaction failed Nu s-a reuşit semnarea tranzacţiei - - Start minimized - Începe minimizat - This is experimental software. Acesta este un program experimental. @@ -3032,10 +2971,6 @@ Unable to bind to %s on this computer (bind returned error %s) Nu se poate lega la %s pe acest calculator. (Legarea a întors eroarea %s) - - Use UPnP to map the listening port (default: 1 when listening) - Foloseşte UPnP pentru a vedea porturile (implicit: 1 cînd ascultă) - Username for JSON-RPC connections Utilizator pentru conexiunile JSON-RPC @@ -3048,22 +2983,10 @@ Warning Avertisment - - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Avertisment: Argument nesuportat -benchmark ignorat, folosiţi -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Avertisment: Argument nesuportat -debugnet ignorat, folosiţi -debug=net. - Zapping all transactions from wallet... Şterge toate tranzacţiile din portofel... - - on startup - la pornire - wallet.dat corrupt, salvage failed wallet.dat corupt, salvare nereuşită @@ -3076,18 +2999,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Execută comanda cînd cel mai bun bloc se modifică (%s în cmd este înlocuit cu hash-ul blocului) - - Upgrade wallet to latest format - Actualizează portofelul la ultimul format - - - Rescan the block chain for missing wallet transactions - Rescanează lanţul de bloc pentru tranzacţiile portofel lipsă - - - Use OpenSSL (https) for JSON-RPC connections - Foloseşte OpenSSL (https) pentru conexiunile JSON-RPC - This help message Acest mesaj de ajutor @@ -3112,10 +3023,6 @@ (default: %s) (implicit: %s) - - Acceptable ciphers (default: %s) - Cifruri acceptabile (implicit: %s) - Error loading wallet.dat Eroare la încărcarea wallet.dat @@ -3132,14 +3039,6 @@ Invalid -proxy address: '%s' Adresa -proxy nevalidă: '%s' - - Server certificate file (default: %s) - Fişierul certificat al serverului (implicit: %s) - - - Server private key (default: %s) - Cheia privată a serverului (implicit: %s) - Set minimum block size in bytes (default: %u) Setare mărime minimă bloc în octeţi (implicit: %u) diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts index 004208d34..00dfd833a 100644 --- a/src/qt/locale/bitcoin_ru.ts +++ b/src/qt/locale/bitcoin_ru.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -93,7 +93,11 @@ Exporting Failed Экспорт не удался - + + There was an error trying to save the address list to %1. Please try again. + Произошла ошибка при попытке сохранить список адресов, %1. Пожалуйста, попробуйте еще раз. + + AddressTableModel @@ -216,6 +220,17 @@ Пароль бумажника успешно изменён. + + BanTableModel + + IP/Netmask + IP/префикс + + + Banned Until + Заблокировано до + + BitcoinGUI @@ -418,6 +433,10 @@ Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options Показать помощь по Bitcoin Core и получить список доступных параметров командной строки. + + %n active connection(s) to Bitcoin network + %n активных соединений с сетью Bitcoin%n активных соединений с сетью Bitcoin%n активных соединений с сетью Bitcoin%n активных соединений с сетью Bitcoin + No block source available... Источник блоков недоступен... @@ -426,10 +445,26 @@ Processed %n block(s) of transaction history. Обработан %n блок истории транзакций.Обработано %n блока истории транзакций.Обработано %n блоков истории транзакций.Обработано %n блоков истории транзакций. + + %n hour(s) + %n час%n часа%n часов%n часов + + + %n day(s) + %n день%n дня%n дней%n дней + + + %n week(s) + %n неделю%n недели%n недель%n недель + %1 and %2 %1 и %2 + + %n year(s) + %n год%n лет%n лет%n года + %1 behind %1 позади @@ -847,6 +882,34 @@ command-line options параметры командной строки + + UI Options: + Настройки интерфейса: + + + Choose data directory on startup (default: %u) + Выбрать каталог данных при запуске (по умолчанию: %u) + + + Set language, for example "de_DE" (default: system locale) + Выберите язык, например "de_DE" (по умолчанию: как в системе) + + + Start minimized + Запускать свёрнутым + + + Set SSL root certificates for payment request (default: -system-) + Указать корневые SSL-сертификаты для запроса платежа (по умолчанию: -system-) + + + Show splash screen on startup (default: %u) + Показывать экран-заставку при запуске (по умолчанию: %u) + + + Reset all settings changes made over the GUI + Сбросить все настройки сделанные через графический интерфейс + Intro @@ -886,7 +949,15 @@ Error Ошибка - + + %n GB of free space available + %n ГБ свободного места доступно%n ГБ свободного места доступно%n ГБ свободного места доступно%n ГБ свободного места доступно + + + (of %n GB needed) + (из необходимых %n ГБ)(из необходимых %n ГБ)(из необходимых %n ГБ)(из необходимых %n ГБ) + + OpenURIDialog @@ -1036,6 +1107,34 @@ Port of the proxy (e.g. 9050) Порт прокси-сервера (например, 9050) + + Used for reaching peers via: + Используется для достижения участников через: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Показывается, если включено прокси SOCKS5 по умолчанию, используемое для соединения с участниками по этому типу сети. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Подключаться к сети Bitcoin через прокси SOCKS5 для скрытых сервисов Tor. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Использовать отдельный прокси SOCKS5 для соединения с участниками через скрытые сервисы Tor: + &Window &Окно @@ -1254,10 +1353,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Запрос платежа %1 слишком большой (%2 байтов, разрешено %3 байтов). - - Payment request DoS protection - DoS-защита запроса платежа - Error communicating with %1: %2 Ошибка связи с %1: %2 @@ -1410,6 +1505,18 @@ Current number of blocks Текущее число блоков + + Memory Pool + Пул памяти + + + Current number of transactions + Текущее число транзакций + + + Memory usage + Использование памяти + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. Открыть отладочный лог-файл Bitcoin Core из текущего каталога данных. Это может занять несколько секунд для больших лог-файлов. @@ -1426,10 +1533,18 @@ &Peers &Участники + + Banned peers + Заблокированные участники + Select a peer to view detailed information. Выберите участника для просмотра подробностей. + + Whitelisted + Доверенный + Direction Направление @@ -1438,6 +1553,18 @@ Version Версия + + Starting Block + Начальный блок + + + Synced Headers + Синхронизировано заголовков + + + Synced Blocks + Синхронизировано блоков + User Agent Юзер-агент @@ -1446,14 +1573,6 @@ Services Сервисы - - Starting Height - Начальная высота - - - Sync Height - Высота синхронизации - Ban Score Очков бана @@ -1470,18 +1589,18 @@ Last Receive Последний раз получено - - Bytes Sent - Байт передано - - - Bytes Received - Байт получено - Ping Time Время задержки + + The duration of a currently outstanding ping. + Длительность текущего пинга. + + + Ping Wait + Время задержки + Time Offset Смещение времени @@ -1530,6 +1649,34 @@ Clear console Очистить консоль + + &Disconnect Node + &Отключить узел + + + Ban Node for + Заблокировать узел на + + + 1 &hour + 1 &час + + + 1 &day + 1 &день + + + 1 &week + 1 &неделю + + + 1 &year + 1 &год + + + &Unban Node + &Разблокировать узел + Welcome to the Bitcoin Core RPC console. Добро пожаловать в RPC-консоль Bitcoin Core. @@ -1558,6 +1705,10 @@ %1 GB %1 ГБ + + (node id: %1) + (номер узла: %1) + via %1 через %1 @@ -1575,12 +1726,16 @@ Исходящие - Unknown - Неизвестно + Yes + Да - Fetching... - Получение... + No + Нет + + + Unknown + Неизвестно @@ -1947,8 +2102,8 @@ Копировать размен - Total Amount %1 (= %2) - Общая сумма %1 (= %2) + Total Amount %1 + Общая сумма %1 or @@ -1982,6 +2137,14 @@ Payment request expired. Запрос платежа просрочен. + + Pay only the required fee of %1 + Заплатить только обязательную комиссию %1 + + + Estimated to begin confirmation within %n block(s). + Подтверждение ожидается через %n блок.Подтверждение ожидается через %n блока.Подтверждение ожидается через %n блоков.Подтверждение ожидается через %n блоков. + The recipient address is not valid. Please recheck. Адрес получателя неверный. Пожалуйста, перепроверьте. @@ -2296,6 +2459,10 @@ Status Статус + + , broadcast through %n node(s) + , разослано через %n узел, разослано через %n узла, разослано через %n узлов, разослано через %n узлов + Date Дата @@ -2332,6 +2499,10 @@ Credit Кредит + + matures in %n more block(s) + будет доступно через %n блокбудет доступно через %n блокабудет доступно через %n блоковбудет доступно через %n блоков + not accepted не принято @@ -2404,6 +2575,10 @@ , has not been successfully broadcast yet , ещё не было успешно разослано + + Open for %n more block(s) + Открыто для ещё %n блокаОткрыто для ещё %n блоковОткрыто для ещё %n блоковОткрыто для ещё %n блоков + unknown неизвестно @@ -2434,6 +2609,10 @@ Immature (%1 confirmations, will be available after %2) Незрелый (%1 подтверждений, будет доступен после %2) + + Open for %n more block(s) + Открыто для ещё %n блокаОткрыто для ещё %n блоковОткрыто для ещё %n блоковОткрыто для ещё %n блоков + Open until %1 Открыто до %1 @@ -2462,6 +2641,10 @@ Unconfirmed Неподтверждено + + Confirming (%1 of %2 recommended confirmations) + Подтверждено(%1 подтверждений, рекомендуется %2 подтверждений) + Conflicted В противоречии @@ -2593,6 +2776,10 @@ Copy transaction ID Скопировать ID транзакции + + Copy raw transaction + Скопировать исходную транзакции + Edit label Изменить метку @@ -2740,13 +2927,53 @@ Accept command line and JSON-RPC commands Принимать командную строку и команды JSON-RPC + + If <category> is not supplied or if <category> = 1, output all debugging information. + Если <category> не предоставлена или равна 1, выводить всю отладочную информацию. + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Максимальная сумма комиссий (%s) для одной транзакции в бумажнике; слишком низкое значение может вызвать прерывание больших транзакций (по умолчанию: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + Внимание: убедитесь, что дата и время на Вашем компьютере выставлены верно! Если Ваши часы идут неправильно, Bitcoin Core будет работать некорректно. + + + Prune configured below the minimum of %d MiB. Please use a higher number. + Удаление блоков выставлено ниже, чем минимум в %d Мб. Пожалуйста, используйте большее значение. + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + Удаление: последняя синхронизация кошелька вышла за рамки удаленных данных. Вам нужен -reindex (скачать всю цепь блоков в случае удаленного узла) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + Уменьшить размер хранилища за счёт удаления (обрезания) старых блоков. Этот режим несовместим с -txindex и -rescan. Внимание: переключение этой опции обратно потребует полной загрузки цепи блоков. (по умолчанию: 0 = отключить удаление блоков, >%u = целевой размер в Мб для файлов блоков) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + Повторное сканирование не возможно в режиме удаления. Вам надо будет использовать -reindex, который загрузит заново всю цепь блоков. + + + Error: A fatal internal error occurred, see debug.log for details + Ошибка: произошла неустранимая ошибка, подробности в debug.log + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Комиссия (в %s/Кб) для добавления к вашим транзакциям (по умолчанию: %s) + + + Pruning blockstore... + Очистка хранилища блоков... + Run in the background as a daemon and accept commands Запускаться в фоне как демон и принимать команды - Use the test network - Использовать тестовую сеть + Unable to start HTTP server. See debug log for details. + Невозможно запустить HTTP сервер. Смотри debug лог для подробностей. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2768,18 +2995,14 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Выполнить команду, когда меняется транзакция в бумажнике (%s в команде заменяется на TxID) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Максимальная сумма комиссий для одной транзакции в бумажнике; слишком низкое значение может вызвать прерывание больших транзакций (по умолчанию: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Уменьшить размер хранилища за счёт удаления (обрезания) старых блоков. Этот режим отключает поддержку бумажника и несовместим с -txindex. Внимание: переключение этой опции обратно потребует полной загрузки цепи блоков. (по умолчанию: 0 = отключить удаление блоков, >%u = целевой размер в Мб для файлов блоков) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Задать число потоков проверки скрипта (от %u до %d, 0=авто, <0 = оставить столько ядер свободными, по умолчанию: %d) + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + База данных блоков содержит блок, который появляется из будущего. Это может из-за некорректно установленных даты и времени на вашем компьютере. Остается только перестроивать базу блоков, если вы уверены, что дата и время корректны. + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Это пре-релизная тестовая сборка - используйте на свой страх и риск - не используйте для добычи или торговых приложений @@ -2788,6 +3011,10 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. Не удалось забиндиться на %s на этом компьютере. Возможно, Bitcoin Core уже запущен. + + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + Использовать UPnP для проброса порта (по умолчанию: 1, если используется прослушивание и нет -proxy) + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) ВНИМАНИЕ: сгенерировано ненормально большое число блоков, %d блоков получено за последние %d часов (ожидалось %d) @@ -2796,10 +3023,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) ВНИМАНИЕ: проверьте сетевое подключение, получено %d блоков за последние %d часов (ожидалось %d) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Внимание: установлено очень большое значение -paytxfee. Это комиссия, которую вы заплатите при проведении транзакции. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Внимание: похоже, в сети нет полного согласия! Некоторый майнеры, возможно, испытывают проблемы. @@ -2808,10 +3031,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Внимание: мы не полностью согласны с подключенными участниками! Вам или другим участникам, возможно, следует обновиться. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Внимание: ошибка чтения wallet.dat! Все ключи прочитаны верно, но данные транзакций или записи адресной книги могут отсутствовать или быть неправильными. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Внимание: wallet.dat повреждён, данные спасены! Оригинальный wallet.dat сохранён как wallet.{timestamp}.bak в %s; если ваш баланс или транзакции некорректны, вы должны восстановить файл из резервной копии. @@ -2821,17 +3040,13 @@ Вносить в белый список участников, подключающихся с указанной маски сети или IP. Можно использовать многократно. - (default: 1) - (по умолчанию: 1) + -maxmempool must be at least %d MB + -maxmempool должен быть как минимум %d MB <category> can be: <category> может быть: - - Attempt to recover private keys from a corrupt wallet.dat - Попытаться восстановить приватные ключи из повреждённого wallet.dat - Block creation options: Параметры создания блоков: @@ -2860,6 +3075,22 @@ Do you want to rebuild the block database now? Пересобрать БД блоков прямо сейчас? + + Enable publish hash block in <address> + Включить публичный хеш блока в <address> + + + Enable publish hash transaction in <address> + Включить публичный хеш транзакции в <address> + + + Enable publish raw block in <address> + Включить публичный сырой блок в <address> + + + Enable publish raw transaction in <address> + Включить публичную сырую транзакцию в <address> + Error initializing block database Ошибка инициализации БД блоков @@ -2876,10 +3107,6 @@ Error opening block database Не удалось открыть БД блоков - - Error: A fatal internal error occured, see debug.log for details - Ошибка: произошла неустранимая ошибка, детали в debug.log - Error: Disk space is low! Ошибка: мало места на диске! @@ -2888,10 +3115,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Не удалось начать прослушивание на порту. Используйте -listen=0 если вас это устраивает. - - If <category> is not supplied, output all debugging information. - Если <category> не предоставлена, выводить всю отладочную информацию. - Importing... Импорт ... @@ -2904,6 +3127,10 @@ Invalid -onion address: '%s' Неверный -onion адрес: '%s' + + Keep the transaction memory pool below <n> megabytes (default: %u) + Сбрасывать транзакции из памяти на диск каждые <n> мегабайт (по умолчанию: %u) + Not enough file descriptors available. Недостаточно файловых дескрипторов. @@ -2932,10 +3159,26 @@ Specify wallet file (within data directory) Укажите файл бумажника (внутри каталога данных) + + Unsupported argument -benchmark ignored, use -debug=bench. + Неподдерживаемый аргумент -benchmark проигнорирован, используйте -debug=bench. + + + Unsupported argument -debugnet ignored, use -debug=net. + Неподдерживаемый аргумент -debugnet проигнорирован, используйте -debug=net. + + + Unsupported argument -tor found, use -onion. + Обнаружен не поддерживаемый параметр -tor, используйте -onion. + Use UPnP to map the listening port (default: %u) Использовать UPnP для проброса порта (по умолчанию: %u) + + User Agent comment (%s) contains unsafe characters. + Комментарий пользователя (%s) содержит небезопасные символы. + Verifying blocks... Проверка блоков... @@ -2960,18 +3203,10 @@ You need to rebuild the database using -reindex to change -txindex Вам необходимо пересобрать базы данных с помощью -reindex, чтобы изменить -txindex - - Imports blocks from external blk000??.dat file - Импортировать блоки из внешнего файла blk000??.dat - 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 Разрешить подключения JSON-RPC с указанного источника. Разрешённые значения для <ip> — отдельный IP (например, 1.2.3.4), сеть/маска сети (например, 1.2.3.4/255.255.255.0) или сеть/CIDR (например, 1.2.3.4/24). Эту опцию можно использовать многократно - - An error occurred while setting up the RPC address %s port %u for listening: %s - Произошла ошибка в процессе открытия RPC адреса %s порта %u для прослушивания: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Привязаться к указанному адресу и внести в белый список подключающихся к нему участников. Используйте [хост]:порт для IPv6 @@ -2996,17 +3231,13 @@ Error: Listening for incoming connections failed (listen returned error %s) Ошибка: не удалось начать прослушивание входящих подключений (прослушивание вернуло ошибку %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Ошибка: обнаружен неподдерживаемый аргумент -socks. Выбор версии SOCKS более невозможен, поддерживаются только прокси SOCKS5. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Выполнить команду, когда приходит соответствующее сообщение о тревоге или наблюдается очень длинное расщепление цепи (%s в команде заменяется на сообщение) - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Комиссии (в BTC/Кб) меньшие этого значения считаются нулевыми для трансляции (по умолчанию: %s) + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + Комиссии (в %s/Кб) меньшие этого значения считаются нулевыми для создания, ретрансляции, получения транзакции (по умолчанию: %s) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -3020,10 +3251,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) Наибольший размер данных в носителе данных транзакций, которые мы передаем и генерируем (по умолчанию: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - Удаление блоков выставлено ниже, чем минимум в %d Мб. Пожалуйста, используйте большее значение. - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Запрашивать адреса участников с помощью DNS, если адресов мало (по умолчанию: 1, если не указан -connect) @@ -3048,38 +3275,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Этот продукт включает ПО, разработанное OpenSSL Project для использования в OpenSSL Toolkit <https://www.openssl.org/> и криптографическое ПО, написанное Eric Young и ПО для работы с UPnP, написанное Thomas Bernard. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - Для использования bitcoind или опции bitcoin-qt -server, вы должны установить опцию rpcpassword в конфигурационном файле: - %s -Рекомендуется использовать следующий случайный пароль: -rpcuser=bitcoinrpc -rpcpassword=%s -(вам не нужно запоминать этот пароль) -Имя и пароль ДОЛЖНЫ различаться. -Если файл не существует, создайте его и установите право доступа только для чтения только для владельца. -Также рекомендуется включить alertnotify для оповещения о проблемах; -Например: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Внимание: установлено очень большое значение -paytxfee. Такие большие комиссии могут быть уплачены в отдельной транзакции. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Внимание: убедитесь, что дата и время на Вашем компьютере выставлены верно. Если Ваши часы идут неправильно, Bitcoin Core будет работать некорректно. - 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 Участники из белого списка не могуть быть забанены за DoS, и их транзакции всегда транслируются, даже если они уже содержатся в памяти. Полезно, например, для шлюза. @@ -3101,17 +3296,21 @@ rpcpassword=%s Активируется лучшая цепь... - Can't run with a wallet in prune mode. - Нельзя работать с бумажником в режиме с удалением блоков. + Always relay transactions received from whitelisted peers (default: %d) + Всегда транслировать транзакции, полученные из белого списка участников (по умолчанию: %d) + + + Attempt to recover private keys from a corrupt wallet.dat on startup + Попытаться восстановить приватные ключи из повреждённого wallet.dat при запуске + + + Automatically create Tor hidden service (default: %d) + Автоматически создавать скрытый Tor сервис (по умолчанию: %d) Cannot resolve -whitebind address: '%s' Не удаётся разрешить адрес в параметре -whitebind: '%s' - - Choose data directory on startup (default: 0) - Выбрать каталог данных при запуске (по умолчанию: 0) - Connect through SOCKS5 proxy Подключаться через SOCKS5 прокси @@ -3120,10 +3319,6 @@ rpcpassword=%s Copyright (C) 2009-%i The Bitcoin Core Developers Все права защищены © 2009-%i Разработчики Bitcoin Core - - Could not parse -rpcbind value %s as network address - Не удалось разобрать значение %s параметра -rpcbind как сетевой адрес - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Ошибка загрузки wallet.dat: бумажник требует более новую версию Bitcoin Core @@ -3133,12 +3328,8 @@ rpcpassword=%s Ошибка чтения базы данных, работа завершается. - Error: Unsupported argument -tor found, use -onion. - Ошибка: обнаружен неподдерживаемый параметр -tor, используйте -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Комиссия (в BTC/Кб) для добавления к вашим транзакциям (по умолчанию: %s) + Imports blocks from external blk000??.dat file on startup + Импортировать блоки из внешнего файла blk000?.dat при запуске Information @@ -3180,18 +3371,10 @@ rpcpassword=%s Node relay options: Параметры трансляции узла: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Параметры RPC SSL: (см. Bitcoin вики для инструкций по настройке SSL) - RPC server options: Параметры сервера RPC: - - RPC support for HTTP persistent connections (default: %d) - Поддержка RPC постоянных HTTP подключений (по умолчанию: %d) - Rebuild block chain index from current blk000??.dat files on startup Перестроить при запуске индекс цепи блоков из текущих файлов blk000??.dat @@ -3200,6 +3383,14 @@ rpcpassword=%s Receive and display P2P network alerts (default: %u) Получать и отображать P2P сетевые тревоги (по умолчанию: %u) + + Reducing -maxconnections from %d to %d, because of system limitations. + Уменьшите -maxconnections с %d до %d, из-за ограничений системы. + + + Rescan the block chain for missing wallet transactions on startup + Перепроверить цепь блоков на предмет отсутствующих в бумажнике транзакций при запуске + Send trace/debug info to console instead of debug.log file Выводить информацию трассировки/отладки на консоль вместо файла debug.log @@ -3208,22 +3399,10 @@ rpcpassword=%s Send transactions as zero-fee transactions if possible (default: %u) Осуществить транзакцию бесплатно, если возможно (по умолчанию: %u) - - Set SSL root certificates for payment request (default: -system-) - Указать корневые SSL-сертификаты для запроса платежа (по умолчанию: -system-) - - - Set language, for example "de_DE" (default: system locale) - Выберите язык, например "de_DE" (по умолчанию: как в системе) - Show all debugging options (usage: --help -help-debug) Показать все отладочные параметры (использование: --help -help-debug) - - Show splash screen on startup (default: 1) - Показывать сплэш при запуске (по умолчанию: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Сжимать файл debug.log при запуске клиента (по умолчанию: 1, если нет -debug) @@ -3232,10 +3411,6 @@ rpcpassword=%s Signing transaction failed Не удалось подписать транзакцию - - Start minimized - Запускать свёрнутым - The transaction amount is too small to pay the fee Сумма транзакции слишком мала для уплаты комиссии @@ -3244,6 +3419,14 @@ rpcpassword=%s This is experimental software. Это экспериментальное ПО. + + Tor control port password (default: empty) + Пароль контроля порта Tor (по умолчанию: пустой) + + + Tor control port to use if onion listening enabled (default: %s) + Порт контроля Tor используется, если включено прослушивание onion (по умолчанию: %s) + Transaction amount too small Сумма транзакции слишком мала @@ -3260,17 +3443,13 @@ rpcpassword=%s Transaction too large Транзакция слишком большая - - UI Options: - Настройки интерфейса: - Unable to bind to %s on this computer (bind returned error %s) Невозможно привязаться к %s на этом компьютере (bind вернул ошибку %s) - Use UPnP to map the listening port (default: 1 when listening) - Использовать UPnP для проброса порта (по умолчанию: 1, если используется прослушивание) + Upgrade wallet to latest format on startup + Обновить бумажник до последнего формата при запуске Username for JSON-RPC connections @@ -3285,20 +3464,16 @@ rpcpassword=%s Внимание - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Внимание: неподдерживаемый аргумент -benchmark проигнорирован, используйте -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Внимание: неподдерживаемый аргумент -debugnet проигнорирован, используйте -debug=net. + Whether to operate in a blocks only mode (default: %u) + Будет работать в режиме только блоков (по умолчанию: %u) Zapping all transactions from wallet... Стираем все транзакции из кошелька... - on startup - при запуске + ZeroMQ notification options: + ZeroMQ параметры оповещения: wallet.dat corrupt, salvage failed @@ -3312,18 +3487,6 @@ rpcpassword=%s Execute command when the best block changes (%s in cmd is replaced by block hash) Выполнить команду, когда появляется новый блок (%s в команде заменяется на хэш блока) - - Upgrade wallet to latest format - Обновить бумажник до последнего формата - - - Rescan the block chain for missing wallet transactions - Перепроверить цепь блоков на предмет отсутствующих в бумажнике транзакций - - - Use OpenSSL (https) for JSON-RPC connections - Использовать OpenSSL (https) для подключений JSON-RPC - This help message Эта справка @@ -3344,6 +3507,26 @@ rpcpassword=%s (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = сохранять метаданные транзакции: например, владельца аккаунта и информацию запроса платежа; 2 = отбросить метаданные) + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + Установлено очень большое значение -maxtxfee. Такие большие комиссии могут быть уплачены в отдельной транзакции. + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Установлено очень большое значение -paytxfee. Такие большие комиссии могут быть уплачены в отдельной транзакции. + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + Не хранить транзакции в памяти дольше, чем <n> часов (по умолчанию %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Ошибка чтения wallet.dat! Все ключи прочитаны верно, но данные транзакций или записи адресной книги могут отсутствовать или быть неправильными. + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + Комиссии (в %s/Кб) меньшие этого значения считаются нулевыми при создании транзакций (по умолчанию: %s) + How thorough the block verification of -checkblocks is (0-4, default: %u) Насколько тщательна проверка контрольных блоков -checkblocks (0-4, по умолчанию: %u) @@ -3360,17 +3543,33 @@ rpcpassword=%s Output debugging information (default: %u, supplying <category> is optional) Выводить отладочную информацию (по умолчанию: %u, указание <category> необязательно) + + Support filtering of blocks and transaction with bloom filters (default: %u) + Поддерживать фильтрацию блоков и транзакций с помощью фильтра Блума (по умолчанию: %u) + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + Текущая длина строки версии сети (%i) превышает максимальную длину (%i). Увеливается количество или размер uacomments. + + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + Пытается ограничить исходящий трафик до (в МБ за 24ч), 0 = не ограничивать (по умолчанию: %d) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Обнаружен не поддерживаемый аргумент -socks. Выбор версии SOCKS более невозможен, поддерживаются только прокси SOCKS5. + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) Использовать отдельный прокси SOCKS5 для соединения с участниками через скрытые сервисы Tor (по умолчанию: %s) - (default: %s) - (по умолчанию: %s) + 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. This option can be specified multiple times + Имя пользователя и хэш пароля для JSON-RPC соединений. Поле <userpw> использует формат: <USERNAME>:<SALT>$<HASH>. Каноничный пример скрипта на питоне включен в "share/rpcuser". Эта опция может быть указана несколько раз - Acceptable ciphers (default: %s) - Допустимые шифры (по умолчанию: %s) + (default: %s) + (по умолчанию: %s) Always query for peer addresses via DNS lookup (default: %u) @@ -3432,18 +3631,14 @@ rpcpassword=%s Relay non-P2SH multisig (default: %u) Транслировать не-P2SH мультиподпись (по умолчанию: %u) - - Server certificate file (default: %s) - Файл сертификата сервера (по умолчанию: %s) - - - Server private key (default: %s) - Закрытый ключ сервера (по умолчанию: %s) - Set key pool size to <n> (default: %u) Установить размер пула ключей в <n> (по умолчанию: %u) + + Set minimum block size in bytes (default: %u) + Задать минимальный размер блока в байтах (по умолчанию: %u) + Set the number of threads to service RPC calls (default: %d) Задать число потоков выполнения запросов RPC (по умолчанию: %d) diff --git a/src/qt/locale/bitcoin_ru_RU.ts b/src/qt/locale/bitcoin_ru_RU.ts new file mode 100644 index 000000000..53a1c1d8a --- /dev/null +++ b/src/qt/locale/bitcoin_ru_RU.ts @@ -0,0 +1,245 @@ + + + AddressBookPage + + + AddressTableModel + + + AskPassphraseDialog + + + BanTableModel + + + BitcoinGUI + + Bitcoin Core + Bitcoin Core + + + &About Bitcoin Core + О Bitcoin Core + + + &Command-line options + Опции командной строки + + + Error + Ошибка + + + Warning + Предупреждение + + + Information + Информация + + + + ClientModel + + + CoinControlDialog + + Date + Дата + + + Confirmations + Подтверждения + + + Confirmed + Подтвержденные + + + Copy address + Копировать адрес + + + yes + Да + + + no + Нет + + + + EditAddressDialog + + Edit Address + Изменить адрес + + + + FreespaceChecker + + + HelpMessageDialog + + Bitcoin Core + Bitcoin Core + + + version + версия + + + About Bitcoin Core + О Bitcoin Core + + + Command-line options + Опции командной строки + + + command-line options + Опции командной строки + + + + Intro + + Bitcoin Core + Bitcoin Core + + + Error + Ошибка + + + + OpenURIDialog + + Open URI + Открыть URI + + + URI: + URI: + + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QRImageWidget + + + RPCConsole + + &Information + Информация + + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + + RecentRequestsTableModel + + Date + Дата + + + + SendCoinsDialog + + + SendCoinsEntry + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + Bitcoin Core + Bitcoin Core + + + + TrafficGraphWidget + + + TransactionDesc + + Date + Дата + + + + TransactionDescDialog + + + TransactionTableModel + + Date + Дата + + + + TransactionView + + Copy address + Копировать адрес + + + Confirmed + Подтвержденные + + + Date + Дата + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + + bitcoin-core + + Information + Информация + + + Warning + Предупреждение + + + Error + Ошибка + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_sah.ts b/src/qt/locale/bitcoin_sah.ts deleted file mode 100644 index 9ca08ee7d..000000000 --- a/src/qt/locale/bitcoin_sah.ts +++ /dev/null @@ -1,110 +0,0 @@ - - - AddressBookPage - - - AddressTableModel - - - AskPassphraseDialog - - - BitcoinGUI - - - ClientModel - - - CoinControlDialog - - - EditAddressDialog - - - FreespaceChecker - - - HelpMessageDialog - - - Intro - - - OpenURIDialog - - - OptionsDialog - - - OverviewPage - - - PaymentServer - - - PeerTableModel - - - QObject - - - QRImageWidget - - - RPCConsole - - - ReceiveCoinsDialog - - - ReceiveRequestDialog - - - RecentRequestsTableModel - - - SendCoinsDialog - - - SendCoinsEntry - - - ShutdownWindow - - - SignVerifyMessageDialog - - - SplashScreen - - - TrafficGraphWidget - - - TransactionDesc - - - TransactionDescDialog - - - TransactionTableModel - - - TransactionView - - - UnitDisplayStatusBarControl - - - WalletFrame - - - WalletModel - - - WalletView - - - bitcoin-core - - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index 48d5a0914..8c779cbe9 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,9 @@ Heslo k peňaženke bolo úspešne zmenené. + + BanTableModel + BitcoinGUI @@ -871,7 +874,7 @@ command-line options voľby príkazového riadku - + Intro @@ -1068,6 +1071,10 @@ Port of the proxy (e.g. 9050) Port proxy (napr. 9050) + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Použiť samostatný SOCKS5 proxy server na dosiahnutie počítačov cez skryté služby Tor: + &Window Okno @@ -1286,10 +1293,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Požiadavka na platbu %1 je príliš veľká (%2 bajtov, povolené je %3 bajtov). - - Payment request DoS protection - Ochrana pred zahltením požiadavkami na platbu - Error communicating with %1: %2 Chyba komunikácie s %1: %2 @@ -1478,14 +1481,6 @@ Services Služby - - Starting Height - Počiatočná výška - - - Sync Height - Synchronizovaná výška - Ban Score Skóre zákazu @@ -1502,14 +1497,6 @@ Last Receive Posledné prijatie - - Bytes Sent - Odoslaných bajtov - - - Bytes Received - Prijatých bajtov - Ping Time Čas odozvy @@ -1610,10 +1597,6 @@ Unknown neznámy - - Fetching... - Získava sa... - ReceiveCoinsDialog @@ -1978,10 +1961,6 @@ Copy change Kopírovať zmenu - - Total Amount %1 (= %2) - Celková suma %1 (= %2) - or alebo @@ -2014,10 +1993,6 @@ Payment request expired. Vypršala platnosť požiadavky na platbu. - - Pay only the minimum fee of %1 - Zaplatiť minimálny poplatok %1 - The recipient address is not valid. Please recheck. Adresa príjemcu je neplatná. Prosím, overte ju. @@ -2776,10 +2751,6 @@ Run in the background as a daemon and accept commands Bežať na pozadí ako démon a prijímať príkazy - - Use the test network - Použiť testovaciu sieť - Accept connections from outside (default: 1 if no -proxy or -connect) Prijať spojenia zvonku (predvolené: 1 ak žiadne -proxy alebo -connect) @@ -2812,10 +2783,6 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. Nepodarilo sa pripojiť na %s na tomto počítači. Bitcoin Jadro je už pravdepodobne spustené. - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Varovanie: -paytxfee je nastavené veľmi vysoko. Toto sú transakčné poplatky ktoré zaplatíte ak odošlete transakciu. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Varovanie: Javí sa že sieť sieť úplne nesúhlasí! Niektorí mineri zjavne majú ťažkosti. @@ -2826,10 +2793,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Varovanie: Zjavne sa úplne nezhodujeme s našimi peer-mi! Možno potrebujete prejsť na novšiu verziu alebo ostatné uzly potrebujú vyššiu verziu. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Varovanie: chyba pri čítaní wallet.dad! Všetky kľúče sú čitateľné ale transakčné dáta alebo záznamy v adresári môžu byť nesprávne. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Varovanie: wallet.dat je poškodený, údaje úspešne získané! Pôvodný wallet.dat uložený ako wallet.{timestamp}.bak v %s; ak váš zostatok alebo transakcie niesu správne, mali by ste súbor obnoviť zo zálohy. @@ -2838,18 +2801,10 @@ The network does not appear to fully agree! Some miners appear to be experiencin Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. Uzle na zoznam povolených, ktoré sa pripájajú z danej netmask alebo IP adresy. Môže byť zadané viac krát. - - (default: 1) - (predvolené: 1) - <category> can be: <category> môže byť: - - Attempt to recover private keys from a corrupt wallet.dat - Pokus zachrániť súkromné kľúče z poškodeného wallet.dat - Block creation options: Voľby vytvorenia bloku: @@ -2894,10 +2849,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin Error opening block database Chyba otvárania databázy blokov - - Error: A fatal internal error occured, see debug.log for details - Chyba: Nastala fatálna interná chyba. Pre podrobnosti pozrite debug.log - Error: Disk space is low! Chyba: Málo miesta na disku! @@ -2906,10 +2857,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin Failed to listen on any port. Use -listen=0 if you want this. Chyba počúvania na ktoromkoľvek porte. Použi -listen=0 ak toto chcete. - - If <category> is not supplied, output all debugging information. - Ak nie je uvedená <category>, na výstupe zobrazuj všetky informácie pre ladenie. - Importing... Prebieha import ... @@ -2966,18 +2913,10 @@ The network does not appear to fully agree! Some miners appear to be experiencin You need to rebuild the database using -reindex to change -txindex Potrebujete prebudovať databázu použitím -reindex zmeniť -txindex - - Imports blocks from external blk000??.dat file - Importuje bloky z externého súboru blk000??.dat - 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 Povoliť JSON-RPC pripojenia zo zadaného zdroja. Pre <ip> sú platné jednoduché IP (napr. 1.2.3.4), sieť/netmask (napr. 1.2.3.4/255.255.255.0) alebo sieť/CIDR (napr. 1.2.3.4/24). Táto možnosť môže byť zadaná niekoľko krát - - An error occurred while setting up the RPC address %s port %u for listening: %s - Pri nastavovaní RPC adresy %s na porte %u pre počúvanie došlo k chybe: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Spojiť s danou adresou a povolenými partnerskými zariadeniami ktoré sa tam pripájajú. Použite zápis [host]:port pre IPv6 @@ -2998,18 +2937,10 @@ The network does not appear to fully agree! Some miners appear to be experiencin Error: Listening for incoming connections failed (listen returned error %s) Chyba: Počúvanie prichádzajúcich spojení zlyhalo (vrátená chyba je %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Chyba: Nájdený nepodporovaný argument -socks. Nastavenie SOCKS verzie nie je už možné, podporované sú už iba proxy SOCKS5. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Vykonať príkaz po prijatí patričného varovania alebo uvidíme veľmi dlhé rozdvojenie siete (%s v cmd je nahradené správou) - - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Poplatky (v BTC/Kb) nižšie ako toľkoto sa považujú za nulové pri postupovaní transakcií (predvolené: %s) - If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) Ak nie je nastavené paytxfee, pridať dostatočný poplatok aby sa transakcia začala potvrdzovať priemerne v rámci bloku (predvolené: %u) @@ -3038,10 +2969,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Tento produkt obsahuje softvér vyvinutý projektom OpenSSL pre použitie sady nástrojov OpenSSL <https://www.openssl.org/> a kryptografického softvéru napísaného Eric Young a UPnP softvér napísaný Thomas Bernard. - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Upozornenie: -maxtxfee je nastavené príliš vysoko! Takto vysoké poplatky by mali byť zaplatené za jednu transakciu. - 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 Uzle na zoznam povolených nemôžu byť DoS zakázané a ich transakcie vždy postúpené ďalej, aj v prípade, ak sú už pamäťovej fronte. Užitočné napr. pre brány @@ -3058,10 +2985,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin Cannot resolve -whitebind address: '%s' Nedá sa vyriešiť -whitebind adresa: '%s' - - Choose data directory on startup (default: 0) - Zvoľte dátový priečinok pri štarte (prednastavené: 0) - Connect through SOCKS5 proxy Pripojiť cez proxy server SOCKS5 @@ -3070,10 +2993,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin Copyright (C) 2009-%i The Bitcoin Core Developers Autorské práva (C) 2009-%i Vývojári jadra Bitcoin - - Could not parse -rpcbind value %s as network address - Nedá sa analyzovať -rpcbind hodnota %s ako sieťová adresa - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Chyba pri čítaní wallet.dat: Peňaženka vyžaduje vyššiu verziu Jadra Bitcoin @@ -3082,14 +3001,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin Error reading from database, shutting down. Chyba pri načítaní z databázy, ukončuje sa. - - Error: Unsupported argument -tor found, use -onion. - Chyba: nájdený nepodporovaný argument -tor, použite -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Poplatok (v BTC/kB), ktorý sa pridá k transakciám, ktoré odosielate (predvolený: %s) - Information Informácia @@ -3126,18 +3037,10 @@ The network does not appear to fully agree! Some miners appear to be experiencin Node relay options: Prenosové možnosti uzla: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Možnosti RPC SSL: (Pozri v Bitcoin Wiki pokyny pre SSL nastavenie) - RPC server options: Možnosti servra RPC: - - RPC support for HTTP persistent connections (default: %d) - Podpora RPC pre trvalé HTTP spojenia (predvolené: %d) - Receive and display P2P network alerts (default: %u) Obdržať a zobraziť sieťové P2P varovania (predvolené: %u) @@ -3150,22 +3053,10 @@ The network does not appear to fully agree! Some miners appear to be experiencin Send transactions as zero-fee transactions if possible (default: %u) Poslať ako transakcie bez poplatku, ak je to možné (predvolené: %u) - - Set SSL root certificates for payment request (default: -system-) - Nastaviť koreňový certifikát pre výzvy na platbu (prednastavené: -system-) - - - Set language, for example "de_DE" (default: system locale) - Nastaviť jazyk, napríklad "sk_SK" (predvolené: systémový) - Show all debugging options (usage: --help -help-debug) Zobraziť všetky možnosti ladenia (použitie: --help --help-debug) - - Show splash screen on startup (default: 1) - Zobraziť splash screen pri spustení (predvolené: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Zmenšiť debug.log pri spustení klienta (predvolené: 1 ak bez -debug) @@ -3174,10 +3065,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin Signing transaction failed Podpísanie správy zlyhalo - - Start minimized - Spustiť minimalizované - This is experimental software. Toto je experimentálny softvér. @@ -3198,18 +3085,10 @@ The network does not appear to fully agree! Some miners appear to be experiencin Transaction too large Transakcia príliš veľká - - UI Options: - Možnosti používateľského rozhrania: - Unable to bind to %s on this computer (bind returned error %s) Na tomto počítači sa nedá vytvoriť väzba %s (vytvorenie väzby vrátilo chybu %s) - - Use UPnP to map the listening port (default: 1 when listening) - Skúsiť použiť UPnP pre mapovanie počúvajúceho portu (default: 1 when listening) - Username for JSON-RPC connections Užívateľské meno pre JSON-RPC spojenia @@ -3218,22 +3097,10 @@ The network does not appear to fully agree! Some miners appear to be experiencin Warning Upozornenie - - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Upozornenie: Nepodporovaný argument -benchmark bol ignorovaný, použite -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Upozornenie: Nepodporovaný argument -debugnet bol ignorovaný, použite -debug=net. - Zapping all transactions from wallet... Zmazať všetky transakcie z peňaženky... - - on startup - pri štarte - wallet.dat corrupt, salvage failed wallet.dat je poškodený, záchrana zlyhala @@ -3246,18 +3113,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin Execute command when the best block changes (%s in cmd is replaced by block hash) Vykonaj príkaz, ak zmeny v najlepšom bloku (%s v príkaze nahradí blok hash) - - Upgrade wallet to latest format - Aktualizuj peňaženku na najnovší formát. - - - Rescan the block chain for missing wallet transactions - Znovu skenovať reťaz blokov pre chýbajúce transakcie - - - Use OpenSSL (https) for JSON-RPC connections - Použiť OpenSSL (https) pre JSON-RPC spojenia - This help message Táto pomocná správa @@ -3302,10 +3157,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin (default: %s) (predvolené: %s) - - Acceptable ciphers (default: %s) - Prijateľné šifry (predvolené: %s) - Always query for peer addresses via DNS lookup (default: %u) Vždy sa dotazovať adresy partnerských uzlov cez vyhľadávanie DNS (predvolené: %u) @@ -3314,6 +3165,10 @@ The network does not appear to fully agree! Some miners appear to be experiencin Error loading wallet.dat Chyba načítania wallet.dat + + Generate coins (default: %u) + Generovať mince (predvolené: %u) + How many blocks to check at startup (default: %u, 0 = all) Koľko blokov overiť pri spustení (predvolené: %u, 0 = všetky) @@ -3358,14 +3213,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin Relay non-P2SH multisig (default: %u) Prenášať non-P2SH multi-podpis (predvolené: %u) - - Server certificate file (default: %s) - Certifikačný súbor servera (predvolené: %s) - - - Server private key (default: %s) - Privátny kľúč servera (predvolené: %s) - Set key pool size to <n> (default: %u) Nastaviť veľkosť kľúča fronty na <n> (predvolené: %u) diff --git a/src/qt/locale/bitcoin_sl_SI.ts b/src/qt/locale/bitcoin_sl_SI.ts index 39dcb6e99..c62c8cf27 100644 --- a/src/qt/locale/bitcoin_sl_SI.ts +++ b/src/qt/locale/bitcoin_sl_SI.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,9 @@ Geslo za dostop do denarnice je bilo uspešno zamenjano. + + BanTableModel + BitcoinGUI @@ -871,7 +874,7 @@ command-line options možnosti ukazne vrstice - + Intro @@ -914,7 +917,11 @@ %n GB of free space available %n GiB prostega prostora na voljo%n GiB prostega prostora na voljo%n GiB prostega prostora na voljo%n GiB prostega prostora na voljo - + + (of %n GB needed) + (od potrebnih %n GiB)(od potrebnih %n GiB)(od potrebnih %n GiB)(od potrebnih %n GiB) + + OpenURIDialog @@ -1064,6 +1071,10 @@ Port of the proxy (e.g. 9050) Vrata posredniškega strežnika (npr. 9050) + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Za dostop do soležnikov preko skritih storitev Tor uporabi drug posredniški strežnik SOCKS5: + &Window O&kno @@ -1282,10 +1293,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Zahtevek za plačilo %1 je prevelik (%2 bajtov, dovoljenih je %3 bajtov.) - - Payment request DoS protection - Zaščita pred napadom denial-of-service zahtevka za plačilo - Error communicating with %1: %2 Napaka pri povezavi z %1: %2 @@ -1474,14 +1481,6 @@ Services Storitve - - Starting Height - Začetna višina - - - Sync Height - Trenutna višina - Ban Score Kazenske točke @@ -1498,14 +1497,6 @@ Last Receive Nazadnje prejeto - - Bytes Sent - Oddanih bajtov - - - Bytes Received - Prejetih bajtov - Ping Time Odzivni čas @@ -1603,12 +1594,16 @@ Odhodna - Unknown - Neznano + Yes + Da - Fetching... - Pridobivam ... + No + Ne + + + Unknown + Neznano @@ -1974,10 +1969,6 @@ Copy change Kopiraj vračilo - - Total Amount %1 (= %2) - Skupni znesek %1 (= %2) - or ali @@ -2014,10 +2005,6 @@ Estimated to begin confirmation within %n block(s). Predviden začetek potrditev po %n najdenem bloku.Predviden začetek potrditev po %n najdenih blokih.Predviden začetek potrditev po %n najdenih blokih.Predviden začetek potrditev po %n najdenih blokih. - - Pay only the minimum fee of %1 - Plačilo samo minimalne provizije v znesku %1 - The recipient address is not valid. Please recheck. Naslov prejemnika je neveljaven. Prosimo, preverite. @@ -2800,10 +2787,6 @@ Run in the background as a daemon and accept commands Teci v ozadju in sprejemaj ukaze - - Use the test network - Uporabi testno omrežje - Accept connections from outside (default: 1 if no -proxy or -connect) Sprejemaj zunanje povezave (privzeto: 1, razen če ste vklopili opciji -proxy ali -connect) @@ -2820,14 +2803,6 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Izvedi ukaz, ko bo transakcija denarnice se spremenila (V cmd je bil TxID zamenjan za %s) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Največji še veljavni skupni znesek provizij pri transakcijah z uporabo ene denarnice. Prenizka nastavitev lahko povzroči izločitev večjih transakcij (privzeto %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Omogoči obrezovanje (brisanje) starejših blokov in s tem prihrani pri prostoru za shranjevanje. Ta način delovanja onemogoči uporabo denarnice in ni združljivo z opcijo -txindex. Opozorilo: Če kasneje to opcijo povrnete na privzeto vrednost, boste morali ponovno prenesti celotno verigo. (privzeto: 0 = onemogoči obrezovanje, >%u = ciljna velikost datotek blokov v MiB) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Nastavi število niti za preverjanje skript (%u do %d, 0 = samodejno, <0 toliko procesorskih jeder naj ostane prostih, privzeto: %d) @@ -2848,10 +2823,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) OPOZORILO: Preverite vašo omrežno povezavo. Št. prejetih blokov: %d v št. ur: %d (pričakovanih je %d blokov) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Opozorilo: Vrednost opcije -paytxfee je zelo visoka. To je provizija, ki jo boste plačali, če izvedete plačilo. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Opozorilo: Trenutno na omrežju ni videti konsenza! Videti je, kot da bi imeli nekateri rudarji težave. @@ -2860,10 +2831,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Opozorilo: Trenutno se s soležniki ne strinjam v popolnosti! Mogoče bi morali vi ali drugi udeleženci posodobiti odjemalce. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Opozorilo: napaka pri branju datoteke wallet.dat! Vsi ključi so bili pravilno prebrani, podatki o transakciji ali imenik vnešenih naslovov so morda izgubljeni ali nepravilni. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Opozorilo: Datoteka wallet.dat je bila okvarjena, podatki pa so bili kljub temu rešeni! Originalna datoteka je bila shranjena kot wallet.{čas.oznaka}.bak v mapo %s. Če sta skupno stanje ali seznam transakcij napačna, morate datoteko restavrirati iz varnostne kopije. @@ -2872,18 +2839,10 @@ Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. Sprejemaj povezave samo od soležnikov, ki so na naslovih, ki ustrezajo navedeni omrežni maski ali naslovu. Opcijo lahko navedete večkrat. - - (default: 1) - (privzeto: 1) - <category> can be: <category> je lahko: - - Attempt to recover private keys from a corrupt wallet.dat - Skušaj obnoviti zasebne ključe iz okvarjene datoteke wallet.dat - Block creation options: Možnosti ustvarjanja blokov: @@ -2928,10 +2887,6 @@ Error opening block database Napaka pri odpiranju podatkovne baze blokov - - Error: A fatal internal error occured, see debug.log for details - Napaka: Med izvajanjem je prišlo do nepopravljive napake. Podrobnosti so v datoteki debug.log - Error: Disk space is low! Opozorilo: Premalo prostora na disku! @@ -2940,10 +2895,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Ni mogoče poslušati na nobenih vratih. Če to zares želite, uporabite opcijo -listen=0. - - If <category> is not supplied, output all debugging information. - Če element <category> ni naveden, izpisuje vse informacije za razhroščevanje. - Importing... Uvažam ... @@ -3012,18 +2963,10 @@ You need to rebuild the database using -reindex to change -txindex Ob spremembi vrednosti opcije -txindex boste morali obnoviti bazo podatkov z uporabo opcije -reindex - - Imports blocks from external blk000??.dat file - Uvozi bloke iz zunanje datoteke blk000??.dat - 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 Iz navedenega vira dovoli povezave na JSON-RPC. Veljavne oblike vrednosti parametra <ip> so: edinstven naslov IP (npr.: 1.2.3.4), kombinacija omrežje/netmask (npr.: 1.2.3.4/255.255.255.0), ali pa kombinacija omrežje/CIDR (1.2.3.4/24). To opcijo lahko navedete večkrat. - - An error occurred while setting up the RPC address %s port %u for listening: %s - Prišlo je do napake med zagonom poslušalca RPC na naslovu %s in vratih %u: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Veži dani naslov in sprejemaj povezave samo od navedenih soležnikov. Za naslove protokola IPv6 uporabite zapis [gostitelj]:vrata. @@ -3048,18 +2991,10 @@ Error: Listening for incoming connections failed (listen returned error %s) Napaka: Ni mogoče sprejemati dohodnih povezav (vrnjena napaka: %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Napaka: Navedli ste nepodprto vrednost opcije -socks. Različice protokola SOCKS ni več mogoče navesti, podprti so samo posredniški strežniki tipa SOCKS5. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Ko bo prejeto ustrezno opozorilo, ali ko bo opažena zelo dolga razvejitev, izvedi navedeni ukazni niz. (Niz %s bo nadomeščen z vsebino sporočila.) - - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Provizije (v BTC/KiB), ki so manjše od te vrednosti, se pri posredovanju smatrajo za nične (privzeto: %s) - If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) Če opcija -paytxfee ni nastavljena, nastavi znesek provizije tako visoko, da bodo transakcije potrjene v povprečno n blokih. (privzeto: %u) @@ -3068,10 +3003,6 @@ Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u) Na vsak posredniški strežnik se prijavi z drugimi naključnimi podatki. Tako je omogočena osamitev tokov v omrežju Tor (privzeto: %u) - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Opozorilo: Preverite, če sta datum in ura na vašem računalniku točna! Bitcoin Core ne bo dobro deloval, če je nastavljeni čas nepravilen. - (default: %u) (privzeto: %u) @@ -3080,18 +3011,10 @@ Activating best chain... Preklapljam na najboljšo verigo ... - - Can't run with a wallet in prune mode. - Če je omogočena funkcija obrezovanja, ni mogoče uporabljati denarnice. - Cannot resolve -whitebind address: '%s' Naslova %s, podanega pri opciji -whitebind ni mogoče razrešiti. - - Choose data directory on startup (default: 0) - Ob zagonu pozovi uporabnika, naj izbere podatkovno mapo (privzeto: 0) - Connect through SOCKS5 proxy Poveži se preko posredniškega strežnika SOCKS5 @@ -3100,14 +3023,22 @@ Copyright (C) 2009-%i The Bitcoin Core Developers Copyright (C) 2009-%i The Bitcoin Core Developers - - Could not parse -rpcbind value %s as network address - Vrednost %s opcije -rpcbind ni prepoznaven omrežni naslov - Information Informacije + + Invalid amount for -maxtxfee=<amount>: '%s' + Neveljavna količina za -maxtxfee=<amount>: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Neveljavna količina za -minrelaytxfee=<amount>: '%s' + + + Invalid amount for -mintxfee=<amount>: '%s' + Neveljavna količina za -mintxfee=<amount>: '%s' + Need to specify a port with -whitebind: '%s' Pri opciji -whitebind morate navesti vrata: %s @@ -3116,18 +3047,6 @@ Send trace/debug info to console instead of debug.log file Pošilja sledilne/razhroščevalne informacije na konzolo namesto v datoteko debug.log - - Set SSL root certificates for payment request (default: -system-) - Nastavi korenske certifikate SSL za preverjanje zahtevkov za plačilo (privzeto: -system-) - - - Set language, for example "de_DE" (default: system locale) - Nastavi jezik, npr. "sl_SI" (privzeto: jezik sistema) - - - Show splash screen on startup (default: 1) - Ob zagonu prikaži uvodni zaslon (privzeto: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Ob zagonu skrajšaj datoteko debug.log (privzeto: 1, če ni vklopljena opcija -debug) @@ -3136,10 +3055,6 @@ Signing transaction failed Transakcije ni bilo mogoče podpisati. - - Start minimized - Zaženi v minimiranem oknu - This is experimental software. Program je eksperimentalne narave. @@ -3156,10 +3071,6 @@ Transaction too large Transkacija je prevelika - - UI Options: - Možnosti uporabniškega vmesnika: - Unable to bind to %s on this computer (bind returned error %s) Na tem računalniku ni bilo mogoče vezati naslova %s (vrnjena napaka: %s) @@ -3176,10 +3087,6 @@ Zapping all transactions from wallet... Brišem vse transakcije iz denarnice ... - - on startup - ob zagonu - wallet.dat corrupt, salvage failed Datoteka wallet.dat je poškodovana in je ni bilo mogoče obnoviti. @@ -3192,18 +3099,6 @@ Execute command when the best block changes (%s in cmd is replaced by block hash) Izvedi ukaz, ko je najden najboljši blok (niz %s v ukazu bo zamenjan s hash vrednostjo bloka) - - Upgrade wallet to latest format - Nadgradi denarnico na najnovejšo različico - - - Rescan the block chain for missing wallet transactions - S ponovnim pregledom verige blokov poišči manjkajoče transakcije iz denarnice - - - Use OpenSSL (https) for JSON-RPC connections - Uporabi OpenSSL (https) za povezave na JSON-RPC - This help message To sporočilo pomoči @@ -3228,10 +3123,6 @@ (default: %s) (privzeto: %s) - - Acceptable ciphers (default: %s) - Sprejemljivi tipi šifriranja (privzeto: %s) - Error loading wallet.dat Napaka pri nalaganju wallet.dat diff --git a/src/qt/locale/bitcoin_sq.ts b/src/qt/locale/bitcoin_sq.ts index 6ed985688..994b06599 100644 --- a/src/qt/locale/bitcoin_sq.ts +++ b/src/qt/locale/bitcoin_sq.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -168,6 +168,9 @@ Dekriptimi i portofolit dështoi + + BanTableModel + BitcoinGUI @@ -198,6 +201,10 @@ &Options... &Opsione + + &Receiving addresses... + Duke marr adresen + Change the passphrase used for wallet encryption Ndrysho frazkalimin e përdorur per enkriptimin e portofolit @@ -418,6 +425,10 @@ Options Opsionet + + W&allet + Portofol + OverviewPage @@ -444,6 +455,10 @@ RPCConsole + + &Information + Informacion + &Open &Hap @@ -460,16 +475,28 @@ Unknown i/e panjohur - + ReceiveCoinsDialog + + &Amount: + Shuma: + &Label: &Etiketë: + + Clear + Pastro + ReceiveRequestDialog + + Copy &Address + &Kopjo adresen + Address Adresë @@ -508,6 +535,10 @@ Send Coins Dërgo Monedha + + Insufficient funds! + Fonde te pamjaftueshme + Amount: Shuma: @@ -567,6 +598,10 @@ Alt+P Alt+P + + Pay To: + Paguaj drejt: + ShutdownWindow @@ -618,6 +653,10 @@ Date Data + + Transaction + transaksionit + Amount Sasia @@ -754,6 +793,10 @@ bitcoin-core + + Options: + Opsionet: + Information Informacion diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts index ddaab9ab2..b6ba896b3 100644 --- a/src/qt/locale/bitcoin_sr.ts +++ b/src/qt/locale/bitcoin_sr.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -132,6 +132,9 @@ Лозинка за приступ новчанику је успешно промењена. + + BanTableModel + BitcoinGUI @@ -218,6 +221,10 @@ Tabs toolbar Трака са картицама + + &About Bitcoin Core + O Bitcoin Coru + Up to date Ажурно @@ -334,6 +341,10 @@ Options Поставке + + W&allet + новчаник + &Unit to show amounts in: &Јединица за приказивање износа: @@ -371,10 +382,18 @@ ReceiveCoinsDialog + + &Amount: + Iznos: + &Label: &Етикета + + &Message: + Poruka: + Copy label kopiraj naziv @@ -386,6 +405,10 @@ ReceiveRequestDialog + + Copy &Address + Kopirajte adresu + Address Адреса @@ -398,6 +421,10 @@ Label Етикета + + Message + Poruka + RecentRequestsTableModel @@ -409,6 +436,10 @@ Label Етикета + + Message + Poruka + Amount iznos @@ -447,6 +478,10 @@ SendCoinsEntry + + A&mount: + Iznos: + &Label: &Етикета @@ -510,6 +545,14 @@ label етикета + + Message + Poruka + + + Transaction + transakcije + Amount iznos @@ -750,10 +793,6 @@ Run in the background as a daemon and accept commands Radi u pozadini kao daemon servis i prihvati komande - - Use the test network - Koristi testnu mrežu - Username for JSON-RPC connections Korisničko ime za JSON-RPC konekcije @@ -762,14 +801,6 @@ Password for JSON-RPC connections Lozinka za JSON-RPC konekcije - - Rescan the block chain for missing wallet transactions - Ponovo skeniraj lanac blokova za nedostajuće transakcije iz novčanika - - - Use OpenSSL (https) for JSON-RPC connections - Koristi OpenSSL (https) za JSON-RPC konekcije - This help message Ova poruka Pomoći diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index 013915401..756114351 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -221,6 +221,17 @@ Var vänlig och försök igen. Plånbokens lösenord har ändrats. + + BanTableModel + + IP/Netmask + IP/nätmask + + + Banned Until + Bannad tills + + BitcoinGUI @@ -727,6 +738,10 @@ Var vänlig och försök igen. This label turns red if any recipient receives an amount smaller than %1. Denna etikett blir röd om någon mottagare får ett belopp mindre än %1. + + Can vary +/- %1 satoshi(s) per input. + Kan variera +/- %1 satoshi per inmatning. + yes ja @@ -868,6 +883,34 @@ Var vänlig och försök igen. command-line options kommandoradsalternativ + + UI Options: + UI-inställningar: + + + Choose data directory on startup (default: %u) + Välj datakatalog vid uppstart (standard: %u) + + + Set language, for example "de_DE" (default: system locale) + Ange språk, till exempel "de_DE" (standard: systemspråk) + + + Start minimized + Starta minimerad + + + Set SSL root certificates for payment request (default: -system-) + Ange SSL rotcertifikat för betalningsansökan (standard: -system-) + + + Show splash screen on startup (default: %u) + Visa startbild vid uppstart (standard: %u) + + + Reset all settings changes made over the GUI + Återställ alla inställningar som gjorts över GUI + Intro @@ -1065,6 +1108,34 @@ Var vänlig och försök igen. Port of the proxy (e.g. 9050) Proxyns port (t.ex. 9050) + + Used for reaching peers via: + Används för att nå noder via: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Visas, om den angivna standard-SOCKS5-proxyn används för att nå noder via den här nätverkstypen. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Anslut till Bitcoin-nätverket genom en separat SOCKS5-proxy för dolda tjänster i Tor. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Använd separat SOCKS5-proxy för att nå noder via dolda tjänster i Tor: + &Window &Fönster @@ -1283,10 +1354,6 @@ Var vänlig och försök igen. Payment request %1 is too large (%2 bytes, allowed %3 bytes). Betalningsbegäran %1 är för stor (%2 bytes, tillåten %3 bytes) - - Payment request DoS protection - Betalningsbegäran begär DoS-skydd - Error communicating with %1: %2 Kommunikationsfel med %1: %2 @@ -1439,6 +1506,18 @@ Var vänlig och försök igen. Current number of blocks Aktuellt antal block + + Memory Pool + Minnespool + + + Current number of transactions + Nuvarande antal transaktioner + + + Memory usage + Minnesåtgång + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. Öppna felsökningsloggfilen för Bitcoin Core från den nuvarande datakatalogen. Detta kan ta några sekunder om loggfilen är stor. @@ -1455,10 +1534,18 @@ Var vänlig och försök igen. &Peers &Klienter + + Banned peers + Bannade noder + Select a peer to view detailed information. Välj en klient för att se detaljerad information. + + Whitelisted + Vitlistad + Direction Riktning @@ -1467,6 +1554,18 @@ Var vänlig och försök igen. Version Version + + Starting Block + Startblock + + + Synced Headers + Synkade huvuden + + + Synced Blocks + Synkade block + User Agent Användaragent @@ -1475,14 +1574,6 @@ Var vänlig och försök igen. Services Tjänster - - Starting Height - Starthöjd - - - Sync Height - Synchöjd - Ban Score Banpoäng @@ -1499,18 +1590,18 @@ Var vänlig och försök igen. Last Receive Senast mottagen - - Bytes Sent - Bytes sänt - - - Bytes Received - Bytes mottaget - Ping Time Pingtid + + The duration of a currently outstanding ping. + Tidsåtgången för en nuvarande utestående ping. + + + Ping Wait + Pingväntetid + Time Offset Tidsförskjutning @@ -1559,6 +1650,34 @@ Var vänlig och försök igen. Clear console Rensa konsollen + + &Disconnect Node + &Koppla från nod + + + Ban Node for + Banna nod i + + + 1 &hour + 1 &timme + + + 1 &day + 1 &dag + + + 1 &week + 1 &vecka + + + 1 &year + 1 &år + + + &Unban Node + &Ta bort ban från nod + Welcome to the Bitcoin Core RPC console. Välkommen till RPC-konsolen för Bitcoin Core. @@ -1587,6 +1706,10 @@ Var vänlig och försök igen. %1 GB %1 GB + + (node id: %1) + (nod-id: %1) + via %1 via %1 @@ -1604,16 +1727,24 @@ Var vänlig och försök igen. Utgående - Unknown - Okänd + Yes + Ja - Fetching... - Hämtar... + No + Nej + + + Unknown + Okänd ReceiveCoinsDialog + + &Amount: + &Belopp: + &Label: &Etikett: @@ -1972,8 +2103,8 @@ Var vänlig och försök igen. Kopiera växel - Total Amount %1 (= %2) - Totalt %1 (= %2) + Total Amount %1 + Total summa %1 or @@ -2007,14 +2138,14 @@ Var vänlig och försök igen. Payment request expired. Betalningsbegäran löpte ut. + + Pay only the required fee of %1 + Betala endast den nödvändiga avgiften på %1 + Estimated to begin confirmation within %n block(s). Uppskattas till att påbörja bekräftelse inom %n block.Uppskattas till att påbörja bekräftelse inom %n block. - - Pay only the minimum fee of %1 - Betala endast den minimala avgiften på %1 - The recipient address is not valid. Please recheck. Mottagarens adress är ogiltig. Kontrollera igen. @@ -2098,6 +2229,10 @@ Var vänlig och försök igen. The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally. Avgiften dras från beloppet som skickas. Mottagaren kommer att få mindre bitcoins än du angivit i belopp-fältet. Om flera mottagare valts kommer avgiften delas jämt. + + S&ubtract fee from amount + S&ubtrahera avgiften från beloppet + Message: Meddelande: @@ -2642,6 +2777,10 @@ Var vänlig och försök igen. Copy transaction ID Kopiera transaktions ID + + Copy raw transaction + Kopiera rå transaktion + Edit label Ändra etikett @@ -2789,13 +2928,53 @@ Var vänlig och försök igen. Accept command line and JSON-RPC commands Tillåt kommandon från kommandotolken och JSON-RPC-kommandon + + If <category> is not supplied or if <category> = 1, output all debugging information. + Om <kategori> inte anges eller om <category> = 1, visa all avlusningsinformation. + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Maximal total avgift (i %s) att använda i en plånbokstransaktion. Sätts denna för lågtkan stora transaktioner komma att avbrytas (förvalt: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + Vänligen kontrollera att din dators datum och tid är korrekt! Om din klocka går fel kommer Bitcoin Core inte att fungera ordentligt. + + + Prune configured below the minimum of %d MiB. Please use a higher number. + Beskärning konfigurerad under miniminivån %d MiB. Vänligen använd ett högre värde. + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + Beskärning: sista plånbokssynkroniseringen ligger utanför beskuren data. Du måste använda -reindex (ladda ner hela blockkedjan igen eftersom noden beskurits) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + Minska lagringsbehovet genom att beskära (ta bort) gamla block. Detta läge är inkompatibelt med -txindex och -rescan. Varning: Ändras denna inställning måste hela blockkedjan laddas ner igen. (förvalt: 0 = inaktivera beskärning av block, >%u = målstorlek i MiB att använda för blockfiler) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + Omskanningar kan inte göras i beskuret läge. Du måste använda -reindex vilket kommer ladda ner hela blockkedjan igen. + + + Error: A fatal internal error occurred, see debug.log for details + Fel: Ett kritiskt internt fel uppstod, se debug.log för detaljer + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Avgift (i %s/kB) att lägga till på transaktioner du skickar (förvalt: %s) + + + Pruning blockstore... + Rensar blockstore... + Run in the background as a daemon and accept commands Kör i bakgrunden som tjänst och acceptera kommandon - Use the test network - Använd testnätverket + Unable to start HTTP server. See debug log for details. + Kunde inte starta HTTP-server. Se avlusningsloggen för detaljer. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2817,18 +2996,14 @@ Var vänlig och försök igen. Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Exekvera kommando när en plånbokstransaktion ändras (%s i cmd är ersatt av TxID) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Maximal total avgift att använda i en plånbokstransaktion. Sätts denna för lågt kommer stora transaktioner att avbrytas (förvalt: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Reducera lagringsbehovet genom att beskära (ta bort) gamla block. Detta läge avaktiverar plånbokssupport och är inkompatibel med -txindex. Varning: Ändras denna inställning måste hela blockkedjan laddas ner igen. 0 = avaktivera beskärning av blocks, >%u = målstorlek i MiB att använda för blockfiler) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Ange antalet skriptkontrolltrådar (%u till %d, 0 = auto, <0 = lämna så många kärnor lediga, förval: %d) + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + Blockdatabasen innehåller ett block som verkar vara från framtiden. Detta kan vara på grund av att din dators datum och tid är felaktiga. Bygg bara om blockdatabasen om du är säker på att datorns datum och tid är korrekt + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Detta är ett förhands testbygge - använd på egen risk - använd inte för mining eller handels applikationer @@ -2837,6 +3012,10 @@ Var vänlig och försök igen. Unable to bind to %s on this computer. Bitcoin Core is probably already running. Det går inte att binda till %s på den här datorn. Bitcoin Core är förmodligen redan igång. + + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + Använd UPnP för att mappa den lyssnande porten (förvalt: 1 när lyssning aktiverat och utan -proxy) + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) Varning: Onormalt antal block block genererade. %d block mottagna senaste %d timmarna (%d förväntade) @@ -2845,10 +3024,6 @@ Var vänlig och försök igen. WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) Varning: Kontrollera din närverksanslutning. %d block mottagna senaste %d timmarna, (%d förväntade) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Varning: -paytxfee är satt väldigt hög! Detta är avgiften du kommer betala för varje transaktion. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Varning: Nätverket verkar inte vara helt överens! Några miners verkar ha problem. @@ -2857,10 +3032,6 @@ Var vänlig och försök igen. Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Varning: Vi verkar inte helt överens med våra peers! Du kan behöva uppgradera, eller andra noder kan behöva uppgradera. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Varning: fel vid läsning av wallet.dat! Alla nycklar lästes korrekt, men transaktionsdatan eller adressbokens poster kanske saknas eller är felaktiga. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Varning: wallet.dat korrupt, datan har räddats! Den ursprungliga wallet.dat har sparas som wallet.{timestamp}.bak i %s; om ditt saldo eller transaktioner är felaktiga ska du återställa från en säkerhetskopia. @@ -2870,17 +3041,13 @@ Var vänlig och försök igen. Vitlista klienter som ansluter från angivna nätmasker eller IP-adresser. Kan specificeras flera gånger. - (default: 1) - (förvalt: 1) + -maxmempool must be at least %d MB + -maxmempool måste vara minst %d MB <category> can be: <category> Kan vara: - - Attempt to recover private keys from a corrupt wallet.dat - Försök att rädda de privata nycklarna från en korrupt wallet.dat - Block creation options: Block skapande inställningar: @@ -2891,7 +3058,7 @@ Var vänlig och försök igen. Connection options: - Anslutningsoptioner: + Anslutningsalternativ: Corrupted block database detected @@ -2899,7 +3066,7 @@ Var vänlig och försök igen. Debugging/Testing options: - Avlusnings/Testnings optioner: + Avlusnings/Test-alternativ: Do not load the wallet and disable wallet RPC calls @@ -2909,6 +3076,22 @@ Var vänlig och försök igen. Do you want to rebuild the block database now? Vill du bygga om blockdatabasen nu? + + Enable publish hash block in <address> + Aktivera publicering av hashblock i <adress> + + + Enable publish hash transaction in <address> + Aktivera publicering av hashtransaktion i <adress> + + + Enable publish raw block in <address> + Aktivera publicering av råa block i <adress> + + + Enable publish raw transaction in <address> + Aktivera publicering av råa transaktioner i <adress> + Error initializing block database Fel vid initiering av blockdatabasen @@ -2925,10 +3108,6 @@ Var vänlig och försök igen. Error opening block database Fel vid öppning av blockdatabasen - - Error: A fatal internal error occured, see debug.log for details - Fel: Ett fatalt internt fel inträffade. Se debug.log för detaljer - Error: Disk space is low! Fel: Hårddiskutrymme är lågt! @@ -2937,10 +3116,6 @@ Var vänlig och försök igen. Failed to listen on any port. Use -listen=0 if you want this. Misslyckades att lyssna på någon port. Använd -listen=0 om du vill detta. - - If <category> is not supplied, output all debugging information. - Om <category> inte anges, skrivs all avlusningsinformation ut. - Importing... Importerar... @@ -2953,6 +3128,10 @@ Var vänlig och försök igen. Invalid -onion address: '%s' Ogiltig -onion adress:'%s' + + Keep the transaction memory pool below <n> megabytes (default: %u) + Håll minnespoolen över transaktioner under <n> megabyte (förvalt: %u) + Not enough file descriptors available. Inte tillräckligt med filbeskrivningar tillgängliga. @@ -2981,10 +3160,26 @@ Var vänlig och försök igen. Specify wallet file (within data directory) Ange plånboksfil (inom datakatalogen) + + Unsupported argument -benchmark ignored, use -debug=bench. + Argumentet -benchmark stöds inte och ignoreras, använd -debug=bench. + + + Unsupported argument -debugnet ignored, use -debug=net. + Argumentet -debugnet stöds inte och ignoreras, använd -debug=net. + + + Unsupported argument -tor found, use -onion. + Argumentet -tor hittades men stöds inte, använd -onion. + Use UPnP to map the listening port (default: %u) Använd UPnP för att mappa den lyssnande porten (förvalt: %u) + + User Agent comment (%s) contains unsafe characters. + Kommentaren i användaragent (%s) innehåller osäkra tecken. + Verifying blocks... Verifierar block... @@ -3009,17 +3204,9 @@ Var vänlig och försök igen. You need to rebuild the database using -reindex to change -txindex Du måste återskapa databasen med -reindex för att ändra -txindex - - Imports blocks from external blk000??.dat file - Importerar block från extern blk000??.dat fil - 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 - Tillåt JSON-RPC anslutningar från specifik kalla. Tillåtet för <ip> är enkel IP (t.ex 1.2.3.4), en nätverk/nätmask (t.ex. 1.2.3.4/255.255.255.0) eller ett nätverk/CIDR (t.ex. 1.2.3.4/24). Denna option kan specificeras flera gånger - - - An error occurred while setting up the RPC address %s port %u for listening: %s - Ett fel uppstod vid upprättandet av RPC adress %s port %u för att lyssna: %s + Tillåt JSON-RPC-anslutningar från specifik källa. Tillåtna <ip> är enkel IP (t.ex 1.2.3.4), en nätverk/nätmask (t.ex. 1.2.3.4/255.255.255.0) eller ett nätverk/CIDR (t.ex. 1.2.3.4/24). Detta alternativ anges flera gånger Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 @@ -3027,7 +3214,7 @@ Var vänlig och försök igen. Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces) - Bind till angiven adress för att lyssna på JSON-RPC anslutningar. Använd [värd]:port notation for IPv6. Denna option kan specificeras flera gånger (förvalt: bind till alla gränssnitt) + Bind till angiven adress för att lyssna på JSON-RPC-anslutningar. Använd [värd]:port-format for IPv6. Detta alternativ kan anges flera gånger (förvalt: bind till alla gränssnitt) Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running. @@ -3045,17 +3232,13 @@ Var vänlig och försök igen. Error: Listening for incoming connections failed (listen returned error %s) Fel: Avlyssning av inkommande anslutningar misslyckades (Avlyssningen returnerade felkod %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Fel: Argumentet -socks stöds inte. Att sätta SOCKS version är inte möjligt längre. Endast SOCKS5 proxy stöds. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Exekvera kommando när ett relevant meddelande är mottagen eller när vi ser en väldigt lång förgrening (%s i cmd är utbytt med ett meddelande) - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Avgifter (i BTC/Kb) mindre än detta betraktas som nollavgift för vidarebefodran (förvalt: %s) + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + Avgifter (i %s/kB) mindre än detta betraktas som nollavgift för vidarebefordran, mining och transaktionsskapande (förvalt: %s) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -3069,10 +3252,6 @@ Var vänlig och försök igen. Maximum size of data in data carrier transactions we relay and mine (default: %u) Maximal storlek på data i databärartransaktioner som vi reläar och bryter (förvalt: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - Beskärning konfigurerad under miniminivån %d MB. Var vänlig använd ett högre värde. - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Sök efter klientadresser med DNS sökningen, om det finns otillräckligt med adresser (förvalt: 1 om inte -connect) @@ -3085,6 +3264,10 @@ Var vänlig och försök igen. Set maximum size of high-priority/low-fee transactions in bytes (default: %d) Sätt den maximala storleken av hög-prioriterade/låg-avgifts transaktioner i byte (förvalt: %d) + + Set the number of threads for coin generation if enabled (-1 = all cores, default: %d) + Ange antalet trådar för myntgenerering om påslagen (-1= alla kärnor, förval: %d) + The transaction amount is too small to send after the fee has been deducted Transaktionen är för liten att skicka efter det att avgiften har dragits @@ -3093,41 +3276,9 @@ Var vänlig och försök igen. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användning i OpenSSL Toolkit <https://www.openssl.org/> och kryptografisk mjukvara utvecklad av Eric Young samt UPnP-mjukvara skriven av Thomas Bernard. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - För att använda bitconid,eller -server optionen till bitcoin-qt så mäste du sätta ett rpclösensord i konfigurationsfilen: -%s -Det är rekommenderat att använda följande slumpade lösenord: -rpcuser=bitcoinrpc -rpcpassword=%s -(du behöver inte komma ihåg lösenordet) -Användarnamnet och lösenordet FÅR INTE vara detsamma. -Om filen inte existerar, skapa den med enbart ägarläsbara filrättigheter. -Det är också rekommenderat att sätta alertnotify så du meddelas om problem; -till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Varning: -maxtxfee är satt väldigt hög! Så höga avgifter kan betalas för en enstaka transaktion. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Varning: Vänligen kolla så att din dators datum och tid är korrekt! Om din klocka går fel kommer Bitcoin Core inte att fungera korrekt. - 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 - Vitlistade klienter kan inte bli DoS bannade och deras transaktioner reläas alltid, även om dom redan är i mempoolen, användbart för t.ex en gateway + Vitlistade klienter kan inte bli DoS-bannade och deras transaktioner reläas alltid, även om dom redan är i mempoolen, användbart för t.ex en gateway You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain @@ -3146,17 +3297,21 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Aktiverar bästa kedjan... - Can't run with a wallet in prune mode. - Kan inte köra med en plånbok i beskärningsläge. + Always relay transactions received from whitelisted peers (default: %d) + Vidarebefordra alltid transaktioner från vitlistade noder (förval: %d) + + + Attempt to recover private keys from a corrupt wallet.dat on startup + Försök att rädda privata nycklar från en korrupt wallet.dat vid uppstart + + + Automatically create Tor hidden service (default: %d) + Skapa automatiskt dold tjänst i Tor (förval: %d) Cannot resolve -whitebind address: '%s' Kan inte matcha -whitebind adress: '%s' - - Choose data directory on startup (default: 0) - Välj datakatalog vid uppstart (förvalt: 0) - Connect through SOCKS5 proxy Anslut genom SOCKS5 proxy @@ -3165,10 +3320,6 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Copyright (C) 2009-%i The Bitcoin Core Developers Copyright (C) 2009-%i Bitcoin Core Utvecklarna - - Could not parse -rpcbind value %s as network address - Kunde inte tolka -rpcbind värdet %s som en nätverksadress - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Fel vid inläsningen av wallet.dat: Kontofilen kräver en senare version av Bitcoin Core @@ -3178,12 +3329,8 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Fel vid läsning från databas, avslutar. - Error: Unsupported argument -tor found, use -onion. - Fel: Argumentet -tor stöds inte, använd -onion. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Avgift (i BTC/Kb) att lägga till på transaktioner du skickar (förvalt: %s) + Imports blocks from external blk000??.dat file on startup + Importera block från extern blk000??.dat-fil vid uppstart Information @@ -3223,19 +3370,11 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Node relay options: - Nodreläoptioner: - - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - RPC SSL optioner: (se Bitcoin Wiki för SSL inställningsinstruktioner) + Nodreläalternativ: RPC server options: - RPC serveroptioner: - - - RPC support for HTTP persistent connections (default: %d) - RPC support för HTTP permanent anslutning (förvalt: %d) + RPC-serveralternativ: Rebuild block chain index from current blk000??.dat files on startup @@ -3245,6 +3384,14 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Receive and display P2P network alerts (default: %u) Mottag och visa P2P nätverksvarningar (förvalt: %u) + + Reducing -maxconnections from %d to %d, because of system limitations. + Minskar -maxconnections från %d till %d, på grund av systembegränsningar. + + + Rescan the block chain for missing wallet transactions on startup + Sök i blockkedjan efter saknade plånbokstransaktioner vid uppstart + Send trace/debug info to console instead of debug.log file Skicka trace-/debuginformation till terminalen istället för till debug.log @@ -3253,21 +3400,9 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Send transactions as zero-fee transactions if possible (default: %u) Sänd transaktioner som nollavgiftstransaktioner om möjligt (förvalt: %u) - - Set SSL root certificates for payment request (default: -system-) - Sätt SSL root-certifikat för betalningsbegäran (förvalt: -system-) - - - Set language, for example "de_DE" (default: system locale) - Ändra språk, till exempel "de_DE" (förvalt: systemets språk) - Show all debugging options (usage: --help -help-debug) - Visa alla avlusningsoptioner (använd: --help -help-debug) - - - Show splash screen on startup (default: 1) - Visa startbilden vid uppstart (förvalt: 1) + Visa alla avlusningsalternativ (använd: --help -help-debug) Shrink debug.log file on client startup (default: 1 when no -debug) @@ -3277,10 +3412,6 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Signing transaction failed Signering av transaktion misslyckades - - Start minimized - Starta som minimerad - The transaction amount is too small to pay the fee Transaktionen är för liten för att betala avgiften @@ -3289,6 +3420,14 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com This is experimental software. Detta är experimentmjukvara. + + Tor control port password (default: empty) + Lösenord för Tor-kontrollport (förval: inget) + + + Tor control port to use if onion listening enabled (default: %s) + Tor-kontrollport att använda om onion är aktiverat (förval: %s) + Transaction amount too small Transaktions belopp för liten @@ -3305,17 +3444,13 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Transaction too large Transaktionen är för stor - - UI Options: - UI Alternativ: - Unable to bind to %s on this computer (bind returned error %s) Det går inte att binda till %s på den här datorn (bind returnerade felmeddelande %s) - Use UPnP to map the listening port (default: 1 when listening) - Använd UPnP för att mappa den lyssnande porten (förvalt: 1 under lyssning) + Upgrade wallet to latest format on startup + Uppgradera plånbok till senaste formatet vid uppstart Username for JSON-RPC connections @@ -3330,20 +3465,16 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Varning - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Varning: Argument -benchmark stöds inte och ignoreras, använd -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Varning: Argument -debugnet stöds inte och ignorerad, använd -debug=net. + Whether to operate in a blocks only mode (default: %u) + Ska allt göras i endast block-läge (förval: %u) Zapping all transactions from wallet... Töm plånboken på alla transaktioner... - on startup - under uppstarten + ZeroMQ notification options: + ZeroMQ-alternativ för notiser: wallet.dat corrupt, salvage failed @@ -3357,18 +3488,6 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Execute command when the best block changes (%s in cmd is replaced by block hash) Exekvera kommando när det bästa blocket ändras (%s i cmd är utbytt av blockhash) - - Upgrade wallet to latest format - Uppgradera plånboken till senaste formatet - - - Rescan the block chain for missing wallet transactions - Sök i blockkedjan efter saknade plånboks transaktioner - - - Use OpenSSL (https) for JSON-RPC connections - Använd OpenSSL (https) för JSON-RPC-anslutningar - This help message Det här hjälp medelandet @@ -3389,6 +3508,26 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = spara tx metadata t.ex. kontoägare och betalningsbegäransinformation, 2 = släng tx metadata) + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + -maxtxfee är väldigt högt satt! Så höga avgifter kan komma att betalas för en enstaka transaktion. + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + -paytxfee är väldigt högt satt! Det här är avgiften du kommer betala om du skickar en transaktion. + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + Håll inte transaktioner i minnespoolen längre än <n> timmar (förvalt: %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Fel vid läsning av wallet.dat! Alla nycklar lästes korrekt, men transaktionsdata eller adressbokens poster kanske saknas eller är felaktiga. + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + Avgifter (i %s/kB) mindre än detta anses vara nollavgifter vid skapande av transaktion (standard: %s) + How thorough the block verification of -checkblocks is (0-4, default: %u) Hur grundlig blockverifikationen vid -checkblocks är (0-4, förvalt: %u) @@ -3405,17 +3544,33 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Output debugging information (default: %u, supplying <category> is optional) Skriv ut avlusningsinformation (förvalt: %u, att ange <category> är frivilligt) + + Support filtering of blocks and transaction with bloom filters (default: %u) + Stöd filtrering av block och transaktioner med bloomfilter (standard: %u) + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + Total längd på strängen för nätverksversion (%i) överskrider maxlängden (%i). Minska numret eller storleken på uacomments. + + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + Försöker hålla utgående trafik under givet mål (i MiB per 24 timmar), 0 = ingen gräns (förvalt: %d) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Argumentet -socks hittades och stöds inte. Det är inte längre möjligt att sätta SOCKS-version längre, bara SOCKS5-proxy stöds. + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) Använd separat SOCKS5 proxy för att nå kollegor via dolda tjänster i Tor (förvalt: -%s) - (default: %s) - (förvalt: %s) + 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. This option can be specified multiple times + Användarnamn och hashat lösenord för JSON-RPC-anslutningar. Fältet <userpw> kommer i formatet: <USERNAME>:<SALT>$<HASH>. Ett kanoniskt pythonskript finns inkluderat i share/rpcuser. Detta alternativ kan anges flera gånger - Acceptable ciphers (default: %s) - Accepterbara chiffer (förvalt: %s) + (default: %s) + (förvalt: %s) Always query for peer addresses via DNS lookup (default: %u) @@ -3475,15 +3630,7 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Relay non-P2SH multisig (default: %u) - Reläa icke P2SH multisig (förvalt: %u) - - - Server certificate file (default: %s) - Serverns certifikatfil (förvalt: %s) - - - Server private key (default: %s) - Serverns privata nyckel (förvalt: %s) + Reläa icke-P2SH multisig (förvalt: %u) Set key pool size to <n> (default: %u) diff --git a/src/qt/locale/bitcoin_th_TH.ts b/src/qt/locale/bitcoin_th_TH.ts index 098050296..79a55cdd5 100644 --- a/src/qt/locale/bitcoin_th_TH.ts +++ b/src/qt/locale/bitcoin_th_TH.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -104,6 +104,9 @@ ถอดรหัสกระเป๋าเงินล้มเหลว + + BanTableModel + BitcoinGUI @@ -279,6 +282,10 @@ ReceiveCoinsDialog + + &Label: + &ชื่อ: + ReceiveRequestDialog @@ -315,6 +322,10 @@ SendCoinsEntry + + &Label: + &ชื่อ: + ShutdownWindow @@ -382,5 +393,9 @@ bitcoin-core + + Options: + ตัวเลือก: + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts index dcc82e644..96fca8bb2 100644 --- a/src/qt/locale/bitcoin_tr.ts +++ b/src/qt/locale/bitcoin_tr.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,17 @@ Cüzdan parolası başarılı bir şekilde değiştirildi. + + BanTableModel + + IP/Netmask + IP/Ağ maskesi + + + Banned Until + Şu vakte kadar yasaklı: + + BitcoinGUI @@ -871,6 +882,34 @@ command-line options komut satırı seçenekleri + + UI Options: + Arayüz Seçenekleri: + + + Choose data directory on startup (default: %u) + Başlangıçta veri klasörü seç (varsayılan: %u) + + + Set language, for example "de_DE" (default: system locale) + Lisan belirt, mesela "de_De" (varsayılan: sistem dili) + + + Start minimized + Küçültülmüş olarak başlat + + + Set SSL root certificates for payment request (default: -system-) + Ödeme talebi için SSL kök sertifikalarını belirle (varsayılan: -system-) + + + Show splash screen on startup (default: %u) + Başlatıldığında başlangıç ekranını göster (varsayılan: %u) + + + Reset all settings changes made over the GUI + Arayüzde yapılan tüm seçenek değişikliklerini sıfırla + Intro @@ -1068,6 +1107,34 @@ Port of the proxy (e.g. 9050) Vekil sunucunun portu (mesela 9050) + + Used for reaching peers via: + Eşlere ulaşmak için kullanılır, şu yoluyla: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Bu şebeke türü yoluyla eşlere bağlanmak için belirtilen varsayılan SOCKS5 vekil sunucusunun kullanılıp kullanılmadığını gösterir. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Bitcoin şebekesine gizli Tor servisleri için ayrı bir SOCKS5 vekil sunucusu vasıtasıyla bağlan. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Eşlere gizli Tor servisleri ile ulaşmak için ayrı SOCKS5 vekil sunucusu kullan: + &Window &Pencere @@ -1286,10 +1353,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). %1 ödeme talebi çok büyük (%2 bayt, müsaade edilen %3 bayt). - - Payment request DoS protection - Ödeme talebi DoS koruması - Error communicating with %1: %2 %1 ile iletişimde hata: %2 @@ -1442,6 +1505,18 @@ Current number of blocks Güncel blok sayısı + + Memory Pool + Bellek Alanı + + + Current number of transactions + Güncel muamele sayısı + + + Memory usage + Bellek kullanımı + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. Güncel veri klasöründen Bitcoin Çekirdeği hata ayıklama kütük dosyasını açar. Büyük kütük dosyaları için bu birkaç saniye alabilir. @@ -1458,10 +1533,18 @@ &Peers &Eşler + + Banned peers + Yasaklı eşler + Select a peer to view detailed information. Ayrıntılı bilgi görmek için bir eş seçin. + + Whitelisted + Beyaz listedekiler + Direction Yön @@ -1470,6 +1553,18 @@ Version Sürüm + + Starting Block + Başlangıç Bloku + + + Synced Headers + Eşleşmiş Başlıklar + + + Synced Blocks + Eşleşmiş Bloklar + User Agent Kullanıcı Yazılımı @@ -1478,14 +1573,6 @@ Services Servisler - - Starting Height - Başlama Yüksekliği - - - Sync Height - Eşleşme Yüksekliği - Ban Score Yasaklama Skoru @@ -1502,18 +1589,18 @@ Last Receive Son Alma - - Bytes Sent - Yollanan Baytlar - - - Bytes Received - Alınan Baytlar - Ping Time Ping Süresi + + The duration of a currently outstanding ping. + Güncel olarak göze çarpan bir ping'in süresi. + + + Ping Wait + Ping Beklemesi + Time Offset Saat Farkı @@ -1562,6 +1649,34 @@ Clear console Konsolu temizle + + &Disconnect Node + Düğümle Bağlantıyı &Kes + + + Ban Node for + Düğümü şu süre için yasakla: + + + 1 &hour + 1 &saat + + + 1 &day + 1 &gün + + + 1 &week + 1 &hafta + + + 1 &year + 1 &yıl + + + &Unban Node + Düğümün Yasağını Kald&ır + Welcome to the Bitcoin Core RPC console. Bitcoin Çekirdeği RPC konsoluna hoş geldiniz. @@ -1590,6 +1705,10 @@ %1 GB %1 GB + + (node id: %1) + (düğüm kimliği: %1) + via %1 %1 vasıtasıyla @@ -1607,12 +1726,16 @@ Giden - Unknown - Bilinmiyor + Yes + Evet - Fetching... - Alınıyor... + No + Hayır + + + Unknown + Bilinmiyor @@ -1979,8 +2102,8 @@ Para üstünü kopyala - Total Amount %1 (= %2) - Toplam meblağ %1 (= %2) + Total Amount %1 + Toplam Meblağ %1 or @@ -2015,8 +2138,12 @@ Ödeme talebinin ömrü doldu. - Pay only the minimum fee of %1 - Sadece asgari ücret olan %1 tutarını öde + Pay only the required fee of %1 + Sadece gerekli ücret olan %1 tutarını öde + + + Estimated to begin confirmation within %n block(s). + Tahmini olarak %n blok içinde teyide başlanacaktır.Tahmini olarak %n blok içinde teyide başlanacaktır. The recipient address is not valid. Please recheck. @@ -2649,6 +2776,10 @@ Copy transaction ID Muamele kimliğini kopyala + + Copy raw transaction + Ham muameleyi kopyala + Edit label Etiketi düzenle @@ -2796,13 +2927,53 @@ Accept command line and JSON-RPC commands Komut satırı ve JSON-RPC komutlarını kabul et + + If <category> is not supplied or if <category> = 1, output all debugging information. + Eğer <kategori> belirtilmemişse ya da <kategori> = 1 ise, tüm hata ayıklama verilerini dök. + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Tek cüzdan muamelesinde kullanılacak azami toplam ücret (%s olarak); bunu çok düşük olarak ayarlamak büyük muameleleri iptal edebilir (varsayılan: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + Lütfen bilgisayarınızın saat ve tarihinin doğru olduğunu kontol ediniz! Saatinizde gecikme varsa Bitcoin Çekirdeği doğru şekilde çalışamaz. + + + Prune configured below the minimum of %d MiB. Please use a higher number. + Prune, asgari değer olan %d MiB'den düşük olarak ayarlanmıştır. Lütfen daha yüksek bir sayı kullanınız. + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + Budama: son cüzdan eşleşmesi budanmış verilerin ötesine gitmektedir. -reindex kullanmanız gerekmektedir (Budanmış düğüm ise tüm blok zincirini tekrar indirmeniz gerekir.) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + Depolama gerekliliğini eski blokları budayarak (silerek) düşür. Bu kip -txindex ve -rescan ile uyumsuzdur. İkaz: Bu ayarı geri almak tüm blok zincirini yeniden indirmeyi gerektirir. (varsayılan: 0 = blokları silmeyi devre dışı bırak, >%u = MiB olarak blok dosyaları için kullanılacak hedef boyut) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + Tekrar taramalar budanmış kipte mümkün değildir. Tüm blok zincirini tekrar indirecek olan -reindex seçeneğini kullanmanız gerekecektir. + + + Error: A fatal internal error occurred, see debug.log for details + Hata: Ölümcül dahili bir hata meydana geldi, ayrıntılar için debug.log dosyasına bakınız + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Yolladığınız muamelelere eklenecek ücret (%s/kB olarak) (varsayılan: %s) + + + Pruning blockstore... + Blockstore budanıyor... + Run in the background as a daemon and accept commands Arka planda daemon (servis) olarak çalış ve komutları kabul et - Use the test network - Deneme şebekesini kullan + Unable to start HTTP server. See debug log for details. + HTTP sunucusu başlatılamadı. Ayrıntılar için debug.log dosyasına bakınız. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2824,18 +2995,14 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Bir cüzdan muamelesi değiştiğinde komutu çalıştır (komuttaki %s muamele kimliği ile değiştirilecektir) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Tek cüzdan muamelesinde kullanılacak azami toplam ücret; bunu çok düşük olarak ayarlamak büyük muameleleri iptal edebilir (varsayılan: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Depolama gerekliliğini eski blokları silerek düşür. Bu kip cüzdan desteğini devre dışı bırakır ve -txindex ile uyumsuzdur. İkaz: Bu ayarı geri almak tüm blok zincirini yeniden indirmeyi gerektirir. (varsayılan: 0 = blokları silmeyi devre dışı bırak, >%u = MB olarak blok dosyaları için kullanılacak hedef boyut) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Betik kontrolü iş parçacıklarının sayısını belirler (%u ilâ %d, 0 = otomatik, <0 = bu sayıda çekirdeği kullanma, varsayılan: %d) + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + Blok veritabanı gelecekten gibi görünen bir blok içermektedir. Bu, bilgisayarınızın saat ve tarihinin yanlış ayarlanmış olmasından kaynaklanabilir. Blok veritabanını sadece bilgisayarınızın tarih ve saatinin doğru olduğundan eminseniz yeniden derleyin. + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Bu yayın öncesi bir deneme sürümüdür - tüm riski siz üstlenmiş olursunuz - bitcoin oluşturmak ya da ticari uygulamalar için kullanmayınız @@ -2844,6 +3011,10 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. Bu bilgisayarda %s unsuruna bağlanılamadı. Bitcoin Çekirdeği muhtemelen hâlihazırda çalışmaktadır. + + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + Dinlenecek portu haritalamak için UPnP kullan (varsayılan: dinlenildiğinde ve -proxy olmadığında 1) + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) İKAZ: anormal yüksek sayıda blok oluşturulmuştur, %d blok son %d saat içinde alınmıştır (%d bekleniyordu) @@ -2852,10 +3023,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) İKAZ: ağ bağlantınızı kontrol ediniz, %d blok son %d saat içinde alınmıştır (%d bekleniyordu) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Uyarı: -paytxfee çok yüksek bir değere ayarlanmış! Bu, muamele gönderirseniz ödeyeceğiniz muamele ücretidir. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Uyarı: şebeke tamamen mutabık değil gibi görünüyor! Bazı madenciler sorun yaşıyor gibi görünüyor. @@ -2864,10 +3031,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Uyarı: eşlerimizle tamamen mutabık değiliz gibi görünüyor! Güncelleme yapmanız gerekebilir ya da diğer düğümlerin güncelleme yapmaları gerekebilir. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Uyarı: wallet.dat dosyasının okunması sırasında bir hata meydana geldi! Tüm anahtarlar doğru bir şekilde okundu, ancak muamele verileri ya da adres defteri unsurları hatalı veya eksik olabilir. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Uyarı: wallet.dat bozuk, veriler geri kazanıldı! Özgün wallet.dat, wallet.{zamandamgası}.bak olarak %s klasörüne kaydedildi; bakiyeniz ya da muameleleriniz yanlışsa bir yedeklemeden tekrar yüklemeniz gerekir. @@ -2877,17 +3040,13 @@ Belirtilen ağ maskesi ya da IP adresinden bağlanan eşleri beyaz listeye al. Birden fazla kez belirtilebilir. - (default: 1) - (varsayılan: 1) + -maxmempool must be at least %d MB + -maxmempool asgari %d MB olmalıdır <category> can be: <kategori> şunlar olabilir: - - Attempt to recover private keys from a corrupt wallet.dat - Bozuk bir wallet.dat dosyasından özel anahtarları geri kazanmayı dene - Block creation options: Blok oluşturma seçenekleri: @@ -2916,6 +3075,22 @@ Do you want to rebuild the block database now? Blok veritabanını şimdi yeniden inşa etmek istiyor musunuz? + + Enable publish hash block in <address> + Blok karma değerinin <adres>te yayınlanmasını etkinleştir + + + Enable publish hash transaction in <address> + Karma değer muamelesinin <adres>te yayınlanmasını etkinleştir + + + Enable publish raw block in <address> + Ham blokun <adres>te yayınlanmasını etkinleştir + + + Enable publish raw transaction in <address> + Ham muamelenin <adres>te yayınlanmasını etkinleştir + Error initializing block database Blok veritabanını başlatılırken bir hata meydana geldi @@ -2932,10 +3107,6 @@ Error opening block database Blok veritabanının açılışı sırasında hata - - Error: A fatal internal error occured, see debug.log for details - Hata: Ölümcül dahili bir hata meydana geldi, ayrıntılar için debug.log dosyasına bakınız - Error: Disk space is low! Hata: Disk alanı düşük! @@ -2944,10 +3115,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Herhangi bir portun dinlenmesi başarısız oldu. Bunu istiyorsanız -listen=0 seçeneğini kullanınız. - - If <category> is not supplied, output all debugging information. - <kategori> sağlanmamışsa tüm hata ayıklama verilerini dök. - Importing... İçe aktarılıyor... @@ -2960,6 +3127,10 @@ Invalid -onion address: '%s' Geçersiz -onion adresi: '%s' + + Keep the transaction memory pool below <n> megabytes (default: %u) + Muamele bellek alanını <n> megabayttan düşük tut (varsayılan: %u) + Not enough file descriptors available. Kafi derecede dosya tanımlayıcıları mevcut değil. @@ -2988,10 +3159,26 @@ Specify wallet file (within data directory) Cüzdan dosyası belirtiniz (veri klasörünün içinde) + + Unsupported argument -benchmark ignored, use -debug=bench. + Desteklenmeyen -benchmark argümanı görmezden gelindi, -debug=bench kullanınız. + + + Unsupported argument -debugnet ignored, use -debug=net. + Desteklenmeyen -debugnet argümanı görmezden gelindi, debug=net kullanınız. + + + Unsupported argument -tor found, use -onion. + Deskteklenmeyen -tor argümanı bulundu, -onion kullanınız. + Use UPnP to map the listening port (default: %u) Dinleme portunu haritalamak için UPnP kullan (varsayılan: %u) + + User Agent comment (%s) contains unsafe characters. + Kullanıcı Aracı açıklaması (%s) güvensiz karakterler içermektedir. + Verifying blocks... Bloklar kontrol ediliyor... @@ -3016,18 +3203,10 @@ You need to rebuild the database using -reindex to change -txindex -txindex'i değiştirmek için veritabanını -reindex kullanarak tekrar inşa etmeniz gerekmektedir - - Imports blocks from external blk000??.dat file - Harici blk000??.dat dosyasından blokları içe aktarır - 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 Belirtilen kaynaktan JSON-RPC bağlantılarını kabul et. Bir <ip> için geçerli olanlar şunlardır: salt IP adresi (mesela 1.2.3.4), bir şebeke/ağ maskesi (örneğin 1.2.3.4/255.255.255.0) ya da bir şebeke/CIDR (mesela 1.2.3.4/24). Bu seçenek birden fazla kez belirtilebilir - - An error occurred while setting up the RPC address %s port %u for listening: %s - Dinleme için RPC adresi %s port %u kurulurken bir hata meydana geldi: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Belirtilen adrese bağlan ve ona bağlanan eşleri beyaz listeye al. IPv6 için [makine]:port imlasını kullanınız @@ -3052,17 +3231,13 @@ Error: Listening for incoming connections failed (listen returned error %s) Hata: İçeri gelen bağlantıların dinlenmesi başarısız oldu (dinleme %s hatasını verdi) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Hata: Desteklenmeyen -socks argümanı bulundu. SOCKS sürümünün ayarlanması artık mümkün değildir, sadece SOCKS5 vekilleri desteklenmektedir. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) İlgili bir uyarı alındığında ya da gerçekten uzun bir çatallama gördüğümüzde komutu çalıştır (komuttaki %s mesaj ile değiştirilir) - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Kb başına BTC olarak bundan düşük ücretler aktarım için sıfır değerinde ücret olarak kabul edilir (varsayılan: %s) + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + Bundan düşük ücretler (%s/kB olarak) aktarma, oluşturma ve muamele yaratma için sıfır değerinde ücret olarak kabul edilir (varsayılan: %s) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -3076,10 +3251,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) Aktardığımız ve oluşturduğumuz veri taşıyıcı muamelelerindeki azami veri boyutu (varsayılan: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - Prune, asgari değer olan %d MB'den düşük olarak ayarlanmıştır. Lütfen daha yüksek bir sayı kullanınız. - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Adres sayısı azaldıysa DNS sorgulamasıyla eş adresleri ara (varsayılan: 1 -connect kullanılmadıysa) @@ -3104,38 +3275,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Bu ürün OpenSSL projesi tarafından OpenSSL araç takımı (http://www.openssl.org/) için geliştirilen yazılımlar, Eric Young (eay@cryptsoft.com) tarafından hazırlanmış şifreleme yazılımları ve Thomas Bernard tarafından programlanmış UPnP yazılımı içerir. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - bitcoind ya da bitcoin-qt ile -server seçeneğini kullanmak için yapılandırma dosyasında bir rpc parolası belirtmeniz gerekir: -%s -Aşağıdaki rastgele oluşturulan parolayı kullanmanız tavsiye edilir: -rpcuser=bitcoinrpc -rpcpassword=%s -(bu parolayı hatırlamanız gerekli değildir) -Kullanıcı ismi ile parolanın FARKLI olmaları gerekir. -Dosya mevcut değilse, sadece sahibi için okumayla sınırlı izin ile oluşturunuz. -Sorunlar hakkında bildiri almak için alertnotify unsurunu ayarlamanız tavsiye edilir; -mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - İkaz: -maxtxfee çok yüksek bir değere ayarlanmış! Bu denli yüksek ücretler tek bir muamelede ödenebilir. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Uyarı: Lütfen bilgisayarınızın saat ve tarihinin doğru olduğunu kontol ediniz! Saatinizde gecikme varsa Bitcoin Çekirdeği doğru şekilde çalışamaz. - 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 Beyaz listeye alınan eşler DoS yasaklamasına uğramazlar ve muameleleri zaten mempool'da olsalar da daima aktarılır, bu mesela bir geçit için kullanışlıdır @@ -3157,17 +3296,21 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com En iyi zincir etkinleştiriliyor... - Can't run with a wallet in prune mode. - Prune kipindeki bir cüzdan ile çalışamaz. + Always relay transactions received from whitelisted peers (default: %d) + Beyaz listedeki eşlerden gelen muameleleri daima aktar (varsayılan: %d) + + + Attempt to recover private keys from a corrupt wallet.dat on startup + Başlangıçta bozuk bir wallet.dat dosyasından özel anahtarları geri kazanmayı dene + + + Automatically create Tor hidden service (default: %d) + Otomatik olarak gizli Tor servisi oluştur (varsayılan: %d) Cannot resolve -whitebind address: '%s' -whitebind adresi çözümlenemedi: '%s' - - Choose data directory on startup (default: 0) - Başlangıçta veri klasörü seç (varsayılan: 0) - Connect through SOCKS5 proxy SOCKS5 vekil sunucusu vasıtasıyla bağlan @@ -3176,10 +3319,6 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Copyright (C) 2009-%i The Bitcoin Core Developers Telif hakkı 2009-%i Bitcoin Çekirdeği Geliştiricileri - - Could not parse -rpcbind value %s as network address - -rpcbind değeri %s şebeke adresi olarak ayrıştırılamadı - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core wallet.dat dosyasının yüklenmesinde hata: Cüzdan Bitcoin Çekirdeğinin daha yeni bir sürümünü gerektirmektedir @@ -3189,12 +3328,8 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Veritabanından okumada hata, kapatılıyor. - Error: Unsupported argument -tor found, use -onion. - Hata: Deskteklenmeyen -tor argümanı bulundu, -onion kullanınız. - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Yolladığınız muamelelere kB başına BTC olarak eklenecek ücret (varsayılan: %s) + Imports blocks from external blk000??.dat file on startup + Başlangıçta harici blk000??.dat dosyasından blokları içe aktarır Information @@ -3236,18 +3371,10 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Node relay options: Düğüm röle seçenekleri: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - RPC SSL seçenekleri: (SSL kurulumu yönergeleri için Bitcoin vikisine bakınız) - RPC server options: RPC sunucu seçenekleri: - - RPC support for HTTP persistent connections (default: %d) - Kalıcı HTTP bağlantıları için RPC desteği (varsayılan: %d) - Rebuild block chain index from current blk000??.dat files on startup Başlangıçta blok zinciri indeksini güncel blk000??.dat dosyalarından tekrar inşa et @@ -3256,6 +3383,14 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Receive and display P2P network alerts (default: %u) P2P ağından gelen önemli uyarıları alın ve gösterin (önseçili değer: %u) + + Reducing -maxconnections from %d to %d, because of system limitations. + Sistem sınırlamaları sebebiyle -maxconnections %d değerinden %d değerine düşürülmüştür. + + + Rescan the block chain for missing wallet transactions on startup + Başlangıçta blok zincirini eksik cüzdan muameleleri için tekrar tara + Send trace/debug info to console instead of debug.log file Trace/hata ayıklama verilerini debug.log dosyası yerine konsola gönder @@ -3264,22 +3399,10 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Send transactions as zero-fee transactions if possible (default: %u) Muameleleri mümkünse ücretsiz olarak gönder (varsayılan: %u) - - Set SSL root certificates for payment request (default: -system-) - Ödeme talebi için SSL kök sertifikalarını belirle (varsayılan: -system-) - - - Set language, for example "de_DE" (default: system locale) - Lisan belirt, mesela "de_De" (varsayılan: sistem dili) - Show all debugging options (usage: --help -help-debug) Tüm hata ayıklama seçeneklerini göster (kullanımı: --help -help-debug) - - Show splash screen on startup (default: 1) - Başlatıldığında başlangıç ekranını göster (varsayılan: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) İstemci başlatıldığında debug.log dosyasını küçült (varsayılan: -debug bulunmadığında 1) @@ -3288,10 +3411,6 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Signing transaction failed Muamelenin imzalanması başarısız oldu - - Start minimized - Küçültülmüş olarak başlat - The transaction amount is too small to pay the fee Muamele meblağı ücreti ödemek için çok düşük @@ -3300,6 +3419,14 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com This is experimental software. Bu, deneysel bir yazılımdır. + + Tor control port password (default: empty) + Tor kontrol portu parolası (varsayılan: boş) + + + Tor control port to use if onion listening enabled (default: %s) + Eğer onion dinlenmesi etkinse kullanılacak Tor kontrol portu (varsayılan: %s) + Transaction amount too small Muamele meblağı çok düşük @@ -3316,17 +3443,13 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Transaction too large Muamele çok büyük - - UI Options: - Arayüz Seçenkleri: - Unable to bind to %s on this computer (bind returned error %s) Bu bilgisayarda %s unsuruna bağlanılamadı (bağlanma %s hatasını verdi) - Use UPnP to map the listening port (default: 1 when listening) - Dinlenecek portu haritalamak için UPnP kullan (varsayılan: dinlenildiğinde 1) + Upgrade wallet to latest format on startup + Başlangıçta cüzdanı en yeni biçime güncelle Username for JSON-RPC connections @@ -3341,20 +3464,16 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Uyarı - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Uyarı: Deskteklenmeyen -benchmark argümanı görmezden gelindi, -debug=bench kullanınız. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Uyarı: Desteklenmeyen -debugnet argümanı görmezden gelindi, debug=net kullanınız. + Whether to operate in a blocks only mode (default: %u) + Salt blok kipinde çalışılıp çalışılmayacağı (varsayılan: %u) Zapping all transactions from wallet... Cüzdandaki tüm muameleler kaldırılıyor... - on startup - başlangıçta + ZeroMQ notification options: + ZeroMQ bildirim seçenekleri: wallet.dat corrupt, salvage failed @@ -3368,18 +3487,6 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Execute command when the best block changes (%s in cmd is replaced by block hash) En iyi blok değiştiğinde komutu çalıştır (komut için %s parametresi blok hash değeri ile değiştirilecektir) - - Upgrade wallet to latest format - Cüzdanı en yeni biçime güncelle - - - Rescan the block chain for missing wallet transactions - Blok zincirini eksik cüzdan muameleleri için tekrar tara - - - Use OpenSSL (https) for JSON-RPC connections - JSON-RPC bağlantıları için OpenSSL (https) kullan - This help message Bu yardım mesajı @@ -3400,6 +3507,26 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = tx meta verilerini tut mesela hesap sahibi ve ödeme talebi bilgileri, 2 = tx meta verilerini at) + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + -maxtxfee çok yüksek bir değere ayarlanmış! Bu denli yüksek ücretler tek bir muamelede ödenebilir. + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + -paytxfee çok yüksek bir değere ayarlanmış! Bu, muamele gönderirseniz ödeyeceğiniz muamele ücretidir. + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + Muameleleri bellek alanında <n> saatten fazla tutma (varsayılan: %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + wallet.dat dosyasının okunması sırasında bir hata meydana geldi! Tüm anahtarlar doğru bir şekilde okundu, ancak muamele verileri ya da adres defteri unsurları hatalı veya eksik olabilir. + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + Bundan düşük ücretler (%s/kB olarak) muamele oluşturulması için sıfır değerinde ücret olarak kabul edilir (varsayılan: %s) + How thorough the block verification of -checkblocks is (0-4, default: %u) -checkblocks'un blok kontrolünün ne kadar kapsamlı olacağı (0 ilâ 4, varsayılan: %u) @@ -3416,17 +3543,33 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Output debugging information (default: %u, supplying <category> is optional) Hata ayıklama bilgisi dök (varsayılan: %u, <kategori> sağlanması seçime dayalıdır) + + Support filtering of blocks and transaction with bloom filters (default: %u) + Blokların ve muamelelerin bloom filtreleri ile süzülmesini destekle (varsayılan: %u) + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + Şebeke sürümü zincirinin toplam boyutu (%i) azami boyutu geçmektedir (%i). Kullanıcı aracı açıklamasının sayısı veya boyutunu azaltınız. + + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + Giden trafiği belirtilen hedefin altında tutmaya çalışır (24 saat başı MiB olarak), 0 = sınırsız (varsayılan: %d) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Desteklenmeyen -socks argümanı bulundu. SOCKS sürümünün ayarlanması artık mümkün değildir, sadece SOCKS5 vekilleri desteklenmektedir. + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) Eşlere gizli Tor servisleri ile ulaşmak için ayrı SOCKS5 vekil sunucusu kullan (varsayılan: %s) - (default: %s) - (varsayılan: %s) + 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. This option can be specified multiple times + JSON-RPC bağlantıları için kullanıcı ismi ve karmalanmış parola. <userpw> alanı şu biçimdedir: <USERNAME>:<SALT>$<HASH>. Kanonik bir Python betiği share/rpcuser klasöründe bulunabilir. Bu seçenek birden çok kez belirtilebilir. - Acceptable ciphers (default: %s) - Kabul edilebilir şifreler (varsayılan: %s) + (default: %s) + (varsayılan: %s) Always query for peer addresses via DNS lookup (default: %u) @@ -3488,14 +3631,6 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Relay non-P2SH multisig (default: %u) P2SH olmayan çoklu imzaları aktar (varsayılan: %u) - - Server certificate file (default: %s) - Sunucu sertifika dosyası (varsayılan: %s) - - - Server private key (default: %s) - Sunucu özel anahtarı (varsayılan: %s) - Set key pool size to <n> (default: %u) Anahtar alan boyutunu <n> değerine ayarla (varsayılan: %u) diff --git a/src/qt/locale/bitcoin_tr_TR.ts b/src/qt/locale/bitcoin_tr_TR.ts new file mode 100644 index 000000000..10866b011 --- /dev/null +++ b/src/qt/locale/bitcoin_tr_TR.ts @@ -0,0 +1,281 @@ + + + AddressBookPage + + Right-click to edit address or label + Adresi veya etiketi düzenlemek için sağ tıklayın + + + Create a new address + Yeni adres oluştur + + + &New + &Yeni + + + Copy the currently selected address to the system clipboard + Seçili adresi panoya kopyala + + + &Copy + &Kopyala + + + C&lose + K&apat + + + &Copy Address + &Adresi Kopyala + + + Delete the currently selected address from the list + Seçili adresi listeden sil + + + Export the data in the current tab to a file + Seçili sekmedeki veriyi dosya olarak dışa aktar + + + &Export + &Dışa Aktar + + + &Delete + &Sil + + + Choose the address to send coins to + Para göndereceğiniz adresi seçin + + + Choose the address to receive coins with + Parayı alacağınız adresi seçin + + + C&hoose + S&eç + + + Sending addresses + Gönderim adresleri + + + Receiving addresses + Alış adresleri + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Bunlar ödeme gönderebileceğiniz Bitcoin adreslerinizdir. Para göndermeden önce mutlaka alıcı adresini ve tutarı kontrol edin. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Bunlar ödeme alabileceğiniz Bitcoin adreslerinizdir. Her işlem için yeni bir adres kullanmanız önerilir. + + + Copy &Label + Kopyala &Etiketle + + + &Edit + &Düzenle + + + Export Address List + Adres Listesini Dışa Aktar + + + Exporting Failed + Dışa Aktarma Başarısız Oldu + + + There was an error trying to save the address list to %1. Please try again. + Adres listesini %1'e kaydederken bir hata oluştu. Lütfen tekrar deneyin. + + + + AddressTableModel + + Label + Etiket + + + Address + Adres + + + (no label) + (etiket yok) + + + + AskPassphraseDialog + + + BanTableModel + + + BitcoinGUI + + &Receiving addresses... + Alış adresleri + + + + ClientModel + + + CoinControlDialog + + (no label) + (etiket yok) + + + + EditAddressDialog + + &Label + Etiket + + + &Address + Adres + + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + Copy &Address + &Adresi Kopyala + + + Address + Adres + + + Label + Etiket + + + + RecentRequestsTableModel + + Label + Etiket + + + (no label) + (etiket yok) + + + + SendCoinsDialog + + (no label) + (etiket yok) + + + + SendCoinsEntry + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + Label + Etiket + + + + TransactionView + + Exporting Failed + Dışa Aktarma Başarısız Oldu + + + Label + Etiket + + + Address + Adres + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + &Export + &Dışa Aktar + + + Export the data in the current tab to a file + Seçili sekmedeki veriyi dosya olarak dışa aktar + + + + bitcoin-core + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts index 21ab4ac19..ea783aa85 100644 --- a/src/qt/locale/bitcoin_uk.ts +++ b/src/qt/locale/bitcoin_uk.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,17 @@ Пароль було успішно змінено. + + BanTableModel + + IP/Netmask + IP/Маска підмережі + + + Banned Until + Заблоковано До + + BitcoinGUI @@ -871,6 +882,34 @@ command-line options параметри командного рядка + + UI Options: + Параметри інтерфейсу: + + + Choose data directory on startup (default: %u) + Обирати каталог даних під час запуску (типово: %u) + + + Set language, for example "de_DE" (default: system locale) + Встановити мову (наприклад: "de_DE") (типово: системна) + + + Start minimized + Запускати згорнутим + + + Set SSL root certificates for payment request (default: -system-) + Вказати кореневі SSL-сертифікати для запиту платежу (типово: -системні-) + + + Show splash screen on startup (default: %u) + Показувати заставку під час запуску (типово: %u) + + + Reset all settings changes made over the GUI + Скинути налаштування, які було змінено через графічний інтерфейс користувача + Intro @@ -1068,6 +1107,34 @@ Port of the proxy (e.g. 9050) Порт проксі-сервера (наприклад 9050) + + Used for reaching peers via: + Приєднуватися до учасників через: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Вказує на використання наявного типового проксі SOCKS5, що використувується задля встановлення зв'язку з пірами через мережу такого типу. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Підключатися до мережі Bitcoin через окремий SOCKS5 проксі для прихованих сервісів Tor. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Використовувати окремий SOCKS5-проксі для з'єднання з учасниками через приховані сервіси Tor: + &Window &Вікно @@ -1286,10 +1353,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). Запит платежу %1 занадто великий (%2 байт, дозволено %3 байт). - - Payment request DoS protection - Оплата потребує захисту DoS - Error communicating with %1: %2 Помилка зв'язку з %1: %2 @@ -1442,6 +1505,18 @@ Current number of blocks Поточне число блоків + + Memory Pool + Пул пам'яті + + + Current number of transactions + Поточне число транзакцій + + + Memory usage + Використання пам'яті + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. Відкрити файл журналу налагодження Bitcoin Core з поточного каталогу даних. Це може зайняти кілька секунд для великих файлів журналів. @@ -1458,10 +1533,18 @@ &Peers &Учасники + + Banned peers + Заблоковані вузли + Select a peer to view detailed information. Виберіть учасника для перегляду детальнішої інформації + + Whitelisted + В білому списку + Direction Напрямок @@ -1470,6 +1553,18 @@ Version Версія + + Starting Block + Початковий Блок + + + Synced Headers + Синхронізовані Заголовки + + + Synced Blocks + Синхронізовані Блоки + User Agent Клієнт користувача @@ -1478,14 +1573,6 @@ Services Сервіси - - Starting Height - Початкова висота - - - Sync Height - Висота синхронізації - Ban Score Очки бану @@ -1502,18 +1589,18 @@ Last Receive Востаннє отримано - - Bytes Sent - Байтів відправлено - - - Bytes Received - Байтів отримано - Ping Time Затримка + + The duration of a currently outstanding ping. + Тривалість поточної затримки. + + + Ping Wait + Поточна Затримка + Time Offset Різниця часу @@ -1562,6 +1649,34 @@ Clear console Очистити консоль + + &Disconnect Node + &Від'єднати Вузол + + + Ban Node for + Заблокувати Вузол на + + + 1 &hour + 1 &годину + + + 1 &day + 1 &день + + + 1 &week + 1 &тиждень + + + 1 &year + 1 &рік + + + &Unban Node + &Розблокувати Вузол + Welcome to the Bitcoin Core RPC console. Вітаємо у RPC-консолі Bitcoin Core. @@ -1590,6 +1705,10 @@ %1 GB %1 ГБ + + (node id: %1) + (ІД вузла: %1) + via %1 через %1 @@ -1607,12 +1726,16 @@ Вихідний - Unknown - Невідома + Yes + Так - Fetching... - Отримання... + No + Ні + + + Unknown + Невідома @@ -1979,8 +2102,8 @@ Копіювати решту - Total Amount %1 (= %2) - Всього %1 (= %2) + Total Amount %1 + Всього %1 or @@ -2014,14 +2137,14 @@ Payment request expired. Запит платежу прострочено. + + Pay only the required fee of %1 + Сплатіть лише мінімальну комісію у розмірі %1 + Estimated to begin confirmation within %n block(s). Перше підтвердження очікується протягом %n блоку.Перше підтвердження очікується протягом %n блоків.Перше підтвердження очікується протягом %n блоків. - - Pay only the minimum fee of %1 - Платити тільки мінімальну комісію у розмірі %1 - The recipient address is not valid. Please recheck. Адреса отримувача неправильна. Будь ласка, перевірте її. @@ -2653,6 +2776,10 @@ Copy transaction ID Скопіювати ID транзакції + + Copy raw transaction + Скопіювати RAW транзакцію + Edit label Редагувати мітку @@ -2800,13 +2927,53 @@ Accept command line and JSON-RPC commands Приймати команди із командного рядка та команди JSON-RPC + + If <category> is not supplied or if <category> = 1, output all debugging information. + Якщо <category> не задано, або ж якщо <category> = 1, виводить всю налагоджувальну інформацію. + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + Максимальна загальна комісія (в %s) за одну транзакцію; занадто низьке значення може скасувати відправку великих транзакцій (типово: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + Будь ласка, перевірте коректність дати і часу на своєму комп'ютері! За наявності значної похибки Bitcoin Core буде працювати неправильно. + + + Prune configured below the minimum of %d MiB. Please use a higher number. + Встановлений розмір ланцюжка блоків є замалим (меншим за %d МіБ). Будь ласка, виберіть більше число. + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + Операція відсікання: остання синхронізація вмісту гаманцю не обмежується діями над скороченими данними. Вам необхідно зробити переіндексацію -reindex (заново завантажити веcь ланцюжок блоків в разі появи скороченого ланцюга) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + Зменшити вимоги до наявного простору на носії даних за допомогою скорочення ланцюжка (видалення старих блоків). Цей режим несумісний з параметрами -txindex та -rescan. Увага: при поверненні до типового значення видалені частини ланцюжка буде повторно завантажено. (типово: 0 = вимкнути скорочення ланцюжка, >%u = очікуваний розмір файлів блоків в МіБ) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + Неможливо провести повторне сканування зі скороченим ланцюжком. Вам необхідно використати -reindex для завантаження повного ланцюжка блоків. + + + Error: A fatal internal error occurred, see debug.log for details + Помилка: Сталася фатальна помилка (детальніший опис наведено в debug.log) + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Комісія (в %s/КБ), що додаватиметься до вихідних транзакцій (типово: %s) + + + Pruning blockstore... + Скорочення кількості блоків... + Run in the background as a daemon and accept commands Запустити в фоновому режимі (як демон) та приймати команди - Use the test network - Використовувати тестову мережу + Unable to start HTTP server. See debug log for details. + Неможливо запустити HTTP-сервер. Детальніший опис наведено в журналі зневадження. Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2828,18 +2995,14 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Виконати команду, коли транзакція гаманця зміниться (замість %s в команді буде підставлено ідентифікатор транзакції) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - Максимальна загальна комісія за одну транзакцію; занадто низьке значення може скасувати відправку великих транзакцій (типово: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Зменшити вимоги до наявного простору на носії даних за допомогою скорочення ланцюжка (видалення старих блоків). Цей режим вимикає підтримку гаманця та є несумісним з параметром -txindex. Увага: при поверненні до типового значення видалені частини ланцюжка буде повторно завантажено. (типово: 0 = вимкнути скорочення ланцюжка, >%u = очікуваний розмір файлів блоків в МіБ) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Встановити кількість потоків скрипту перевірки (від %u до %d, 0 = автоматично, <0 = вказує кількість вільних ядер, типово: %d) + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + Схоже, що база даних блоків містить блок з майбутнього. Це може статися із-за некоректно встановленої дати та/або часу. Перебудовуйте базу даних блоків лише тоді, коли ви переконані, що встановлено правильну дату і час + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Це тестова збірка пре-релізної версії - використовуйте на свій страх і ризик - не застосовувати для добування монет або торгівлі @@ -2848,6 +3011,10 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. Неможливо прив'язатися до %s на цьому комп'ютері. Можливо, Bitcoin Core вже запущено. + + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + Використовувати UPnP для відображення порту, що прослуховується (типово: 1 при прослуховуванні та за відсутності -proxy) + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) УВАГА: аномально висока кількість згенерованих блоків, %d блок(ів) було отримано за останні %d годин(и) (має бути %d) @@ -2856,10 +3023,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) УВАГА: перевірте ваше мережеве з'єднання, %d блок(ів) було отримано за останні %d годин(и) (має бути %d) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - Увага: встановлено занадто велику комісію (-paytxfee). Комісія зніматиметься кожен раз коли ви проводитимете транзакції. - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. Увага: Частина мережі використовує інший головний ланцюжок! Деякі добувачі, можливо, зазнають проблем. @@ -2868,10 +3031,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Увага: Наш ланцюжок блоків відрізняється від ланцюжків підключених учасників! Можливо, вам, або іншим вузлам, необхідно оновитися. - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Увага: помилка читання wallet.dat! Всі ключі прочитано коректно, але дані транзакцій чи записи адресної книги можуть бути пропущені, або пошкоджені. - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. Увага: файл wallet.dat пошкоджено, дані врятовано! Оригінальний wallet.dat збережено як wallet.{timestamp}.bak до %s; якщо Ваш баланс чи транзакції неправильні, Ви можете відновити їх з резервної копії. @@ -2881,17 +3040,13 @@ Додати учасників, що під'єднуються з заданої підмережі чи IP-адреси, в білий список. Можна вказувати декілька разів. - (default: 1) - (типово: 1) + -maxmempool must be at least %d MB + -maxmempool має бути не менше %d МБ <category> can be: <category> може бути: - - Attempt to recover private keys from a corrupt wallet.dat - Спроба відновити закриті ключі з пошкодженого wallet.dat - Block creation options: Опції створення блоку: @@ -2920,6 +3075,22 @@ Do you want to rebuild the block database now? Ви хочете перебудувати базу даних блоків зараз? + + Enable publish hash block in <address> + Дозволено введення хеш блоку в рядок <address> + + + Enable publish hash transaction in <address> + Дозволено введення хеш транзакції в рядок <address> + + + Enable publish raw block in <address> + Дозволено введення RAW блоку в рядок <address> + + + Enable publish raw transaction in <address> + Дозволено введення RAW транзакції в рядок <address> + Error initializing block database Помилка ініціалізації бази даних блоків @@ -2936,10 +3107,6 @@ Error opening block database Помилка відкриття блоку бази даних - - Error: A fatal internal error occured, see debug.log for details - Помилка: Сталася фатальна помилка (детальніший опис наведено в debug.log) - Error: Disk space is low! Помилка: Мало вільного місця на диску! @@ -2948,10 +3115,6 @@ Failed to listen on any port. Use -listen=0 if you want this. Не вдалося слухати на жодному порту. Використовуйте -listen=0, якщо ви хочете цього. - - If <category> is not supplied, output all debugging information. - Якщо <category> не задано, виводить всю налагоджувальну інформацію. - Importing... Імпорт... @@ -2964,6 +3127,10 @@ Invalid -onion address: '%s' Помилка в адресі -onion: «%s» + + Keep the transaction memory pool below <n> megabytes (default: %u) + Утримувати розмір пам'яті для пулу транзакцій меншим за <n> мегабайтів (типово: %u) + Not enough file descriptors available. Бракує доступних дескрипторів файлів. @@ -2992,9 +3159,25 @@ Specify wallet file (within data directory) Вкажіть файл гаманця (в межах каталогу даних) + + Unsupported argument -benchmark ignored, use -debug=bench. + Параметр -benchmark не підтримується та буде проігноровано; використовуйте -debug=bench. + + + Unsupported argument -debugnet ignored, use -debug=net. + Параметр -debugnet не підтримується та буде проігноровано; використовуйте -debug=net. + + + Unsupported argument -tor found, use -onion. + Параметр -tor не підтримується; використовуйте -onion. + Use UPnP to map the listening port (default: %u) - Намагатись використовувати UPnP для відображення порту, що прослуховується, на роутері (типово: %u) + Використовувати UPnP для відображення порту, що прослуховується (типово: %u) + + + User Agent comment (%s) contains unsafe characters. + Коментар до Клієнта Користувача (%s) містить небезпечні символи. Verifying blocks... @@ -3020,18 +3203,10 @@ You need to rebuild the database using -reindex to change -txindex Вам необхідно перебудувати базу даних з використанням -reindex для того, щоб змінити -txindex - - Imports blocks from external blk000??.dat file - Імпорт блоків з зовнішнього файлу blk000??.dat - 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 Дозволити підключення по протоколу JSON-RPC зі вказаного джерела. Правильною для <ip> є окрема IP-адреса (наприклад, 1.2.3.4), IP-адреса та маска підмережі (наприклад, 1.2.3.4/255.255.255.0) або CIDR-адреса (наприклад, 1.2.3.4/24). Цей параметр можна вказувати декілька разів. - - An error occurred while setting up the RPC address %s port %u for listening: %s - Сталася помилка при спробі відкрити порт RPC-адреси %s:%u для прослуховування: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 Прив'язатися до даної адреси та вносити до білого списку учасників, що під'єднуються до неї. Використовуйте запис виду [хост]:порт для IPv6 @@ -3056,17 +3231,13 @@ Error: Listening for incoming connections failed (listen returned error %s) Помилка: Не вдалося налаштувати прослуховування вхідних підключень (listen повернув помилку: %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Помилка: Параметр -socks не підтримується. Можливість вказувати версію SOCKS було видалено, так як підтримується лише SOCKS5. - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) Виконати команду при надходженні важливого сповіщення або при спостереженні тривалого розгалуження ланцюжка (замість %s буде підставлено повідомлення) - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - Комісії (в BTC/КБ), що менші за вказану, вважатимуться нульовими (для ретрансляції) (типово: %s) + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + Комісії (в %s/kB), що менші за вказану, вважатимуться нульовими для зміни, аналізу та створення транзакцій (типово: %s) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -3080,10 +3251,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) Максимальний розмір даних в транзакціях носіїв даних, що ми передаємо і добуваємо (за замовчуванням: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - Встановлений розмір ланцюжка блоків є замалим (менший за %d МБ). Будь ласка, виберіть більше число. - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Дізнаватися адреси учасників через DNS при замалій кількості відомих адрес (типово: 1 за відсутності -connect) @@ -3108,38 +3275,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Цей продукт включає в себе програмне забезпечення, розроблене в рамках проекту OpenSSL <https://www.openssl.org/>, криптографічне програмне забезпечення, написане Еріком Янгом, та функції для роботи з UPnP, написані Томасом Бернардом. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - Для використання bitcoind, або bitcoin-qt з параметром -server, ви повинні встановити rpcpassword в файлі конфігурації: -%s -Рекомендується використати такий випадковий пароль: -rpcuser=bitcoinrpc -rpcpassword=%s -(вам не треба запам'ятовувати цей пароль) -Ім'я користувача та пароль ПОВИННІ бути різними. -Якщо файлу не існує, створіть його, обмеживши доступ правом читання для власника. -Також рекомендується використовувати alertnotify для того, щоб отримувати сповіщення про проблеми; -наприклад: alertnotify=echo %%s | mail -s "Сповіщення Bitcoin" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Увага: установлено дуже велике значення -maxtxfee! Такі великі комісії можуть бути сплачені в окремій транзакції. - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - Увага: будь ласка, перевірте дату і час на своєму комп'ютері! Якщо ваш годинник йде неправильно, Bitcoin Core може працювати некоректно. - 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 Учасники, що знаходяться в білому списку, не можуть бути заблоковані за DoS та їхні транзакції завжди ретранслюватимуться (навіть якщо вони є в пам'яті), що може бути корисним, наприклад, для шлюзу @@ -3161,17 +3296,21 @@ rpcpassword=%s Активація найкращого ланцюжка... - Can't run with a wallet in prune mode. - Використання гаманця зі скороченим ланцюжком блоків неможливе. + Always relay transactions received from whitelisted peers (default: %d) + Завжди передавайте транзакції отримані від пірів з білого списку (типово: %d) + + + Attempt to recover private keys from a corrupt wallet.dat on startup + Спочатку спробуйте відновити приватні ключі в пошкодженому wallet.dat + + + Automatically create Tor hidden service (default: %d) + Автоматичне з'єднання з прихованим сервісом Tor (типово: %d) Cannot resolve -whitebind address: '%s' Не вдалося розпізнати адресу для -whitebind: «%s» - - Choose data directory on startup (default: 0) - Обрати каталог даних під час запуску (типово: 0) - Connect through SOCKS5 proxy Підключитись через SOCKS5-проксі @@ -3180,10 +3319,6 @@ rpcpassword=%s Copyright (C) 2009-%i The Bitcoin Core Developers (C) 2009-%i Розробники Bitcoin Core - - Could not parse -rpcbind value %s as network address - Неможливо розпізнати мережеву адресу для параметру -rpcbind (%s) - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core Помилка при завантаженні wallet.dat: Гаманець потребує новішої версії Bitcoin Core @@ -3193,12 +3328,8 @@ rpcpassword=%s Помилка читання бази даних, припиняю роботу. - Error: Unsupported argument -tor found, use -onion. - Помилка: Параметр -tor не підтримується, використовуйте -onion - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - Комісія (в BTC/КБ), що додаватиметься до вихідних транзакцій (типово: %s) + Imports blocks from external blk000??.dat file on startup + Спочатку імпортує блоки з зовнішнього файлу blk000??.dat Information @@ -3240,18 +3371,10 @@ rpcpassword=%s Node relay options: Параметри вузла ретрансляції: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - Параметри RPC SSL: (див. Bitcoin Wiki для налаштування SSL) - RPC server options: Параметри сервера RPC: - - RPC support for HTTP persistent connections (default: %d) - Підтримка RPC для постійних HTTP-з'єднань (типово: %d) - Rebuild block chain index from current blk000??.dat files on startup При запуску перебудувати індекс ланцюжка блоків з поточних файлів blk000??.dat @@ -3260,6 +3383,14 @@ rpcpassword=%s Receive and display P2P network alerts (default: %u) Отримувати та відображати попередження з мережі (типово: %u) + + Reducing -maxconnections from %d to %d, because of system limitations. + Зменшення значення -maxconnections з %d до %d із-за обмежень системи. + + + Rescan the block chain for missing wallet transactions on startup + Спочатку переглянте ланцюжок блоків на наявність втрачених транзакцій гаманця + Send trace/debug info to console instead of debug.log file Відсилати налагоджувальну інформацію на консоль, а не у файл debug.log @@ -3268,22 +3399,10 @@ rpcpassword=%s Send transactions as zero-fee transactions if possible (default: %u) Не сплачувати комісію за надсилання транзакцій, якщо це можливо (типово: %u) - - Set SSL root certificates for payment request (default: -system-) - Вказати кореневі SSL-сертифікати для запиту платежу (типово: -системні-) - - - Set language, for example "de_DE" (default: system locale) - Встановлення мови, наприклад "de_DE" (типово: системна) - Show all debugging options (usage: --help -help-debug) Показати всі налагоджувальні параметри (використання: --help -help-debug) - - Show splash screen on startup (default: 1) - Показувати заставку під час запуску (типово: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) Стискати файл debug.log під час старту клієнта (типово: 1 коли відсутній параметр -debug) @@ -3292,10 +3411,6 @@ rpcpassword=%s Signing transaction failed Підписання транзакції не вдалося - - Start minimized - Запускати згорнутим - The transaction amount is too small to pay the fee Неможливо сплатити комісію із-за малої суми транзакції @@ -3304,6 +3419,14 @@ rpcpassword=%s This is experimental software. Це програмне забезпечення є експериментальним. + + Tor control port password (default: empty) + Пароль управління порт протоколом Tor (типово: empty) + + + Tor control port to use if onion listening enabled (default: %s) + Скористайтесь управлінням порт протоколом Tor, в разі перехоплення обміну цибулевої маршрутизації (типово: %s) + Transaction amount too small Сума транзакції занадто мала @@ -3320,17 +3443,13 @@ rpcpassword=%s Transaction too large Транзакція занадто велика - - UI Options: - Параметри інтерфейсу: - Unable to bind to %s on this computer (bind returned error %s) Неможливо прив'язатися до %s на цьому комп'ютері (bind повернув помилку: %s) - Use UPnP to map the listening port (default: 1 when listening) - Намагатись використовувати UPnP для відображення порту, що прослуховується на роутері (типово: 1 коли прослуховується) + Upgrade wallet to latest format on startup + Спочатку оновіть гаманець до останньої версії Username for JSON-RPC connections @@ -3345,20 +3464,16 @@ rpcpassword=%s Попередження - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - Увага: Параметр -benchmark не підтримується та буде проігнорований, використовуйте -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - Увага: Параметр -debugnet не підтримується та буде проігнорований, використовуйте -debug=net. + Whether to operate in a blocks only mode (default: %u) + Чи слід працювати в режимі тільки блоки (типово: %u) Zapping all transactions from wallet... Видалення всіх транзакцій з гаманця... - on startup - під час запуску + ZeroMQ notification options: + Параметри сповіщень ZeroMQ: wallet.dat corrupt, salvage failed @@ -3372,18 +3487,6 @@ rpcpassword=%s Execute command when the best block changes (%s in cmd is replaced by block hash) Виконати команду, коли з'явиться новий блок (%s в команді змінюється на хеш блоку) - - Upgrade wallet to latest format - Модернізувати гаманець до найновішого формату - - - Rescan the block chain for missing wallet transactions - Пересканувати ланцюжок блоків, в пошуку втрачених транзакцій - - - Use OpenSSL (https) for JSON-RPC connections - Використовувати OpenSSL (https) для JSON-RPC-з'єднань - This help message Дана довідка @@ -3404,6 +3507,26 @@ rpcpassword=%s (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = утримувати метадані транзакцій (до яких відноситься інформація про власника рахунку та запити платежів), 2 - відкинути) + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + Встановлено дуже велике значення -maxtxfee! Такі великі комісії можуть бути сплачені окремою транзакцією. + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Встановлено дуже велике значення -paytxfee! Цю комісію буде сплачено для проведення транзакції. + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + Не тримати транзакції в пам'яті довше <n> годин (типово: %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Помилка читання wallet.dat! Всі ключі прочитано коректно, але дані транзакцій чи записи адресної книги можуть бути пропущені або пошкоджені. + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + Комісії (в %s/kB), що менші за вказану, вважатимуться нульовими для створення транзакцій (типово: %s) + How thorough the block verification of -checkblocks is (0-4, default: %u) Рівень ретельності перевірки блоків (0-4, типово: %u) @@ -3420,17 +3543,33 @@ rpcpassword=%s Output debugging information (default: %u, supplying <category> is optional) Виводити налагоджувальну інформацію (типово: %u, вказання <category> необов'язкове) + + Support filtering of blocks and transaction with bloom filters (default: %u) + Фільтрація блоків та транзакцій з допомогою фільтрів Блума (типово: %u) + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + Загальна довжина рядку мережевої версії (%i) перевищує максимально допустиму (%i). Зменшіть число чи розмір коментарів клієнта користувача. + + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + Намагається зберегти вихідний трафік відповідно до зданого значення (в MIB за 24 години), 0 = без обмежень (типово: %d) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Параметр -socks не підтримується. Можливість вказувати версію SOCKS було видалено, так як підтримується лише SOCKS5. + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) Використовувати окремий SOCKS5-проксі для з'єднання з учасниками через приховані сервіси Tor (типово: %s) - (default: %s) - (типово: %s) + 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. This option can be specified multiple times + Логін та хешований пароль для зв'язків JSON-RPC. Поле <userpw> має формат: <USERNAME>:<SALT>$<HASH>. Класичний Python script додано до share/rpcuser. Цей параметр може бути застосований декілька разів. - Acceptable ciphers (default: %s) - Допустимі шифри (типово: %s) + (default: %s) + (типово: %s) Always query for peer addresses via DNS lookup (default: %u) @@ -3492,14 +3631,6 @@ rpcpassword=%s Relay non-P2SH multisig (default: %u) Ретранслювати не-P2SH транзакції з мультипідписом (типово: %u) - - Server certificate file (default: %s) - Файл сертифіката сервера (типово: %s) - - - Server private key (default: %s) - Закритий ключ сервера (типово: %s) - Set key pool size to <n> (default: %u) Встановити розмір пулу ключів <n> (типово: %u) diff --git a/src/qt/locale/bitcoin_ur_PK.ts b/src/qt/locale/bitcoin_ur_PK.ts index d4242d5e3..e37c87baa 100644 --- a/src/qt/locale/bitcoin_ur_PK.ts +++ b/src/qt/locale/bitcoin_ur_PK.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -108,6 +108,9 @@ پاس فریز تبدیل کریں + + BanTableModel + BitcoinGUI @@ -120,6 +123,10 @@ CoinControlDialog + + Amount: + رقم: + Amount رقم @@ -135,6 +142,14 @@ EditAddressDialog + + &Label + چٹ + + + &Address + پتہ + FreespaceChecker @@ -182,6 +197,10 @@ ReceiveRequestDialog + + Copy &Address + کاپی پتہ + Address پتہ @@ -216,6 +235,14 @@ SendCoinsDialog + + Insufficient funds! + ناکافی فنڈز + + + Amount: + رقم: + Balance: بیلنس: diff --git a/src/qt/locale/bitcoin_uz@Cyrl.ts b/src/qt/locale/bitcoin_uz@Cyrl.ts index cc0a4bba0..86724564f 100644 --- a/src/qt/locale/bitcoin_uz@Cyrl.ts +++ b/src/qt/locale/bitcoin_uz@Cyrl.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -212,6 +212,9 @@ Ҳамён пароли муваффақиятли алмаштирилди. + + BanTableModel + BitcoinGUI @@ -789,6 +792,10 @@ About Bitcoin Core Bitcoin Core ҳақида + + Command-line options + Буйруқлар сатри мосламалари + Usage: Фойдаланиш: @@ -797,7 +804,7 @@ command-line options буйруқлар қатори орқали мослаш - + Intro @@ -898,6 +905,14 @@ Third party transaction URLs Бегона тараф ўтказмалари URL манзиллари + + &Network + Тармоқ + + + W&allet + Ҳамён + Proxy &IP: Прокси &IP рақами: @@ -1033,12 +1048,44 @@ Recent transactions Сўнгги пул ўтказмалари - + + Unconfirmed transactions to watch-only addresses + Тасдиқланмаган ўтказмалар-фақат манзилларини кўриш + + + Current total balance in watch-only addresses + Жорий умумий баланс фақат кўринадиган манзилларда + + PaymentServer + + URI handling + URI осилиб қолмоқда + + + Invalid payment address %1 + Нотўғри тўлов манзили %1 + + + Payment request rejected + Тўлов сўрови инкор этилди + + + Payment request network doesn't match client network. + Тўлов сўрови тармоғи мижоз тармоғига мос келмайди. + + + Payment request error + Тўлов сўрови хато + PeerTableModel + + User Agent + Фойдаланувчи вакил + Ping Time Ping вақти @@ -1050,6 +1097,10 @@ Amount Миқдори + + Enter a Bitcoin address (e.g. %1) + Bitcoin манзилини киритинг (масалан. %1) + %1 m %1 д @@ -1145,12 +1196,20 @@ Батафсил маълумотларни кўриш учун уламни танланг. - Starting Height - Узунликнинг бошланиши + Direction + Йўналиш - Sync Height - Узунликни синхронлаш + Version + Версия + + + User Agent + Фойдаланувчи вакил + + + Services + Хизматлар Ban Score @@ -1168,14 +1227,6 @@ Last Receive Сўнгги қабул қилинган - - Bytes Sent - Жўнатилган байтлар - - - Bytes Received - Қабул қилинган байтлар - Ping Time Ping вақти @@ -1257,12 +1308,24 @@ ҳеч қачон - Unknown - Номаълум + Inbound + Ички йўналиш - Fetching... - Олинмоқда... + Outbound + Ташқи йўналиш + + + Yes + Ҳа + + + No + Йўқ + + + Unknown + Номаълум @@ -1342,10 +1405,30 @@ ReceiveRequestDialog + + QR Code + QR Коди + + + Copy &Address + Нусҳалаш & Манзил + &Save Image... Расмни &сақлаш + + Request payment to %1 + %1 дан Тўловни сўраш + + + Payment information + Тўлов маълумоти + + + URI + URI + Address Манзил @@ -1358,6 +1441,10 @@ Label Ёрлик + + Message + Хабар + RecentRequestsTableModel @@ -1369,6 +1456,10 @@ Label Ёрлик + + Message + Хабар + Amount Миқдори @@ -1377,13 +1468,33 @@ (no label) (Ёрлик мавжуд эмас) - + + (no message) + (Хабар йўқ) + + + (no amount) + (Миқдор мавжуд эмас) + + SendCoinsDialog Send Coins Тангаларни жунат + + Coin Control Features + Танга бошқаруви ҳусусиятлари + + + automatically selected + автоматик тарзда танланган + + + Insufficient funds! + Кам миқдор + Quantity: Сони: @@ -1420,6 +1531,34 @@ Custom change address Бошқа ўзгартирилган манзил + + Transaction Fee: + Ўтказма тўлови + + + Choose... + Танлов + + + per kilobyte + Хар килобайтига + + + Recommended: + Тавсия этилган + + + Confirmation time: + Тасдиқ вақти + + + normal + Нормал + + + fast + Тезкор + Send to multiple recipients at once Бирданига бир нечта қабул қилувчиларга жўнатиш @@ -1432,6 +1571,10 @@ Dust: Ахлат қутиси: + + Clear &All + Барчасини & Тозалаш + Balance: Баланс @@ -1440,10 +1583,18 @@ Confirm the send action Жўнатиш амалини тасдиқлаш + + S&end + Жў&натиш + Confirm send coins Тангалар жўнаишни тасдиқлаш + + %1 to %2 + %1 дан %2 + Copy quantity Нусха сони @@ -1472,6 +1623,10 @@ Copy change Нусха қайтими + + or + ёки + The amount to pay must be larger than 0. Тўлов миқдори 0. дан катта бўлиши керак. @@ -1519,6 +1674,14 @@ &Label: &Ёрлиқ: + + Choose previously used address + Олдин фойдаланилган манзилни танла + + + This is a normal payment. + Бу нормал тўлов. + Alt+A Alt+A @@ -1531,12 +1694,24 @@ Alt+P Alt+P + + Message: + Хабар + + + Pay To: + Тўлов олувчи: + ShutdownWindow SignVerifyMessageDialog + + Choose previously used address + Олдин фойдаланилган манзилни танла + Alt+A Alt+A @@ -1553,7 +1728,15 @@ Signature Имзо - + + Clear &All + Барчасини & Тозалаш + + + Message verified. + Хабар тасдиқланди. + + SplashScreen @@ -1590,14 +1773,78 @@ Date Сана + + Source + Манба + + + Generated + Яратилган + + + From + Дан + + + To + Га + + + own address + ўз манзили + + + label + ёрлиқ + + + Credit + Кредит (қарз) + + + not accepted + қабул қилинмади + + + Transaction fee + Ўтказма тўлови + + + Net amount + Умумий миқдор + + + Message + Хабар + + + Comment + Шарҳ + Transaction ID ID + + Merchant + Савдо + + + Transaction + Ўтказма + Amount Миқдори + + true + рост + + + false + ёлғон + , has not been successfully broadcast yet , ҳалигача трансляция қилингани йўқ @@ -1644,14 +1891,26 @@ Generated but not accepted Яратилди, аммо қабул қилинмади + + Offline + Оффлайн + Label Ёрлиқ + + Unconfirmed + Тасдиқланмаган + Received with Ёрдамида қабул қилиш + + Received from + Дан қабул қилиш + Sent to Жўнатиш @@ -1763,10 +2022,26 @@ Edit label Ёрликни тахрирлаш + + Show transaction details + Ўтказма тафсилотларини кўрсатиш + + + Export Transaction History + Ўтказмалар тарихини экспорт қилиш + + + Watch-only + Фақат кўришга + Exporting Failed Экспорт қилиб бўлмади + + The transaction history was successfully saved to %1. + Ўтказмалар тарихи %1 га муваффаққиятли сақланди. + Comma separated file (*.csv) Вергул билан ажратилган файл (*.csv) @@ -1809,7 +2084,11 @@ WalletFrame - + + No wallet has been loaded. + Хали бирорта хамён юкланмади + + WalletModel @@ -1847,25 +2126,13 @@ Демон сифатида орқа фонда ишга туширинг ва буйруқларга рози бўлинг - Use the test network - Синов тармоғидан фойдаланинг - - - Choose data directory on startup (default: 0) - Ишга тушиш вақтида маълумотлар директориясини танлаш (стандарт: 0) + Connection options: + Уланиш кўрсаткичлари: Information Маълумот - - Set SSL root certificates for payment request (default: -system-) - Тўлов сўровлари учун SSL асос сертификатларини ўрнатиш (стандарт: -system-) - - - Start minimized - Йиғилганларни бошлаш - Username for JSON-RPC connections JSON-RPC уланишлари учун фойдаланувчи номи @@ -1878,10 +2145,6 @@ Password for JSON-RPC connections JSON-RPC уланишлари учун парол - - Use OpenSSL (https) for JSON-RPC connections - JSON-RPC уланишлари учун OpenSSL (https)дан фойдаланиш - This help message Бу ёрдам хабари @@ -1890,6 +2153,10 @@ Loading addresses... Манзиллар юкланмоқда... + + Insufficient funds + Кам миқдор + Loading block index... Тўсиқ индекси юкланмоқда... diff --git a/src/qt/locale/bitcoin_vi.ts b/src/qt/locale/bitcoin_vi.ts index 64d11d464..47745a3bc 100644 --- a/src/qt/locale/bitcoin_vi.ts +++ b/src/qt/locale/bitcoin_vi.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -48,6 +48,9 @@ AskPassphraseDialog + + BanTableModel + BitcoinGUI @@ -56,6 +59,10 @@ CoinControlDialog + + Amount: + Số lượng: + Amount Số lượng @@ -67,6 +74,14 @@ EditAddressDialog + + &Label + Nhãn dữ liệu + + + &Address + Địa chỉ + FreespaceChecker @@ -110,6 +125,10 @@ ReceiveRequestDialog + + Copy &Address + Sao chép địa chỉ + Address Địa chỉ @@ -140,6 +159,10 @@ SendCoinsDialog + + Amount: + Số lượng: + (no label) (chưa có nhãn) diff --git a/src/qt/locale/bitcoin_vi_VN.ts b/src/qt/locale/bitcoin_vi_VN.ts index 7bcded744..d55fa6188 100644 --- a/src/qt/locale/bitcoin_vi_VN.ts +++ b/src/qt/locale/bitcoin_vi_VN.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -136,6 +136,9 @@ Ví đã được mã hóa + + BanTableModel + BitcoinGUI @@ -162,6 +165,10 @@ Show information about Qt Xem thông tin về Qt + + &Receiving addresses... + Địa chỉ nhận + Open &URI... Mở &URI... @@ -351,6 +358,14 @@ EditAddressDialog + + &Label + Nhãn + + + &Address + Địa chỉ + FreespaceChecker @@ -414,6 +429,10 @@ MB MB + + W&allet + + &Display &Hiển thị @@ -464,6 +483,10 @@ RPCConsole + + &Information + Thông tin + General Nhìn Chung @@ -487,6 +510,10 @@ ReceiveCoinsDialog + + &Amount: + Lượng: + Copy label Copy nhãn @@ -498,6 +525,10 @@ ReceiveRequestDialog + + Copy &Address + &Copy Địa Chỉ + Address Địa chỉ @@ -532,6 +563,10 @@ SendCoinsDialog + + Insufficient funds! + Không đủ tiền + Quantity: Lượng: @@ -567,6 +602,10 @@ SendCoinsEntry + + A&mount: + Lượng: + ShutdownWindow @@ -670,6 +709,14 @@ bitcoin-core + + Options: + Lựa chọn: + + + (default: %u) + (mặc định: %u) + Information Thông tin @@ -682,10 +729,6 @@ Warning Chú ý - - on startup - khi khởi động - This help message Thông điệp trợ giúp này diff --git a/src/qt/locale/bitcoin_zh.ts b/src/qt/locale/bitcoin_zh.ts new file mode 100644 index 000000000..aeb4faa71 --- /dev/null +++ b/src/qt/locale/bitcoin_zh.ts @@ -0,0 +1,221 @@ + + + AddressBookPage + + + AddressTableModel + + + AskPassphraseDialog + + + BanTableModel + + + BitcoinGUI + + Error + 错误 + + + Warning + 警告 + + + + ClientModel + + + CoinControlDialog + + Date + 日期 + + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + Error + 错误 + + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + + RecentRequestsTableModel + + Date + 日期 + + + + SendCoinsDialog + + Insufficient funds! + 余额不足 + + + Choose... + 选择... + + + Pay only the required fee of %1 + 仅支付全额的%1 + + + The recipient address is not valid. Please recheck. + 收款人地址无效,请再次确认。 + + + Warning: Invalid Bitcoin address + 警告:比特币地址无效 + + + + SendCoinsEntry + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + Date + 日期 + + + + TransactionDescDialog + + + TransactionTableModel + + Date + 日期 + + + + TransactionView + + Date + 日期 + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + + bitcoin-core + + Transaction amounts must be positive + 转账额度须为正数 + + + Transaction too large for fee policy + 根据费率标准,本次转账超额 + + + Transaction too large + 超额转账 + + + Warning + 警告 + + + wallet.dat corrupt, salvage failed + wallet.dat文件受损,修复失败 + + + This help message + 此条帮助信息 + + + Loading addresses... + 正在载入地址... + + + Error loading wallet.dat: Wallet corrupted + wallet.dat文件加载错误:钱包受损 + + + Error loading wallet.dat + wallet.dat文件加载错误 + + + Insufficient funds + 余额不足 + + + Loading wallet... + 正在载入钱包... + + + Rescanning... + 再次扫描... + + + Done loading + 载入完成 + + + Error + 错误 + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index 4470b2601..0ae2c95c6 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -23,7 +23,7 @@ C&lose - 关闭(&C) + 关闭(&l) &Copy Address @@ -35,7 +35,7 @@ Export the data in the current tab to a file - 导出当前数据到文件 + 导出当前分页里的数据到文件 &Export @@ -47,11 +47,11 @@ Choose the address to send coins to - 选择发款地址 + 选择发币地址 Choose the address to receive coins with - 选择收款地址 + 选择收币地址 C&hoose @@ -133,7 +133,7 @@ Encrypt wallet - 钱包加密 + 加密钱包 This operation needs your wallet passphrase to unlock the wallet. @@ -185,7 +185,7 @@ Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. - 请输入新的钱包密码. <br/>密码须包含<b>10个以上字符</b>,或<b>8个以上单词</b>. + 请输入新的钱包密码. <br/>密码须包含<b>10个以上随机字符</b>,或<b>8个以上单词</b>. Enter the old passphrase and new passphrase to the wallet. @@ -220,6 +220,17 @@ 修改钱包密码成功。 + + BanTableModel + + IP/Netmask + IP/网络掩码 + + + Banned Until + 在此之前禁止: + + BitcoinGUI @@ -260,7 +271,7 @@ About &Qt - 关于 &Qt + 关于Qt(&Q) Show information about Qt @@ -296,7 +307,7 @@ Bitcoin Core client - 比特币核心钱包 + 比特币核心钱包客户端 Importing blocks from disk... @@ -304,7 +315,7 @@ Reindexing blocks on disk... - 正在为数据块建立索引... + 正在为数据块重建索引... Send coins to a Bitcoin address @@ -871,6 +882,34 @@ command-line options 命令行选项 + + UI Options: + 界面选项: + + + Choose data directory on startup (default: %u) + 在启动时选择目录(默认%u) + + + Set language, for example "de_DE" (default: system locale) + 设置语言, 例如“zh-CN”(默认:系统语言) + + + Start minimized + 启动时最小化 + + + Set SSL root certificates for payment request (default: -system-) + 设置付款请求的SSL根证书(默认:-系统-) + + + Show splash screen on startup (default: %u) + 显示启动画面(默认:%u) + + + Reset all settings changes made over the GUI + 重置所有图形界面所做的更改 + Intro @@ -1034,7 +1073,7 @@ If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed. - 如果禁用未确认的零钱,则零钱至少需要1个确认才能使用。同时账户余额显示会受到影响。 + 如果禁用未确认的零钱,则零钱至少需要1个确认才能使用。同时账户余额计算会受到影响。 &Spend unconfirmed change @@ -1068,6 +1107,34 @@ Port of the proxy (e.g. 9050) 代理端口(例如 9050) + + Used for reaching peers via: + 连接到同伴的方式: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + 如果默认的SOCKS5代理被用于在该网络下连接同伴,则显示 + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + 在Tor匿名网络下通过不同的SOCKS5代理连接比特币网络 + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + 通过Tor隐藏服务连接节点时 使用不同的SOCKS5代理 + &Window 窗口(&W) @@ -1286,10 +1353,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). 支付请求 %1 太大 (%2 字节。只允许 %3 字节)。 - - Payment request DoS protection - 支付请求防滥用保护 - Error communicating with %1: %2 %1: %2 通讯出错 @@ -1442,6 +1505,18 @@ Current number of blocks 当前数据块数量 + + Memory Pool + 资金池 + + + Current number of transactions + 当前交易数量 + + + Memory usage + 内存使用 + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. 从当前的数据目录打开比特币核心调试日志文件。对于较大的日志文件,这可能需要几秒钟。 @@ -1458,10 +1533,18 @@ &Peers 同伴(&P) + + Banned peers + 节点黑名单 + Select a peer to view detailed information. 选择节点查看详细信息。 + + Whitelisted + 白名单 + Direction 方向 @@ -1470,6 +1553,18 @@ Version 版本 + + Starting Block + 正在启动数据块 + + + Synced Headers + 同步区块头 + + + Synced Blocks + 同步区块链 + User Agent 用户代理 @@ -1478,14 +1573,6 @@ Services 服务 - - Starting Height - 开始高度 - - - Sync Height - 同步高度 - Ban Score 禁止得分 @@ -1502,18 +1589,14 @@ Last Receive 最后接收 - - Bytes Sent - 发送字节 - - - Bytes Received - 接收字节 - Ping Time Ping 时间 + + Ping Wait + Ping等待 + Time Offset 时间偏移 @@ -1562,6 +1645,34 @@ Clear console 清空控制台 + + &Disconnect Node + (&D)断开节点连接 + + + Ban Node for + 禁止节点连接时长: + + + 1 &hour + 1 小时(&H) + + + 1 &day + 1 天(&D) + + + 1 &week + 1 周(&W) + + + 1 &year + 1 年(&Y) + + + &Unban Node + (&U)允许节点连接 + Welcome to the Bitcoin Core RPC console. 欢迎使用 比特币核心 RPC 控制台。 @@ -1590,6 +1701,10 @@ %1 GB %1 GB + + (node id: %1) + (节点ID: %1) + via %1 通过 %1 @@ -1607,12 +1722,16 @@ 传出 - Unknown - 未知 + Yes + - Fetching... - 获取中... + No + + + + Unknown + 未知 @@ -1872,7 +1991,7 @@ Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process. - 交易量小时只支付最小交易费是可以的。但是请注意,当交易量大时您的交易可能永远无法确认。 + 交易量小时只支付最小交易费是可以的。但是请注意,当交易量大到超出网络可处理时您的交易可能永远无法确认。 (read the tooltip) @@ -1936,7 +2055,7 @@ Confirm the send action - 确认并发送货币 + 确认发送货币 S&end @@ -1979,8 +2098,8 @@ 复制零钱 - Total Amount %1 (= %2) - 总额 %1 (= %2) + Total Amount %1 + 总金额 %1 or @@ -2014,14 +2133,14 @@ Payment request expired. 支付请求已过期。 + + Pay only the required fee of %1 + 只支付必要费用 %1 + Estimated to begin confirmation within %n block(s). 预计 %n 个数据块后被确认。 - - Pay only the minimum fee of %1 - 只支付最小费用 %1 - The recipient address is not valid. Please recheck. 接收人地址无效。请重新检查。 @@ -2653,6 +2772,10 @@ Copy transaction ID 复制交易编号 + + Copy raw transaction + 复制原始交易 + Edit label 编辑标签 @@ -2803,6 +2926,38 @@ 接受命令行和 JSON-RPC 命令 + + If <category> is not supplied or if <category> = 1, output all debugging information. + 如果<category>未提供或<category> = 1,输出所有调试信息。 + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + 最大单次转账费用(%s),设置太低可能导致大宗交易失败(默认:%s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + 警请检查电脑的日期时间设置是否正确!时间错误可能会导致比特币客户端运行异常。 + + + Prune configured below the minimum of %d MiB. Please use a higher number. + 修剪值被设置为低于最小值%d MiB,请使用更大的数值。 + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + 无法在开启修剪的状态下重扫描,请使用 -reindex重新下载完整的区块链。 + + + Error: A fatal internal error occurred, see debug.log for details + 错误:发生了致命的内部错误,详情见 debug.log 文件 + + + Fee (in %s/kB) to add to transactions you send (default: %s) + 为付款交易添加交易费 (%s/kB) (默认: %s) + + + Pruning blockstore... + 正在修剪区块存储... + Run in the background as a daemon and accept commands 在后台运行并接受命令 @@ -2810,9 +2965,8 @@ - Use the test network - 使用测试网络 - + Unable to start HTTP server. See debug log for details. + 无法启动HTTP服务,查看日志获取更多信息 Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2834,18 +2988,14 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) 当最佳区块变化时执行命令 (命令行中的 %s 会被替换成区块哈希值) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - 单次交易最多使用交易费;设置太低可能导致大宗交易中止 (默认: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - 通过修剪(删除)旧数据块减少存储需求。此模式将禁用钱包支持,并与 -txindex 不兼容。警告:还原此设置需要重新下载整个数据链。(默认: 0 = 禁用修剪数据块, >%u = 数据块文件目标大小,单位 MiB) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) 设置脚本验证的程序 (%u 到 %d, 0 = 自动, <0 = 保留自由的核心, 默认值: %d) + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + 区块数据库包含未来的交易,这可能是由本机错误的日期时间引起。若确认本机日期时间正确,请重新建立区块数据库。 + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications 这是测试用的预发布版本 - 请谨慎使用 - 不要用来挖矿,或者在正式商用环境下使用 @@ -2854,6 +3004,10 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. 无法 %s的绑定到电脑上,比特币核心钱包可能已经在运行。 + + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + 使用UPnP暴露本机监听端口(默认:1 当正在监听且不使用代理) + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) 警告:数据块生成数量异常,最近 %d 小时收到了 %d 个数据块(预期为 %d 个) @@ -2862,10 +3016,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) 警告:请检查您的网络连接,最近 %d 小时收到了 %d 个数据块(预期为 %d 个) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - 警告:-paytxfee 交易费设置得太高了!每笔交易都将支付交易费。 - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. 警告:网络似乎并不完全同意!有些矿工似乎遇到了问题。 @@ -2874,10 +3024,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. 警告:我们的同行似乎不完全同意!您可能需要升级,或者其他节点可能需要升级。 - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - 警告:钱包文件wallet.dat读取失败!最重要的公钥、私钥数据都没有问题,但是交易记录或地址簿数据不正确,或者存在数据丢失。 - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. 警告:钱包文件wallet.dat损坏! 原始的钱包文件已经备份到%s目录下并重命名为{timestamp}.bak 。如果您的账户余额或者交易记录不正确,请使用您的钱包备份文件恢复。 @@ -2887,17 +3033,13 @@ 节点白名单,网络掩码或IP址。可多次指定。 - (default: 1) - (默认值: 1) + -maxmempool must be at least %d MB + -maxmempool 最小为%d MB <category> can be: <category> 可能是: - - Attempt to recover private keys from a corrupt wallet.dat - 尝试从损坏的钱包文件wallet.dat中恢复私钥 - Block creation options: 数据块创建选项: @@ -2926,6 +3068,22 @@ Do you want to rebuild the block database now? 你想现在就重建块数据库吗? + + Enable publish hash block in <address> + 允许在<address>广播哈希区块 + + + Enable publish hash transaction in <address> + 允许在<address>广播哈希交易 + + + Enable publish raw block in <address> + 允许在<address>广播原始区块 + + + Enable publish raw transaction in <address> + 允许在<address>广播原始交易 + Error initializing block database 初始化数据块数据库出错 @@ -2942,10 +3100,6 @@ Error opening block database 导入数据块数据库出错 - - Error: A fatal internal error occured, see debug.log for details - 错误:发生了致命的内部错误,请打开debug.log查看详细信息 - Error: Disk space is low! 错误:磁盘剩余空间低! @@ -2954,10 +3108,6 @@ Failed to listen on any port. Use -listen=0 if you want this. 监听端口失败。请使用 -listen=0 参数。 - - If <category> is not supplied, output all debugging information. - 如果<category>未提供,将输出所有调试信息。 - Importing... 导入中... @@ -2970,6 +3120,10 @@ Invalid -onion address: '%s' 无效的 -onion 地址:“%s” + + Keep the transaction memory pool below <n> megabytes (default: %u) + 保持交易内存池大小低于<n>MB(默认:%u) + Not enough file descriptors available. 没有足够的文件描述符可用。 @@ -2998,6 +3152,18 @@ Specify wallet file (within data directory) 指定钱包文件(数据目录内) + + Unsupported argument -benchmark ignored, use -debug=bench. + 忽略不支持的选项 -benchmark,使用 -debug=bench + + + Unsupported argument -debugnet ignored, use -debug=net. + 忽略不支持的选项 -debugnet,使用 -debug=net。 + + + Unsupported argument -tor found, use -onion. + 忽略不支持的选项 -tor,使用 -oinon + Use UPnP to map the listening port (default: %u) 使用UPnp映射监听端口 (默认: %u) @@ -3026,18 +3192,10 @@ You need to rebuild the database using -reindex to change -txindex 您需要将 -reindex 改为 -txindex 以重建数据库 - - Imports blocks from external blk000??.dat file - 从blk000??.dat文件导入数据块 - 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 允许来自指定地址的 JSON-RPC 连接。 <ip>为单一IP (如: 1.2.3.4), 网络/掩码 (如: 1.2.3.4/255.255.255.0), 网络/CIDR (如: 1.2.3.4/24)。该选项可多次指定。 - - An error occurred while setting up the RPC address %s port %u for listening: %s - 设置RPC监听端口 %s:%u 时发生错误: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 绑定到指定地址和连接的白名单节点。 IPv6使用 [主机]:端口 格式 @@ -3062,18 +3220,10 @@ Error: Listening for incoming connections failed (listen returned error %s) 错误:监听外部连接失败 (监听返回错误 %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - 错误:不支持的 -socks 参数。不再支持设置SOCKS版本,现在只支持 SOCKS5代理。 - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) 当收到相关提醒或者我们看到一个长分叉时执行命令(%s 将替换为消息) - - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - 交易费(BTC/kb)比这更小的交易在转发时将被视为零费交易 (默认: %s) - If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) 如果未设置交易费用,自动添加足够的交易费以确保交易在平均n个数据块内被确认 (默认: %u) @@ -3086,10 +3236,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) Maximum size of data in data carrier transactions we relay and mine (default: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - 修剪被配置为比最小值 %d MB 更低。请使用更大的数字。 - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) 通过DNS查询每个地址,如果短地址 (默认值: 1 除非 -连接) @@ -3114,38 +3260,6 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - 要使用 bitcoind 或者 bitcoin-qt 中的 -server 选项,您必须在配置文件中设置一个密码: -%s -建议您使用下列随机密码: -rpcuser=bitcoinrpc -rpcpassword=%s -(您不需要记住这个密码) -用户名和密码不能相同。 -如果该文件不存在,创建一个文件并设置权限为仅创建者可读。 -此外,还建议您设置 alertnotify 以便您能注意到问题: -例如 alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - 警告:-maxtxfee 设置的太高了!每进行一笔交易时您都要花费这么多费用。 - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - 警告:请检查电脑的日期时间设置是否正确!时间错误可能会导致比特币客户端运行异常。 - 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 白名单节点不能被DoS banned ,且转发所有来自他们的交易(即便这些交易已经存在于mempool中),常用于网关 @@ -3166,18 +3280,10 @@ rpcpassword=%s Activating best chain... 正在激活最佳数据链... - - Can't run with a wallet in prune mode. - 不能在修剪模式下运行一个钱包。 - Cannot resolve -whitebind address: '%s' 无法解析 -whitebind 地址: '%s' - - Choose data directory on startup (default: 0) - 在启动时选择数据目录(默认:0) - Connect through SOCKS5 proxy 通过 SOCKS5 代理连接 @@ -3186,10 +3292,6 @@ rpcpassword=%s Copyright (C) 2009-%i The Bitcoin Core Developers 版权所有 (C) 2009-%i Bitcoin Core 开发者 - - Could not parse -rpcbind value %s as network address - 无法解析 -rpcbind 的值 %s 为网络地址 - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core 加载wallet.dat错误:需要新版的比特币核心钱包 @@ -3198,14 +3300,6 @@ rpcpassword=%s Error reading from database, shutting down. 读取数据库出错,关闭中。 - - Error: Unsupported argument -tor found, use -onion. - 错误:发现了不支持的参数 -tor,请使用 -onion。 - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - 为付款交易添加交易费 (BTC/kb) (默认: %s) - Information 信息 @@ -3234,6 +3328,10 @@ rpcpassword=%s Invalid netmask specified in -whitelist: '%s' -whitelist: '%s' 指定的网络掩码无效 + + Keep at most <n> unconnectable transactions in memory (default: %u) + 内存中最多保留 <n> 笔孤立的交易 (默认: %u) + Need to specify a port with -whitebind: '%s' -whitebind: '%s' 需要指定一个端口 @@ -3242,18 +3340,10 @@ rpcpassword=%s Node relay options: 节点中继选项: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - RPC SSL选项:(见有关比特币设置用于SSL说明的维基百科) - RPC server options: RPC 服务器选项: - - RPC support for HTTP persistent connections (default: %d) - RPC 支持 HTTP 持久连接 (默认: %d) - Rebuild block chain index from current blk000??.dat files on startup 启动时重新为当前的 blk000??.dat 文件建立索引 @@ -3262,6 +3352,10 @@ rpcpassword=%s Receive and display P2P network alerts (default: %u) 收到并且显示P2P网络的告警(默认:%u) + + Rescan the block chain for missing wallet transactions on startup + 重新扫描区块链以查找遗漏的钱包交易 + Send trace/debug info to console instead of debug.log file 跟踪/调试信息输出到控制台,不输出到 debug.log 文件 @@ -3270,22 +3364,10 @@ rpcpassword=%s Send transactions as zero-fee transactions if possible (default: %u) 发送时尽可能 不支付交易费用 (默认: %u) - - Set SSL root certificates for payment request (default: -system-) - 设置SSL根证书的付款请求(默认:-系统-) - - - Set language, for example "de_DE" (default: system locale) - 设置语言, 例如“zh-TW”(默认为系统语言) - Show all debugging options (usage: --help -help-debug) 显示所有调试选项 (用法: --帮助 -帮助调试) - - Show splash screen on startup (default: 1) - 启动时显示版权页 (缺省: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) 客户端启动时压缩debug.log文件(缺省:no-debug模式时为1) @@ -3294,11 +3376,6 @@ rpcpassword=%s Signing transaction failed 签署交易失败 - - Start minimized - 启动时最小化 - - The transaction amount is too small to pay the fee 交易金额太小,不足以支付交易费 @@ -3323,17 +3400,13 @@ rpcpassword=%s Transaction too large 交易太大 - - UI Options: - 界面选项: - Unable to bind to %s on this computer (bind returned error %s) 无法在此计算机上绑定 %s (绑定返回错误 %s) - Use UPnP to map the listening port (default: 1 when listening) - 使用UPnp映射监听端口(缺省: 监听状态设为1) + Upgrade wallet to latest format on startup + 程序启动时升级钱包到最新格式 Username for JSON-RPC connections @@ -3348,20 +3421,16 @@ rpcpassword=%s 警告 - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - 警告:不支持的参数 -benchmark 已忽略,请使用 -debug=bench。 - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - 警告:不支持的参数 -debugnet 已忽略,请使用 -debug=net。 + Whether to operate in a blocks only mode (default: %u) + 是否用块方进行 (%u) Zapping all transactions from wallet... Zapping all transactions from wallet... - on startup - 启动中 + ZeroMQ notification options: + ZeroMQ 通知选项: wallet.dat corrupt, salvage failed @@ -3376,18 +3445,6 @@ rpcpassword=%s Execute command when the best block changes (%s in cmd is replaced by block hash) 当最佳数据块变化时执行命令 (命令行中的 %s 会被替换成数据块哈希值) - - Upgrade wallet to latest format - 将钱包升级到最新的格式 - - - Rescan the block chain for missing wallet transactions - 重新扫描区块链以查找遗漏的钱包交易 - - - Use OpenSSL (https) for JSON-RPC connections - 为 JSON-RPC 连接使用 OpenSSL (https) 连接 - This help message 本帮助信息 @@ -3425,6 +3482,10 @@ rpcpassword=%s Output debugging information (default: %u, supplying <category> is optional) 输出调试信息 (默认: %u, 提供 <category> 是可选项) + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + 尝试保持上传带宽低于(MiB/24h),0=无限制(默认:%d) + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) 通过Tor隐藏服务连接节点时 使用不同的SOCKS5代理 (默认: %s) @@ -3434,8 +3495,8 @@ rpcpassword=%s (默认: %s) - Acceptable ciphers (default: %s) - 可接受的密码算法 (默认: %s) + Always query for peer addresses via DNS lookup (default: %u) + 始终通过 DNS 查询节点地址 (默认: %u) Error loading wallet.dat @@ -3493,14 +3554,6 @@ rpcpassword=%s Relay non-P2SH multisig (default: %u) 是否转发 非P2SH格式的多签名交易 (默认: %u) - - Server certificate file (default: %s) - 服务器证书文件 (默认: %s) - - - Server private key (default: %s) - 服务器私钥 (默认: %s) - Set key pool size to <n> (default: %u) 设置私钥池大小为 <n> (默认:%u) diff --git a/src/qt/locale/bitcoin_zh_HK.ts b/src/qt/locale/bitcoin_zh_HK.ts deleted file mode 100644 index 7062377f4..000000000 --- a/src/qt/locale/bitcoin_zh_HK.ts +++ /dev/null @@ -1,110 +0,0 @@ - - - AddressBookPage - - - AddressTableModel - - - AskPassphraseDialog - - - BitcoinGUI - - - ClientModel - - - CoinControlDialog - - - EditAddressDialog - - - FreespaceChecker - - - HelpMessageDialog - - - Intro - - - OpenURIDialog - - - OptionsDialog - - - OverviewPage - - - PaymentServer - - - PeerTableModel - - - QObject - - - QRImageWidget - - - RPCConsole - - - ReceiveCoinsDialog - - - ReceiveRequestDialog - - - RecentRequestsTableModel - - - SendCoinsDialog - - - SendCoinsEntry - - - ShutdownWindow - - - SignVerifyMessageDialog - - - SplashScreen - - - TrafficGraphWidget - - - TransactionDesc - - - TransactionDescDialog - - - TransactionTableModel - - - TransactionView - - - UnitDisplayStatusBarControl - - - WalletFrame - - - WalletModel - - - WalletView - - - bitcoin-core - - \ No newline at end of file diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts index 9a93d896f..402609592 100644 --- a/src/qt/locale/bitcoin_zh_TW.ts +++ b/src/qt/locale/bitcoin_zh_TW.ts @@ -1,4 +1,4 @@ - + AddressBookPage @@ -220,6 +220,17 @@ 錢包密碼改成功了。 + + BanTableModel + + IP/Netmask + 網路位址/遮罩 + + + Banned Until + 禁止期限 + + BitcoinGUI @@ -340,11 +351,11 @@ &Send - 已傳送 + 付款 &Receive - 已接收 + 收款 Show information about Bitcoin Core @@ -392,7 +403,7 @@ Request payments (generates QR codes and bitcoin: URIs) - 要求付款(產生 QR Code 和位元幣付款協議的 URI) + 要求付款(產生 QR Code 和位元幣付款協議的資源識別碼: URI) &About Bitcoin Core @@ -412,7 +423,7 @@ Open a bitcoin: URI or payment request - 開啓 bitcoin 協議的 URI 或付款要求 + 開啓 bitcoin 協議的資源識別碼(URI)或付款要求 &Command-line options @@ -871,6 +882,34 @@ command-line options 命令列選項 + + UI Options: + 使用介面選項: + + + Choose data directory on startup (default: %u) + 啓動時選擇資料目錄(預設值: %u) + + + Set language, for example "de_DE" (default: system locale) + 設定語言,比如說 de_DE (預設值: 系統語系) + + + Start minimized + 啓動時縮到最小 + + + Set SSL root certificates for payment request (default: -system-) + 設定付款請求時所使用的 SSL 根憑證(預設值: 系統憑證庫) + + + Show splash screen on startup (default: %u) + 顯示啓動畫面(預設值: %u) + + + Reset all settings changes made over the GUI + 重置所有在使用界面更改的設定 + Intro @@ -896,7 +935,7 @@ Use a custom data directory: - 使用自定的資料目錄: + 使用自訂的資料目錄: Bitcoin Core @@ -986,7 +1025,7 @@ Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - 在交易頁籤的情境選單出現的第三方(比如說區塊探索網站)網址連結。網址中的 %s 會被取代為交易的雜湊值。可以用直線符號 | 來分隔多個連結。 + 在交易頁籤的情境選單出現的第三方網址連結(URL),比如說區塊探索網站。網址中的 %s 會被取代為交易的雜湊值。可以用直線符號 | 來分隔多個連結。 Third party transaction URLs @@ -1068,6 +1107,34 @@ Port of the proxy (e.g. 9050) 代理伺服器的通訊埠(像是 9050) + + Used for reaching peers via: + 用來跟其他節點聯絡的中介: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + 如果對這種網路類型,有指定用來跟其他節點聯絡的 SOCKS5 代理伺服器的話,就會顯示在這裡。 + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + 透過另外的 SOCKS5 代理伺服器來連線到位元幣網路中的 Tor 隱藏服務。 + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + 用另外的 SOCKS5 代理伺服器,來透過 Tor 隱藏服務跟其他節點聯絡: + &Window 視窗 @@ -1252,11 +1319,11 @@ Payment request fetch URL is invalid: %1 - 取得付款要求的 URL 無效: %1 + 取得付款要求的網址連結(URL)無效: %1 URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. - 沒辦法解析 URI 位址!可能是因為位元幣位址無效,或是 URI 參數格式錯誤。 + 沒辦法解析資源識別碼(URI)!可能是因為位元幣位址無效,或是 URI 參數格式錯誤。 Payment request file handling @@ -1286,10 +1353,6 @@ Payment request %1 is too large (%2 bytes, allowed %3 bytes). 付款要求 %1 過大 (%2 位元組, 上限 %3 位元組). - - Payment request DoS protection - 支付請求的分佈式阻斷服務攻擊DoS保護 - Error communicating with %1: %2 跟 %1 通訊時發生錯誤: %2 @@ -1442,26 +1505,46 @@ Current number of blocks 目前區塊數 + + Memory Pool + 記憶體暫存池 + + + Current number of transactions + 目前交易數目 + + + Memory usage + 記憶體使用量 + Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files. 從目前的資料目錄下開啓位元幣核心的除錯紀錄檔。當紀錄檔很大時,可能會花好幾秒的時間。 Received - 收款 + 收到 Sent - 付款 + 送出 &Peers 節點 + + Banned peers + 被禁節點 + Select a peer to view detailed information. 選一個節點來看詳細資訊 + + Whitelisted + 列在白名單 + Direction 方向 @@ -1470,6 +1553,18 @@ Version 版本 + + Starting Block + 起始區塊 + + + Synced Headers + 已同步前導資料 + + + Synced Blocks + 已同步區塊 + User Agent 使用者代理 @@ -1478,14 +1573,6 @@ Services 服務 - - Starting Height - 起始高度 - - - Sync Height - 同步高度 - Ban Score 惡劣分數 @@ -1502,18 +1589,18 @@ Last Receive 最近收到 - - Bytes Sent - 送出位元組 - - - Bytes Received - 收到位元組 - Ping Time Ping 時間 + + The duration of a currently outstanding ping. + 目前這一次 ping 已經過去的時間。 + + + Ping Wait + Ping 等待時間 + Time Offset 時間差 @@ -1544,11 +1631,11 @@ In: - 輸入: + 來: Out: - 輸出: + 去: Build date @@ -1562,6 +1649,34 @@ Clear console 清主控台 + + &Disconnect Node + 跟節點斷線 + + + Ban Node for + 禁止節點連線: + + + 1 &hour + 1 小時 + + + 1 &day + 1 天 + + + 1 &week + 1 星期 + + + 1 &year + 1 年 + + + &Unban Node + 解禁解點連線 + Welcome to the Bitcoin Core RPC console. 歡迎使用位元幣核心 RPC 主控台。 @@ -1590,6 +1705,10 @@ %1 GB %1 GB (十億位元組) + + (node id: %1) + (節點識別碼: %1) + via %1 經由 %1 @@ -1607,12 +1726,16 @@ 出去 - Unknown - 不明 + Yes + - Fetching... - 正在擷取中... + No + + + + Unknown + 不明 @@ -1840,7 +1963,7 @@ Custom change address - 自定找零位址 + 自訂找零位址 Transaction Fee: @@ -1979,8 +2102,8 @@ 複製找零金額 - Total Amount %1 (= %2) - 總金額 %1 (= %2) + Total Amount %1 + 總金額 %1 or @@ -2015,8 +2138,12 @@ 付款的要求過期了。 - Pay only the minimum fee of %1 - 只付最低手續費 %1 + Pay only the required fee of %1 + 只付必要的手續費 %1 + + + Estimated to begin confirmation within %n block(s). + 預計可在 %n 個區塊內開始確認。 The recipient address is not valid. Please recheck. @@ -2111,11 +2238,11 @@ This is an unauthenticated payment request. - 這是個沒驗證過的付款要求。 + 這是個沒有驗證過身份的付款要求。 This is an authenticated payment request. - 這是個已驗證的付款要求。 + 這是個已經驗證過身份的付款要求。 Enter a label for this address to add it to the list of used addresses @@ -2123,7 +2250,7 @@ A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network. - 附加在位元幣付款協議 URI 中的訊息,會和交易內容一起存起來,給你自己做參考。注意: 這個訊息不會送到位元幣網路上。 + 附加在位元幣付款協議的資源識別碼(URI)中的訊息,會和交易內容一起存起來,給你自己做參考。注意: 這個訊息不會送到位元幣網路上。 Pay To: @@ -2138,7 +2265,7 @@ ShutdownWindow Bitcoin Core is shutting down... - 位元幣核心正在關閉中... + 正在關閉位元幣核心中... Do not shut down the computer until this window disappears. @@ -2649,6 +2776,10 @@ Copy transaction ID 複製交易識別碼 + + Copy raw transaction + 複製交易原始資料 + Edit label 編輯標記 @@ -2797,13 +2928,53 @@ 接受指令列和 JSON-RPC 指令 + + If <category> is not supplied or if <category> = 1, output all debugging information. + 如果沒有提供 <category> 或是值為 1 就會輸出所有的除錯資訊。 + + + Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) + 一次錢包交易允許付出最高的總手續費(單位是 %s);設定太低的話,可能會無法進行資料量大的交易(預設值: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. + 請檢查電腦日期和時間是否正確!位元幣核心沒辦法在時鐘不準的情況下正常運作。 + + + Prune configured below the minimum of %d MiB. Please use a higher number. + 設定的修剪值小於最小需求的 %d 百萬位元組(MiB)。請指定大一點的數字。 + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + 修剪模式:錢包的最後同步狀態是在被修剪掉的區塊資料中。你需要用 -reindex 參數執行(會重新下載整個區塊鏈) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + 修剪(刪除)掉老舊區塊來減少需要的儲存空間。這種模式會關閉錢包功能,並且和 -txindex 及 -rescan 參數不相容。警告: 從這種模式還原會需要重新下載一整個區塊鏈。(預設值: 0 表示不修剪區塊,>%u 表示為區塊檔案的目標大小,單位是百萬位元組 MiB) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + 在修剪模式下沒辦法重新掃描區塊鏈。你需要配合使用 -reindex 參數來重新下載整個區塊鏈。 + + + Error: A fatal internal error occurred, see debug.log for details + 錯誤: 發生了致命的內部錯誤,詳情請看 debug.log + + + Fee (in %s/kB) to add to transactions you send (default: %s) + 交易付款時每千位元組(kB)的交易手續費(單位是 %s,預設值: %s) + + + Pruning blockstore... + 正在修剪區塊資料庫中... + Run in the background as a daemon and accept commands 用護靈模式在背後執行並接受指令 - Use the test network - 使用測試網路 + Unable to start HTTP server. See debug log for details. + 無法啟動 HTTP 伺服器。詳情請看除錯紀錄。 Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2825,18 +2996,14 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) 當錢包有交易改變時要執行的指令(指令中的 %s 會被取代成交易識別碼) - - Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s) - 一次錢包交易允許付出最高的總手續費;設定太低的話,可能會無法進行資料量大的交易(預設值: %s) - - - Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - 修剪(刪除)掉老舊區塊來減少儲存空間的需求。這種模式會關閉錢包功能,並且和 -txindex 參數不相容。警告: 從這種模式還原會需要重新下載一整個區塊鏈。(預設值: 0 表示不修剪區塊,>%u 表示為區塊檔案的目標大小,單位是百萬位元組 MiB) - Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) 設定指令碼驗證的執行緒數目 (%u 到 %d,0 表示程式自動決定,小於 0 表示保留處理器核心不用的數目,預設值: %d) + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + 區塊資料庫中有來自未來的區塊。可能是你電腦的日期時間不對。如果確定電腦日期時間沒錯的話,就重建區塊資料庫看看。 + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications 這是個還沒發表的測試版本 - 使用請自負風險 - 請不要用來開採或商業應用 @@ -2845,6 +3012,10 @@ Unable to bind to %s on this computer. Bitcoin Core is probably already running. 沒辦法繫結在這台電腦上的 %s 。位元幣核心可能已經在執行了。 + + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + 是否要使用「通用即插即用」協定(UPnP),來設定聽候連線的通訊埠的對應(預設值: 當有聽候連線且沒有指定 -proxy 參數時為 1) + WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) 警告: 收到了不尋常地多的 %d 個區塊在過去 %d 小時內生產出來(預期是 %d 個) @@ -2853,10 +3024,6 @@ WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) 警告: 請檢查你的網路連線狀況,收到了 %d 個區塊是在過去 %d 小時內生產出來(預期是 %d 個) - - Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - 警告: -paytxfee 設定了很高的金額!這可是你交易付款所要付的手續費。 - Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. 警告: 位元幣網路對於區塊鏈結的決定目前有分歧!看來有些礦工會有問題。 @@ -2865,10 +3032,6 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. 警告: 我們和某些連線的節點對於區塊鏈結的決定不同!你可能需要升級,或是需要等其它的節點升級。 - - Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - 警告: 讀取錢包檔 wallet.dat 時發生錯誤!所有的密鑰都正確讀取了,但是交易資料或位址簿資料可能會缺少或不正確。 - Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. 警告: 錢包檔 wallet.dat 壞掉,但資料被拯救回來了!原來的 wallet.dat 會改儲存在 %s, 檔名是 wallet.{timestamp}.bak. 如果餘額或交易資料有誤,你應該要用備份資料復原回來。 @@ -2878,17 +3041,13 @@ 把來自指定網域或位址的節點放進白名單。這個選項可以設定多次。 - (default: 1) - (預設值: 1) + -maxmempool must be at least %d MB + 參數 -maxmempool 至少要給 %d 百萬位元組(MB) <category> can be: <category> 可以是: - - Attempt to recover private keys from a corrupt wallet.dat - 嘗試從壞掉的錢包檔 wallet.dat 復原密鑰 - Block creation options: 區塊製造選項: @@ -2917,6 +3076,22 @@ Do you want to rebuild the block database now? 你想要現在重建區塊資料庫嗎? + + Enable publish hash block in <address> + 開啟傳送區塊雜湊值到目標 ZeroMQ 位址 <address> 去 + + + Enable publish hash transaction in <address> + 開啟傳送交易雜湊值到目標 ZeroMQ 位址 <address> 去 + + + Enable publish raw block in <address> + 開啟傳送區塊原始資料到目標 ZeroMQ 位址 <address> 去 + + + Enable publish raw transaction in <address> + 開啟傳送交易原始資料到目標 ZeroMQ 位址 <address> 去 + Error initializing block database 初始化區塊資料庫時發生錯誤 @@ -2933,10 +3108,6 @@ Error opening block database 打開區塊資料庫時發生錯誤 - - Error: A fatal internal error occured, see debug.log for details - 錯誤:一個致命的內部錯誤,到debug.log看更多細節 - Error: Disk space is low! 錯誤: 磁碟空間很少! @@ -2945,10 +3116,6 @@ Failed to listen on any port. Use -listen=0 if you want this. 在任意的通訊埠聽候失敗。如果你希望這樣的話,可以設定 -listen=0. - - If <category> is not supplied, output all debugging information. - 如果沒有提供 <category> 就會輸出所有的除錯資訊。 - Importing... 正在匯入中... @@ -2961,13 +3128,17 @@ Invalid -onion address: '%s' 無效的 -onion 位址: '%s' + + Keep the transaction memory pool below <n> megabytes (default: %u) + 在記憶體暫存池中保持最多 <n> 個百萬位元組的交易(預設值: %u) + Not enough file descriptors available. 檔案描述元不足。 Only connect to nodes in network <net> (ipv4, ipv6 or onion) - 只有連接到網絡節點 <net> (IPv4,IPv6或onion) + 只和 <net> 網路上的節點連線(ipv4, ipv6, 或 onion) Prune cannot be configured with a negative value. @@ -2989,6 +3160,26 @@ Specify wallet file (within data directory) 指定錢包檔(會在資料目錄中) + + Unsupported argument -benchmark ignored, use -debug=bench. + 忽略了不再支援的 -benchmark 參數,請改用 -debug=bench + + + Unsupported argument -debugnet ignored, use -debug=net. + 忽略了不再支援的 -debugnet 參數,請改用 -debug=net + + + Unsupported argument -tor found, use -onion. + 找到不再支援的 -tor 參數,請改用 -onion 參數。 + + + Use UPnP to map the listening port (default: %u) + 使用通用隨插即用 (UPnP) 協定來設定對應的服務連接埠(預設值: %u) + + + User Agent comment (%s) contains unsafe characters. + 使用者代理註解(%s)中含有不安全的字元。 + Verifying blocks... 正在驗證區塊資料... @@ -3013,18 +3204,10 @@ You need to rebuild the database using -reindex to change -txindex 改變 -txindex 參數後,必須要用 -reindex 參數來重建資料庫 - - Imports blocks from external blk000??.dat file - 從其它來源的 blk000??.dat 檔匯入區塊 - 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 允許指定的來源建立 JSON-RPC 連線。<ip> 的有效值可以是一個單獨位址(像是 1.2.3.4),一個網段/網段罩遮值(像是 1.2.3.4/255.255.255.0),或是網段/CIDR值(像是 1.2.3.4/24)。這個選項可以設定多次。 - - An error occurred while setting up the RPC address %s port %u for listening: %s - 設定在網路上以位址 %s 和通訊埠 %u 聽候 RPC 連線時發生錯誤: %s - Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 和指定的位址繫結,並且把連線過來的節點放進白名單。IPv6 請用 [主機]:通訊埠 這種格式 @@ -3049,17 +3232,13 @@ Error: Listening for incoming connections failed (listen returned error %s) 錯誤: 聽候外來連線失敗(回傳錯誤 %s) - - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - 錯誤: 找到不再支援的 -socks 參數。現在只支援 SOCKS5 協定的代理伺服器了,因為不再能夠指定 SOCKS 協定版本。 - Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) 當收到相關警示,或發現相當長的分支時,所要執行的指令(指令中的 %s 會被取代成警示訊息) - Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s) - 當處理轉發的交易時,如果每千位元組(Kb)的手續費比這個值低,就視為沒付手續費 (預設值: %s) + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + 當處理轉發的交易、挖礦、或製造交易時,如果每千位元組(kB)的手續費比這個值(單位是 %s)低,就視為沒付手續費(預設值: %s) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -3073,10 +3252,6 @@ Maximum size of data in data carrier transactions we relay and mine (default: %u) 轉發和開採時,對只帶資料的交易的大小上限(預設值: %u) - - Prune configured below the minimum of %d MB. Please use a higher number. - 設定的修剪值小於最小需求的 %d MB. 請指定大一點的數字。 - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) 是否允許在節點位址數目不足時,使用域名查詢來搜尋節點 (預設值: 當沒用 -connect 時為 1) @@ -3101,41 +3276,9 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. 此產品也包含了由 OpenSSL Project 所開發的 OpenSSL Toolkit 軟體 <https://www.openssl.org/>, 和由 Eric Young 撰寫的加解密軟體,以及由 Thomas Bernard 所撰寫的 UPnP 軟體。 - - To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file: -%s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -The username and password MUST NOT be the same. -If the file does not exist, create it with owner-readable-only file permissions. -It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - 要使用 bitcoind, 或是對 bitcoin-qt 指定 -server 選項,你必須要在以下設定檔中設定 RPC 密碼(選項: rpcpassword): -%s -建議你使用以下隨機產生的密碼: -rpcuser=bitcoinrpc -rpcpassword=%s -(你不用記住這個密碼) -注意使用者名稱(rpcuser)和密碼(rpcpassword)不可以相同! -如果設定檔還不存在,請在新增時,設定檔案權限為"只有主人才能讀取"。 -也建議你設定警示通知,這樣發生問題時你才會被通知到; -比如說設定: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - - - - Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. - 警告: -maxtxfee 設定了很高的金額!這可是一次交易就有可能付出的最高手續費。 - - - Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly. - 警告: 請檢查電腦日期和時間是否正確!位元幣核心沒辦法在時鐘不準的情況下正常運作。 - 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 - 在白名單中的節點不會因為偵測到阻斷服務攻擊而被停用。來自這些節點的交易也一定會被轉發,即使說交易本來就在記憶池裡了也一樣。適用於像是閘道伺服器。 + 在白名單中的節點不會因為偵測到阻斷服務攻擊(DoS)而被停用。來自這些節點的交易也一定會被轉發,即使說交易本來就在記憶池裡了也一樣。適用於像是閘道伺服器。 You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain @@ -3154,17 +3297,21 @@ rpcpassword=%s 啟用最佳鏈結... - Can't run with a wallet in prune mode. - 不能在有錢包時執行修剪模式。 + Always relay transactions received from whitelisted peers (default: %d) + 無條件轉發從白名點節點收到的交易(預設值: %d) + + + Attempt to recover private keys from a corrupt wallet.dat on startup + 啟動時嘗試從壞掉的錢包檔 wallet.dat 復原密鑰 + + + Automatically create Tor hidden service (default: %d) + 自動產生 Tor 隱藏服務(預設值: %d) Cannot resolve -whitebind address: '%s' 沒辦法解析 -whitebind 指定的位址: '%s' - - Choose data directory on startup (default: 0) - 啓動時選擇資料目錄(預設值: 0) - Connect through SOCKS5 proxy 透過 SOCKS5 代理伺服器連線 @@ -3173,10 +3320,6 @@ rpcpassword=%s Copyright (C) 2009-%i The Bitcoin Core Developers 版權為位元幣核心開發人員自西元 2009 至 %i 年起所有 - - Could not parse -rpcbind value %s as network address - 沒辦法解析 -rpcbind 參數值 %s 為網路位址 - Error loading wallet.dat: Wallet requires newer version of Bitcoin Core 載入 wallet.dat 檔案時發生錯誤: 這個錢包需要新版的位元幣核心 @@ -3186,12 +3329,8 @@ rpcpassword=%s 讀取資料庫時發生錯誤,要關閉了。 - Error: Unsupported argument -tor found, use -onion. - 錯誤: 找到不再支援的 -tor 參數,請改用 -onion 參數。 - - - Fee (in BTC/kB) to add to transactions you send (default: %s) - 交易付款時每千位元組(kB)的交易手續費 (預設值: %s) + Imports blocks from external blk000??.dat file on startup + 啟動時從其它來源的 blk000??.dat 檔匯入區塊 Information @@ -3233,22 +3372,26 @@ rpcpassword=%s Node relay options: 節點轉發選項: - - RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) - RPC SSL 選項: (SSL 設定程序請見 Bitcoin Wiki) - RPC server options: RPC 伺服器選項: - - RPC support for HTTP persistent connections (default: %d) - RPC 是否支援 HTTP 持久連線(預設值: %d) - Rebuild block chain index from current blk000??.dat files on startup 啟動時從目前的區塊檔 blk000??.dat 重建區塊鏈的索引 + + Receive and display P2P network alerts (default: %u) + 接收並顯示對等網路(P2P)警示 (預設值: %u) + + + Reducing -maxconnections from %d to %d, because of system limitations. + 因為系統的限制,將 -maxconnections 參數從 %d 降到了 %d + + + Rescan the block chain for missing wallet transactions on startup + 啟動時重新掃描區塊鏈,來尋找錢包可能漏掉的交易。 + Send trace/debug info to console instead of debug.log file 在終端機顯示追蹤或除錯資訊,而不是寫到檔案 debug.log 中 @@ -3257,22 +3400,10 @@ rpcpassword=%s Send transactions as zero-fee transactions if possible (default: %u) 盡可能送出不用付手續費的交易(預設值: %u) - - Set SSL root certificates for payment request (default: -system-) - 設定付款請求時所使用的 SSL 根憑證 (預設值: 系統憑證庫) - - - Set language, for example "de_DE" (default: system locale) - 設定語言,比如說 de_DE (預設值: 系統語系) - Show all debugging options (usage: --help -help-debug) 顯示所有的除錯選項 (用法: --help --help-debug) - - Show splash screen on startup (default: 1) - 顯示啓動畫面(預設值: 1) - Shrink debug.log file on client startup (default: 1 when no -debug) 客戶端軟體啓動時把 debug.log 檔縮小(預設值: 當沒有 -debug 時為 1) @@ -3281,10 +3412,6 @@ rpcpassword=%s Signing transaction failed 簽署交易失敗 - - Start minimized - 啓動時縮到最小 - The transaction amount is too small to pay the fee 交易金額太少而付不起手續費 @@ -3293,6 +3420,14 @@ rpcpassword=%s This is experimental software. 這套軟體屬於實驗性質。 + + Tor control port password (default: empty) + Tor 控制埠密碼(預設值: 空白) + + + Tor control port to use if onion listening enabled (default: %s) + 開啟聽候 onion 連線時的 Tor 控制埠號碼(預設值: %s) + Transaction amount too small 交易金額太小 @@ -3309,17 +3444,13 @@ rpcpassword=%s Transaction too large 交易位元量太大 - - UI Options: - 使用介面選項: - Unable to bind to %s on this computer (bind returned error %s) 無法和這台電腦上的 %s 繫結(回傳錯誤 %s) - Use UPnP to map the listening port (default: 1 when listening) - 是否要使用「通用即插即用」協定(UPnP),來設定聽候連線的通訊埠的對應(預設值: 當有聽候連線時為 1) + Upgrade wallet to latest format on startup + 啟動時把錢包檔案升級成最新的格式 Username for JSON-RPC connections @@ -3334,20 +3465,16 @@ rpcpassword=%s 警告 - Warning: Unsupported argument -benchmark ignored, use -debug=bench. - 警告: 忽略了不再支援的 -benchmark 參數,請改用 -debug=bench. - - - Warning: Unsupported argument -debugnet ignored, use -debug=net. - 警告: 忽略了不再支援的 -debugnet 參數,請改用 -debug=net. + Whether to operate in a blocks only mode (default: %u) + 是否要用只要區塊模式運作(預設值: %u) Zapping all transactions from wallet... 正在砍掉錢包中的所有交易... - on startup - 當啟動時 + ZeroMQ notification options: + ZeroMQ 通知選項: wallet.dat corrupt, salvage failed @@ -3361,18 +3488,6 @@ rpcpassword=%s Execute command when the best block changes (%s in cmd is replaced by block hash) 當最新區塊改變時要執行的指令(指令中的 %s 會被取代成區塊雜湊值) - - Upgrade wallet to latest format - 把錢包檔案升級成最新的格式 - - - Rescan the block chain for missing wallet transactions - 重新掃描區塊鏈,來尋找錢包可能漏掉的交易。 - - - Use OpenSSL (https) for JSON-RPC connections - 在 JSON-RPC 連線使用 OpenSSL (https) - This help message 這些說明訊息 @@ -3393,6 +3508,26 @@ rpcpassword=%s (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 表示保留交易描述資料,像是帳戶使用者和付款請求資訊;2 表示丟掉交易描述資料) + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + 參數 -maxtxfee 設定了很高的金額!這可是你一次交易就有可能付出的最高手續費。 + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + 參數 -paytxfee 設定了很高的金額!這可是你交易付款時所要付的手續費。 + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + 不要讓交易留在記憶池中超過 <n> 個小時(預設值: %u) + + + Error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + 讀取錢包檔 wallet.dat 時發生錯誤!所有的密鑰都正確讀取了,但是交易資料或位址簿資料可能會缺少或不正確。 + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + 當製造交易時,如果每千位元組(kB)的手續費比這個值(單位是 %s)低,就視為沒付手續費(預設值: %s) + How thorough the block verification of -checkblocks is (0-4, default: %u) 使用 -checkblocks 檢查區塊的仔細程度(0 到 4,預設值: %u) @@ -3409,18 +3544,34 @@ rpcpassword=%s Output debugging information (default: %u, supplying <category> is optional) 輸出除錯資訊(預設值: %u, 不一定要指定 <category>) + + Support filtering of blocks and transaction with bloom filters (default: %u) + 支援用布倫過濾器來過濾區塊和交易(預設值: %u) + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + 網路版本字串的總長度(%i)超過最大長度(%i)了。請減少 uacomment 參數的數目或長度。 + + + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) + 試著保持輸出流量在目標值以下,單位是每 24 小時的百萬位元組(MiB)數,0 表示沒有限制(預設值: %d) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + 找到不再支援的 -socks 參數。現在只支援 SOCKS5 協定的代理伺服器,因此不可以指定 SOCKS 協定版本了。 + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) - 使用另外的 SOCK5 代理伺服器,來透過 Tor 隱藏服務跟節點聯繫(預設值: %s) + 使用另外的 SOCK5 代理伺服器,來透過 Tor 隱藏服務跟其他節點聯絡(預設值: %s) + + + 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. This option can be specified multiple times + JSON-RPC 連線要用的使用者名稱和雜湊密碼。<userpw> 的格式是:<使用者名稱>:<調味值>$<雜湊值>。在 share/rpcuser 目錄下有一個示範的 python 程式。這個選項可以給很多次。 (default: %s) (預設值: %s) - - Acceptable ciphers (default: %s) - 可以接受的加密演算法(預設值: %s) - Always query for peer addresses via DNS lookup (default: %u) 是否一定要用域名查詢來搜尋節點(預設值: %u) @@ -3481,14 +3632,6 @@ rpcpassword=%s Relay non-P2SH multisig (default: %u) 允許轉發非 P2SH 的多簽章交易(預設值: %u) - - Server certificate file (default: %s) - 伺服器憑證檔(預設值: %s) - - - Server private key (default: %s) - 伺服器密鑰檔(預設值: %s) - Set key pool size to <n> (default: %u) 設定密鑰池大小為 <n> (預設值: %u) diff --git a/src/qt/macdockiconhandler.h b/src/qt/macdockiconhandler.h index 8bd867c10..1c28593d4 100644 --- a/src/qt/macdockiconhandler.h +++ b/src/qt/macdockiconhandler.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/macnotificationhandler.h b/src/qt/macnotificationhandler.h index bd66b96b2..d4749b3d5 100644 --- a/src/qt/macnotificationhandler.h +++ b/src/qt/macnotificationhandler.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp index 5c84fd772..5ba780801 100644 --- a/src/qt/networkstyle.cpp +++ b/src/qt/networkstyle.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014 The Bitcoin Core developers +// Copyright (c) 2014-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index 5a564248e..a45afde56 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/notificator.h b/src/qt/notificator.h index f2a15e9c3..f92b791d4 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp index 1c843aecb..5a6616134 100644 --- a/src/qt/openuridialog.cpp +++ b/src/qt/openuridialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/openuridialog.h b/src/qt/openuridialog.h index 28b8f56ca..e94593d5b 100644 --- a/src/qt/openuridialog.h +++ b/src/qt/openuridialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index f57c1203f..95a3fa8d2 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -18,7 +18,7 @@ #include "txdb.h" // for -dbcache defaults #ifdef ENABLE_WALLET -#include "wallet/wallet.h" // for CWallet::minTxFee +#include "wallet/wallet.h" // for CWallet::GetRequiredFee() #endif #include @@ -34,8 +34,7 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : QDialog(parent), ui(new Ui::OptionsDialog), model(0), - mapper(0), - fProxyIpsValid(true) + mapper(0) { ui->setupUi(this); @@ -60,12 +59,11 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool))); connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool))); + connect(ui->connectSocks, SIGNAL(toggled(bool)), this, SLOT(updateProxyValidationState())); connect(ui->connectSocksTor, SIGNAL(toggled(bool)), ui->proxyIpTor, SLOT(setEnabled(bool))); connect(ui->connectSocksTor, SIGNAL(toggled(bool)), ui->proxyPortTor, SLOT(setEnabled(bool))); - - ui->proxyIp->installEventFilter(this); - ui->proxyIpTor->installEventFilter(this); + connect(ui->connectSocksTor, SIGNAL(toggled(bool)), this, SLOT(updateProxyValidationState())); /* Window elements init */ #ifdef Q_OS_MAC @@ -80,6 +78,11 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : /* Display elements init */ QDir translations(":translations"); + + ui->bitcoinAtStartup->setToolTip(ui->bitcoinAtStartup->toolTip().arg(tr(PACKAGE_NAME))); + ui->bitcoinAtStartup->setText(ui->bitcoinAtStartup->text().arg(tr(PACKAGE_NAME))); + + ui->lang->setToolTip(ui->lang->toolTip().arg(tr(PACKAGE_NAME))); ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant("")); Q_FOREACH(const QString &langStr, translations.entryList()) { @@ -119,7 +122,12 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : mapper->setOrientation(Qt::Vertical); /* setup/change UI elements when proxy IPs are invalid/valid */ - connect(this, SIGNAL(proxyIpChecks(QValidatedLineEdit *, int)), this, SLOT(doProxyIpChecks(QValidatedLineEdit *, int))); + ui->proxyIp->setCheckValidator(new ProxyAddressValidator(parent)); + ui->proxyIpTor->setCheckValidator(new ProxyAddressValidator(parent)); + connect(ui->proxyIp, SIGNAL(validationDidChange(QValidatedLineEdit *)), this, SLOT(updateProxyValidationState())); + connect(ui->proxyIpTor, SIGNAL(validationDidChange(QValidatedLineEdit *)), this, SLOT(updateProxyValidationState())); + connect(ui->proxyPort, SIGNAL(textChanged(const QString&)), this, SLOT(updateProxyValidationState())); + connect(ui->proxyPortTor, SIGNAL(textChanged(const QString&)), this, SLOT(updateProxyValidationState())); } OptionsDialog::~OptionsDialog() @@ -200,18 +208,6 @@ void OptionsDialog::setMapper() mapper->addMapping(ui->thirdPartyTxUrls, OptionsModel::ThirdPartyTxUrls); } -void OptionsDialog::enableOkButton() -{ - /* prevent enabling of the OK button when data modified, if there is an invalid proxy address present */ - if(fProxyIpsValid) - setOkButtonState(true); -} - -void OptionsDialog::disableOkButton() -{ - setOkButtonState(false); -} - void OptionsDialog::setOkButtonState(bool fState) { ui->okButton->setEnabled(fState); @@ -269,24 +265,20 @@ void OptionsDialog::clearStatusLabel() ui->statusLabel->clear(); } -void OptionsDialog::doProxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort) +void OptionsDialog::updateProxyValidationState() { - Q_UNUSED(nProxyPort); - - CService addrProxy; - - /* Check for a valid IPv4 / IPv6 address */ - if (!(fProxyIpsValid = LookupNumeric(pUiProxyIp->text().toStdString().c_str(), addrProxy))) + QValidatedLineEdit *pUiProxyIp = ui->proxyIp; + QValidatedLineEdit *otherProxyWidget = (pUiProxyIp == ui->proxyIpTor) ? ui->proxyIp : ui->proxyIpTor; + if (pUiProxyIp->isValid() && (!ui->proxyPort->isEnabled() || ui->proxyPort->text().toInt() > 0) && (!ui->proxyPortTor->isEnabled() || ui->proxyPortTor->text().toInt() > 0)) { - disableOkButton(); - pUiProxyIp->setValid(false); - ui->statusLabel->setStyleSheet("QLabel { color: red; }"); - ui->statusLabel->setText(tr("The supplied proxy address is invalid.")); + setOkButtonState(otherProxyWidget->isValid()); //only enable ok button if both proxys are valid + ui->statusLabel->clear(); } else { - enableOkButton(); - ui->statusLabel->clear(); + setOkButtonState(false); + ui->statusLabel->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel->setText(tr("The supplied proxy address is invalid.")); } } @@ -312,18 +304,18 @@ void OptionsDialog::updateDefaultProxyNets() (strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachTor->setChecked(true) : ui->proxyReachTor->setChecked(false); } -bool OptionsDialog::eventFilter(QObject *object, QEvent *event) +ProxyAddressValidator::ProxyAddressValidator(QObject *parent) : +QValidator(parent) { - if(event->type() == QEvent::FocusOut) - { - if(object == ui->proxyIp) - { - Q_EMIT proxyIpChecks(ui->proxyIp, ui->proxyPort->text().toInt()); - } - else if(object == ui->proxyIpTor) - { - Q_EMIT proxyIpChecks(ui->proxyIpTor, ui->proxyPortTor->text().toInt()); - } - } - return QDialog::eventFilter(object, event); +} + +QValidator::State ProxyAddressValidator::validate(QString &input, int &pos) const +{ + Q_UNUSED(pos); + // Validate the proxy + proxyType addrProxy = proxyType(CService(input.toStdString(), 9050), true); + if (addrProxy.IsValid()) + return QValidator::Acceptable; + + return QValidator::Invalid; } diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 348489c59..e944fb9ee 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -6,6 +6,7 @@ #define BITCOIN_QT_OPTIONSDIALOG_H #include +#include class OptionsModel; class QValidatedLineEdit; @@ -18,6 +19,18 @@ namespace Ui { class OptionsDialog; } +/** Proxy address widget validator, checks for a valid proxy address. + */ +class ProxyAddressValidator : public QValidator +{ + Q_OBJECT + +public: + explicit ProxyAddressValidator(QObject *parent); + + State validate(QString &input, int &pos) const; +}; + /** Preferences dialog. */ class OptionsDialog : public QDialog { @@ -30,14 +43,7 @@ public: void setModel(OptionsModel *model); void setMapper(); -protected: - bool eventFilter(QObject *object, QEvent *event); - private Q_SLOTS: - /* enable OK button */ - void enableOkButton(); - /* disable OK button */ - void disableOkButton(); /* set OK button state (enabled / disabled) */ void setOkButtonState(bool fState); void on_resetButton_clicked(); @@ -46,7 +52,7 @@ private Q_SLOTS: void showRestartWarning(bool fPersistent = false); void clearStatusLabel(); - void doProxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort); + void updateProxyValidationState(); /* query the networks, for which the default proxy is used */ void updateDefaultProxyNets(); @@ -57,7 +63,6 @@ private: Ui::OptionsDialog *ui; OptionsModel *model; QDataWidgetMapper *mapper; - bool fProxyIpsValid; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 65e490570..d091bb9e6 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -26,10 +26,10 @@ #include #include -OptionsModel::OptionsModel(QObject *parent) : +OptionsModel::OptionsModel(QObject *parent, bool resetSettings) : QAbstractListModel(parent) { - Init(); + Init(resetSettings); } void OptionsModel::addOverriddenOption(const std::string &option) @@ -38,8 +38,11 @@ void OptionsModel::addOverriddenOption(const std::string &option) } // Writes all missing QSettings with their default values -void OptionsModel::Init() +void OptionsModel::Init(bool resetSettings) { + if (resetSettings) + Reset(); + QSettings settings; // Ensure restart flag is unset on client startup diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 8448cad8d..841711dd2 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -24,7 +24,7 @@ class OptionsModel : public QAbstractListModel Q_OBJECT public: - explicit OptionsModel(QObject *parent = 0); + explicit OptionsModel(QObject *parent = 0, bool resetSettings = false); enum OptionID { StartAtStartup, // bool @@ -48,7 +48,7 @@ public: OptionIDRowCount, }; - void Init(); + void Init(bool resetSettings = false); void Reset(); int rowCount(const QModelIndex & parent = QModelIndex()) const; diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index a56c80ac6..d577345e4 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 4139eb35d..911443c76 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index 78a783dea..20e1f79ff 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -145,7 +145,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c int error = X509_STORE_CTX_get_error(store_ctx); // For testing payment requests, we allow self signed root certs! // This option is just shown in the UI options, if -help-debug is enabled. - if (!(error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && GetBoolArg("-allowselfsignedrootcertificates", false))) { + if (!(error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && GetBoolArg("-allowselfsignedrootcertificates", DEFAULT_SELFSIGNED_ROOTCERTS))) { throw SSLVerifyError(X509_verify_cert_error_string(error)); } else { qDebug() << "PaymentRequestPlus::getMerchant: Allowing self signed root certificate, because -allowselfsignedrootcertificates is true."; @@ -201,7 +201,7 @@ QList > PaymentRequestPlus::getPayTo() const const unsigned char* scriptStr = (const unsigned char*)details.outputs(i).script().data(); CScript s(scriptStr, scriptStr+details.outputs(i).script().size()); - result.append(make_pair(s, details.outputs(i).amount())); + result.append(std::make_pair(s, details.outputs(i).amount())); } return result; } diff --git a/src/qt/paymentrequestplus.h b/src/qt/paymentrequestplus.h index 99a7186b8..a73fe5f29 100644 --- a/src/qt/paymentrequestplus.h +++ b/src/qt/paymentrequestplus.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin developers +// Copyright (c) 2011-2015 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,6 +15,8 @@ #include #include +static const bool DEFAULT_SELFSIGNED_ROOTCERTS = false; + // // Wraps dumb protocol buffer paymentRequest // with extra methods diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 31a6d65a8..c80aebb00 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index fa120a435..2d27ed078 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 770a86054..84ad0052f 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -85,7 +85,7 @@ public: } if (sortColumn >= 0) - // sort cacheNodeStats (use stable sort to prevent rows jumping around unneceesarily) + // sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily) qStableSort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder)); // build index map @@ -147,7 +147,7 @@ int PeerTableModel::rowCount(const QModelIndex &parent) const int PeerTableModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); - return columns.length();; + return columns.length(); } QVariant PeerTableModel::data(const QModelIndex &index, int role) const diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index 5f149ea87..a2aaaa5d2 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp index 346369392..baa2eb67f 100644 --- a/src/qt/qvalidatedlineedit.cpp +++ b/src/qt/qvalidatedlineedit.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -99,9 +99,25 @@ void QValidatedLineEdit::checkValidity() } else setValid(false); + + Q_EMIT validationDidChange(this); } void QValidatedLineEdit::setCheckValidator(const QValidator *v) { checkValidator = v; } + +bool QValidatedLineEdit::isValid() +{ + // use checkValidator in case the QValidatedLineEdit is disabled + if (checkValidator) + { + QString address = text(); + int pos = 0; + if (checkValidator->validate(address, pos) == QValidator::Acceptable) + return true; + } + + return valid; +} diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h index 8665acda5..66734cc9d 100644 --- a/src/qt/qvalidatedlineedit.h +++ b/src/qt/qvalidatedlineedit.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -18,6 +18,7 @@ public: explicit QValidatedLineEdit(QWidget *parent); void clear(); void setCheckValidator(const QValidator *v); + bool isValid(); protected: void focusInEvent(QFocusEvent *evt); @@ -31,6 +32,9 @@ public Q_SLOTS: void setValid(bool valid); void setEnabled(bool enabled); +Q_SIGNALS: + void validationDidChange(QValidatedLineEdit *validatedLineEdit); + private Q_SLOTS: void markValid(); void checkValidity(); diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp index 800436661..146f3dd57 100644 --- a/src/qt/qvaluecombobox.cpp +++ b/src/qt/qvaluecombobox.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/qvaluecombobox.h b/src/qt/qvaluecombobox.h index 5b20e6a5a..f26630231 100644 --- a/src/qt/qvaluecombobox.h +++ b/src/qt/qvaluecombobox.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 7fb68cc32..0b355837a 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -82,6 +82,7 @@ void ReceiveCoinsDialog::setModel(WalletModel *model) tableView->setSelectionMode(QAbstractItemView::ContiguousSelection); tableView->setColumnWidth(RecentRequestsTableModel::Date, DATE_COLUMN_WIDTH); tableView->setColumnWidth(RecentRequestsTableModel::Label, LABEL_COLUMN_WIDTH); + tableView->setColumnWidth(RecentRequestsTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH); connect(tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index eaaf129a9..226fd65cf 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -36,7 +36,7 @@ public: enum ColumnWidths { DATE_COLUMN_WIDTH = 130, LABEL_COLUMN_WIDTH = 120, - AMOUNT_MINIMUM_COLUMN_WIDTH = 160, + AMOUNT_MINIMUM_COLUMN_WIDTH = 180, MINIMUM_COLUMN_WIDTH = 130 }; diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index 0c4a20cf9..a1e9156ee 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -144,7 +144,7 @@ void ReceiveRequestDialog::update() html += "" + GUIUtil::HtmlEscape(uri) + "
"; html += ""+tr("Address")+": " + GUIUtil::HtmlEscape(info.address) + "
"; if(info.amount) - html += ""+tr("Amount")+": " + BitcoinUnits::formatWithUnit(model->getDisplayUnit(), info.amount) + "
"; + html += ""+tr("Amount")+": " + BitcoinUnits::formatHtmlWithUnit(model->getDisplayUnit(), info.amount) + "
"; if(!info.label.isEmpty()) html += ""+tr("Label")+": " + GUIUtil::HtmlEscape(info.label) + "
"; if(!info.message.isEmpty()) diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h index 69f84ebbd..4cab4caff 100644 --- a/src/qt/receiverequestdialog.h +++ b/src/qt/receiverequestdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 5692a7aae..2335d6b28 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -83,7 +83,7 @@ QVariant RecentRequestsTableModel::data(const QModelIndex &index, int role) cons } case Amount: if (rec->recipient.amount == 0 && role == Qt::DisplayRole) - return tr("(no amount)"); + return tr("(no amount requested)"); else if (role == Qt::EditRole) return BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount, false, BitcoinUnits::separatorNever); else @@ -125,12 +125,7 @@ void RecentRequestsTableModel::updateAmountColumnTitle() /** Gets title for amount column including current display unit if optionsModel reference available. */ QString RecentRequestsTableModel::getAmountTitle() { - QString amountTitle = tr("Amount"); - if (this->walletModel->getOptionsModel() != NULL) - { - amountTitle += " ("+BitcoinUnits::name(this->walletModel->getOptionsModel()->getDisplayUnit()) + ")"; - } - return amountTitle; + return (this->walletModel->getOptionsModel() != NULL) ? tr("Requested") + " ("+BitcoinUnits::name(this->walletModel->getOptionsModel()->getDisplayUnit()) + ")" : ""; } QModelIndex RecentRequestsTableModel::index(int row, int column, const QModelIndex &parent) const diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h index 64faa72d4..f3cf03f4e 100644 --- a/src/qt/recentrequeststablemodel.h +++ b/src/qt/recentrequeststablemodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/res/bitcoin-qt-res.rc b/src/qt/res/bitcoin-qt-res.rc index 9f66d0af7..19c3d5d97 100644 --- a/src/qt/res/bitcoin-qt-res.rc +++ b/src/qt/res/bitcoin-qt-res.rc @@ -19,13 +19,13 @@ BEGIN BLOCK "040904E4" // U.S. English - multilingual (hex) BEGIN VALUE "CompanyName", "Bitcoin" - VALUE "FileDescription", "Bitcoin Core (GUI node for Bitcoin)" + VALUE "FileDescription", PACKAGE_NAME " (GUI node for Bitcoin)" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "bitcoin-qt" VALUE "LegalCopyright", COPYRIGHT_STR VALUE "LegalTrademarks1", "Distributed under the MIT software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php." VALUE "OriginalFilename", "bitcoin-qt.exe" - VALUE "ProductName", "Bitcoin Core" + VALUE "ProductName", PACKAGE_NAME VALUE "ProductVersion", VER_PRODUCTVERSION_STR END END diff --git a/src/qt/res/icons/about.png b/src/qt/res/icons/about.png index 83eb3c07e..4143be8ba 100644 Binary files a/src/qt/res/icons/about.png and b/src/qt/res/icons/about.png differ diff --git a/src/qt/res/icons/chevron.png b/src/qt/res/icons/chevron.png new file mode 100644 index 000000000..2309fb38e Binary files /dev/null and b/src/qt/res/icons/chevron.png differ diff --git a/src/qt/res/icons/fontbigger.png b/src/qt/res/icons/fontbigger.png new file mode 100644 index 000000000..5ca5c563b Binary files /dev/null and b/src/qt/res/icons/fontbigger.png differ diff --git a/src/qt/res/icons/fontsmaller.png b/src/qt/res/icons/fontsmaller.png new file mode 100644 index 000000000..1a6bb3a61 Binary files /dev/null and b/src/qt/res/icons/fontsmaller.png differ diff --git a/src/qt/res/icons/transaction_abandoned.png b/src/qt/res/icons/transaction_abandoned.png new file mode 100644 index 000000000..8ca6445c2 Binary files /dev/null and b/src/qt/res/icons/transaction_abandoned.png differ diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index f387a3ec8..d8647d902 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1,7 +1,11 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + #include "rpcconsole.h" #include "ui_debugwindow.h" @@ -12,8 +16,8 @@ #include "bantablemodel.h" #include "chainparams.h" -#include "rpcserver.h" -#include "rpcclient.h" +#include "rpc/server.h" +#include "rpc/client.h" #include "util.h" #include @@ -27,10 +31,12 @@ #include #include #include +#include #include #include #include #include +#include #if QT_VERSION < 0x050000 #include @@ -41,9 +47,9 @@ // TODO: receive errors and debug messages through ClientModel const int CONSOLE_HISTORY = 50; -const QSize ICON_SIZE(24, 24); - const int INITIAL_TRAFFIC_GRAPH_MINS = 30; +const QSize FONT_RANGE(4, 40); +const char fontSizeSettingsKey[] = "consoleFontSize"; const struct { const char *url; @@ -245,25 +251,31 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) : cachedNodeid(-1), platformStyle(platformStyle), peersTableContextMenu(0), - banTableContextMenu(0) + banTableContextMenu(0), + consoleFontSize(0) { ui->setupUi(this); GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this); + ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(tr(PACKAGE_NAME))); + if (platformStyle->getImagesOnButtons()) { ui->openDebugLogfileButton->setIcon(platformStyle->SingleColorIcon(":/icons/export")); } ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); + ui->fontBiggerButton->setIcon(platformStyle->SingleColorIcon(":/icons/fontbigger")); + ui->fontSmallerButton->setIcon(platformStyle->SingleColorIcon(":/icons/fontsmaller")); // Install event filter for up and down arrow ui->lineEdit->installEventFilter(this); ui->messagesWidget->installEventFilter(this); connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); + connect(ui->fontBiggerButton, SIGNAL(clicked()), this, SLOT(fontBigger())); + connect(ui->fontSmallerButton, SIGNAL(clicked()), this, SLOT(fontSmaller())); connect(ui->btnClearTrafficGraph, SIGNAL(clicked()), ui->trafficGraph, SLOT(clear())); // set library version labels - ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION)); #ifdef ENABLE_WALLET ui->berkeleyDBVersion->setText(DbEnv::version(0, 0, 0)); #else @@ -272,7 +284,9 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) : #endif // Register RPC timer interface rpcTimerInterface = new QtRPCTimerInterface(); - RPCRegisterTimerInterface(rpcTimerInterface); + // avoid accidentally overwriting an existing, non QTThread + // based timer interface + RPCSetTimerInterfaceIfUnset(rpcTimerInterface); startExecutor(); setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS); @@ -280,6 +294,8 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) : ui->detailWidget->hide(); ui->peerHeading->setText(tr("Select a peer to view detailed information.")); + QSettings settings; + consoleFontSize = settings.value(fontSizeSettingsKey, QFontInfo(QFont()).pointSize()).toInt(); clear(); } @@ -287,7 +303,7 @@ RPCConsole::~RPCConsole() { GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this); Q_EMIT stopExecutor(); - RPCUnregisterTimerInterface(rpcTimerInterface); + RPCUnsetTimerInterface(rpcTimerInterface); delete rpcTimerInterface; delete ui; } @@ -337,12 +353,14 @@ void RPCConsole::setClientModel(ClientModel *model) setNumConnections(model->getNumConnections()); connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); - setNumBlocks(model->getNumBlocks(), model->getLastBlockDate()); - connect(model, SIGNAL(numBlocksChanged(int,QDateTime)), this, SLOT(setNumBlocks(int,QDateTime))); + setNumBlocks(model->getNumBlocks(), model->getLastBlockDate(), model->getVerificationProgress(NULL)); + connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(setNumBlocks(int,QDateTime,double))); updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent()); connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64))); + connect(model, SIGNAL(mempoolSizeChanged(long,size_t)), this, SLOT(setMempoolSize(long,size_t))); + // set up peer table ui->peerWidget->setModel(model->getPeerTableModel()); ui->peerWidget->verticalHeader()->hide(); @@ -426,9 +444,23 @@ void RPCConsole::setClientModel(ClientModel *model) ui->clientVersion->setText(model->formatFullVersion()); ui->clientUserAgent->setText(model->formatSubVersion()); ui->clientName->setText(model->clientName()); - ui->buildDate->setText(model->formatBuildDate()); + ui->dataDir->setText(model->dataDir()); ui->startupTime->setText(model->formatClientStartupTime()); ui->networkName->setText(QString::fromStdString(Params().NetworkIDString())); + + //Setup autocomplete and attach it + QStringList wordList; + std::vector commandList = tableRPC.listCommands(); + for (size_t i = 0; i < commandList.size(); ++i) + { + wordList << commandList[i].c_str(); + } + + autoCompleter = new QCompleter(wordList, this); + ui->lineEdit->setCompleter(autoCompleter); + + // clear the lineEdit after activating from QCompleter + connect(autoCompleter, SIGNAL(activated(const QString&)), ui->lineEdit, SLOT(clear()), Qt::QueuedConnection); } } @@ -443,11 +475,49 @@ static QString categoryClass(int category) } } -void RPCConsole::clear() +void RPCConsole::fontBigger() +{ + setFontSize(consoleFontSize+1); +} + +void RPCConsole::fontSmaller() +{ + setFontSize(consoleFontSize-1); +} + +void RPCConsole::setFontSize(int newSize) +{ + QSettings settings; + + //don't allow a insane font size + if (newSize < FONT_RANGE.width() || newSize > FONT_RANGE.height()) + return; + + // temp. store the console content + QString str = ui->messagesWidget->toHtml(); + + // replace font tags size in current content + str.replace(QString("font-size:%1pt").arg(consoleFontSize), QString("font-size:%1pt").arg(newSize)); + + // store the new font size + consoleFontSize = newSize; + settings.setValue(fontSizeSettingsKey, consoleFontSize); + + // clear console (reset icon sizes, default stylesheet) and re-add the content + float oldPosFactor = 1.0 / ui->messagesWidget->verticalScrollBar()->maximum() * ui->messagesWidget->verticalScrollBar()->value(); + clear(false); + ui->messagesWidget->setHtml(str); + ui->messagesWidget->verticalScrollBar()->setValue(oldPosFactor * ui->messagesWidget->verticalScrollBar()->maximum()); +} + +void RPCConsole::clear(bool clearHistory) { ui->messagesWidget->clear(); - history.clear(); - historyPtr = 0; + if(clearHistory) + { + history.clear(); + historyPtr = 0; + } ui->lineEdit->clear(); ui->lineEdit->setFocus(); @@ -458,19 +528,23 @@ void RPCConsole::clear() ui->messagesWidget->document()->addResource( QTextDocument::ImageResource, QUrl(ICON_MAPPING[i].url), - platformStyle->SingleColorImage(ICON_MAPPING[i].source).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + platformStyle->SingleColorImage(ICON_MAPPING[i].source).scaled(QSize(consoleFontSize*2, consoleFontSize*2), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); } // Set default style sheet + QFontInfo fixedFontInfo(GUIUtil::fixedPitchFont()); ui->messagesWidget->document()->setDefaultStyleSheet( + QString( "table { }" - "td.time { color: #808080; padding-top: 3px; } " + "td.time { color: #808080; font-size: %2; padding-top: 3px; } " + "td.message { font-family: %1; font-size: %2; white-space:pre-wrap; } " "td.cmd-request { color: #006060; } " "td.cmd-error { color: red; } " "b { color: #006060; } " - ); + ).arg(fixedFontInfo.family(), QString("%1pt").arg(consoleFontSize)) + ); - message(CMD_REPLY, (tr("Welcome to the Bitcoin Core RPC console.") + "
" + + message(CMD_REPLY, (tr("Welcome to the %1 RPC console.").arg(tr(PACKAGE_NAME)) + "
" + tr("Use up and down arrows to navigate history, and Ctrl-L to clear screen.") + "
" + tr("Type help for an overview of available commands.")), true); } @@ -494,7 +568,7 @@ void RPCConsole::message(int category, const QString &message, bool html) if(html) out += message; else - out += GUIUtil::HtmlEscape(message, true); + out += GUIUtil::HtmlEscape(message, false); out += ""; ui->messagesWidget->append(out); } @@ -511,12 +585,22 @@ void RPCConsole::setNumConnections(int count) ui->numberOfConnections->setText(connections); } -void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate) +void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress) { ui->numberOfBlocks->setText(QString::number(count)); ui->lastBlockTime->setText(blockDate.toString()); } +void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage) +{ + ui->mempoolNumberTxs->setText(QString::number(numberOfTxs)); + + if (dynUsage < 1000000) + ui->mempoolSize->setText(QString::number(dynUsage/1000.0, 'f', 2) + " KB"); + else + ui->mempoolSize->setText(QString::number(dynUsage/1000000.0, 'f', 2) + " MB"); +} + void RPCConsole::on_lineEdit_returnPressed() { QString cmd = ui->lineEdit->text(); @@ -849,4 +933,9 @@ void RPCConsole::showOrHideBanTableIfRequired() bool visible = clientModel->getBanTableModel()->shouldShow(); ui->banlistWidget->setVisible(visible); ui->banHeading->setVisible(visible); -} \ No newline at end of file +} + +void RPCConsole::setTabFocus(enum TabTypes tabType) +{ + ui->tabWidget->setCurrentIndex(tabType); +} diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index b86f77678..2923587bc 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,6 +11,7 @@ #include "net.h" #include +#include class ClientModel; class PlatformStyle; @@ -44,6 +45,13 @@ public: CMD_ERROR }; + enum TabTypes { + TAB_INFO = 0, + TAB_CONSOLE = 1, + TAB_GRAPH = 2, + TAB_PEERS = 3 + }; + protected: virtual bool eventFilter(QObject* obj, QEvent *event); void keyPressEvent(QKeyEvent *); @@ -70,12 +78,18 @@ private Q_SLOTS: void clearSelectedNode(); public Q_SLOTS: - void clear(); + void clear(bool clearHistory = true); + void fontBigger(); + void fontSmaller(); + void setFontSize(int newSize); + /** Append the message to the message widget */ void message(int category, const QString &message, bool html = false); /** Set number of connections shown in the UI */ void setNumConnections(int count); /** Set number of blocks and last block date shown in the UI */ - void setNumBlocks(int count, const QDateTime& blockDate); + void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress); + /** Set size (number of transactions and memory usage) of the mempool in the UI */ + void setMempoolSize(long numberOfTxs, size_t dynUsage); /** Go forward or back in history */ void browseHistory(int offset); /** Scroll console view to end */ @@ -90,6 +104,8 @@ public Q_SLOTS: void banSelectedNode(int bantime); /** Unban a selected node on the Bans tab */ void unbanSelectedNode(); + /** set which tab has the focus (is visible) */ + void setTabFocus(enum TabTypes tabType); Q_SIGNALS: // For RPC command executor @@ -106,7 +122,7 @@ private: enum ColumnWidths { ADDRESS_COLUMN_WIDTH = 200, - SUBVERSION_COLUMN_WIDTH = 100, + SUBVERSION_COLUMN_WIDTH = 150, PING_COLUMN_WIDTH = 80, BANSUBNET_COLUMN_WIDTH = 200, BANTIME_COLUMN_WIDTH = 250 @@ -122,6 +138,8 @@ private: RPCTimerInterface *rpcTimerInterface; QMenu *peersTableContextMenu; QMenu *banTableContextMenu; + int consoleFontSize; + QCompleter *autoCompleter; }; #endif // BITCOIN_QT_RPCCONSOLE_H diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index a083a6f80..780a6c970 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -104,8 +104,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa settings.setValue("nTransactionFee", (qint64)DEFAULT_TRANSACTION_FEE); if (!settings.contains("fPayOnlyMinFee")) settings.setValue("fPayOnlyMinFee", false); - if (!settings.contains("fSendFreeTransactions")) - settings.setValue("fSendFreeTransactions", false); ui->groupFee->setId(ui->radioSmartFee, 0); ui->groupFee->setId(ui->radioCustomFee, 1); ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true); @@ -115,7 +113,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa ui->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt()); ui->customFee->setValue(settings.value("nTransactionFee").toLongLong()); ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool()); - ui->checkBoxFreeTx->setChecked(settings.value("fSendFreeTransactions").toBool()); minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool()); } @@ -124,7 +121,7 @@ void SendCoinsDialog::setClientModel(ClientModel *clientModel) this->clientModel = clientModel; if (clientModel) { - connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime)), this, SLOT(updateSmartFeeLabel())); + connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(updateSmartFeeLabel())); } } @@ -170,9 +167,7 @@ void SendCoinsDialog::setModel(WalletModel *model) connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls())); connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables())); connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); - connect(ui->checkBoxFreeTx, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables())); - connect(ui->checkBoxFreeTx, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); - ui->customFee->setSingleStep(CWallet::minTxFee.GetFeePerK()); + ui->customFee->setSingleStep(CWallet::GetRequiredFee(1000)); updateFeeSectionControls(); updateMinFeeLabel(); updateSmartFeeLabel(); @@ -189,7 +184,6 @@ SendCoinsDialog::~SendCoinsDialog() settings.setValue("nSmartFeeSliderPosition", ui->sliderSmartFee->value()); settings.setValue("nTransactionFee", (qint64)ui->customFee->value()); settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked()); - settings.setValue("fSendFreeTransactions", ui->checkBoxFreeTx->isChecked()); delete ui; } @@ -312,8 +306,9 @@ void SendCoinsDialog::on_sendButton_clicked() if(u != model->getOptionsModel()->getDisplayUnit()) alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount)); } - questionString.append(tr("Total Amount %1
(=%2)
") - .arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount)) + questionString.append(tr("Total Amount %1") + .arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount))); + questionString.append(QString("
(=%2)
") .arg(alternativeUnits.join(" " + tr("or") + "
"))); QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"), @@ -372,8 +367,6 @@ SendCoinsEntry *SendCoinsDialog::addEntry() connect(entry, SIGNAL(payAmountChanged()), this, SLOT(coinControlUpdateLabels())); connect(entry, SIGNAL(subtractFeeFromAmountChanged()), this, SLOT(coinControlUpdateLabels())); - updateTabsAndLabels(); - // Focus the field, so that entry can start immediately entry->clear(); entry->setFocus(); @@ -382,6 +375,8 @@ SendCoinsEntry *SendCoinsDialog::addEntry() QScrollBar* bar = ui->scrollArea->verticalScrollBar(); if(bar) bar->setSliderPosition(bar->maximum()); + + updateTabsAndLabels(); return entry; } @@ -530,7 +525,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn msgParams.second = CClientUIInterface::MSG_ERROR; break; case WalletModel::AbsurdFee: - msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 10000000)); + msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), maxTxFee)); break; case WalletModel::PaymentRequestExpired: msgParams.first = tr("Payment request expired."); @@ -569,7 +564,7 @@ void SendCoinsDialog::on_buttonMinimizeFee_clicked() void SendCoinsDialog::setMinimumFee() { ui->radioCustomPerKilobyte->setChecked(true); - ui->customFee->setValue(CWallet::minTxFee.GetFeePerK()); + ui->customFee->setValue(CWallet::GetRequiredFee(1000)); } void SendCoinsDialog::updateFeeSectionControls() @@ -584,7 +579,7 @@ void SendCoinsDialog::updateFeeSectionControls() ui->checkBoxMinimumFee ->setEnabled(ui->radioCustomFee->isChecked()); ui->labelMinFeeWarning ->setEnabled(ui->radioCustomFee->isChecked()); ui->radioCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked()); - ui->radioCustomAtLeast ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked()); + ui->radioCustomAtLeast ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked() && CoinControlDialog::coinControl->HasSelected()); ui->customFee ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked()); } @@ -599,10 +594,11 @@ void SendCoinsDialog::updateGlobalFeeVariables() { nTxConfirmTarget = defaultConfirmTarget; payTxFee = CFeeRate(ui->customFee->value()); - fPayAtLeastCustomFee = ui->radioCustomAtLeast->isChecked(); - } - fSendFreeTransactions = ui->checkBoxFreeTx->isChecked(); + // if user has selected to set a minimum absolute fee, pass the value to coincontrol + // set nMinimumTotalFee to 0 in case of user has selected that the fee is per KB + CoinControlDialog::coinControl->nMinimumTotalFee = ui->radioCustomAtLeast->isChecked() ? ui->customFee->value() : 0; + } } void SendCoinsDialog::updateFeeMinimizedLabel() @@ -621,8 +617,8 @@ void SendCoinsDialog::updateFeeMinimizedLabel() void SendCoinsDialog::updateMinFeeLabel() { if (model && model->getOptionsModel()) - ui->checkBoxMinimumFee->setText(tr("Pay only the minimum fee of %1").arg( - BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::minTxFee.GetFeePerK()) + "/kB") + ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg( + BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::GetRequiredFee(1000)) + "/kB") ); } @@ -632,18 +628,21 @@ void SendCoinsDialog::updateSmartFeeLabel() return; int nBlocksToConfirm = defaultConfirmTarget - ui->sliderSmartFee->value(); - CFeeRate feeRate = mempool.estimateFee(nBlocksToConfirm); + int estimateFoundAtBlocks = nBlocksToConfirm; + CFeeRate feeRate = mempool.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks); if (feeRate <= CFeeRate(0)) // not enough data => minfee { - ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::minTxFee.GetFeePerK()) + "/kB"); + ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), + std::max(CWallet::fallbackFee.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB"); ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...) ui->labelFeeEstimation->setText(""); } else { - ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB"); + ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), + std::max(feeRate.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB"); ui->labelSmartFee2->hide(); - ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", nBlocksToConfirm)); + ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", estimateFoundAtBlocks)); } updateFeeMinimizedLabel(); @@ -705,8 +704,7 @@ void SendCoinsDialog::coinControlFeatureChanged(bool checked) if (!checked && model) // coin control features disabled CoinControlDialog::coinControl->SetNull(); - if (checked) - coinControlUpdateLabels(); + coinControlUpdateLabels(); } // Coin Control: button inputs -> show actual coin control dialog @@ -780,16 +778,31 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text) // Coin Control: update labels void SendCoinsDialog::coinControlUpdateLabels() { - if (!model || !model->getOptionsModel() || !model->getOptionsModel()->getCoinControlFeatures()) + if (!model || !model->getOptionsModel()) return; + if (model->getOptionsModel()->getCoinControlFeatures()) + { + // enable minimum absolute fee UI controls + ui->radioCustomAtLeast->setVisible(true); + + // only enable the feature if inputs are selected + ui->radioCustomAtLeast->setEnabled(CoinControlDialog::coinControl->HasSelected()); + } + else + { + // in case coin control is disabled (=default), hide minimum absolute fee UI controls + ui->radioCustomAtLeast->setVisible(false); + return; + } + // set pay amounts CoinControlDialog::payAmounts.clear(); CoinControlDialog::fSubtractFeeFromAmount = false; for(int i = 0; i < ui->entries->count(); ++i) { SendCoinsEntry *entry = qobject_cast(ui->entries->itemAt(i)->widget()); - if(entry) + if(entry && !entry->isHidden()) { SendCoinsRecipient rcp = entry->getValue(); CoinControlDialog::payAmounts.append(rcp.amount); diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 391905ffc..ec171734f 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 44aa8ad1a..d063f2c89 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -40,7 +40,7 @@ SendCoinsEntry::SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *pare // normal bitcoin address field GUIUtil::setupAddressWidget(ui->payTo, this); // just a label for displaying bitcoin address(es) - ui->payTo_is->setFont(GUIUtil::bitcoinAddressFont()); + ui->payTo_is->setFont(GUIUtil::fixedPitchFont()); // Connect signals connect(ui->payAmount, SIGNAL(valueChanged()), this, SIGNAL(payAmountChanged())); diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h index 107ab7015..a8be670c2 100644 --- a/src/qt/sendcoinsentry.h +++ b/src/qt/sendcoinsentry.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 60e8e36eb..8e2e8a509 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -51,8 +51,8 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *platformSt ui->messageIn_VM->installEventFilter(this); ui->signatureIn_VM->installEventFilter(this); - ui->signatureOut_SM->setFont(GUIUtil::bitcoinAddressFont()); - ui->signatureIn_VM->setFont(GUIUtil::bitcoinAddressFont()); + ui->signatureOut_SM->setFont(GUIUtil::fixedPitchFont()); + ui->signatureIn_VM->setFont(GUIUtil::fixedPitchFont()); } SignVerifyMessageDialog::~SignVerifyMessageDialog() diff --git a/src/qt/signverifymessagedialog.h b/src/qt/signverifymessagedialog.h index d651d5049..d2e04cd4f 100644 --- a/src/qt/signverifymessagedialog.h +++ b/src/qt/signverifymessagedialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index c15b64c32..b46321fa8 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -1,7 +1,11 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + #include "splashscreen.h" #include "networkstyle.h" @@ -38,9 +42,9 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) #endif // define text to place - QString titleText = tr("Bitcoin Core"); + QString titleText = tr(PACKAGE_NAME); QString versionText = QString("Version %1").arg(QString::fromStdString(FormatFullVersion())); - QString copyrightText = QChar(0xA9)+QString(" 2009-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Bitcoin Core developers")); + QString copyrightText = QString::fromUtf8(CopyrightHolders(strprintf("\xc2\xA9 %u-%u ", 2009, COPYRIGHT_YEAR)).c_str()); QString titleAddText = networkStyle->getTitleAddText(); QString font = QApplication::font().toString(); @@ -75,10 +79,9 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) // check font size and drawing with pixPaint.setFont(QFont(font, 33*fontFactor)); QFontMetrics fm = pixPaint.fontMetrics(); - int titleTextWidth = fm.width(titleText); - if(titleTextWidth > 160) { - // strange font rendering, Arial probably not found - fontFactor = 0.75; + int titleTextWidth = fm.width(titleText); + if (titleTextWidth > 176) { + fontFactor = fontFactor * 176 / titleTextWidth; } pixPaint.setFont(QFont(font, 33*fontFactor)); @@ -98,8 +101,13 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) pixPaint.drawText(pixmap.width()/devicePixelRatio-titleTextWidth-paddingRight+2,paddingTop+titleVersionVSpace,versionText); // draw copyright stuff - pixPaint.setFont(QFont(font, 10*fontFactor)); - pixPaint.drawText(pixmap.width()/devicePixelRatio-titleTextWidth-paddingRight,paddingTop+titleCopyrightVSpace,copyrightText); + { + pixPaint.setFont(QFont(font, 10*fontFactor)); + const int x = pixmap.width()/devicePixelRatio-titleTextWidth-paddingRight; + const int y = paddingTop+titleCopyrightVSpace; + QRect copyrightRect(x, y, pixmap.width() - x - paddingRight, pixmap.height() - y); + pixPaint.drawText(copyrightRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, copyrightText); + } // draw additional text if special network if(!titleAddText.isEmpty()) { diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h index 29d16d4ea..821f39db1 100644 --- a/src/qt/splashscreen.h +++ b/src/qt/splashscreen.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/paymentrequestdata.h b/src/qt/test/paymentrequestdata.h index c548ffe42..74a2db8ea 100644 --- a/src/qt/test/paymentrequestdata.h +++ b/src/qt/test/paymentrequestdata.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp index fa5696325..84ccfea73 100644 --- a/src/qt/test/paymentservertests.cpp +++ b/src/qt/test/paymentservertests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/paymentservertests.h b/src/qt/test/paymentservertests.h index 71d61fcbe..9ffcbb02a 100644 --- a/src/qt/test/paymentservertests.h +++ b/src/qt/test/paymentservertests.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index f91de2008..db193420b 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/uritests.h b/src/qt/test/uritests.h index 434169dcd..499484279 100644 --- a/src/qt/test/uritests.h +++ b/src/qt/test/uritests.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp index 9b67445bc..601d554c0 100644 --- a/src/qt/trafficgraphwidget.cpp +++ b/src/qt/trafficgraphwidget.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/trafficgraphwidget.h b/src/qt/trafficgraphwidget.h index 6336a8d14..00660574a 100644 --- a/src/qt/trafficgraphwidget.h +++ b/src/qt/trafficgraphwidget.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 801c6c62d..bae0cbd1c 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -35,9 +35,11 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) { int nDepth = wtx.GetDepthInMainChain(); if (nDepth < 0) - return tr("conflicted"); + return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth); else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) return tr("%1/offline").arg(nDepth); + else if (nDepth == 0) + return tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool"))) + (wtx.isAbandoned() ? ", "+tr("abandoned") : ""); else if (nDepth < 6) return tr("%1/unconfirmed").arg(nDepth); else @@ -238,7 +240,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty()) strHTML += "
" + tr("Comment") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "
"; - strHTML += "" + tr("Transaction ID") + ": " + TransactionRecord::formatSubTxId(wtx.GetHash(), rec->idx) + "
"; + strHTML += "" + tr("Transaction ID") + ": " + rec->getTxID() + "
"; + strHTML += "" + tr("Output index") + ": " + QString::number(rec->getOutputIndex()) + "
"; // Message from normal bitcoin:URI (bitcoin:123...?message=example) Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm) diff --git a/src/qt/transactiondesc.h b/src/qt/transactiondesc.h index 5467348ee..01b90b130 100644 --- a/src/qt/transactiondesc.h +++ b/src/qt/transactiondesc.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactiondescdialog.cpp b/src/qt/transactiondescdialog.cpp index fadaa98f4..f7b6995b2 100644 --- a/src/qt/transactiondescdialog.cpp +++ b/src/qt/transactiondescdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactiondescdialog.h b/src/qt/transactiondescdialog.h index 54374e359..f1371b385 100644 --- a/src/qt/transactiondescdialog.h +++ b/src/qt/transactiondescdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index 7981eb7c9..9dcb72f55 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index acea9a1e3..7db02cd61 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index d8623daf5..4fe47181f 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -239,6 +239,8 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) else if (status.depth == 0) { status.status = TransactionStatus::Unconfirmed; + if (wtx.isAbandoned()) + status.status = TransactionStatus::Abandoned; } else if (status.depth < RecommendedNumConfirmations) { @@ -260,11 +262,10 @@ bool TransactionRecord::statusUpdateNeeded() QString TransactionRecord::getTxID() const { - return formatSubTxId(hash, idx); + return QString::fromStdString(hash.ToString()); } -QString TransactionRecord::formatSubTxId(const uint256 &hash, int vout) +int TransactionRecord::getOutputIndex() const { - return QString::fromStdString(hash.ToString() + strprintf("-%03d", vout)); + return idx; } - diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index a5bc37571..8c754c3aa 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -33,6 +33,7 @@ public: Unconfirmed, /**< Not yet mined into a block **/ Confirming, /**< Confirmed, but waiting for the recommended number of confirmations **/ Conflicted, /**< Conflicts with other transaction or mempool **/ + Abandoned, /**< Abandoned from the wallet **/ /// Generated (mined) transactions Immature, /**< Mined but waiting for maturity */ MaturesWarning, /**< Transaction will likely not mature because no nodes have confirmed */ @@ -128,8 +129,8 @@ public: /** Return the unique identifier for this transaction (part) */ QString getTxID() const; - /** Format subtransaction id */ - static QString formatSubTxId(const uint256 &hash, int vout); + /** Return the output index of the subtransaction */ + int getOutputIndex() const; /** Update status from core wallet tx. */ diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 98ad1a44b..b29ecf834 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,6 +13,7 @@ #include "transactionrecord.h" #include "walletmodel.h" +#include "core_io.h" #include "main.h" #include "sync.h" #include "uint256.h" @@ -220,6 +221,18 @@ public: } return QString(); } + + QString getTxHex(TransactionRecord *rec) + { + LOCK2(cs_main, wallet->cs_wallet); + std::map::iterator mi = wallet->mapWallet.find(rec->hash); + if(mi != wallet->mapWallet.end()) + { + std::string strHex = EncodeHexTx(static_cast(mi->second)); + return QString::fromStdString(strHex); + } + return QString(); + } }; TransactionTableModel::TransactionTableModel(const PlatformStyle *platformStyle, CWallet* wallet, WalletModel *parent): @@ -299,6 +312,9 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons case TransactionStatus::Unconfirmed: status = tr("Unconfirmed"); break; + case TransactionStatus::Abandoned: + status = tr("Abandoned"); + break; case TransactionStatus::Confirming: status = tr("Confirming (%1 of %2 recommended confirmations)").arg(wtx->status.depth).arg(TransactionRecord::RecommendedNumConfirmations); break; @@ -455,6 +471,8 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx) return COLOR_TX_STATUS_OFFLINE; case TransactionStatus::Unconfirmed: return QIcon(":/icons/transaction_0"); + case TransactionStatus::Abandoned: + return QIcon(":/icons/transaction_abandoned"); case TransactionStatus::Confirming: switch(wtx->status.depth) { @@ -560,6 +578,11 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const case Qt::TextAlignmentRole: return column_alignments[index.column()]; case Qt::ForegroundRole: + // Use the "danger" color for abandoned transactions + if(rec->status.status == TransactionStatus::Abandoned) + { + return COLOR_TX_STATUS_DANGER; + } // Non-confirmed (but not immature) as transactions are grey if(!rec->status.countsForBalance && rec->status.status != TransactionStatus::Immature) { @@ -594,6 +617,36 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const return rec->getTxID(); case TxHashRole: return QString::fromStdString(rec->hash.ToString()); + case TxHexRole: + return priv->getTxHex(rec); + case TxPlainTextRole: + { + QString details; + QDateTime date = QDateTime::fromTime_t(static_cast(rec->time)); + QString txLabel = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address)); + + details.append(date.toString("M/d/yy HH:mm")); + details.append(" "); + details.append(formatTxStatus(rec)); + details.append(". "); + if(!formatTxType(rec).isEmpty()) { + details.append(formatTxType(rec)); + details.append(" "); + } + if(!rec->address.empty()) { + if(txLabel.isEmpty()) + details.append(tr("(no label)") + " "); + else { + details.append("("); + details.append(txLabel); + details.append(") "); + } + details.append(QString::fromStdString(rec->address)); + details.append(" "); + } + details.append(formatTxAmount(rec, false, BitcoinUnits::separatorNever)); + return details; + } case ConfirmedRole: return rec->status.countsForBalance; case FormattedAmountRole: diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index 2089f703a..6932646e1 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -60,6 +60,10 @@ public: TxIDRole, /** Transaction hash */ TxHashRole, + /** Transaction data, hex-encoded */ + TxHexRole, + /** Whole transaction as plain text */ + TxPlainTextRole, /** Is transaction confirmed? */ ConfirmedRole, /** Formatted amount, without brackets when unconfirmed */ diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 54e5a8272..a352228c3 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -37,7 +37,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) : QWidget(parent), model(0), transactionProxyModel(0), - transactionView(0) + transactionView(0), abandonAction(0) { // Build filter row setContentsMargins(0,0,0,0); @@ -137,10 +137,13 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa transactionView = view; // Actions + abandonAction = new QAction(tr("Abandon transaction"), this); QAction *copyAddressAction = new QAction(tr("Copy address"), this); QAction *copyLabelAction = new QAction(tr("Copy label"), this); QAction *copyAmountAction = new QAction(tr("Copy amount"), this); QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this); + QAction *copyTxHexAction = new QAction(tr("Copy raw transaction"), this); + QAction *copyTxPlainText = new QAction(tr("Copy full transaction details"), this); QAction *editLabelAction = new QAction(tr("Edit label"), this); QAction *showDetailsAction = new QAction(tr("Show transaction details"), this); @@ -149,8 +152,12 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa contextMenu->addAction(copyLabelAction); contextMenu->addAction(copyAmountAction); contextMenu->addAction(copyTxIDAction); - contextMenu->addAction(editLabelAction); + contextMenu->addAction(copyTxHexAction); + contextMenu->addAction(copyTxPlainText); contextMenu->addAction(showDetailsAction); + contextMenu->addSeparator(); + contextMenu->addAction(abandonAction); + contextMenu->addAction(editLabelAction); mapperThirdPartyTxUrls = new QSignalMapper(this); @@ -166,10 +173,13 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex))); connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint))); + connect(abandonAction, SIGNAL(triggered()), this, SLOT(abandonTx())); connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress())); connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel())); connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID())); + connect(copyTxHexAction, SIGNAL(triggered()), this, SLOT(copyTxHex())); + connect(copyTxPlainText, SIGNAL(triggered()), this, SLOT(copyTxPlainText())); connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel())); connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails())); } @@ -264,7 +274,7 @@ void TransactionView::chooseDate(int idx) break; case LastMonth: transactionProxyModel->setDateRange( - QDateTime(QDate(current.year(), current.month()-1, 1)), + QDateTime(QDate(current.year(), current.month(), 1).addMonths(-1)), QDateTime(QDate(current.year(), current.month(), 1))); break; case ThisYear: @@ -354,12 +364,37 @@ void TransactionView::exportClicked() void TransactionView::contextualMenu(const QPoint &point) { QModelIndex index = transactionView->indexAt(point); + QModelIndexList selection = transactionView->selectionModel()->selectedRows(0); + + // check if transaction can be abandoned, disable context menu action in case it doesn't + uint256 hash; + hash.SetHex(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString()); + abandonAction->setEnabled(model->transactionCanBeAbandoned(hash)); + if(index.isValid()) { contextMenu->exec(QCursor::pos()); } } +void TransactionView::abandonTx() +{ + if(!transactionView || !transactionView->selectionModel()) + return; + QModelIndexList selection = transactionView->selectionModel()->selectedRows(0); + + // get the hash from the TxHashRole (QVariant / QString) + uint256 hash; + QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString(); + hash.SetHex(hashQStr.toStdString()); + + // Abandon the wallet transaction over the walletModel + model->abandonTransaction(hash); + + // Update the table + model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false); +} + void TransactionView::copyAddress() { GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::AddressRole); @@ -380,6 +415,16 @@ void TransactionView::copyTxID() GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxIDRole); } +void TransactionView::copyTxHex() +{ + GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxHexRole); +} + +void TransactionView::copyTxPlainText() +{ + GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxPlainTextRole); +} + void TransactionView::editLabel() { if(!transactionView->selectionModel() ||!model) @@ -518,12 +563,8 @@ bool TransactionView::eventFilter(QObject *obj, QEvent *event) QKeyEvent *ke = static_cast(event); if (ke->key() == Qt::Key_C && ke->modifiers().testFlag(Qt::ControlModifier)) { - QModelIndex i = this->transactionView->currentIndex(); - if (i.isValid() && i.column() == TransactionTableModel::Amount) - { - GUIUtil::setClipboard(i.data(TransactionTableModel::FormattedAmountRole).toString()); - return true; - } + GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxPlainTextRole); + return true; } } return QWidget::eventFilter(obj, event); diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index ac157fb98..e9b9d5b6b 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -75,6 +75,7 @@ private: QFrame *dateRangeWidget; QDateTimeEdit *dateFrom; QDateTimeEdit *dateTo; + QAction *abandonAction; QWidget *createDateRangeWidget(); @@ -93,8 +94,11 @@ private Q_SLOTS: void copyLabel(); void copyAmount(); void copyTxID(); + void copyTxHex(); + void copyTxPlainText(); void openThirdPartyTxUrl(QString url); void updateWatchOnlyColumn(bool fHaveWatchOnly); + void abandonTx(); Q_SIGNALS: void doubleClicked(const QModelIndex&); diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 5e26f3e01..947bcdb15 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -1,13 +1,20 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + #include "utilitydialog.h" #include "ui_helpmessagedialog.h" #include "bitcoingui.h" #include "clientmodel.h" +#include "guiconstants.h" +#include "intro.h" +#include "paymentrequestplus.h" #include "guiutil.h" #include "clientversion.h" @@ -30,7 +37,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : { ui->setupUi(this); - QString version = tr("Bitcoin Core") + " " + tr("version") + " " + QString::fromStdString(FormatFullVersion()); + QString version = tr(PACKAGE_NAME) + " " + tr("version") + " " + QString::fromStdString(FormatFullVersion()); /* On x86 add a bit specifier to the version so that users can distinguish between * 32 and 64 bit builds. On other architectures, 32/64 bit may be more ambigious. */ @@ -42,7 +49,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : if (about) { - setWindowTitle(tr("About Bitcoin Core")); + setWindowTitle(tr("About %1").arg(tr(PACKAGE_NAME))); /// HTML-format the license message from the core QString licenseInfo = QString::fromStdString(LicenseInfo()); @@ -52,7 +59,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : uri.setMinimal(true); // use non-greedy matching licenseInfoHTML.replace(uri, "\\1"); // Replace newlines with HTML breaks - licenseInfoHTML.replace("\n\n", "

"); + licenseInfoHTML.replace("\n", "
"); ui->aboutMessage->setTextFormat(Qt::RichText); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); @@ -70,7 +77,22 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : cursor.insertText(header); cursor.insertBlock(); - QString coreOptions = QString::fromStdString(HelpMessage(HMM_BITCOIN_QT)); + std::string strUsage = HelpMessage(HMM_BITCOIN_QT); + const bool showDebug = GetBoolArg("-help-debug", false); + strUsage += HelpMessageGroup(tr("UI Options:").toStdString()); + if (showDebug) { + strUsage += HelpMessageOpt("-allowselfsignedrootcertificates", strprintf("Allow self signed root certificates (default: %u)", DEFAULT_SELFSIGNED_ROOTCERTS)); + } + strUsage += HelpMessageOpt("-choosedatadir", strprintf(tr("Choose data directory on startup (default: %u)").toStdString(), DEFAULT_CHOOSE_DATADIR)); + strUsage += HelpMessageOpt("-lang=", tr("Set language, for example \"de_DE\" (default: system locale)").toStdString()); + strUsage += HelpMessageOpt("-min", tr("Start minimized").toStdString()); + strUsage += HelpMessageOpt("-rootcertificates=", tr("Set SSL root certificates for payment request (default: -system-)").toStdString()); + strUsage += HelpMessageOpt("-splash", strprintf(tr("Show splash screen on startup (default: %u)").toStdString(), DEFAULT_SPLASHSCREEN)); + strUsage += HelpMessageOpt("-resetguisettings", tr("Reset all settings changed in the GUI").toStdString()); + if (showDebug) { + strUsage += HelpMessageOpt("-uiplatform", strprintf("Select platform to customize UI for (one of windows, macosx, other; default: %s)", BitcoinGUI::DEFAULT_UIPLATFORM)); + } + QString coreOptions = QString::fromStdString(strUsage); text = version + "\n" + header + "\n" + coreOptions; QTextTableFormat tf; @@ -144,7 +166,7 @@ ShutdownWindow::ShutdownWindow(QWidget *parent, Qt::WindowFlags f): { QVBoxLayout *layout = new QVBoxLayout(); layout->addWidget(new QLabel( - tr("Bitcoin Core is shutting down...") + "

" + + tr("%1 is shutting down...").arg(tr(PACKAGE_NAME)) + "

" + tr("Do not shut down the computer until this window disappears."))); setLayout(layout); } diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h index 47282ae2d..843bd7f67 100644 --- a/src/qt/utilitydialog.h +++ b/src/qt/utilitydialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index ba8c28464..e4ca5e183 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 9a56e97f9..9a5bc273c 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 5c21db8bd..ce230d6ae 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -290,8 +290,10 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact return TransactionCreationFailed; } - // reject absurdly high fee > 0.1 bitcoin - if (nFeeRequired > 10000000) + // reject absurdly high fee. (This can never happen because the + // wallet caps the fee at maxTxFee. This merely serves as a + // belt-and-suspenders check) + if (nFeeRequired > maxTxFee) return AbsurdFee; } @@ -666,3 +668,18 @@ bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t else return wallet->AddDestData(dest, key, sRequest); } + +bool WalletModel::transactionCanBeAbandoned(uint256 hash) const +{ + LOCK2(cs_main, wallet->cs_wallet); + const CWalletTx *wtx = wallet->GetWalletTx(hash); + if (!wtx || wtx->isAbandoned() || wtx->GetDepthInMainChain() > 0 || wtx->InMempool()) + return false; + return true; +} + +bool WalletModel::abandonTransaction(uint256 hash) const +{ + LOCK2(cs_main, wallet->cs_wallet); + return wallet->AbandonTransaction(hash); +} diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index a5e877d81..e5470bf61 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -200,6 +200,9 @@ public: void loadReceiveRequests(std::vector& vReceiveRequests); bool saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest); + bool transactionCanBeAbandoned(uint256 hash) const; + bool abandonTransaction(uint256 hash) const; + private: CWallet *wallet; bool fHaveWatchOnly; diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index 6a9b2d5bd..8c970ee8a 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h index 7765fea4a..64922efad 100644 --- a/src/qt/walletmodeltransaction.h +++ b/src/qt/walletmodeltransaction.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 77efdb5cd..6ce98ef16 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 2a6a6a2df..dbb289f42 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/random.cpp b/src/random.cpp index 0ba0de908..6155c0d8c 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rest.cpp b/src/rest.cpp index c46d7a8bd..2dff8d7da 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -1,14 +1,15 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "chain.h" +#include "chainparams.h" #include "primitives/block.h" #include "primitives/transaction.h" #include "main.h" #include "httpserver.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "streams.h" #include "sync.h" #include "txmempool.h" @@ -223,7 +224,7 @@ static bool rest_block(HTTPRequest* req, if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)"); - if (!ReadBlockFromDisk(block, pblockindex)) + if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } @@ -272,6 +273,9 @@ static bool rest_block_notxdetails(HTTPRequest* req, const std::string& strURIPa return rest_block(req, strURIPart, false); } +// A bit of a hack - dependency on a function defined in rpc/blockchain.cpp +UniValue getblockchaininfo(const UniValue& params, bool fHelp); + static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) @@ -360,7 +364,7 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) CTransaction tx; uint256 hashBlock = uint256(); - if (!GetTransaction(hash, tx, hashBlock, true)) + if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); @@ -493,7 +497,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS) return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size())); - // check spentness and form a bitmap (as well as a JSON capable human-readble string representation) + // check spentness and form a bitmap (as well as a JSON capable human-readable string representation) vector bitmap; vector outs; std::string bitmapStringRepresentation; diff --git a/src/reverselock.h b/src/reverselock.h index 567636e16..fac1ccb79 100644 --- a/src/reverselock.h +++ b/src/reverselock.h @@ -15,10 +15,12 @@ public: explicit reverse_lock(Lock& lock) : lock(lock) { lock.unlock(); + lock.swap(templock); } ~reverse_lock() { - lock.lock(); + templock.lock(); + templock.swap(lock); } private: @@ -26,6 +28,7 @@ private: reverse_lock& operator=(reverse_lock const&); Lock& lock; + Lock templock; }; #endif // BITCOIN_REVERSELOCK_H diff --git a/src/rpcblockchain.cpp b/src/rpc/blockchain.cpp similarity index 79% rename from src/rpcblockchain.cpp rename to src/rpc/blockchain.cpp index 837b12aca..2390e9cf2 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,18 +10,22 @@ #include "coins.h" #include "consensus/validation.h" #include "main.h" +#include "policy/policy.h" #include "primitives/transaction.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "streams.h" #include "sync.h" #include "txmempool.h" #include "util.h" #include "utilstrencodings.h" +#include "hash.h" #include #include +#include // boost::thread::interrupt + using namespace std; extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); @@ -69,9 +73,11 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", blockindex->nVersion)); + result.push_back(Pair("versionHex", strprintf("%08x", blockindex->nVersion))); result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex())); result.push_back(Pair("nameclaimroot", blockindex->hashClaimTrie.GetHex())); result.push_back(Pair("time", (int64_t)blockindex->nTime)); + result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", (uint64_t)blockindex->nNonce)); result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); @@ -88,7 +94,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { UniValue result(UniValue::VOBJ); - result.push_back(Pair("hash", block.GetHash().GetHex())); + result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (chainActive.Contains(blockindex)) @@ -97,6 +103,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); + result.push_back(Pair("versionHex", strprintf("%08x", block.nVersion))); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); result.push_back(Pair("nameclaimroot", block.hashClaimTrie.GetHex())); UniValue txs(UniValue::VARR); @@ -113,6 +120,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx } result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); + result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); @@ -194,13 +202,14 @@ UniValue mempoolToJSON(bool fVerbose = false) UniValue info(UniValue::VOBJ); info.push_back(Pair("size", (int)e.GetTxSize())); info.push_back(Pair("fee", ValueFromAmount(e.GetFee()))); + info.push_back(Pair("modifiedfee", ValueFromAmount(e.GetModifiedFee()))); info.push_back(Pair("time", e.GetTime())); info.push_back(Pair("height", (int)e.GetHeight())); info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight()))); info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height()))); info.push_back(Pair("descendantcount", e.GetCountWithDescendants())); info.push_back(Pair("descendantsize", e.GetSizeWithDescendants())); - info.push_back(Pair("descendantfees", e.GetFeesWithDescendants())); + info.push_back(Pair("descendantfees", e.GetModFeesWithDescendants())); const CTransaction& tx = e.GetTx(); set setDepends; BOOST_FOREACH(const CTxIn& txin, tx.vin) @@ -251,13 +260,14 @@ UniValue getrawmempool(const UniValue& params, bool fHelp) " \"transactionid\" : { (json object)\n" " \"size\" : n, (numeric) transaction size in bytes\n" " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n" + " \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\n" " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n" " \"height\" : n, (numeric) block height when transaction entered pool\n" " \"startingpriority\" : n, (numeric) priority when transaction entered pool\n" " \"currentpriority\" : n, (numeric) transaction priority now\n" " \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n" " \"descendantsize\" : n, (numeric) size of in-mempool descendants (including this one)\n" - " \"descendantfees\" : n, (numeric) fees of in-mempool descendants (including this one)\n" + " \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n" " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n" " \"transactionid\", (string) parent transaction id\n" " ... ]\n" @@ -318,13 +328,16 @@ UniValue getblockheader(const UniValue& params, bool fHelp) " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" + " \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n" " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"nonce\" : n, (numeric) The nonce\n" " \"bits\" : \"1d00ffff\", (string) The bits\n" " \"difficulty\" : x.xxx, (numeric) The difficulty\n" " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" - " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" + " \"nextblockhash\" : \"hash\", (string) The hash of the next block\n" + " \"chainwork\" : \"0000...1f3\" (string) Expected number of hashes required to produce the current chain (in hex)\n" "}\n" "\nResult (for verbose=false):\n" "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" @@ -375,6 +388,7 @@ UniValue getblock(const UniValue& params, bool fHelp) " \"size\" : n, (numeric) The block size\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" + " \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n" " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" " \"nameclaimroot\" : \"xxxx\", (string) The hash of the root of the name claim trie\n" " \"tx\" : [ (array of string) The transaction ids\n" @@ -382,9 +396,11 @@ UniValue getblock(const UniValue& params, bool fHelp) " ,...\n" " ],\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"nonce\" : n, (numeric) The nonce\n" " \"bits\" : \"1d00ffff\", (string) The bits\n" " \"difficulty\" : x.xxx, (numeric) The difficulty\n" + " \"chainwork\" : \"xxxx\", (string) Expected number of hashes required to produce the chain up to this block (in hex)\n" " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" "}\n" @@ -413,7 +429,7 @@ UniValue getblock(const UniValue& params, bool fHelp) if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); - if(!ReadBlockFromDisk(block, pblockindex)) + if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); if (!fVerbose) @@ -427,6 +443,60 @@ UniValue getblock(const UniValue& params, bool fHelp) return blockToJSON(block, pblockindex); } +struct CCoinsStats +{ + int nHeight; + uint256 hashBlock; + uint64_t nTransactions; + uint64_t nTransactionOutputs; + uint64_t nSerializedSize; + uint256 hashSerialized; + CAmount nTotalAmount; + + CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), nTotalAmount(0) {} +}; + +//! Calculate statistics about the unspent transaction output set +static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats) +{ + boost::scoped_ptr pcursor(view->Cursor()); + + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + stats.hashBlock = pcursor->GetBestBlock(); + { + LOCK(cs_main); + stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight; + } + ss << stats.hashBlock; + CAmount nTotalAmount = 0; + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + uint256 key; + CCoins coins; + if (pcursor->GetKey(key) && pcursor->GetValue(coins)) { + stats.nTransactions++; + ss << key; + for (unsigned int i=0; iGetValueSize(); + ss << VARINT(0); + } else { + return error("%s: unable to read value", __func__); + } + pcursor->Next(); + } + stats.hashSerialized = ss.GetHash(); + stats.nTotalAmount = nTotalAmount; + return true; +} + UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -453,7 +523,7 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) CCoinsStats stats; FlushStateToDisk(); - if (pcoinsTip->GetStats(stats)) { + if (GetUTXOStats(pcoinsTip, stats)) { ret.push_back(Pair("height", (int64_t)stats.nHeight)); ret.push_back(Pair("bestblock", stats.hashBlock.GetHex())); ret.push_back(Pair("transactions", (int64_t)stats.nTransactions)); @@ -473,8 +543,8 @@ UniValue gettxout(const UniValue& params, bool fHelp) "\nReturns details about an unspent transaction output.\n" "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" - "2. n (numeric, required) vout value\n" - "3. includemempool (boolean, optional) Whether to included the mem pool\n" + "2. n (numeric, required) vout number\n" + "3. includemempool (boolean, optional) Whether to include the mem pool\n" "\nResult:\n" "{\n" " \"bestblock\" : \"hash\", (string) the block hash\n" @@ -547,13 +617,15 @@ UniValue gettxout(const UniValue& params, bool fHelp) UniValue verifychain(const UniValue& params, bool fHelp) { + int nCheckLevel = GetArg("-checklevel", DEFAULT_CHECKLEVEL); + int nCheckDepth = GetArg("-checkblocks", DEFAULT_CHECKBLOCKS); if (fHelp || params.size() > 2) throw runtime_error( "verifychain ( checklevel numblocks )\n" "\nVerifies blockchain database.\n" "\nArguments:\n" - "1. checklevel (numeric, optional, 0-4, default=3) How thorough the block verification is.\n" - "2. numblocks (numeric, optional, default=288, 0=all) The number of blocks to check.\n" + "1. checklevel (numeric, optional, 0-4, default=" + strprintf("%d", nCheckLevel) + ") How thorough the block verification is.\n" + "2. numblocks (numeric, optional, default=" + strprintf("%d", nCheckDepth) + ", 0=all) The number of blocks to check.\n" "\nResult:\n" "true|false (boolean) Verified or not\n" "\nExamples:\n" @@ -563,14 +635,12 @@ UniValue verifychain(const UniValue& params, bool fHelp) LOCK(cs_main); - int nCheckLevel = GetArg("-checklevel", 3); - int nCheckDepth = GetArg("-checkblocks", 288); if (params.size() > 0) nCheckLevel = params[0].get_int(); if (params.size() > 1) nCheckDepth = params[1].get_int(); - return CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth); + return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth); } /** Implementation of IsSuperMajority with better feedback */ @@ -603,6 +673,26 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* return rv; } +static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Consensus::DeploymentPos id) +{ + UniValue rv(UniValue::VOBJ); + const ThresholdState thresholdState = VersionBitsTipState(consensusParams, id); + switch (thresholdState) { + case THRESHOLD_DEFINED: rv.push_back(Pair("status", "defined")); break; + case THRESHOLD_STARTED: rv.push_back(Pair("status", "started")); break; + case THRESHOLD_LOCKED_IN: rv.push_back(Pair("status", "locked_in")); break; + case THRESHOLD_ACTIVE: rv.push_back(Pair("status", "active")); break; + case THRESHOLD_FAILED: rv.push_back(Pair("status", "failed")); break; + } + if (THRESHOLD_STARTED == thresholdState) + { + rv.push_back(Pair("bit", consensusParams.vDeployments[id].bit)); + } + rv.push_back(Pair("startTime", consensusParams.vDeployments[id].nStartTime)); + rv.push_back(Pair("timeout", consensusParams.vDeployments[id].nTimeout)); + return rv; +} + UniValue getblockchaininfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -616,6 +706,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) " \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n" " \"bestblockhash\": \"...\", (string) the hash of the currently best block\n" " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" + " \"mediantime\": xxxxxx, (numeric) median time for the current best block\n" " \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n" " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n" " \"pruned\": xx, (boolean) if the blocks are subject to pruning\n" @@ -632,7 +723,15 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) " },\n" " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n" " }, ...\n" - " ]\n" + " ],\n" + " \"bip9_softforks\": { (object) status of BIP9 softforks in progress\n" + " \"xxxx\" : { (string) name of the softfork\n" + " \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"lockedin\", \"active\", \"failed\"\n" + " \"bit\": xx, (numeric) the bit, 0-28, in the block version field used to signal this soft fork\n" + " \"startTime\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\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" + " }\n" "}\n" "\nExamples:\n" + HelpExampleCli("getblockchaininfo", "") @@ -647,6 +746,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex())); obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast())); obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()))); obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); obj.push_back(Pair("pruned", fPruneMode)); @@ -654,9 +754,13 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) const Consensus::Params& consensusParams = Params().GetConsensus(); CBlockIndex* tip = chainActive.Tip(); UniValue softforks(UniValue::VARR); + UniValue bip9_softforks(UniValue::VOBJ); softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams)); softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams)); + softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams)); + bip9_softforks.push_back(Pair("csv", BIP9SoftForkDesc(consensusParams, Consensus::DEPLOYMENT_CSV))); obj.push_back(Pair("softforks", softforks)); + obj.push_back(Pair("bip9_softforks", bip9_softforks)); if (fPruneMode) { @@ -780,6 +884,9 @@ UniValue mempoolInfoToJSON() ret.push_back(Pair("size", (int64_t) mempool.size())); ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize())); ret.push_back(Pair("usage", (int64_t) mempool.DynamicMemoryUsage())); + size_t maxmempool = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; + ret.push_back(Pair("maxmempool", (int64_t) maxmempool)); + ret.push_back(Pair("mempoolminfee", ValueFromAmount(mempool.GetMinFee(maxmempool).GetFeePerK()))); return ret; } @@ -792,9 +899,11 @@ UniValue getmempoolinfo(const UniValue& params, bool fHelp) "\nReturns details on the active state of the TX memory pool.\n" "\nResult:\n" "{\n" - " \"size\": xxxxx (numeric) Current tx count\n" - " \"bytes\": xxxxx (numeric) Sum of all tx sizes\n" - " \"usage\": xxxxx (numeric) Total memory usage for the mempool\n" + " \"size\": xxxxx, (numeric) Current tx count\n" + " \"bytes\": xxxxx, (numeric) Sum of all tx sizes\n" + " \"usage\": xxxxx, (numeric) Total memory usage for the mempool\n" + " \"maxmempool\": xxxxx, (numeric) Maximum memory usage for the mempool\n" + " \"mempoolminfee\": xxxxx (numeric) Minimum fee for tx to be accepted\n" "}\n" "\nExamples:\n" + HelpExampleCli("getmempoolinfo", "") @@ -828,11 +937,11 @@ UniValue invalidateblock(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); CBlockIndex* pblockindex = mapBlockIndex[hash]; - InvalidateBlock(state, pblockindex); + InvalidateBlock(state, Params().GetConsensus(), pblockindex); } if (state.IsValid()) { - ActivateBestChain(state); + ActivateBestChain(state, Params()); } if (!state.IsValid()) { @@ -871,7 +980,7 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp) } if (state.IsValid()) { - ActivateBestChain(state); + ActivateBestChain(state, Params()); } if (!state.IsValid()) { @@ -880,3 +989,31 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp) return NullUniValue; } + +static const CRPCCommand commands[] = +{ // category name actor (function) okSafeMode + // --------------------- ------------------------ ----------------------- ---------- + { "blockchain", "getblockchaininfo", &getblockchaininfo, true }, + { "blockchain", "getbestblockhash", &getbestblockhash, true }, + { "blockchain", "getblockcount", &getblockcount, true }, + { "blockchain", "getblock", &getblock, true }, + { "blockchain", "getblockhash", &getblockhash, true }, + { "blockchain", "getblockheader", &getblockheader, true }, + { "blockchain", "getchaintips", &getchaintips, true }, + { "blockchain", "getdifficulty", &getdifficulty, true }, + { "blockchain", "getmempoolinfo", &getmempoolinfo, true }, + { "blockchain", "getrawmempool", &getrawmempool, true }, + { "blockchain", "gettxout", &gettxout, true }, + { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true }, + { "blockchain", "verifychain", &verifychain, true }, + + /* Not shown in help */ + { "hidden", "invalidateblock", &invalidateblock, true }, + { "hidden", "reconsiderblock", &reconsiderblock, true }, +}; + +void RegisterBlockchainRPCCommands(CRPCTable &tableRPC) +{ + for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) + tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); +} diff --git a/src/rpcclaimtrie.cpp b/src/rpc/claimtrie.cpp similarity index 99% rename from src/rpcclaimtrie.cpp rename to src/rpc/claimtrie.cpp index ded83626a..388225609 100644 --- a/src/rpcclaimtrie.cpp +++ b/src/rpc/claimtrie.cpp @@ -1,6 +1,6 @@ #include "main.h" #include "nameclaim.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "univalue.h" #include "txmempool.h" diff --git a/src/rpcclient.cpp b/src/rpc/client.cpp similarity index 91% rename from src/rpcclient.cpp rename to src/rpc/client.cpp index f1c3d333f..e2d79cc04 100644 --- a/src/rpcclient.cpp +++ b/src/rpc/client.cpp @@ -1,11 +1,10 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcclient.h" - -#include "rpcprotocol.h" +#include "rpc/client.h" +#include "rpc/protocol.h" #include "util.h" #include @@ -19,8 +18,8 @@ using namespace std; class CRPCConvertParam { public: - std::string methodName; //! method whose params want conversion - int paramIdx; //! 0-based idx of param to convert + std::string methodName; //!< method whose params want conversion + int paramIdx; //!< 0-based idx of param to convert }; static const CRPCConvertParam vRPCConvertParams[] = @@ -31,6 +30,9 @@ static const CRPCConvertParam vRPCConvertParams[] = { "setgenerate", 0 }, { "setgenerate", 1 }, { "generate", 0 }, + { "generate", 1 }, + { "generatetoaddress", 0 }, + { "generatetoaddress", 2 }, { "getnetworkhashps", 0 }, { "getnetworkhashps", 1 }, { "sendtoaddress", 1 }, @@ -76,6 +78,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getrawtransaction", 1 }, { "createrawtransaction", 0 }, { "createrawtransaction", 1 }, + { "createrawtransaction", 2 }, { "signrawtransaction", 1 }, { "signrawtransaction", 2 }, { "sendrawtransaction", 1 }, @@ -95,6 +98,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getrawmempool", 0 }, { "estimatefee", 0 }, { "estimatepriority", 0 }, + { "estimatesmartfee", 0 }, + { "estimatesmartpriority", 0 }, { "prioritisetransaction", 1 }, { "prioritisetransaction", 2 }, { "claimname", 2}, @@ -168,4 +173,3 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vectornChainWork - pb0->nChainWork; int64_t timeDiff = maxTime - minTime; - return (int64_t)(workDiff.getdouble() / timeDiff); + return workDiff.getdouble() / timeDiff; } UniValue getnetworkhashps(const UniValue& params, bool fHelp) @@ -99,7 +100,7 @@ UniValue getgenerate(const UniValue& params, bool fHelp) throw runtime_error( "getgenerate\n" "\nReturn if the server is set to generate coins or not. The default is false.\n" - "It is set with the command line argument -gen (or lbrycrd.conf setting gen)\n" + "It is set with the command line argument -gen (or " + std::string(BITCOIN_CONF_FILENAME) + " setting gen)\n" "It can also be set with the setgenerate call.\n" "\nResult\n" "true|false (boolean) If the server is set to generate coins or not\n" @@ -109,43 +110,15 @@ UniValue getgenerate(const UniValue& params, bool fHelp) ); LOCK(cs_main); - return GetBoolArg("-gen", false); + return GetBoolArg("-gen", DEFAULT_GENERATE); } -UniValue generate(const UniValue& params, bool fHelp) +UniValue generateBlocks(boost::shared_ptr coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript) { - if (fHelp || params.size() < 1 || params.size() > 1) - throw runtime_error( - "generate numblocks\n" - "\nMine blocks immediately (before the RPC call returns)\n" - "\nNote: this function can only be used on the regtest network\n" - "\nArguments:\n" - "1. numblocks (numeric, required) How many blocks are generated immediately.\n" - "\nResult\n" - "[ blockhashes ] (array) hashes of blocks generated\n" - "\nExamples:\n" - "\nGenerate 11 blocks\n" - + HelpExampleCli("generate", "11") - ); - - if (!Params().MineBlocksOnDemand()) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); - + static const int nInnerLoopCount = 0x10000; int nHeightStart = 0; int nHeightEnd = 0; int nHeight = 0; - int nGenerate = params[0].get_int(); - - boost::shared_ptr coinbaseScript; - GetMainSignals().ScriptForMining(coinbaseScript); - - // If the keypool is exhausted, no script is returned at all. Catch this. - if (!coinbaseScript) - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); - - //throw an error if no script was provided - if (coinbaseScript->reserveScript.empty()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); { // Don't keep cs_main locked LOCK(cs_main); @@ -157,7 +130,7 @@ UniValue generate(const UniValue& params, bool fHelp) UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd) { - auto_ptr pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); + auto_ptr pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); CBlock *pblock = &pblocktemplate->block; @@ -165,19 +138,27 @@ UniValue generate(const UniValue& params, bool fHelp) LOCK(cs_main); IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); } - while (!CheckProofOfWork(pblock->GetPoWHash(), pblock->nBits, Params().GetConsensus())) { - // Yes, there is a chance every nonce could fail to satisfy the -regtest - // target -- 1 in 2^(2^32). That ain't gonna happen. + while (nMaxTries > 0 && pblock->nNonce < nInnerLoopCount && !CheckProofOfWork(pblock->GetPoWHash(), pblock->nBits, Params().GetConsensus())) { ++pblock->nNonce; + --nMaxTries; + } + if (nMaxTries == 0) { + break; + } + if (pblock->nNonce == nInnerLoopCount) { + continue; } CValidationState state; - if (!ProcessNewBlock(state, NULL, pblock, true, NULL)) + if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); - //mark script as important because it was used at least for one coinbase output - coinbaseScript->KeepScript(); + //mark script as important because it was used at least for one coinbase output if the script came from the wallet + if (keepScript) + { + coinbaseScript->KeepScript(); + } } return blockHashes; } @@ -211,7 +192,7 @@ UniValue setgenerate(const UniValue& params, bool fHelp) if (params.size() > 0) fGenerate = params[0].get_bool(); - int nGenProcLimit = -1; + int nGenProcLimit = GetArg("-genproclimit", DEFAULT_GENERATE_THREADS); if (params.size() > 1) { nGenProcLimit = params[1].get_int(); @@ -226,6 +207,75 @@ UniValue setgenerate(const UniValue& params, bool fHelp) return NullUniValue; } +UniValue generate(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "generate numblocks ( maxtries )\n" + "\nMine up to numblocks blocks immediately (before the RPC call returns)\n" + "\nArguments:\n" + "1. numblocks (numeric, required) How many blocks are generated immediately.\n" + "2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n" + "\nResult\n" + "[ blockhashes ] (array) hashes of blocks generated\n" + "\nExamples:\n" + "\nGenerate 11 blocks\n" + + HelpExampleCli("generate", "11") + ); + + int nGenerate = params[0].get_int(); + uint64_t nMaxTries = 1000000; + if (params.size() > 1) { + nMaxTries = params[1].get_int(); + } + + boost::shared_ptr coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); + + // If the keypool is exhausted, no script is returned at all. Catch this. + if (!coinbaseScript) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + + //throw an error if no script was provided + if (coinbaseScript->reserveScript.empty()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); + + return generateBlocks(coinbaseScript, nGenerate, nMaxTries, true); +} + +UniValue generatetoaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 3) + throw runtime_error( + "generatetoaddress numblocks address (maxtries)\n" + "\nMine blocks immediately to a specified address (before the RPC call returns)\n" + "\nArguments:\n" + "1. numblocks (numeric, required) How many blocks are generated immediately.\n" + "2. address (string, required) The address to send the newly generated bitcoin to.\n" + "3. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n" + "\nResult\n" + "[ blockhashes ] (array) hashes of blocks generated\n" + "\nExamples:\n" + "\nGenerate 11 blocks to myaddress\n" + + HelpExampleCli("generatetoaddress", "11 \"myaddress\"") + ); + + int nGenerate = params[0].get_int(); + uint64_t nMaxTries = 1000000; + if (params.size() > 2) { + nMaxTries = params[2].get_int(); + } + + CBitcoinAddress address(params[1].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address"); + + boost::shared_ptr coinbaseScript(new CReserveScript()); + coinbaseScript->reserveScript = GetScriptForDestination(address.Get()); + + return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false); +} + UniValue getmininginfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -426,7 +476,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; CValidationState state; - TestBlockValidity(state, block, pindexPrev, false, true); + TestBlockValidity(state, Params(), block, pindexPrev, false, true); return BIP22ValidationResult(state); } } @@ -510,7 +560,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) pblocktemplate = NULL; } CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = CreateNewBlock(scriptDummy); + pblocktemplate = CreateNewBlock(Params(), scriptDummy); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); @@ -652,7 +702,7 @@ UniValue submitblock(const UniValue& params, bool fHelp) CValidationState state; submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, NULL, &block, true, NULL); + bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL); UnregisterValidationInterface(&sc); if (fBlockPresent) { @@ -726,3 +776,99 @@ UniValue estimatepriority(const UniValue& params, bool fHelp) return mempool.estimatePriority(nBlocks); } + +UniValue estimatesmartfee(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "estimatesmartfee nblocks\n" + "\nWARNING: This interface is unstable and may disappear or change!\n" + "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" + "confirmation within nblocks blocks if possible and return the number of blocks\n" + "for which the estimate is valid.\n" + "\nArguments:\n" + "1. nblocks (numeric)\n" + "\nResult:\n" + "{\n" + " \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in BTC)\n" + " \"blocks\" : n (numeric) block number where estimate was found\n" + "}\n" + "\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate for any number of blocks.\n" + "However it will not return a value below the mempool reject fee.\n" + "\nExample:\n" + + HelpExampleCli("estimatesmartfee", "6") + ); + + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); + + int nBlocks = params[0].get_int(); + + UniValue result(UniValue::VOBJ); + int answerFound; + CFeeRate feeRate = mempool.estimateSmartFee(nBlocks, &answerFound); + result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK()))); + result.push_back(Pair("blocks", answerFound)); + return result; +} + +UniValue estimatesmartpriority(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "estimatesmartpriority nblocks\n" + "\nWARNING: This interface is unstable and may disappear or change!\n" + "\nEstimates the approximate priority a zero-fee transaction needs to begin\n" + "confirmation within nblocks blocks if possible and return the number of blocks\n" + "for which the estimate is valid.\n" + "\nArguments:\n" + "1. nblocks (numeric)\n" + "\nResult:\n" + "{\n" + " \"priority\" : x.x, (numeric) estimated priority\n" + " \"blocks\" : n (numeric) block number where estimate was found\n" + "}\n" + "\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate for any number of blocks.\n" + "However if the mempool reject fee is set it will return 1e9 * MAX_MONEY.\n" + "\nExample:\n" + + HelpExampleCli("estimatesmartpriority", "6") + ); + + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); + + int nBlocks = params[0].get_int(); + + UniValue result(UniValue::VOBJ); + int answerFound; + double priority = mempool.estimateSmartPriority(nBlocks, &answerFound); + result.push_back(Pair("priority", priority)); + result.push_back(Pair("blocks", answerFound)); + return result; +} + +static const CRPCCommand commands[] = +{ // category name actor (function) okSafeMode + // --------------------- ------------------------ ----------------------- ---------- + { "mining", "getnetworkhashps", &getnetworkhashps, true }, + { "mining", "getmininginfo", &getmininginfo, true }, + { "mining", "prioritisetransaction", &prioritisetransaction, true }, + { "mining", "getblocktemplate", &getblocktemplate, true }, + { "mining", "submitblock", &submitblock, true }, + + { "generating", "generate", &generate, true }, + { "generating", "generatetoaddress", &generatetoaddress, true }, + + { "util", "estimatefee", &estimatefee, true }, + { "util", "estimatepriority", &estimatepriority, true }, + { "util", "estimatesmartfee", &estimatesmartfee, true }, + { "util", "estimatesmartpriority", &estimatesmartpriority, true }, +}; + +void RegisterMiningRPCCommands(CRPCTable &tableRPC) +{ + for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) + tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); +} diff --git a/src/rpcmisc.cpp b/src/rpc/misc.cpp similarity index 93% rename from src/rpcmisc.cpp rename to src/rpc/misc.cpp index e06cc1058..1534aa861 100644 --- a/src/rpcmisc.cpp +++ b/src/rpc/misc.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,7 +9,7 @@ #include "main.h" #include "net.h" #include "netbase.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "timedata.h" #include "util.h" #include "utilstrencodings.h" @@ -117,7 +117,7 @@ public: UniValue obj(UniValue::VOBJ); CPubKey vchPubKey; obj.push_back(Pair("isscript", false)); - if (pwalletMain->GetPubKey(keyID, vchPubKey)) { + if (pwalletMain && pwalletMain->GetPubKey(keyID, vchPubKey)) { obj.push_back(Pair("pubkey", HexStr(vchPubKey))); obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); } @@ -128,7 +128,7 @@ public: UniValue obj(UniValue::VOBJ); CScript subscript; obj.push_back(Pair("isscript", true)); - if (pwalletMain->GetCScript(scriptID, subscript)) { + if (pwalletMain && pwalletMain->GetCScript(scriptID, subscript)) { std::vector addresses; txnouttype whichType; int nRequired; @@ -396,3 +396,21 @@ UniValue setmocktime(const UniValue& params, bool fHelp) return NullUniValue; } + +static const CRPCCommand commands[] = +{ // category name actor (function) okSafeMode + // --------------------- ------------------------ ----------------------- ---------- + { "control", "getinfo", &getinfo, true }, /* uses wallet if enabled */ + { "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */ + { "util", "createmultisig", &createmultisig, true }, + { "util", "verifymessage", &verifymessage, true }, + + /* Not shown in help */ + { "hidden", "setmocktime", &setmocktime, true }, +}; + +void RegisterMiscRPCCommands(CRPCTable &tableRPC) +{ + for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) + tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); +} diff --git a/src/rpcnet.cpp b/src/rpc/net.cpp similarity index 84% rename from src/rpcnet.cpp rename to src/rpc/net.cpp index b32ac2f49..d0ba1cfe9 100644 --- a/src/rpcnet.cpp +++ b/src/rpc/net.cpp @@ -1,8 +1,8 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcserver.h" +#include "rpc/server.h" #include "chainparams.h" #include "clientversion.h" @@ -29,7 +29,7 @@ UniValue getconnectioncount(const UniValue& params, bool fHelp) throw runtime_error( "getconnectioncount\n" "\nReturns the number of connections to other nodes.\n" - "\nbResult:\n" + "\nResult:\n" "n (numeric) The connection count\n" "\nExamples:\n" + HelpExampleCli("getconnectioncount", "") @@ -83,22 +83,23 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) throw runtime_error( "getpeerinfo\n" "\nReturns data about each connected network node as a json array of objects.\n" - "\nbResult:\n" + "\nResult:\n" "[\n" " {\n" " \"id\": n, (numeric) Peer index\n" " \"addr\":\"host:port\", (string) The ip address and port of the peer\n" " \"addrlocal\":\"ip:port\", (string) local address\n" " \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n" + " \"relaytxes\":true|false, (boolean) Whether peer has asked us to relay transactions to it\n" " \"lastsend\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n" " \"lastrecv\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive\n" " \"bytessent\": n, (numeric) The total bytes sent\n" " \"bytesrecv\": n, (numeric) The total bytes received\n" " \"conntime\": ttt, (numeric) The connection time in seconds since epoch (Jan 1 1970 GMT)\n" " \"timeoffset\": ttt, (numeric) The time offset in seconds\n" - " \"pingtime\": n, (numeric) ping time\n" - " \"minping\": n, (numeric) minimum observed ping time\n" - " \"pingwait\": n, (numeric) ping wait\n" + " \"pingtime\": n, (numeric) ping time (if available)\n" + " \"minping\": n, (numeric) minimum observed ping time (if any at all)\n" + " \"pingwait\": n, (numeric) ping wait (if non-zero)\n" " \"version\": v, (numeric) The peer version, such as 7001\n" " \"subver\": \"/Satoshi:0.8.5/\", (string) The string version\n" " \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n" @@ -110,6 +111,14 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) " n, (numeric) The heights of blocks we're currently asking from this peer\n" " ...\n" " ]\n" + " \"bytessent_per_msg\": {\n" + " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n" + " ...\n" + " }\n" + " \"bytesrecv_per_msg\": {\n" + " \"addr\": n, (numeric) The total bytes received aggregated by message type\n" + " ...\n" + " }\n" " }\n" " ,...\n" "]\n" @@ -134,14 +143,17 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) if (!(stats.addrLocal.empty())) obj.push_back(Pair("addrlocal", stats.addrLocal)); obj.push_back(Pair("services", strprintf("%016x", stats.nServices))); + obj.push_back(Pair("relaytxes", stats.fRelayTxes)); obj.push_back(Pair("lastsend", stats.nLastSend)); obj.push_back(Pair("lastrecv", stats.nLastRecv)); obj.push_back(Pair("bytessent", stats.nSendBytes)); obj.push_back(Pair("bytesrecv", stats.nRecvBytes)); obj.push_back(Pair("conntime", stats.nTimeConnected)); obj.push_back(Pair("timeoffset", stats.nTimeOffset)); - obj.push_back(Pair("pingtime", stats.dPingTime)); - obj.push_back(Pair("minping", stats.dPingMin)); + if (stats.dPingTime > 0.0) + obj.push_back(Pair("pingtime", stats.dPingTime)); + if (stats.dPingMin < std::numeric_limits::max()/1e6) + obj.push_back(Pair("minping", stats.dPingMin)); if (stats.dPingWait > 0.0) obj.push_back(Pair("pingwait", stats.dPingWait)); obj.push_back(Pair("version", stats.nVersion)); @@ -163,6 +175,20 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) } obj.push_back(Pair("whitelisted", stats.fWhitelisted)); + UniValue sendPerMsgCmd(UniValue::VOBJ); + BOOST_FOREACH(const mapMsgCmdSize::value_type &i, stats.mapSendBytesPerMsgCmd) { + if (i.second > 0) + sendPerMsgCmd.push_back(Pair(i.first, i.second)); + } + obj.push_back(Pair("bytessent_per_msg", sendPerMsgCmd)); + + UniValue recvPerMsgCmd(UniValue::VOBJ); + BOOST_FOREACH(const mapMsgCmdSize::value_type &i, stats.mapRecvBytesPerMsgCmd) { + if (i.second > 0) + recvPerMsgCmd.push_back(Pair(i.first, i.second)); + } + obj.push_back(Pair("bytesrecv_per_msg", recvPerMsgCmd)); + ret.push_back(obj); } @@ -368,7 +394,16 @@ UniValue getnettotals(const UniValue& params, bool fHelp) "{\n" " \"totalbytesrecv\": n, (numeric) Total bytes received\n" " \"totalbytessent\": n, (numeric) Total bytes sent\n" - " \"timemillis\": t (numeric) Total cpu time\n" + " \"timemillis\": t, (numeric) Total cpu time\n" + " \"uploadtarget\":\n" + " {\n" + " \"timeframe\": n, (numeric) Length of the measuring timeframe in seconds\n" + " \"target\": n, (numeric) Target in bytes\n" + " \"target_reached\": true|false, (boolean) True if target is reached\n" + " \"serve_historical_blocks\": true|false, (boolean) True if serving historical blocks\n" + " \"bytes_left_in_cycle\": t, (numeric) Bytes left in current time cycle\n" + " \"time_left_in_cycle\": t (numeric) Seconds left in current time cycle\n" + " }\n" "}\n" "\nExamples:\n" + HelpExampleCli("getnettotals", "") @@ -379,6 +414,15 @@ UniValue getnettotals(const UniValue& params, bool fHelp) obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv())); obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent())); obj.push_back(Pair("timemillis", GetTimeMillis())); + + UniValue outboundLimit(UniValue::VOBJ); + outboundLimit.push_back(Pair("timeframe", CNode::GetMaxOutboundTimeframe())); + outboundLimit.push_back(Pair("target", CNode::GetMaxOutboundTarget())); + outboundLimit.push_back(Pair("target_reached", CNode::OutboundTargetReached(false))); + outboundLimit.push_back(Pair("serve_historical_blocks", !CNode::OutboundTargetReached(true))); + outboundLimit.push_back(Pair("bytes_left_in_cycle", CNode::GetOutboundTargetBytesLeft())); + outboundLimit.push_back(Pair("time_left_in_cycle", CNode::GetMaxOutboundTimeLeftInCycle())); + obj.push_back(Pair("uploadtarget", outboundLimit)); return obj; } @@ -584,3 +628,25 @@ UniValue clearbanned(const UniValue& params, bool fHelp) return NullUniValue; } + +static const CRPCCommand commands[] = +{ // category name actor (function) okSafeMode + // --------------------- ------------------------ ----------------------- ---------- + { "network", "getconnectioncount", &getconnectioncount, true }, + { "network", "ping", &ping, true }, + { "network", "getpeerinfo", &getpeerinfo, true }, + { "network", "addnode", &addnode, true }, + { "network", "disconnectnode", &disconnectnode, true }, + { "network", "getaddednodeinfo", &getaddednodeinfo, true }, + { "network", "getnettotals", &getnettotals, true }, + { "network", "getnetworkinfo", &getnetworkinfo, true }, + { "network", "setban", &setban, true }, + { "network", "listbanned", &listbanned, true }, + { "network", "clearbanned", &clearbanned, true }, +}; + +void RegisterNetRPCCommands(CRPCTable &tableRPC) +{ + for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) + tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); +} diff --git a/src/rpcprotocol.cpp b/src/rpc/protocol.cpp similarity index 97% rename from src/rpcprotocol.cpp rename to src/rpc/protocol.cpp index d83cd87f9..f5275062a 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpc/protocol.cpp @@ -1,9 +1,9 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcprotocol.h" +#include "rpc/protocol.h" #include "random.h" #include "tinyformat.h" diff --git a/src/rpcprotocol.h b/src/rpc/protocol.h similarity index 98% rename from src/rpcprotocol.h rename to src/rpc/protocol.h index 9cf1ab6d9..55d0aac68 100644 --- a/src/rpcprotocol.h +++ b/src/rpc/protocol.h @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpcrawtransaction.cpp b/src/rpc/rawtransaction.cpp similarity index 91% rename from src/rpcrawtransaction.cpp rename to src/rpc/rawtransaction.cpp index ea4ccd536..e5378148b 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -15,7 +15,7 @@ #include "net.h" #include "policy/policy.h" #include "primitives/transaction.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "script/script.h" #include "script/script_error.h" #include "script/sign.h" @@ -62,6 +62,7 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) { entry.push_back(Pair("txid", tx.GetHash().GetHex())); + entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION))); entry.push_back(Pair("version", tx.nVersion)); entry.push_back(Pair("locktime", (int64_t)tx.nLockTime)); UniValue vin(UniValue::VARR); @@ -133,6 +134,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) "{\n" " \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n" " \"txid\" : \"id\", (string) The transaction id (same as provided)\n" + " \"size\" : n, (numeric) The transaction size\n" " \"version\" : n, (numeric) The version\n" " \"locktime\" : ttt, (numeric) The lock time\n" " \"vin\" : [ (array of json objects)\n" @@ -186,7 +188,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) CTransaction tx; uint256 hashBlock; - if (!GetTransaction(hash, tx, hashBlock, true)) + if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); string strHex = EncodeHexTx(tx); @@ -256,7 +258,7 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp) if (pblockindex == NULL) { CTransaction tx; - if (!GetTransaction(oneTxid, tx, hashBlock, false) || hashBlock.IsNull()) + if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock, false) || hashBlock.IsNull()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); if (!mapBlockIndex.count(hashBlock)) throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt"); @@ -264,7 +266,7 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp) } CBlock block; - if(!ReadBlockFromDisk(block, pblockindex)) + if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); unsigned int ntxFound = 0; @@ -301,7 +303,8 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp) UniValue res(UniValue::VARR); vector vMatch; - if (merkleBlock.txn.ExtractMatches(vMatch) != merkleBlock.header.hashMerkleRoot) + vector vIndex; + if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) return res; LOCK(cs_main); @@ -316,9 +319,9 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp) UniValue createrawtransaction(const UniValue& params, bool fHelp) { - if (fHelp || params.size() != 2) + if (fHelp || params.size() < 2 || params.size() > 3) throw runtime_error( - "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...}\n" + "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime )\n" "\nCreate a transaction spending the given inputs and creating new outputs.\n" "Outputs can be addresses or data.\n" "Returns hex-encoded raw transaction.\n" @@ -336,10 +339,11 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) " ]\n" "2. \"outputs\" (string, required) a json object with outputs\n" " {\n" - " \"address\": x.xxx (numeric, required) The key is the lbrycrd address, the value is the " + CURRENCY_UNIT + " amount\n" + " \"address\": x.xxx (numeric or string, required) The key is the lbrycrd address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n" " \"data\": \"hex\", (string, required) The key is \"data\", the value is hex encoded data\n" " ...\n" " }\n" + "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n" "\nResult:\n" "\"transaction\" (string) hex string of the transaction\n" @@ -350,14 +354,22 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"") ); - LOCK(cs_main); - RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM), true); + if (params[0].isNull() || params[1].isNull()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null"); UniValue inputs = params[0].get_array(); UniValue sendTo = params[1].get_obj(); CMutableTransaction rawTx; + if (params.size() > 2 && !params[2].isNull()) { + int64_t nLockTime = params[2].get_int64(); + if (nLockTime < 0 || nLockTime > std::numeric_limits::max()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range"); + rawTx.nLockTime = nLockTime; + } + for (unsigned int idx = 0; idx < inputs.size(); idx++) { const UniValue& input = inputs[idx]; const UniValue& o = input.get_obj(); @@ -371,7 +383,9 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) if (nOutput < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); - CTxIn in(COutPoint(txid, nOutput)); + uint32_t nSequence = (rawTx.nLockTime ? std::numeric_limits::max() - 1 : std::numeric_limits::max()); + CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence); + rawTx.vin.push_back(in); } @@ -417,6 +431,7 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp) "\nResult:\n" "{\n" " \"txid\" : \"id\", (string) The transaction id\n" + " \"size\" : n, (numeric) The transaction size\n" " \"version\" : n, (numeric) The version\n" " \"locktime\" : ttt, (numeric) The lock time\n" " \"vin\" : [ (array of json objects)\n" @@ -494,7 +509,6 @@ UniValue decodescript(const UniValue& params, bool fHelp) + HelpExampleRpc("decodescript", "\"hexstring\"") ); - LOCK(cs_main); RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)); UniValue r(UniValue::VOBJ); @@ -797,19 +811,20 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); uint256 hashTx = tx.GetHash(); - bool fOverrideFees = false; - if (params.size() > 1) - fOverrideFees = params[1].get_bool(); + CAmount nMaxRawTxFee = maxTxFee; + if (params.size() > 1 && params[1].get_bool()) + nMaxRawTxFee = 0; CCoinsViewCache &view = *pcoinsTip; const CCoins* existingCoins = view.AccessCoins(hashTx); bool fHaveMempool = mempool.exists(hashTx); bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000; + CFeeRate txFeeRate = CFeeRate(0); if (!fHaveMempool && !fHaveChain) { // push to local node and sync with wallets CValidationState state; bool fMissingInputs; - if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, !fOverrideFees)) { + if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, &txFeeRate, false, nMaxRawTxFee)) { if (state.IsInvalid()) { throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); } else { @@ -822,7 +837,27 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) } else if (fHaveChain) { throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); } - RelayTransaction(tx); + RelayTransaction(tx, txFeeRate); return hashTx.GetHex(); } + +static const CRPCCommand commands[] = +{ // category name actor (function) okSafeMode + // --------------------- ------------------------ ----------------------- ---------- + { "rawtransactions", "getrawtransaction", &getrawtransaction, true }, + { "rawtransactions", "createrawtransaction", &createrawtransaction, true }, + { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true }, + { "rawtransactions", "decodescript", &decodescript, true }, + { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false }, + { "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */ + + { "blockchain", "gettxoutproof", &gettxoutproof, true }, + { "blockchain", "verifytxoutproof", &verifytxoutproof, true }, +}; + +void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC) +{ + for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) + tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); +} diff --git a/src/rpc/register.h b/src/rpc/register.h new file mode 100644 index 000000000..01aa58a25 --- /dev/null +++ b/src/rpc/register.h @@ -0,0 +1,32 @@ +// Copyright (c) 2009-2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_RPCREGISTER_H +#define BITCOIN_RPCREGISTER_H + +/** These are in one header file to avoid creating tons of single-function + * headers for everything under src/rpc/ */ +class CRPCTable; + +/** Register block chain RPC commands */ +void RegisterBlockchainRPCCommands(CRPCTable &tableRPC); +/** Register P2P networking RPC commands */ +void RegisterNetRPCCommands(CRPCTable &tableRPC); +/** Register miscellaneous RPC commands */ +void RegisterMiscRPCCommands(CRPCTable &tableRPC); +/** Register mining RPC commands */ +void RegisterMiningRPCCommands(CRPCTable &tableRPC); +/** Register raw transaction RPC commands */ +void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC); + +static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC) +{ + RegisterBlockchainRPCCommands(tableRPC); + RegisterNetRPCCommands(tableRPC); + RegisterMiscRPCCommands(tableRPC); + RegisterMiningRPCCommands(tableRPC); + RegisterRawTransactionRPCCommands(tableRPC); +} + +#endif diff --git a/src/rpcserver.cpp b/src/rpc/server.cpp similarity index 55% rename from src/rpcserver.cpp rename to src/rpc/server.cpp index cf1d742f4..05f2a72fd 100644 --- a/src/rpcserver.cpp +++ b/src/rpc/server.cpp @@ -1,9 +1,9 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcserver.h" +#include "rpc/server.h" #include "base58.h" #include "init.h" @@ -33,7 +33,7 @@ static bool fRPCInWarmup = true; static std::string rpcWarmupStatus("RPC server started"); static CCriticalSection cs_rpcWarmup; /* Timer-creating functions */ -static std::vector timerInterfaces; +static RPCTimerInterface* timerInterface = NULL; /* Map of name to timer. * @note Can be changed to std::unique_ptr when C++11 */ static std::map > deadlineTimers; @@ -89,7 +89,8 @@ void RPCTypeCheck(const UniValue& params, void RPCTypeCheckObj(const UniValue& o, const map& typesExpected, - bool fAllowNull) + bool fAllowNull, + bool fStrict) { BOOST_FOREACH(const PAIRTYPE(string, UniValue::VType)& t, typesExpected) { @@ -104,6 +105,18 @@ void RPCTypeCheckObj(const UniValue& o, throw JSONRPCError(RPC_TYPE_ERROR, err); } } + + if (fStrict) + { + BOOST_FOREACH(const string& k, o.getKeys()) + { + if (typesExpected.count(k) == 0) + { + string err = strprintf("Unexpected key %s", k); + throw JSONRPCError(RPC_TYPE_ERROR, err); + } + } + } } CAmount AmountFromValue(const UniValue& value) @@ -256,137 +269,8 @@ static const CRPCCommand vRPCCommands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- /* Overall control/query calls */ - { "control", "getinfo", &getinfo, true }, /* uses wallet if enabled */ { "control", "help", &help, true }, { "control", "stop", &stop, true }, - - /* P2P networking */ - { "network", "getnetworkinfo", &getnetworkinfo, true }, - { "network", "addnode", &addnode, true }, - { "network", "disconnectnode", &disconnectnode, true }, - { "network", "getaddednodeinfo", &getaddednodeinfo, true }, - { "network", "getconnectioncount", &getconnectioncount, true }, - { "network", "getnettotals", &getnettotals, true }, - { "network", "getpeerinfo", &getpeerinfo, true }, - { "network", "ping", &ping, true }, - { "network", "setban", &setban, true }, - { "network", "listbanned", &listbanned, true }, - { "network", "clearbanned", &clearbanned, true }, - - /* Block chain and UTXO */ - { "blockchain", "getblockchaininfo", &getblockchaininfo, true }, - { "blockchain", "getbestblockhash", &getbestblockhash, true }, - { "blockchain", "getblockcount", &getblockcount, true }, - { "blockchain", "getblock", &getblock, true }, - { "blockchain", "getblockhash", &getblockhash, true }, - { "blockchain", "getblockheader", &getblockheader, true }, - { "blockchain", "getchaintips", &getchaintips, true }, - { "blockchain", "getdifficulty", &getdifficulty, true }, - { "blockchain", "getmempoolinfo", &getmempoolinfo, true }, - { "blockchain", "getrawmempool", &getrawmempool, true }, - { "blockchain", "gettxout", &gettxout, true }, - { "blockchain", "gettxoutproof", &gettxoutproof, true }, - { "blockchain", "verifytxoutproof", &verifytxoutproof, true }, - { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true }, - { "blockchain", "verifychain", &verifychain, true }, - - /* Mining */ - { "mining", "getblocktemplate", &getblocktemplate, true }, - { "mining", "getmininginfo", &getmininginfo, true }, - { "mining", "getnetworkhashps", &getnetworkhashps, true }, - { "mining", "prioritisetransaction", &prioritisetransaction, true }, - { "mining", "submitblock", &submitblock, true }, - - /* Coin generation */ - { "generating", "getgenerate", &getgenerate, true }, - { "generating", "setgenerate", &setgenerate, true }, - { "generating", "generate", &generate, true }, - - /* Raw transactions */ - { "rawtransactions", "createrawtransaction", &createrawtransaction, true }, - { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true }, - { "rawtransactions", "decodescript", &decodescript, true }, - { "rawtransactions", "getrawtransaction", &getrawtransaction, true }, - { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false }, - { "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */ -#ifdef ENABLE_WALLET - { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false }, -#endif - - /* Utility functions */ - { "util", "createmultisig", &createmultisig, true }, - { "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */ - { "util", "verifymessage", &verifymessage, true }, - { "util", "estimatefee", &estimatefee, true }, - { "util", "estimatepriority", &estimatepriority, true }, - - /* Not shown in help */ - { "hidden", "invalidateblock", &invalidateblock, true }, - { "hidden", "reconsiderblock", &reconsiderblock, true }, - { "hidden", "setmocktime", &setmocktime, true }, -#ifdef ENABLE_WALLET - { "hidden", "resendwallettransactions", &resendwallettransactions, true}, -#endif - -#ifdef ENABLE_WALLET - /* Wallet */ - { "wallet", "addmultisigaddress", &addmultisigaddress, true }, - { "wallet", "backupwallet", &backupwallet, true }, - { "wallet", "dumpprivkey", &dumpprivkey, true }, - { "wallet", "dumpwallet", &dumpwallet, true }, - { "wallet", "encryptwallet", &encryptwallet, true }, - { "wallet", "getaccountaddress", &getaccountaddress, true }, - { "wallet", "getaccount", &getaccount, true }, - { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true }, - { "wallet", "getbalance", &getbalance, false }, - { "wallet", "getnewaddress", &getnewaddress, true }, - { "wallet", "getrawchangeaddress", &getrawchangeaddress, true }, - { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false }, - { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false }, - { "wallet", "gettransaction", &gettransaction, false }, - { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false }, - { "wallet", "getwalletinfo", &getwalletinfo, false }, - { "wallet", "importprivkey", &importprivkey, true }, - { "wallet", "importwallet", &importwallet, true }, - { "wallet", "importaddress", &importaddress, true }, - { "wallet", "importpubkey", &importpubkey, true }, - { "wallet", "keypoolrefill", &keypoolrefill, true }, - { "wallet", "listaccounts", &listaccounts, false }, - { "wallet", "listaddressgroupings", &listaddressgroupings, false }, - { "wallet", "listlockunspent", &listlockunspent, false }, - { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false }, - { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false }, - { "wallet", "listsinceblock", &listsinceblock, false }, - { "wallet", "listtransactions", &listtransactions, false }, - { "wallet", "listunspent", &listunspent, false }, - { "wallet", "lockunspent", &lockunspent, true }, - { "wallet", "move", &movecmd, false }, - { "wallet", "sendfrom", &sendfrom, false }, - { "wallet", "sendmany", &sendmany, false }, - { "wallet", "claimname", &claimname, false }, - { "wallet", "listnameclaims", &listnameclaims, false }, - { "wallet", "updateclaim", &updateclaim, false }, - { "wallet", "abandonclaim", &abandonclaim, false }, - { "wallet", "supportclaim", &supportclaim, false }, - { "wallet", "abandonsupport", &abandonsupport, false }, - { "wallet", "sendtoaddress", &sendtoaddress, false }, - { "wallet", "setaccount", &setaccount, true }, - { "wallet", "settxfee", &settxfee, true }, - { "wallet", "signmessage", &signmessage, true }, - { "wallet", "walletlock", &walletlock, true }, - { "wallet", "walletpassphrasechange", &walletpassphrasechange, true }, - { "wallet", "walletpassphrase", &walletpassphrase, true }, -#endif // ENABLE_WALLET - - /* Claim trie */ - { "claimtrie", "getclaimsintrie", &getclaimsintrie, true }, - { "claimtrie", "getclaimtrie", &getclaimtrie, true }, - { "claimtrie", "getvalueforname", &getvalueforname, true }, - { "claimtrie", "gettotalclaimednames", &gettotalclaimednames, true }, - { "claimtrie", "gettotalclaims", &gettotalclaims, true }, - { "claimtrie", "gettotalvalueofclaims", &gettotalvalueofclaims, true }, - { "claimtrie", "getclaimsfortx", &getclaimsfortx, true }, - { "claimtrie", "getnameproof", &getnameproof, true }, }; CRPCTable::CRPCTable() @@ -409,6 +293,20 @@ const CRPCCommand *CRPCTable::operator[](const std::string &name) const return (*it).second; } +bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd) +{ + if (IsRPCRunning()) + return false; + + // don't allow overwriting for now + map::const_iterator it = mapCommands.find(name); + if (it != mapCommands.end()) + return false; + + mapCommands[name] = pcmd; + return true; +} + bool StartRPC() { LogPrint("rpc", "Starting RPC\n"); @@ -549,6 +447,17 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms g_rpcSignals.PostCommand(*pcmd); } +std::vector CRPCTable::listCommands() const +{ + std::vector commandList; + typedef std::map commandMap; + + std::transform( mapCommands.begin(), mapCommands.end(), + std::back_inserter(commandList), + boost::bind(&commandMap::value_type::first,_1) ); + return commandList; +} + std::string HelpExampleCli(const std::string& methodname, const std::string& args) { return "> lbrycrd-cli " + methodname + " " + args + "\n"; @@ -560,26 +469,30 @@ std::string HelpExampleRpc(const std::string& methodname, const std::string& arg "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:9245/\n"; } -void RPCRegisterTimerInterface(RPCTimerInterface *iface) +void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface) { - timerInterfaces.push_back(iface); + if (!timerInterface) + timerInterface = iface; } -void RPCUnregisterTimerInterface(RPCTimerInterface *iface) +void RPCSetTimerInterface(RPCTimerInterface *iface) { - std::vector::iterator i = std::find(timerInterfaces.begin(), timerInterfaces.end(), iface); - assert(i != timerInterfaces.end()); - timerInterfaces.erase(i); + timerInterface = iface; +} + +void RPCUnsetTimerInterface(RPCTimerInterface *iface) +{ + if (timerInterface == iface) + timerInterface = NULL; } void RPCRunLater(const std::string& name, boost::function func, int64_t nSeconds) { - if (timerInterfaces.empty()) + if (!timerInterface) throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC"); deadlineTimers.erase(name); - RPCTimerInterface* timerInterface = timerInterfaces[0]; LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name()); - deadlineTimers.insert(std::make_pair(name, timerInterface->NewTimer(func, nSeconds*1000))); + deadlineTimers.insert(std::make_pair(name, boost::shared_ptr(timerInterface->NewTimer(func, nSeconds*1000)))); } -const CRPCTable tableRPC; +CRPCTable tableRPC; diff --git a/src/rpc/server.h b/src/rpc/server.h new file mode 100644 index 000000000..b47133661 --- /dev/null +++ b/src/rpc/server.h @@ -0,0 +1,189 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_RPCSERVER_H +#define BITCOIN_RPCSERVER_H + +#include "amount.h" +#include "rpc/protocol.h" +#include "uint256.h" + +#include +#include +#include +#include + +#include + +#include + +class CRPCCommand; + +namespace RPCServer +{ + void OnStarted(boost::function slot); + void OnStopped(boost::function slot); + void OnPreCommand(boost::function slot); + void OnPostCommand(boost::function slot); +} + +class CBlockIndex; +class CNetAddr; + +class JSONRequest +{ +public: + UniValue id; + std::string strMethod; + UniValue params; + + JSONRequest() { id = NullUniValue; } + void parse(const UniValue& valRequest); +}; + +/** Query whether RPC is running */ +bool IsRPCRunning(); + +/** + * Set the RPC warmup status. When this is done, all RPC calls will error out + * immediately with RPC_IN_WARMUP. + */ +void SetRPCWarmupStatus(const std::string& newStatus); +/* Mark warmup as done. RPC calls will be processed from now on. */ +void SetRPCWarmupFinished(); + +/* returns the current warmup state. */ +bool RPCIsInWarmup(std::string *statusOut); + +/** + * Type-check arguments; throws JSONRPCError if wrong type given. Does not check that + * the right number of arguments are passed, just that any passed are the correct type. + * Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type)); + */ +void RPCTypeCheck(const UniValue& params, + const std::list& typesExpected, bool fAllowNull=false); + +/* + Check for expected keys/value types in an Object. + Use like: RPCTypeCheckObj(object, boost::assign::map_list_of("name", str_type)("value", int_type)); +*/ +void RPCTypeCheckObj(const UniValue& o, + const std::map& typesExpected, bool fAllowNull=false, bool fStrict=false); + +/** Opaque base class for timers returned by NewTimerFunc. + * This provides no methods at the moment, but makes sure that delete + * cleans up the whole state. + */ +class RPCTimerBase +{ +public: + virtual ~RPCTimerBase() {} +}; + +/** + * RPC timer "driver". + */ +class RPCTimerInterface +{ +public: + virtual ~RPCTimerInterface() {} + /** Implementation name */ + virtual const char *Name() = 0; + /** Factory function for timers. + * RPC will call the function to create a timer that will call func in *millis* milliseconds. + * @note As the RPC mechanism is backend-neutral, it can use different implementations of timers. + * This is needed to cope with the case in which there is no HTTP server, but + * only GUI RPC console, and to break the dependency of pcserver on httprpc. + */ + virtual RPCTimerBase* NewTimer(boost::function& func, int64_t millis) = 0; +}; + +/** Set the factory function for timers */ +void RPCSetTimerInterface(RPCTimerInterface *iface); +/** Set the factory function for timer, but only, if unset */ +void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface); +/** Unset factory function for timers */ +void RPCUnsetTimerInterface(RPCTimerInterface *iface); + +/** + * Run func nSeconds from now. + * Overrides previous timer (if any). + */ +void RPCRunLater(const std::string& name, boost::function func, int64_t nSeconds); + +typedef UniValue(*rpcfn_type)(const UniValue& params, bool fHelp); + +class CRPCCommand +{ +public: + std::string category; + std::string name; + rpcfn_type actor; + bool okSafeMode; +}; + +/** + * Bitcoin RPC command dispatcher. + */ +class CRPCTable +{ +private: + std::map mapCommands; +public: + CRPCTable(); + const CRPCCommand* operator[](const std::string& name) const; + std::string help(const std::string& name) const; + + /** + * Execute a method. + * @param method Method to execute + * @param params UniValue Array of arguments (JSON objects) + * @returns Result of the call. + * @throws an exception (UniValue) when an error happens. + */ + UniValue execute(const std::string &method, const UniValue ¶ms) const; + + /** + * Returns a list of registered commands + * @returns List of registered commands. + */ + std::vector listCommands() const; + + + /** + * Appends a CRPCCommand to the dispatch table. + * Returns false if RPC server is already running (dump concurrency protection). + * Commands cannot be overwritten (returns false). + */ + bool appendCommand(const std::string& name, const CRPCCommand* pcmd); +}; + +extern CRPCTable tableRPC; + +/** + * Utilities: convert hex-encoded Values + * (throws error if not hex). + */ +extern uint256 ParseHashV(const UniValue& v, std::string strName); +extern uint256 ParseHashO(const UniValue& o, std::string strKey); +extern std::vector ParseHexV(const UniValue& v, std::string strName); +extern std::vector ParseHexO(const UniValue& o, std::string strKey); + +extern int64_t nWalletUnlockTime; +extern CAmount AmountFromValue(const UniValue& value); +extern UniValue ValueFromAmount(const CAmount& amount); +extern double GetDifficulty(const CBlockIndex* blockindex = NULL); +extern std::string HelpRequiringPassphrase(); +extern std::string HelpExampleCli(const std::string& methodname, const std::string& args); +extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args); + +extern void EnsureWalletIsUnlocked(); + +bool StartRPC(); +void InterruptRPC(); +void StopRPC(); +std::string JSONRPCExecBatch(const UniValue& vReq); + +#endif // BITCOIN_RPCSERVER_H diff --git a/src/rpcserver.h b/src/rpcserver.h deleted file mode 100644 index bb1608b4f..000000000 --- a/src/rpcserver.h +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_RPCSERVER_H -#define BITCOIN_RPCSERVER_H - -#include "amount.h" -#include "rpcprotocol.h" -#include "uint256.h" - -#include -#include -#include -#include - -#include - -#include - -class CRPCCommand; - -namespace RPCServer -{ - void OnStarted(boost::function slot); - void OnStopped(boost::function slot); - void OnPreCommand(boost::function slot); - void OnPostCommand(boost::function slot); -} - -class CBlockIndex; -class CNetAddr; - -class JSONRequest -{ -public: - UniValue id; - std::string strMethod; - UniValue params; - - JSONRequest() { id = NullUniValue; } - void parse(const UniValue& valRequest); -}; - -/** Query whether RPC is running */ -bool IsRPCRunning(); - -/** - * Set the RPC warmup status. When this is done, all RPC calls will error out - * immediately with RPC_IN_WARMUP. - */ -void SetRPCWarmupStatus(const std::string& newStatus); -/* Mark warmup as done. RPC calls will be processed from now on. */ -void SetRPCWarmupFinished(); - -/* returns the current warmup state. */ -bool RPCIsInWarmup(std::string *statusOut); - -/** - * Type-check arguments; throws JSONRPCError if wrong type given. Does not check that - * the right number of arguments are passed, just that any passed are the correct type. - * Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type)); - */ -void RPCTypeCheck(const UniValue& params, - const std::list& typesExpected, bool fAllowNull=false); - -/* - Check for expected keys/value types in an Object. - Use like: RPCTypeCheckObj(object, boost::assign::map_list_of("name", str_type)("value", int_type)); -*/ -void RPCTypeCheckObj(const UniValue& o, - const std::map& typesExpected, bool fAllowNull=false); - -/** Opaque base class for timers returned by NewTimerFunc. - * This provides no methods at the moment, but makes sure that delete - * cleans up the whole state. - */ -class RPCTimerBase -{ -public: - virtual ~RPCTimerBase() {} -}; - -/** - * RPC timer "driver". - */ -class RPCTimerInterface -{ -public: - virtual ~RPCTimerInterface() {} - /** Implementation name */ - virtual const char *Name() = 0; - /** Factory function for timers. - * RPC will call the function to create a timer that will call func in *millis* milliseconds. - * @note As the RPC mechanism is backend-neutral, it can use different implementations of timers. - * This is needed to cope with the case in which there is no HTTP server, but - * only GUI RPC console, and to break the dependency of pcserver on httprpc. - */ - virtual RPCTimerBase* NewTimer(boost::function& func, int64_t millis) = 0; -}; - -/** Register factory function for timers */ -void RPCRegisterTimerInterface(RPCTimerInterface *iface); -/** Unregister factory function for timers */ -void RPCUnregisterTimerInterface(RPCTimerInterface *iface); - -/** - * Run func nSeconds from now. - * Overrides previous timer (if any). - */ -void RPCRunLater(const std::string& name, boost::function func, int64_t nSeconds); - -typedef UniValue(*rpcfn_type)(const UniValue& params, bool fHelp); - -class CRPCCommand -{ -public: - std::string category; - std::string name; - rpcfn_type actor; - bool okSafeMode; -}; - -/** - * Bitcoin RPC command dispatcher. - */ -class CRPCTable -{ -private: - std::map mapCommands; -public: - CRPCTable(); - const CRPCCommand* operator[](const std::string& name) const; - std::string help(const std::string& name) const; - - /** - * Execute a method. - * @param method Method to execute - * @param params UniValue Array of arguments (JSON objects) - * @returns Result of the call. - * @throws an exception (UniValue) when an error happens. - */ - UniValue execute(const std::string &method, const UniValue ¶ms) const; -}; - -extern const CRPCTable tableRPC; - -/** - * Utilities: convert hex-encoded Values - * (throws error if not hex). - */ -extern uint256 ParseHashV(const UniValue& v, std::string strName); -extern uint256 ParseHashO(const UniValue& o, std::string strKey); -extern std::vector ParseHexV(const UniValue& v, std::string strName); -extern std::vector ParseHexO(const UniValue& o, std::string strKey); - -extern int64_t nWalletUnlockTime; -extern CAmount AmountFromValue(const UniValue& value); -extern UniValue ValueFromAmount(const CAmount& amount); -extern double GetDifficulty(const CBlockIndex* blockindex = NULL); -extern std::string HelpRequiringPassphrase(); -extern std::string HelpExampleCli(const std::string& methodname, const std::string& args); -extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args); - -extern void EnsureWalletIsUnlocked(); - -extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpcnet.cpp -extern UniValue getpeerinfo(const UniValue& params, bool fHelp); -extern UniValue ping(const UniValue& params, bool fHelp); -extern UniValue addnode(const UniValue& params, bool fHelp); -extern UniValue disconnectnode(const UniValue& params, bool fHelp); -extern UniValue getaddednodeinfo(const UniValue& params, bool fHelp); -extern UniValue getnettotals(const UniValue& params, bool fHelp); -extern UniValue setban(const UniValue& params, bool fHelp); -extern UniValue listbanned(const UniValue& params, bool fHelp); -extern UniValue clearbanned(const UniValue& params, bool fHelp); - -extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp -extern UniValue importprivkey(const UniValue& params, bool fHelp); -extern UniValue importaddress(const UniValue& params, bool fHelp); -extern UniValue importpubkey(const UniValue& params, bool fHelp); -extern UniValue dumpwallet(const UniValue& params, bool fHelp); -extern UniValue importwallet(const UniValue& params, bool fHelp); - -extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpcmining.cpp -extern UniValue setgenerate(const UniValue& params, bool fHelp); -extern UniValue generate(const UniValue& params, bool fHelp); -extern UniValue getnetworkhashps(const UniValue& params, bool fHelp); -extern UniValue getmininginfo(const UniValue& params, bool fHelp); -extern UniValue prioritisetransaction(const UniValue& params, bool fHelp); -extern UniValue getblocktemplate(const UniValue& params, bool fHelp); -extern UniValue submitblock(const UniValue& params, bool fHelp); -extern UniValue estimatefee(const UniValue& params, bool fHelp); -extern UniValue estimatepriority(const UniValue& params, bool fHelp); - -extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp -extern UniValue getaccountaddress(const UniValue& params, bool fHelp); -extern UniValue getrawchangeaddress(const UniValue& params, bool fHelp); -extern UniValue setaccount(const UniValue& params, bool fHelp); -extern UniValue getaccount(const UniValue& params, bool fHelp); -extern UniValue getaddressesbyaccount(const UniValue& params, bool fHelp); -extern UniValue claimname(const UniValue& params, bool fHelp); -extern UniValue listnameclaims(const UniValue& params, bool fHelp); -extern UniValue updateclaim(const UniValue& params, bool fHelp); -extern UniValue abandonclaim(const UniValue& params, bool fHelp); -extern UniValue supportclaim(const UniValue& params, bool fHelp); -extern UniValue abandonsupport(const UniValue& params, bool fHelp); -extern UniValue sendtoaddress(const UniValue& params, bool fHelp); -extern UniValue signmessage(const UniValue& params, bool fHelp); -extern UniValue verifymessage(const UniValue& params, bool fHelp); -extern UniValue getreceivedbyaddress(const UniValue& params, bool fHelp); -extern UniValue getreceivedbyaccount(const UniValue& params, bool fHelp); -extern UniValue getbalance(const UniValue& params, bool fHelp); -extern UniValue getunconfirmedbalance(const UniValue& params, bool fHelp); -extern UniValue movecmd(const UniValue& params, bool fHelp); -extern UniValue sendfrom(const UniValue& params, bool fHelp); -extern UniValue sendmany(const UniValue& params, bool fHelp); -extern UniValue addmultisigaddress(const UniValue& params, bool fHelp); -extern UniValue createmultisig(const UniValue& params, bool fHelp); -extern UniValue listreceivedbyaddress(const UniValue& params, bool fHelp); -extern UniValue listreceivedbyaccount(const UniValue& params, bool fHelp); -extern UniValue listtransactions(const UniValue& params, bool fHelp); -extern UniValue listaddressgroupings(const UniValue& params, bool fHelp); -extern UniValue listaccounts(const UniValue& params, bool fHelp); -extern UniValue listsinceblock(const UniValue& params, bool fHelp); -extern UniValue gettransaction(const UniValue& params, bool fHelp); -extern UniValue backupwallet(const UniValue& params, bool fHelp); -extern UniValue keypoolrefill(const UniValue& params, bool fHelp); -extern UniValue walletpassphrase(const UniValue& params, bool fHelp); -extern UniValue walletpassphrasechange(const UniValue& params, bool fHelp); -extern UniValue walletlock(const UniValue& params, bool fHelp); -extern UniValue encryptwallet(const UniValue& params, bool fHelp); -extern UniValue validateaddress(const UniValue& params, bool fHelp); -extern UniValue getinfo(const UniValue& params, bool fHelp); -extern UniValue getwalletinfo(const UniValue& params, bool fHelp); -extern UniValue getblockchaininfo(const UniValue& params, bool fHelp); -extern UniValue getnetworkinfo(const UniValue& params, bool fHelp); -extern UniValue setmocktime(const UniValue& params, bool fHelp); -extern UniValue resendwallettransactions(const UniValue& params, bool fHelp); - -extern UniValue getrawtransaction(const UniValue& params, bool fHelp); // in rcprawtransaction.cpp -extern UniValue listunspent(const UniValue& params, bool fHelp); -extern UniValue lockunspent(const UniValue& params, bool fHelp); -extern UniValue listlockunspent(const UniValue& params, bool fHelp); -extern UniValue createrawtransaction(const UniValue& params, bool fHelp); -extern UniValue decoderawtransaction(const UniValue& params, bool fHelp); -extern UniValue decodescript(const UniValue& params, bool fHelp); -extern UniValue fundrawtransaction(const UniValue& params, bool fHelp); -extern UniValue signrawtransaction(const UniValue& params, bool fHelp); -extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); -extern UniValue gettxoutproof(const UniValue& params, bool fHelp); -extern UniValue verifytxoutproof(const UniValue& params, bool fHelp); - -extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpcblockchain.cpp -extern UniValue getbestblockhash(const UniValue& params, bool fHelp); -extern UniValue getdifficulty(const UniValue& params, bool fHelp); -extern UniValue settxfee(const UniValue& params, bool fHelp); -extern UniValue getmempoolinfo(const UniValue& params, bool fHelp); -extern UniValue getrawmempool(const UniValue& params, bool fHelp); -extern UniValue getblockhash(const UniValue& params, bool fHelp); -extern UniValue getblockheader(const UniValue& params, bool fHelp); -extern UniValue getblock(const UniValue& params, bool fHelp); -extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp); -extern UniValue gettxout(const UniValue& params, bool fHelp); -extern UniValue verifychain(const UniValue& params, bool fHelp); -extern UniValue getchaintips(const UniValue& params, bool fHelp); -extern UniValue invalidateblock(const UniValue& params, bool fHelp); -extern UniValue reconsiderblock(const UniValue& params, bool fHelp); - -extern UniValue getclaimsintrie(const UniValue& params, bool fHelp); // in rpcclaimtrie.cpp -extern UniValue getclaimtrie(const UniValue& params, bool fHelp); // in rpcclaimtrie.cpp -extern UniValue getvalueforname(const UniValue& params, bool fHelp); -extern UniValue gettotalclaimednames(const UniValue& params, bool fHelp); -extern UniValue gettotalclaims(const UniValue& params, bool fHelp); -extern UniValue gettotalvalueofclaims(const UniValue& params, bool fHelp); -extern UniValue getclaimsfortx(const UniValue& params, bool fHelp); -extern UniValue getnameproof(const UniValue& params, bool fHelp); - - -bool StartRPC(); -void InterruptRPC(); -void StopRPC(); -std::string JSONRPCExecBatch(const UniValue& vReq); - -#endif // BITCOIN_RPCSERVER_H diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp index b0d5faaf7..47ad1d080 100644 --- a/src/script/bitcoinconsensus.cpp +++ b/src/script/bitcoinconsensus.cpp @@ -1,11 +1,12 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "bitcoinconsensus.h" #include "primitives/transaction.h" +#include "pubkey.h" #include "script/interpreter.h" #include "version.h" @@ -60,7 +61,13 @@ inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror) return 0; } -} // anon namespace +struct ECCryptoClosure +{ + ECCVerifyHandle handle; +}; + +ECCryptoClosure instance_of_eccryptoclosure; +} int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, const unsigned char *txTo , unsigned int txToLen, diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h index 032057779..5b8c33c6b 100644 --- a/src/script/bitcoinconsensus.h +++ b/src/script/bitcoinconsensus.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -44,9 +44,10 @@ typedef enum bitcoinconsensus_error_t /** Script verification flags */ enum { - bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0, - bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts - bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance + bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0, + bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts + bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance + bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65) }; /// Returns 1 if the input nIn of the serialized transaction pointed to by diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index f783a32b1..694ac2038 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,7 +9,6 @@ #include "crypto/ripemd160.h" #include "crypto/sha1.h" #include "crypto/sha256.h" -#include "eccryptoverify.h" #include "pubkey.h" #include "script/script.h" #include "uint256.h" @@ -166,15 +165,10 @@ bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) { if (!IsValidSignatureEncoding(vchSig)) { return set_error(serror, SCRIPT_ERR_SIG_DER); } - unsigned int nLenR = vchSig[3]; - unsigned int nLenS = vchSig[5+nLenR]; - const unsigned char *S = &vchSig[6+nLenR]; - // If the S value is above the order of the curve divided by two, its - // complement modulo the order could have been used instead, which is - // one byte shorter when encoded correctly. - if (!eccrypto::CheckSignatureElement(S, nLenS, true)) + std::vector vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size() - 1); + if (!CPubKey::CheckLowS(vchSigCopy)) { return set_error(serror, SCRIPT_ERR_SIG_HIGH_S); - + } return true; } @@ -274,7 +268,7 @@ bool EvalScript(vector >& stack, const CScript& script, un return set_error(serror, SCRIPT_ERR_PUSH_SIZE); // Note how OP_RESERVED does not count towards the opcode limit. - if (opcode > OP_16 && ++nOpCount > 201) + if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT) return set_error(serror, SCRIPT_ERR_OP_COUNT); if (opcode == OP_CAT || @@ -387,8 +381,45 @@ bool EvalScript(vector >& stack, const CScript& script, un } break; - case OP_NOP5: - case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: + case OP_CHECKSEQUENCEVERIFY: + { + if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) { + // not enabled; treat as a NOP3 + if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); + } + break; + } + + if (stack.size() < 1) + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + + // nSequence, like nLockTime, is a 32-bit unsigned integer + // field. See the comment in CHECKLOCKTIMEVERIFY regarding + // 5-byte numeric operands. + const CScriptNum nSequence(stacktop(-1), fRequireMinimal, 5); + + // In the rare event that the argument may be < 0 due to + // some arithmetic being done first, you can always use + // 0 MAX CHECKSEQUENCEVERIFY. + if (nSequence < 0) + return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME); + + // To provide for future soft-fork extensibility, if the + // operand has the disabled lock-time flag set, + // CHECKSEQUENCEVERIFY behaves as a NOP. + if ((nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0) + break; + + // Compare the specified sequence number with the input. + if (!checker.CheckSequence(nSequence)) + return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME); + + break; + } + + case OP_NOP1: case OP_NOP4: case OP_NOP5: + case OP_NOP9: case OP_NOP10: { if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); @@ -877,10 +908,10 @@ bool EvalScript(vector >& stack, const CScript& script, un return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); - if (nKeysCount < 0 || nKeysCount > 20) + if (nKeysCount < 0 || nKeysCount > MAX_PUBKEYS_PER_MULTISIG) return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT); nOpCount += nKeysCount; - if (nOpCount > 201) + if (nOpCount > MAX_OPS_PER_SCRIPT) return set_error(serror, SCRIPT_ERR_OP_COUNT); int ikey = ++i; i += nKeysCount; @@ -992,12 +1023,12 @@ namespace { */ class CTransactionSignatureSerializer { private: - const CTransaction &txTo; //! reference to the spending transaction (the one being serialized) - const CScript &scriptCode; //! output script being consumed - const unsigned int nIn; //! input index of txTo being signed - const bool fAnyoneCanPay; //! whether the hashtype has the SIGHASH_ANYONECANPAY flag set - const bool fHashSingle; //! whether the hashtype is SIGHASH_SINGLE - const bool fHashNone; //! whether the hashtype is SIGHASH_NONE + const CTransaction& txTo; //!< reference to the spending transaction (the one being serialized) + const CScript& scriptCode; //!< output script being consumed + const unsigned int nIn; //!< input index of txTo being signed + const bool fAnyoneCanPay; //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set + const bool fHashSingle; //!< whether the hashtype is SIGHASH_SINGLE + const bool fHashNone; //!< whether the hashtype is SIGHASH_NONE public: CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) : @@ -1040,7 +1071,7 @@ public: // Serialize the script if (nInput != nIn) // Blank out other inputs' signatures - ::Serialize(s, CScript(), nType, nVersion); + ::Serialize(s, CScriptBase(), nType, nVersion); else SerializeScriptCode(s, nType, nVersion); // Serialize the nSequence @@ -1164,12 +1195,57 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con // prevent this condition. Alternatively we could test all // inputs, but testing just this input minimizes the data // required to prove correct CHECKLOCKTIMEVERIFY execution. - if (txTo->vin[nIn].IsFinal()) + if (CTxIn::SEQUENCE_FINAL == txTo->vin[nIn].nSequence) return false; return true; } +bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) const +{ + // Relative lock times are supported by comparing the passed + // in operand to the sequence number of the input. + const int64_t txToSequence = (int64_t)txTo->vin[nIn].nSequence; + + // Fail if the transaction's version number is not set high + // enough to trigger BIP 68 rules. + if (static_cast(txTo->nVersion) < 2) + return false; + + // Sequence numbers with their most significant bit set are not + // consensus constrained. Testing that the transaction's sequence + // number do not have this bit set prevents using this property + // to get around a CHECKSEQUENCEVERIFY check. + if (txToSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) + return false; + + // Mask off any bits that do not have consensus-enforced meaning + // before doing the integer comparisons + const uint32_t nLockTimeMask = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | CTxIn::SEQUENCE_LOCKTIME_MASK; + const int64_t txToSequenceMasked = txToSequence & nLockTimeMask; + const CScriptNum nSequenceMasked = nSequence & nLockTimeMask; + + // There are two kinds of nSequence: lock-by-blockheight + // and lock-by-blocktime, distinguished by whether + // nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG. + // + // We want to compare apples to apples, so fail the script + // unless the type of nSequenceMasked being tested is the same as + // the nSequenceMasked in the transaction. + if (!( + (txToSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) || + (txToSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) + )) { + return false; + } + + // Now that we know we're comparing apples-to-apples, the + // comparison is a simple numeric one. + if (nSequenceMasked > txToSequenceMasked) + return false; + + return true; +} bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 213e8c765..e5cb7290f 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -81,6 +81,11 @@ enum // // See BIP65 for details. SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), + + // support CHECKSEQUENCEVERIFY opcode + // + // See BIP112 for details + SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10), }; bool CheckSignatureEncoding(const std::vector &vchSig, unsigned int flags, ScriptError* serror); @@ -100,6 +105,11 @@ public: return false; } + virtual bool CheckSequence(const CScriptNum& nSequence) const + { + return false; + } + virtual ~BaseSignatureChecker() {} }; @@ -116,6 +126,7 @@ public: TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {} bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode) const; bool CheckLockTime(const CScriptNum& nLockTime) const; + bool CheckSequence(const CScriptNum& nSequence) const; }; class MutableTransactionSignatureChecker : public TransactionSignatureChecker diff --git a/src/script/script.cpp b/src/script/script.cpp index 48a1a378d..846414756 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -130,14 +130,14 @@ const char* GetOpName(opcodetype opcode) case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY"; // expanson + case OP_NOP1 : return "OP_NOP1"; + case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY"; + case OP_NOP3 : return "OP_NOP3"; + case OP_NOP4 : return "OP_NOP4"; + case OP_NOP5 : return "OP_NOP5"; case OP_CLAIM_NAME : return "OP_CLAIM_NAME"; case OP_SUPPORT_CLAIM : return "OP_SUPPORT_CLAIM"; - case OP_NOP3 : return "OP_NOP3"; case OP_UPDATE_CLAIM : return "OP_UPDATE_CLAIM"; - case OP_NOP5 : return "OP_NOP5"; - case OP_NOP6 : return "OP_NOP6"; - case OP_NOP7 : return "OP_NOP7"; - case OP_NOP8 : return "OP_NOP8"; case OP_NOP9 : return "OP_NOP9"; case OP_NOP10 : return "OP_NOP10"; @@ -170,7 +170,7 @@ unsigned int CScript::GetSigOpCount(bool fAccurate) const if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16) n += DecodeOP_N(lastOpcode); else - n += 20; + n += MAX_PUBKEYS_PER_MULTISIG; } lastOpcode = opcode; } @@ -205,9 +205,9 @@ bool CScript::IsPayToScriptHash() const { // Extra-fast test for pay-to-script-hash CScripts: return (this->size() == 23 && - this->at(0) == OP_HASH160 && - this->at(1) == 0x14 && - this->at(22) == OP_EQUAL); + (*this)[0] == OP_HASH160 && + (*this)[1] == 0x14 && + (*this)[22] == OP_EQUAL); } bool CScript::IsPushOnly(const_iterator pc) const diff --git a/src/script/script.h b/src/script/script.h index 4b301e3cf..8bec81390 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,6 +7,7 @@ #define BITCOIN_SCRIPT_SCRIPT_H #include "crypto/common.h" +#include "prevector.h" #include #include @@ -17,8 +18,15 @@ #include #include +// Maximum number of bytes pushable to the stack static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 20000; // bytes +// Maximum number of non-push operations per script +static const int MAX_OPS_PER_SCRIPT = 201; + +// Maximum number of public keys per multisig +static const int MAX_PUBKEYS_PER_MULTISIG = 20; + // Threshold for nLockTime: below this value it is interpreted as block number, // otherwise as UNIX timestamp. static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC @@ -153,18 +161,19 @@ enum opcodetype OP_CHECKMULTISIGVERIFY = 0xaf, // expansion - OP_NOP1 = 0xb0, - OP_CLAIM_NAME = OP_NOP1, - OP_NOP2 = 0xb1, - OP_SUPPORT_CLAIM = OP_NOP2, + OP_NOP1 = 0xb0, + OP_CHECKLOCKTIMEVERIFY = 0xb1, + OP_NOP2 = OP_CHECKLOCKTIMEVERIFY, OP_NOP3 = 0xb2, - OP_CHECKLOCKTIMEVERIFY = OP_NOP3, + OP_CHECKSEQUENCEVERIFY = OP_NOP3, OP_NOP4 = 0xb3, - OP_UPDATE_CLAIM = OP_NOP4, OP_NOP5 = 0xb4, OP_NOP6 = 0xb5, + OP_CLAIM_NAME = OP_NOP6, OP_NOP7 = 0xb6, + OP_SUPPORT_CLAIM = OP_NOP7, OP_NOP8 = 0xb7, + OP_UPDATE_CLAIM = OP_NOP8, OP_NOP9 = 0xb8, OP_NOP10 = 0xb9, @@ -254,6 +263,11 @@ public: inline CScriptNum& operator+=( const CScriptNum& rhs) { return operator+=(rhs.m_value); } inline CScriptNum& operator-=( const CScriptNum& rhs) { return operator-=(rhs.m_value); } + inline CScriptNum operator&( const int64_t& rhs) const { return CScriptNum(m_value & rhs);} + inline CScriptNum operator&( const CScriptNum& rhs) const { return operator&(rhs.m_value); } + + inline CScriptNum& operator&=( const CScriptNum& rhs) { return operator&=(rhs.m_value); } + inline CScriptNum operator-() const { assert(m_value != std::numeric_limits::min()); @@ -282,6 +296,12 @@ public: return *this; } + inline CScriptNum& operator&=( const int64_t& rhs) + { + m_value &= rhs; + return *this; + } + int getint() const { if (m_value > std::numeric_limits::max()) @@ -350,8 +370,10 @@ private: int64_t m_value; }; +typedef prevector<28, unsigned char> CScriptBase; + /** Serialized script, used inside transaction inputs and outputs */ -class CScript : public std::vector +class CScript : public CScriptBase { protected: CScript& push_int64(int64_t n) @@ -372,9 +394,10 @@ protected: } public: CScript() { } - CScript(const CScript& b) : std::vector(b.begin(), b.end()) { } - CScript(const_iterator pbegin, const_iterator pend) : std::vector(pbegin, pend) { } - CScript(const unsigned char* pbegin, const unsigned char* pend) : std::vector(pbegin, pend) { } + CScript(const CScript& b) : CScriptBase(b.begin(), b.end()) { } + CScript(const_iterator pbegin, const_iterator pend) : CScriptBase(pbegin, pend) { } + CScript(std::vector::const_iterator pbegin, std::vector::const_iterator pend) : CScriptBase(pbegin, pend) { } + CScript(const unsigned char* pbegin, const unsigned char* pend) : CScriptBase(pbegin, pend) { } CScript& operator+=(const CScript& b) { @@ -607,7 +630,7 @@ public: void clear() { // The default std::vector::clear() does not release memory. - std::vector().swap(*this); + CScriptBase().swap(*this); } }; diff --git a/src/script/script_error.h b/src/script/script_error.h index bb10b8a29..26df33932 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -35,7 +35,7 @@ typedef enum ScriptError_t SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, SCRIPT_ERR_UNBALANCED_CONDITIONAL, - /* OP_CHECKLOCKTIMEVERIFY */ + /* CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY */ SCRIPT_ERR_NEGATIVE_LOCKTIME, SCRIPT_ERR_UNSATISFIED_LOCKTIME, diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index 099b4ad0e..bdc0bfdc1 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -1,20 +1,33 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "sigcache.h" +#include "memusage.h" #include "pubkey.h" #include "random.h" #include "uint256.h" #include "util.h" #include -#include +#include namespace { +/** + * We're hashing a nonce into the entries themselves, so we don't need extra + * blinding in the set hash computation. + */ +class CSignatureCacheHasher +{ +public: + size_t operator()(const uint256& key) const { + return key.GetCheapHash(); + } +}; + /** * Valid signature cache, to avoid doing expensive ECDSA signature checking * twice for every transaction (once when accepted into memory pool, and @@ -23,52 +36,54 @@ namespace { class CSignatureCache { private: - //! sigdata_type is (signature hash, signature, public key): - typedef boost::tuple, CPubKey> sigdata_type; - std::set< sigdata_type> setValid; + //! Entries are SHA256(nonce || signature hash || public key || signature): + uint256 nonce; + typedef boost::unordered_set map_type; + map_type setValid; boost::shared_mutex cs_sigcache; -public: - bool - Get(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) - { - boost::shared_lock lock(cs_sigcache); - sigdata_type k(hash, vchSig, pubKey); - std::set::iterator mi = setValid.find(k); - if (mi != setValid.end()) - return true; - return false; +public: + CSignatureCache() + { + GetRandBytes(nonce.begin(), 32); } - void Set(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) + void + ComputeEntry(uint256& entry, const uint256 &hash, const std::vector& vchSig, const CPubKey& pubkey) { - // DoS prevention: limit cache size to less than 10MB - // (~200 bytes per cache entry times 50,000 entries) - // Since there are a maximum of 20,000 signature operations per block - // 50,000 is a reasonable default. - int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000); + CSHA256().Write(nonce.begin(), 32).Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin()); + } + + bool + Get(const uint256& entry) + { + boost::shared_lock lock(cs_sigcache); + return setValid.count(entry); + } + + void Erase(const uint256& entry) + { + boost::unique_lock lock(cs_sigcache); + setValid.erase(entry); + } + + void Set(const uint256& entry) + { + size_t nMaxCacheSize = GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20); if (nMaxCacheSize <= 0) return; boost::unique_lock lock(cs_sigcache); - - while (static_cast(setValid.size()) > nMaxCacheSize) + while (memusage::DynamicUsage(setValid) > nMaxCacheSize) { - // Evict a random entry. Random because that helps - // foil would-be DoS attackers who might try to pre-generate - // and re-use a set of valid signatures just-slightly-greater - // than our cache size. - uint256 randomHash = GetRandHash(); - std::vector unused; - std::set::iterator it = - setValid.lower_bound(sigdata_type(randomHash, unused, unused)); - if (it == setValid.end()) - it = setValid.begin(); - setValid.erase(*it); + map_type::size_type s = GetRand(setValid.bucket_count()); + map_type::local_iterator it = setValid.begin(s); + if (it != setValid.end(s)) { + setValid.erase(*it); + } } - sigdata_type k(hash, vchSig, pubKey); - setValid.insert(k); + setValid.insert(entry); } }; @@ -78,13 +93,21 @@ bool CachingTransactionSignatureChecker::VerifySignature(const std::vector +// DoS prevention: limit cache size to less than 40MB (over 500000 +// entries on 64-bit systems). +static const unsigned int DEFAULT_MAX_SIG_CACHE_SIZE = 40; + class CPubKey; class CachingTransactionSignatureChecker : public TransactionSignatureChecker diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 2aa854784..06d741a76 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,7 +16,7 @@ using namespace std; -typedef vector valtype; +typedef std::vector valtype; TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn) {} @@ -120,7 +120,7 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu bool fSolved = SignStep(creator, subscript, scriptSig, subType) && subType != TX_SCRIPTHASH; // Append serialized subscript whether or not it is completely signed: - scriptSig << static_cast(subscript); + scriptSig << valtype(subscript.begin(), subscript.end()); if (!fSolved) return false; } diff --git a/src/script/sign.h b/src/script/sign.h index 13f45007d..47a9cde7f 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/standard.cpp b/src/script/standard.cpp index bfef8afa1..67b6af327 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,6 +16,7 @@ using namespace std; typedef vector valtype; +bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER; unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY; CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} @@ -160,27 +161,6 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector >& vSolutions) -{ - switch (t) - { - case TX_NONSTANDARD: - case TX_NULL_DATA: - return -1; - case TX_PUBKEY: - return 1; - case TX_PUBKEYHASH: - return 2; - case TX_MULTISIG: - if (vSolutions.size() < 1 || vSolutions[0].size() < 1) - return -1; - return vSolutions[0][0] + 1; - case TX_SCRIPTHASH: - return 1; // doesn't include args needed by the script - } - return -1; -} - bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { vector vSolutions; diff --git a/src/script/standard.h b/src/script/standard.h index ae1bbecca..f348da8e1 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,6 +13,8 @@ #include +static const bool DEFAULT_ACCEPT_DATACARRIER = true; + class CKeyID; class CScript; @@ -25,7 +27,8 @@ public: CScriptID(const uint160& in) : uint160(in) {} }; -static const unsigned int MAX_OP_RETURN_RELAY = 83; //! bytes (+1 for OP_RETURN, +2 for the pushdata opcodes) +static const unsigned int MAX_OP_RETURN_RELAY = 83; //!< bytes (+1 for OP_RETURN, +2 for the pushdata opcodes) +extern bool fAcceptDatacarrier; extern unsigned nMaxDatacarrierBytes; /** @@ -68,7 +71,6 @@ typedef boost::variant CTxDestination; const char* GetTxnOutputType(txnouttype t); bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet); -int ScriptSigArgsExpected(txnouttype t, const std::vector >& vSolutions); bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& addressRet, int& nRequiredRet); diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore index 076ff1295..e0b7b7a48 100644 --- a/src/secp256k1/.gitignore +++ b/src/secp256k1/.gitignore @@ -1,9 +1,12 @@ bench_inv +bench_ecdh bench_sign bench_verify +bench_schnorr_verify bench_recover bench_internal tests +gen_context *.exe *.so *.a @@ -28,6 +31,7 @@ build-aux/ *~ src/libsecp256k1-config.h src/libsecp256k1-config.h.in +src/ecmult_static_context.h m4/libtool.m4 m4/ltoptions.m4 m4/ltsugar.m4 diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml index 0d8089cfe..4e1e73c39 100644 --- a/src/secp256k1/.travis.yml +++ b/src/secp256k1/.travis.yml @@ -8,20 +8,24 @@ compiler: - gcc env: global: - - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no ASM=no BUILD=check EXTRAFLAGS= HOST= + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no matrix: - - SCALAR=32bit + - SCALAR=32bit RECOVERY=yes + - SCALAR=32bit FIELD=32bit ECDH=yes - SCALAR=64bit - - FIELD=64bit + - FIELD=64bit RECOVERY=yes - FIELD=64bit ENDOMORPHISM=yes + - FIELD=64bit ENDOMORPHISM=yes ECDH=yes - FIELD=64bit ASM=x86_64 - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 - - FIELD=32bit + - FIELD=32bit SCHNORR=yes - FIELD=32bit ENDOMORPHISM=yes - BIGNUM=no - - BIGNUM=no ENDOMORPHISM=yes + - BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes + - BIGNUM=no STATICPRECOMPUTATION=no - BUILD=distcheck - - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC + - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC + - EXTRAFLAGS=CFLAGS=-O0 matrix: fast_finish: true include: @@ -55,5 +59,5 @@ before_script: ./autogen.sh script: - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi - - ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR $EXTRAFLAGS $USE_HOST && make -j2 $BUILD + - ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD os: linux diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am index cc15338b7..7772a4e9d 100644 --- a/src/secp256k1/Makefile.am +++ b/src/secp256k1/Makefile.am @@ -19,6 +19,8 @@ noinst_HEADERS += src/eckey.h noinst_HEADERS += src/eckey_impl.h noinst_HEADERS += src/ecmult.h noinst_HEADERS += src/ecmult_impl.h +noinst_HEADERS += src/ecmult_const.h +noinst_HEADERS += src/ecmult_const_impl.h noinst_HEADERS += src/ecmult_gen.h noinst_HEADERS += src/ecmult_gen_impl.h noinst_HEADERS += src/num.h @@ -38,40 +40,72 @@ noinst_HEADERS += src/hash_impl.h noinst_HEADERS += src/field.h noinst_HEADERS += src/field_impl.h noinst_HEADERS += src/bench.h +noinst_HEADERS += contrib/lax_der_parsing.h +noinst_HEADERS += contrib/lax_der_parsing.c +noinst_HEADERS += contrib/lax_der_privatekey_parsing.h +noinst_HEADERS += contrib/lax_der_privatekey_parsing.c pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libsecp256k1.pc libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include $(SECP_INCLUDES) +libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) libsecp256k1_la_LIBADD = $(SECP_LIBS) noinst_PROGRAMS = if USE_BENCHMARK -noinst_PROGRAMS += bench_verify bench_recover bench_sign bench_internal +noinst_PROGRAMS += bench_verify bench_sign bench_internal bench_verify_SOURCES = src/bench_verify.c bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_verify_LDFLAGS = -static -bench_recover_SOURCES = src/bench_recover.c -bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_recover_LDFLAGS = -static bench_sign_SOURCES = src/bench_sign.c bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_sign_LDFLAGS = -static bench_internal_SOURCES = src/bench_internal.c bench_internal_LDADD = $(SECP_LIBS) -bench_internal_LDFLAGS = -static bench_internal_CPPFLAGS = $(SECP_INCLUDES) endif if USE_TESTS noinst_PROGRAMS += tests tests_SOURCES = src/tests.c -tests_CPPFLAGS = -DVERIFY $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) +tests_CPPFLAGS = -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) tests_LDFLAGS = -static TESTS = tests endif -EXTRA_DIST = autogen.sh +if USE_ECMULT_STATIC_PRECOMPUTATION +CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) +CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function + +gen_context_OBJECTS = gen_context.o +gen_context_BIN = gen_context$(BUILD_EXEEXT) +gen_%.o: src/gen_%.c + $(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@ + +$(gen_context_BIN): $(gen_context_OBJECTS) + $(CC_FOR_BUILD) $^ -o $@ + +$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h +$(tests_OBJECTS): src/ecmult_static_context.h +$(bench_internal_OBJECTS): src/ecmult_static_context.h + +src/ecmult_static_context.h: $(gen_context_BIN) + ./$(gen_context_BIN) + +CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h +endif + +EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h + +if ENABLE_MODULE_ECDH +include src/modules/ecdh/Makefile.am.include +endif + +if ENABLE_MODULE_SCHNORR +include src/modules/schnorr/Makefile.am.include +endif + +if ENABLE_MODULE_RECOVERY +include src/modules/recovery/Makefile.am.include +endif diff --git a/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 b/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 new file mode 100644 index 000000000..77fd346a7 --- /dev/null +++ b/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 @@ -0,0 +1,125 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_CC_FOR_BUILD +# +# DESCRIPTION +# +# This macro searches for a C compiler that generates native executables, +# that is a C compiler that surely is not a cross-compiler. This can be +# useful if you have to generate source code at compile-time like for +# example GCC does. +# +# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything +# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD). +# The value of these variables can be overridden by the user by specifying +# a compiler with an environment variable (like you do for standard CC). +# +# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object +# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if +# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are +# substituted in the Makefile. +# +# LICENSE +# +# Copyright (c) 2008 Paolo Bonzini +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD]) +AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_CPP])dnl +AC_REQUIRE([AC_EXEEXT])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl + +dnl Use the standard macros, but make them use other variable names +dnl +pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl +pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl +pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl +pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl +pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl +pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl +pushdef([ac_cv_objext], ac_cv_build_objext)dnl +pushdef([ac_exeext], ac_build_exeext)dnl +pushdef([ac_objext], ac_build_objext)dnl +pushdef([CC], CC_FOR_BUILD)dnl +pushdef([CPP], CPP_FOR_BUILD)dnl +pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl +pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl +pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl +pushdef([host], build)dnl +pushdef([host_alias], build_alias)dnl +pushdef([host_cpu], build_cpu)dnl +pushdef([host_vendor], build_vendor)dnl +pushdef([host_os], build_os)dnl +pushdef([ac_cv_host], ac_cv_build)dnl +pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl +pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl +pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl +pushdef([ac_cv_host_os], ac_cv_build_os)dnl +pushdef([ac_cpp], ac_build_cpp)dnl +pushdef([ac_compile], ac_build_compile)dnl +pushdef([ac_link], ac_build_link)dnl + +save_cross_compiling=$cross_compiling +save_ac_tool_prefix=$ac_tool_prefix +cross_compiling=no +ac_tool_prefix= + +AC_PROG_CC +AC_PROG_CPP +AC_EXEEXT + +ac_tool_prefix=$save_ac_tool_prefix +cross_compiling=$save_cross_compiling + +dnl Restore the old definitions +dnl +popdef([ac_link])dnl +popdef([ac_compile])dnl +popdef([ac_cpp])dnl +popdef([ac_cv_host_os])dnl +popdef([ac_cv_host_vendor])dnl +popdef([ac_cv_host_cpu])dnl +popdef([ac_cv_host_alias])dnl +popdef([ac_cv_host])dnl +popdef([host_os])dnl +popdef([host_vendor])dnl +popdef([host_cpu])dnl +popdef([host_alias])dnl +popdef([host])dnl +popdef([LDFLAGS])dnl +popdef([CPPFLAGS])dnl +popdef([CFLAGS])dnl +popdef([CPP])dnl +popdef([CC])dnl +popdef([ac_objext])dnl +popdef([ac_exeext])dnl +popdef([ac_cv_objext])dnl +popdef([ac_cv_exeext])dnl +popdef([ac_cv_prog_cc_g])dnl +popdef([ac_cv_prog_cc_cross])dnl +popdef([ac_cv_prog_cc_works])dnl +popdef([ac_cv_prog_gcc])dnl +popdef([ac_cv_prog_CPP])dnl + +dnl Finally, set Makefile variables +dnl +BUILD_EXEEXT=$ac_build_exeext +BUILD_OBJEXT=$ac_build_objext +AC_SUBST(BUILD_EXEEXT)dnl +AC_SUBST(BUILD_OBJEXT)dnl +AC_SUBST([CFLAGS_FOR_BUILD])dnl +AC_SUBST([CPPFLAGS_FOR_BUILD])dnl +AC_SUBST([LDFLAGS_FOR_BUILD])dnl +]) diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 index 4a398d6c9..d41bbb648 100644 --- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 +++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 @@ -16,8 +16,7 @@ AC_MSG_RESULT([$has_64bit_asm]) dnl AC_DEFUN([SECP_OPENSSL_CHECK],[ -if test x"$use_pkgconfig" = x"yes"; then - : #NOP + has_libcrypto=no m4_ifdef([PKG_CHECK_MODULES],[ PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no]) if test x"$has_libcrypto" = x"yes"; then @@ -27,11 +26,16 @@ if test x"$use_pkgconfig" = x"yes"; then LIBS="$TEMP_LIBS" fi ]) -else - AC_CHECK_HEADER(openssl/crypto.h,[AC_CHECK_LIB(crypto, main,[has_libcrypto=yes; CRYPTO_LIBS=-lcrypto; AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])] -)]) - LIBS= -fi + if test x$has_libcrypto = xno; then + AC_CHECK_HEADER(openssl/crypto.h,[ + AC_CHECK_LIB(crypto, main,[ + has_libcrypto=yes + CRYPTO_LIBS=-lcrypto + AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed]) + ]) + ]) + LIBS= + fi if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then AC_MSG_CHECKING(for EC functions in libcrypto) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac index 3dc182951..786d8dcfb 100644 --- a/src/secp256k1/configure.ac +++ b/src/secp256k1/configure.ac @@ -17,25 +17,19 @@ PKG_PROG_PKG_CONFIG AC_PATH_TOOL(AR, ar) AC_PATH_TOOL(RANLIB, ranlib) AC_PATH_TOOL(STRIP, strip) +AX_PROG_CC_FOR_BUILD if test "x$CFLAGS" = "x"; then CFLAGS="-O3 -g" fi +AM_PROG_CC_C_O + AC_PROG_CC_C89 if test x"$ac_cv_prog_cc_c89" = x"no"; then AC_MSG_ERROR([c89 compiler support required]) fi -case $host in - *mingw*) - use_pkgconfig=no - ;; - *) - use_pkgconfig=yes - ;; -esac - case $host_os in *darwin*) if test x$cross_compiling != xyes; then @@ -80,6 +74,14 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], CFLAGS="$saved_CFLAGS" ]) +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fvisibility=hidden" +AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) AC_ARG_ENABLE(benchmark, AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]), @@ -95,6 +97,26 @@ AC_ARG_ENABLE(endomorphism, AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]), [use_endomorphism=$enableval], [use_endomorphism=no]) + +AC_ARG_ENABLE(ecmult_static_precomputation, + AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]), + [use_ecmult_static_precomputation=$enableval], + [use_ecmult_static_precomputation=yes]) + +AC_ARG_ENABLE(module_ecdh, + AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (default is no)]), + [enable_module_ecdh=$enableval], + [enable_module_ecdh=no]) + +AC_ARG_ENABLE(module_schnorr, + AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (default is no)]), + [enable_module_schnorr=$enableval], + [enable_module_schnorr=no]) + +AC_ARG_ENABLE(module_recovery, + AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]), + [enable_module_recovery=$enableval], + [enable_module_recovery=no]) AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) @@ -305,6 +327,22 @@ if test x"$use_endomorphism" = x"yes"; then AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) fi +if test x"$use_ecmult_static_precomputation" = x"yes"; then + AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table]) +fi + +if test x"$enable_module_ecdh" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module]) +fi + +if test x"$enable_module_schnorr" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module]) +fi + +if test x"$enable_module_recovery" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) +fi + AC_C_BIGENDIAN() AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) @@ -312,6 +350,10 @@ AC_MSG_NOTICE([Using field implementation: $set_field]) AC_MSG_NOTICE([Using bignum implementation: $set_bignum]) AC_MSG_NOTICE([Using scalar implementation: $set_scalar]) AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism]) +AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) + +AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr]) +AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery]) AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) AC_CONFIG_FILES([Makefile libsecp256k1.pc]) @@ -321,6 +363,10 @@ AC_SUBST(SECP_TEST_LIBS) AC_SUBST(SECP_TEST_INCLUDES) AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) +AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_precomputation" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) dnl make sure nothing new is exported so that we don't break the cache PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" diff --git a/src/secp256k1/contrib/lax_der_parsing.c b/src/secp256k1/contrib/lax_der_parsing.c new file mode 100644 index 000000000..5b141a994 --- /dev/null +++ b/src/secp256k1/contrib/lax_der_parsing.c @@ -0,0 +1,150 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "lax_der_parsing.h" + +int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + size_t rpos, rlen, spos, slen; + size_t pos = 0; + size_t lenbyte; + unsigned char tmpsig[64] = {0}; + int overflow = 0; + + /* Hack to initialize sig with a correctly-parsed but invalid signature. */ + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + + /* Sequence tag byte */ + if (pos == inputlen || input[pos] != 0x30) { + return 0; + } + pos++; + + /* Sequence length bytes */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + pos += lenbyte; + } + + /* Integer tag byte for R */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for R */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + rlen = 0; + while (lenbyte > 0) { + rlen = (rlen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + rlen = lenbyte; + } + if (rlen > inputlen - pos) { + return 0; + } + rpos = pos; + pos += rlen; + + /* Integer tag byte for S */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for S */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + slen = 0; + while (lenbyte > 0) { + slen = (slen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + slen = lenbyte; + } + if (slen > inputlen - pos) { + return 0; + } + spos = pos; + pos += slen; + + /* Ignore leading zeroes in R */ + while (rlen > 0 && input[rpos] == 0) { + rlen--; + rpos++; + } + /* Copy R value */ + if (rlen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 32 - rlen, input + rpos, rlen); + } + + /* Ignore leading zeroes in S */ + while (slen > 0 && input[spos] == 0) { + slen--; + spos++; + } + /* Copy S value */ + if (slen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 64 - slen, input + spos, slen); + } + + if (!overflow) { + overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + if (overflow) { + memset(tmpsig, 0, 64); + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + return 1; +} + diff --git a/src/secp256k1/contrib/lax_der_parsing.h b/src/secp256k1/contrib/lax_der_parsing.h new file mode 100644 index 000000000..6d27871a7 --- /dev/null +++ b/src/secp256k1/contrib/lax_der_parsing.h @@ -0,0 +1,91 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/**** + * Please do not link this file directly. It is not part of the libsecp256k1 + * project and does not promise any stability in its API, functionality or + * presence. Projects which use this code should instead copy this header + * and its accompanying .c file directly into their codebase. + ****/ + +/* This file defines a function that parses DER with various errors and + * violations. This is not a part of the library itself, because the allowed + * violations are chosen arbitrarily and do not follow or establish any + * standard. + * + * In many places it matters that different implementations do not only accept + * the same set of valid signatures, but also reject the same set of signatures. + * The only means to accomplish that is by strictly obeying a standard, and not + * accepting anything else. + * + * Nonetheless, sometimes there is a need for compatibility with systems that + * use signatures which do not strictly obey DER. The snippet below shows how + * certain violations are easily supported. You may need to adapt it. + * + * Do not use this for new systems. Use well-defined DER or compact signatures + * instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and + * secp256k1_ecdsa_signature_parse_compact). + * + * The supported violations are: + * - All numbers are parsed as nonnegative integers, even though X.609-0207 + * section 8.3.3 specifies that integers are always encoded as two's + * complement. + * - Integers can have length 0, even though section 8.3.1 says they can't. + * - Integers with overly long padding are accepted, violation section + * 8.3.2. + * - 127-byte long length descriptors are accepted, even though section + * 8.1.3.5.c says that they are not. + * - Trailing garbage data inside or after the signature is ignored. + * - The length descriptor of the sequence is ignored. + * + * Compared to for example OpenSSL, many violations are NOT supported: + * - Using overly long tag descriptors for the sequence or integers inside, + * violating section 8.1.2.2. + * - Encoding primitive integers as constructed values, violating section + * 8.3.1. + */ + +#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ +#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ + +#include + +# ifdef __cplusplus +extern "C" { +# endif + +/** Parse a signature in "lax DER" format + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input: a pointer to the signature to be parsed + * inputlen: the length of the array pointed to be input + * + * This function will accept any valid DER encoded signature, even if the + * encoded numbers are out of range. In addition, it will accept signatures + * which violate the DER spec in various ways. Its purpose is to allow + * validation of the Bitcoin blockchain, which includes non-DER signatures + * from before the network rules were updated to enforce DER. Note that + * the set of supported violations is a strict subset of what OpenSSL will + * accept. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +int ecdsa_signature_parse_der_lax( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.c b/src/secp256k1/contrib/lax_der_privatekey_parsing.c new file mode 100644 index 000000000..c2e63b4b8 --- /dev/null +++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.c @@ -0,0 +1,113 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "lax_der_privatekey_parsing.h" + +int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) { + const unsigned char *end = privkey + privkeylen; + int lenb = 0; + int len = 0; + memset(out32, 0, 32); + /* sequence header */ + if (end < privkey+1 || *privkey != 0x30) { + return 0; + } + privkey++; + /* sequence length constructor */ + if (end < privkey+1 || !(*privkey & 0x80)) { + return 0; + } + lenb = *privkey & ~0x80; privkey++; + if (lenb < 1 || lenb > 2) { + return 0; + } + if (end < privkey+lenb) { + return 0; + } + /* sequence length */ + len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); + privkey += lenb; + if (end < privkey+len) { + return 0; + } + /* sequence element 0: version number (=1) */ + if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { + return 0; + } + privkey += 3; + /* sequence element 1: octet string, up to 32 bytes */ + if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { + return 0; + } + memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); + if (!secp256k1_ec_seckey_verify(ctx, out32)) { + memset(out32, 0, 32); + return 0; + } + return 1; +} + +int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { + secp256k1_pubkey pubkey; + size_t pubkeylen = 0; + if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { + *privkeylen = 0; + return 0; + } + if (compressed) { + static const unsigned char begin[] = { + 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,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,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 33; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } else { + static const unsigned char begin[] = { + 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,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,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, + 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, + 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 65; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } + return 1; +} diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.h b/src/secp256k1/contrib/lax_der_privatekey_parsing.h new file mode 100644 index 000000000..2fd088f8a --- /dev/null +++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.h @@ -0,0 +1,90 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/**** + * Please do not link this file directly. It is not part of the libsecp256k1 + * project and does not promise any stability in its API, functionality or + * presence. Projects which use this code should instead copy this header + * and its accompanying .c file directly into their codebase. + ****/ + +/* This file contains code snippets that parse DER private keys with + * various errors and violations. This is not a part of the library + * itself, because the allowed violations are chosen arbitrarily and + * do not follow or establish any standard. + * + * It also contains code to serialize private keys in a compatible + * manner. + * + * These functions are meant for compatibility with applications + * that require BER encoded keys. When working with secp256k1-specific + * code, the simple 32-byte private keys normally used by the + * library are sufficient. + */ + +#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ +#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ + +#include + +# ifdef __cplusplus +extern "C" { +# endif + +/** Export a private key in DER format. + * + * Returns: 1 if the private key was valid. + * Args: ctx: pointer to a context object, initialized for signing (cannot + * be NULL) + * Out: privkey: pointer to an array for storing the private key in BER. + * Should have space for 279 bytes, and cannot be NULL. + * privkeylen: Pointer to an int where the length of the private key in + * privkey will be stored. + * In: seckey: pointer to a 32-byte secret key to export. + * compressed: 1 if the key should be exported in + * compressed format, 0 otherwise + * + * This function is purely meant for compatibility with applications that + * require BER encoded keys. When working with secp256k1-specific code, the + * simple 32-byte private keys are sufficient. + * + * Note that this function does not guarantee correct DER output. It is + * guaranteed to be parsable by secp256k1_ec_privkey_import_der + */ +SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der( + const secp256k1_context* ctx, + unsigned char *privkey, + size_t *privkeylen, + const unsigned char *seckey, + int compressed +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Import a private key in DER format. + * Returns: 1 if a private key was extracted. + * Args: ctx: pointer to a context object (cannot be NULL). + * Out: seckey: pointer to a 32-byte array for storing the private key. + * (cannot be NULL). + * In: privkey: pointer to a private key in DER format (cannot be NULL). + * privkeylen: length of the DER private key pointed to be privkey. + * + * This function will accept more than just strict DER, and even allow some BER + * violations. The public key stored inside the DER-encoded private key is not + * verified for correctness, nor are the curve parameters. Use this function + * only if you know in advance it is supposed to contain a secp256k1 private + * key. + */ +SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *privkey, + size_t privkeylen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h index 06afd4c65..7145dbcc5 100644 --- a/src/secp256k1/include/secp256k1.h +++ b/src/secp256k1/include/secp256k1.h @@ -5,6 +5,99 @@ extern "C" { # endif +#include + +/* These rules specify the order of arguments in API calls: + * + * 1. Context pointers go first, followed by output arguments, combined + * output/input arguments, and finally input-only arguments. + * 2. Array lengths always immediately the follow the argument whose length + * they describe, even if this violates rule 1. + * 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated + * later go first. This means: signatures, public nonces, private nonces, + * messages, public keys, secret keys, tweaks. + * 4. Arguments that are not data pointers go last, from more complex to less + * complex: function pointers, algorithm names, messages, void pointers, + * counts, flags, booleans. + * 5. Opaque data pointers follow the function pointer they are to be passed to. + */ + +/** Opaque data structure that holds context information (precomputed tables etc.). + * + * The purpose of context structures is to cache large precomputed data tables + * that are expensive to construct, and also to maintain the randomization data + * for blinding. + * + * Do not create a new context object for each operation, as construction is + * far slower than all other API calls (~100 times slower than an ECDSA + * verification). + * + * A constructed context can safely be used from multiple threads + * simultaneously, but API call that take a non-const pointer to a context + * need exclusive access to it. In particular this is the case for + * secp256k1_context_destroy and secp256k1_context_randomize. + * + * Regarding randomization, either do it once at creation time (in which case + * you do not need any locking for the other calls), or use a read-write lock. + */ +typedef struct secp256k1_context_struct secp256k1_context; + +/** Opaque data structure that holds a parsed and valid public key. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage or transmission, use + * secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. + * + * Furthermore, it is guaranteed that identical public keys (ignoring + * compression) will have identical representation, so they can be memcmp'ed. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_pubkey; + +/** Opaque data structured that holds a parsed ECDSA signature. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage or transmission, use + * the secp256k1_ecdsa_signature_serialize_* and + * secp256k1_ecdsa_signature_serialize_* functions. + * + * Furthermore, it is guaranteed to identical signatures will have identical + * representation, so they can be memcmp'ed. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_ecdsa_signature; + +/** A pointer to a function to deterministically generate a nonce. + * + * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. + * Out: nonce32: pointer to a 32-byte array to be filled by the function. + * In: msg32: the 32-byte message hash being verified (will not be NULL) + * key32: pointer to a 32-byte secret key (will not be NULL) + * algo16: pointer to a 16-byte array describing the signature + * algorithm (will be NULL for ECDSA for compatibility). + * data: Arbitrary data pointer that is passed through. + * attempt: how many iterations we have tried to find a nonce. + * This will almost always be 0, but different attempt values + * are required to result in a different nonce. + * + * Except for test cases, this function should compute some cryptographic hash of + * the message, the algorithm, the key and the attempt. + */ +typedef int (*secp256k1_nonce_function)( + unsigned char *nonce32, + const unsigned char *msg32, + const unsigned char *key32, + const unsigned char *algo16, + void *data, + unsigned int attempt +); + # if !defined(SECP256K1_GNUC_PREREQ) # if defined(__GNUC__)&&defined(__GNUC_MINOR__) # define SECP256K1_GNUC_PREREQ(_maj,_min) \ @@ -26,6 +119,20 @@ extern "C" { # define SECP256K1_INLINE inline # endif +#ifndef SECP256K1_API +# if defined(_WIN32) +# ifdef SECP256K1_BUILD +# define SECP256K1_API __declspec(dllexport) +# else +# define SECP256K1_API +# endif +# elif defined(__GNUC__) && defined(SECP256K1_BUILD) +# define SECP256K1_API __attribute__ ((visibility ("default"))) +# else +# define SECP256K1_API +# endif +#endif + /**Warning attributes * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out * some paranoid null checks. */ @@ -40,305 +147,434 @@ extern "C" { # define SECP256K1_ARG_NONNULL(_x) # endif -/** Opaque data structure that holds context information (precomputed tables etc.). - * Only functions that take a pointer to a non-const context require exclusive - * access to it. Multiple functions that take a pointer to a const context may - * run simultaneously. - */ -typedef struct secp256k1_context_struct secp256k1_context_t; +/** All flags' lower 8 bits indicate what they're for. Do not use directly. */ +#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) +#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) +#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) +/** The higher bits contain the actual data. Do not use directly. */ +#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8) +#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) +#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) /** Flags to pass to secp256k1_context_create. */ -# define SECP256K1_CONTEXT_VERIFY (1 << 0) -# define SECP256K1_CONTEXT_SIGN (1 << 1) +#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) +#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) +#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) + +/** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */ +#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) +#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) /** Create a secp256k1 context object. + * * Returns: a newly created context object. * In: flags: which parts of the context to initialize. */ -secp256k1_context_t* secp256k1_context_create( - int flags +SECP256K1_API secp256k1_context* secp256k1_context_create( + unsigned int flags ) SECP256K1_WARN_UNUSED_RESULT; /** Copies a secp256k1 context object. + * * Returns: a newly created context object. - * In: ctx: an existing context to copy + * Args: ctx: an existing context to copy (cannot be NULL) */ -secp256k1_context_t* secp256k1_context_clone( - const secp256k1_context_t* ctx -) SECP256K1_WARN_UNUSED_RESULT; +SECP256K1_API secp256k1_context* secp256k1_context_clone( + const secp256k1_context* ctx +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; /** Destroy a secp256k1 context object. + * * The context pointer may not be used afterwards. + * Args: ctx: an existing context to destroy (cannot be NULL) */ -void secp256k1_context_destroy( - secp256k1_context_t* ctx +SECP256K1_API void secp256k1_context_destroy( + secp256k1_context* ctx +); + +/** Set a callback function to be called when an illegal argument is passed to + * an API call. It will only trigger for violations that are mentioned + * explicitly in the header. + * + * The philosophy is that these shouldn't be dealt with through a + * specific return value, as calling code should not have branches to deal with + * the case that this code itself is broken. + * + * On the other hand, during debug stage, one would want to be informed about + * such mistakes, and the default (crashing) may be inadvisable. + * When this callback is triggered, the API function called is guaranteed not + * to cause a crash, though its return value and output arguments are + * undefined. + * + * Args: ctx: an existing context object (cannot be NULL) + * In: fun: a pointer to a function to call when an illegal argument is + * passed to the API, taking a message and an opaque pointer + * (NULL restores a default handler that calls abort). + * data: the opaque pointer to pass to fun above. + */ +SECP256K1_API void secp256k1_context_set_illegal_callback( + secp256k1_context* ctx, + void (*fun)(const char* message, void* data), + const void* data ) SECP256K1_ARG_NONNULL(1); -/** Verify an ECDSA signature. - * Returns: 1: correct signature - * 0: incorrect signature - * -1: invalid public key - * -2: invalid signature - * In: ctx: a secp256k1 context object, initialized for verification. - * msg32: the 32-byte message hash being verified (cannot be NULL) - * sig: the signature being verified (cannot be NULL) - * siglen: the length of the signature - * pubkey: the public key to verify with (cannot be NULL) - * pubkeylen: the length of pubkey +/** Set a callback function to be called when an internal consistency check + * fails. The default is crashing. + * + * This can only trigger in case of a hardware failure, miscompilation, + * memory corruption, serious bug in the library, or other error would can + * otherwise result in undefined behaviour. It will not trigger due to mere + * incorrect usage of the API (see secp256k1_context_set_illegal_callback + * for that). After this callback returns, anything may happen, including + * crashing. + * + * Args: ctx: an existing context object (cannot be NULL) + * In: fun: a pointer to a function to call when an internal error occurs, + * taking a message and an opaque pointer (NULL restores a default + * handler that calls abort). + * data: the opaque pointer to pass to fun above. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( - const secp256k1_context_t* ctx, - const unsigned char *msg32, - const unsigned char *sig, - int siglen, - const unsigned char *pubkey, - int pubkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); +SECP256K1_API void secp256k1_context_set_error_callback( + secp256k1_context* ctx, + void (*fun)(const char* message, void* data), + const void* data +) SECP256K1_ARG_NONNULL(1); -/** A pointer to a function to deterministically generate a nonce. - * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. - * In: msg32: the 32-byte message hash being verified (will not be NULL) - * key32: pointer to a 32-byte secret key (will not be NULL) - * attempt: how many iterations we have tried to find a nonce. - * This will almost always be 0, but different attempt values - * are required to result in a different nonce. - * data: Arbitrary data pointer that is passed through. - * Out: nonce32: pointer to a 32-byte array to be filled by the function. - * Except for test cases, this function should compute some cryptographic hash of - * the message, the key and the attempt. +/** Parse a variable-length public key into the pubkey object. + * + * Returns: 1 if the public key was fully valid. + * 0 if the public key could not be parsed or is invalid. + * Args: ctx: a secp256k1 context object. + * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a + * parsed version of input. If not, its value is undefined. + * In: input: pointer to a serialized public key + * inputlen: length of the array pointed to by input + * + * This function supports parsing compressed (33 bytes, header byte 0x02 or + * 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header + * byte 0x06 or 0x07) format public keys. */ -typedef int (*secp256k1_nonce_function_t)( - unsigned char *nonce32, - const unsigned char *msg32, - const unsigned char *key32, - unsigned int attempt, - const void *data -); +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse( + const secp256k1_context* ctx, + secp256k1_pubkey* pubkey, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a pubkey object into a serialized byte sequence. + * + * Returns: 1 always. + * Args: ctx: a secp256k1 context object. + * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if + * compressed==1) byte array to place the serialized key + * in. + * In/Out: outputlen: a pointer to an integer which is initially set to the + * size of output, and is overwritten with the written + * size. + * In: pubkey: a pointer to a secp256k1_pubkey containing an + * initialized public key. + * flags: SECP256K1_EC_COMPRESSED if serialization should be in + * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED. + */ +SECP256K1_API int secp256k1_ec_pubkey_serialize( + const secp256k1_context* ctx, + unsigned char *output, + size_t *outputlen, + const secp256k1_pubkey* pubkey, + unsigned int flags +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Parse an ECDSA signature in compact (64 bytes) format. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input64: a pointer to the 64-byte array to parse + * + * The signature must consist of a 32-byte big endian R value, followed by a + * 32-byte big endian S value. If R or S fall outside of [0..order-1], the + * encoding is invalid. R and S with value 0 are allowed in the encoding. + * + * After the call, sig will always be initialized. If parsing failed or R or + * S are zero, the resulting sig value is guaranteed to fail validation for any + * message and public key. + */ +SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse a DER ECDSA signature. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input: a pointer to the signature to be parsed + * inputlen: the length of the array pointed to be input + * + * This function will accept any valid DER encoded signature, even if the + * encoded numbers are out of range. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +SECP256K1_API int secp256k1_ecdsa_signature_parse_der( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in DER format. + * + * Returns: 1 if enough space was available to serialize, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: output: a pointer to an array to store the DER serialization + * In/Out: outputlen: a pointer to a length integer. Initially, this integer + * should be set to the length of output. After the call + * it will be set to the length of the serialization (even + * if 0 was returned). + * In: sig: a pointer to an initialized signature object + */ +SECP256K1_API int secp256k1_ecdsa_signature_serialize_der( + const secp256k1_context* ctx, + unsigned char *output, + size_t *outputlen, + const secp256k1_ecdsa_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Serialize an ECDSA signature in compact (64 byte) format. + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: output64: a pointer to a 64-byte array to store the compact serialization + * In: sig: a pointer to an initialized signature object + * + * See secp256k1_ecdsa_signature_parse_compact for details about the encoding. + */ +SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( + const secp256k1_context* ctx, + unsigned char *output64, + const secp256k1_ecdsa_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Verify an ECDSA signature. + * + * Returns: 1: correct signature + * 0: incorrect or unparseable signature + * Args: ctx: a secp256k1 context object, initialized for verification. + * In: sig: the signature being verified (cannot be NULL) + * msg32: the 32-byte message hash being verified (cannot be NULL) + * pubkey: pointer to an initialized public key to verify with (cannot be NULL) + * + * To avoid accepting malleable signatures, only ECDSA signatures in lower-S + * form are accepted. + * + * If you need to accept ECDSA signatures from sources that do not obey this + * rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to + * validation, but be aware that doing so results in malleable signatures. + * + * For details, see the comments for that function. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( + const secp256k1_context* ctx, + const secp256k1_ecdsa_signature *sig, + const unsigned char *msg32, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Convert a signature to a normalized lower-S form. + * + * Returns: 1 if sigin was not normalized, 0 if it already was. + * Args: ctx: a secp256k1 context object + * Out: sigout: a pointer to a signature to fill with the normalized form, + * or copy if the input was already normalized. (can be NULL if + * you're only interested in whether the input was already + * normalized). + * In: sigin: a pointer to a signature to check/normalize (cannot be NULL, + * can be identical to sigout) + * + * With ECDSA a third-party can forge a second distinct signature of the same + * message, given a single initial signature, but without knowing the key. This + * is done by negating the S value modulo the order of the curve, 'flipping' + * the sign of the random point R which is not included in the signature. + * + * Forgery of the same message isn't universally problematic, but in systems + * where message malleability or uniqueness of signatures is important this can + * cause issues. This forgery can be blocked by all verifiers forcing signers + * to use a normalized form. + * + * The lower-S form reduces the size of signatures slightly on average when + * variable length encodings (such as DER) are used and is cheap to verify, + * making it a good choice. Security of always using lower-S is assured because + * anyone can trivially modify a signature after the fact to enforce this + * property anyway. + * + * The lower S value is always between 0x1 and + * 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, + * inclusive. + * + * No other forms of ECDSA malleability are known and none seem likely, but + * there is no formal proof that ECDSA, even with this additional restriction, + * is free of other malleability. Commonly used serialization schemes will also + * accept various non-unique encodings, so care should be taken when this + * property is required for an application. + * + * The secp256k1_ecdsa_sign function will by default create signatures in the + * lower-S form, and secp256k1_ecdsa_verify will not accept others. In case + * signatures come from a system that cannot enforce this property, + * secp256k1_ecdsa_signature_normalize must be called before verification. + */ +SECP256K1_API int secp256k1_ecdsa_signature_normalize( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature *sigout, + const secp256k1_ecdsa_signature *sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); /** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of * extra entropy. */ -extern const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979; +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; /** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ -extern const secp256k1_nonce_function_t secp256k1_nonce_function_default; - +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default; /** Create an ECDSA signature. - * Returns: 1: signature created - * 0: the nonce generation function failed, the private key was invalid, or there is not - * enough space in the signature (as indicated by siglen). - * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * msg32: the 32-byte message hash being signed (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) - * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used - * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) - * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) - * In/Out: siglen: pointer to an int with the length of sig, which will be updated - * to contain the actual signature length (<=72). * - * The sig always has an s value in the lower half of the range (From 0x1 - * to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, - * inclusive), unlike many other implementations. - * With ECDSA a third-party can can forge a second distinct signature - * of the same message given a single initial signature without knowing - * the key by setting s to its additive inverse mod-order, 'flipping' the - * sign of the random point R which is not included in the signature. - * Since the forgery is of the same message this isn't universally - * problematic, but in systems where message malleability or uniqueness - * of signatures is important this can cause issues. This forgery can be - * blocked by all verifiers forcing signers to use a canonical form. The - * lower-S form reduces the size of signatures slightly on average when - * variable length encodings (such as DER) are used and is cheap to - * verify, making it a good choice. Security of always using lower-S is - * assured because anyone can trivially modify a signature after the - * fact to enforce this property. Adjusting it inside the signing - * function avoids the need to re-serialize or have curve specific - * constants outside of the library. By always using a canonical form - * even in applications where it isn't needed it becomes possible to - * impose a requirement later if a need is discovered. - * No other forms of ECDSA malleability are known and none seem likely, - * but there is no formal proof that ECDSA, even with this additional - * restriction, is free of other malleability. Commonly used serialization - * schemes will also accept various non-unique encodings, so care should - * be taken when this property is required for an application. - */ -int secp256k1_ecdsa_sign( - const secp256k1_context_t* ctx, - const unsigned char *msg32, - unsigned char *sig, - int *siglen, - const unsigned char *seckey, - secp256k1_nonce_function_t noncefp, - const void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Create a compact ECDSA signature (64 byte + recovery id). * Returns: 1: signature created - * 0: the nonce generation function failed, or the secret key was invalid. - * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * msg32: the 32-byte message hash being signed (cannot be NULL) + * 0: the nonce generation function failed, or the private key was invalid. + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) + * In: msg32: the 32-byte message hash being signed (cannot be NULL) * seckey: pointer to a 32-byte secret key (cannot be NULL) * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) - * Out: sig: pointer to a 64-byte array where the signature will be placed (cannot be NULL) - * In case 0 is returned, the returned signature length will be zero. - * recid: pointer to an int, which will be updated to contain the recovery id (can be NULL) + * + * The created signature is always in lower-S form. See + * secp256k1_ecdsa_signature_normalize for more details. */ -int secp256k1_ecdsa_sign_compact( - const secp256k1_context_t* ctx, - const unsigned char *msg32, - unsigned char *sig64, - const unsigned char *seckey, - secp256k1_nonce_function_t noncefp, - const void *ndata, - int *recid +SECP256K1_API int secp256k1_ecdsa_sign( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature *sig, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + const void *ndata ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -/** Recover an ECDSA public key from a compact signature. - * Returns: 1: public key successfully recovered (which guarantees a correct signature). - * 0: otherwise. - * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) - * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) - * sig64: signature as 64 byte array (cannot be NULL) - * compressed: whether to recover a compressed or uncompressed pubkey - * recid: the recovery id (0-3, as returned by ecdsa_sign_compact) - * Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey (cannot be NULL) - * pubkeylen: pointer to an int that will contain the pubkey length (cannot be NULL) - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact( - const secp256k1_context_t* ctx, - const unsigned char *msg32, - const unsigned char *sig64, - unsigned char *pubkey, - int *pubkeylen, - int compressed, - int recid -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - /** Verify an ECDSA secret key. + * * Returns: 1: secret key is valid * 0: secret key is invalid - * In: ctx: pointer to a context object (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) + * Args: ctx: pointer to a context object (cannot be NULL) + * In: seckey: pointer to a 32-byte secret key (cannot be NULL) */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( - const secp256k1_context_t* ctx, - const unsigned char *seckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Just validate a public key. - * Returns: 1: public key is valid - * 0: public key is invalid - * In: ctx: pointer to a context object (cannot be NULL) - * pubkey: pointer to a 33-byte or 65-byte public key (cannot be NULL). - * pubkeylen: length of pubkey - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_verify( - const secp256k1_context_t* ctx, - const unsigned char *pubkey, - int pubkeylen +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( + const secp256k1_context* ctx, + const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); /** Compute the public key for a secret key. - * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * compressed: whether the computed public key should be compressed - * seckey: pointer to a 32-byte private key (cannot be NULL) - * Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed) - * area to store the public key (cannot be NULL) - * pubkeylen: pointer to int that will be updated to contains the pubkey's - * length (cannot be NULL) + * * Returns: 1: secret was valid, public key stores * 0: secret was invalid, try again + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: pubkey: pointer to the created public key (cannot be NULL) + * In: seckey: pointer to a 32-byte private key (cannot be NULL) */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( - const secp256k1_context_t* ctx, - unsigned char *pubkey, - int *pubkeylen, - const unsigned char *seckey, - int compressed -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Decompress a public key. - * In: ctx: pointer to a context object (cannot be NULL) - * In/Out: pubkey: pointer to a 65-byte array to put the decompressed public key. - * It must contain a 33-byte or 65-byte public key already (cannot be NULL) - * pubkeylen: pointer to the size of the public key pointed to by pubkey (cannot be NULL) - * It will be updated to reflect the new size. - * Returns: 0: pubkey was invalid - * 1: pubkey was valid, and was replaced with its decompressed version - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_decompress( - const secp256k1_context_t* ctx, - unsigned char *pubkey, - int *pubkeylen +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Export a private key in DER format. - * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) +/** Tweak a private key by adding tweak to it. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or if the resulting private key + * would be invalid (only when the tweak is the complement of the + * private key). 1 otherwise. + * Args: ctx: pointer to a context object (cannot be NULL). + * In/Out: seckey: pointer to a 32-byte private key. + * In: tweak: pointer to a 32-byte tweak. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export( - const secp256k1_context_t* ctx, - const unsigned char *seckey, - unsigned char *privkey, - int *privkeylen, - int compressed -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Import a private key in DER format. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_import( - const secp256k1_context_t* ctx, - unsigned char *seckey, - const unsigned char *privkey, - int privkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Tweak a private key by adding tweak to it. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( - const secp256k1_context_t* ctx, - unsigned char *seckey, - const unsigned char *tweak +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *tweak ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Tweak a public key by adding tweak times the generator to it. - * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or if the resulting public key + * would be invalid (only when the tweak is the complement of the + * corresponding private key). 1 otherwise. + * Args: ctx: pointer to a context object initialized for validation + * (cannot be NULL). + * In/Out: pubkey: pointer to a public key object. + * In: tweak: pointer to a 32-byte tweak. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( - const secp256k1_context_t* ctx, - unsigned char *pubkey, - int pubkeylen, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); - -/** Tweak a private key by multiplying it with tweak. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( - const secp256k1_context_t* ctx, - unsigned char *seckey, - const unsigned char *tweak +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *tweak ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Tweak a public key by multiplying it with tweak. - * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) +/** Tweak a private key by multiplying it by a tweak. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. + * Args: ctx: pointer to a context object (cannot be NULL). + * In/Out: seckey: pointer to a 32-byte private key. + * In: tweak: pointer to a 32-byte tweak. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( - const secp256k1_context_t* ctx, - unsigned char *pubkey, - int pubkeylen, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak a public key by multiplying it by a tweak value. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. + * Args: ctx: pointer to a context object initialized for validation + * (cannot be NULL). + * In/Out: pubkey: pointer to a public key obkect. + * In: tweak: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Updates the context randomization. * Returns: 1: randomization successfully updated * 0: error - * In: ctx: pointer to a context object (cannot be NULL) - * seed32: pointer to a 32-byte random seed (NULL resets to initial state) + * Args: ctx: pointer to a context object (cannot be NULL) + * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( - secp256k1_context_t* ctx, - const unsigned char *seed32 +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( + secp256k1_context* ctx, + const unsigned char *seed32 ) SECP256K1_ARG_NONNULL(1); +/** Add a number of public keys together. + * Returns: 1: the sum of the public keys is valid. + * 0: the sum of the public keys is not valid. + * Args: ctx: pointer to a context object + * Out: out: pointer to a public key object for placing the resulting public key + * (cannot be NULL) + * In: ins: pointer to array of pointers to public keys (cannot be NULL) + * n: the number of public keys to add together (must be at least 1) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( + const secp256k1_context* ctx, + secp256k1_pubkey *out, + const secp256k1_pubkey * const * ins, + size_t n +) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); # ifdef __cplusplus } diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h new file mode 100644 index 000000000..4b84d7a96 --- /dev/null +++ b/src/secp256k1/include/secp256k1_ecdh.h @@ -0,0 +1,31 @@ +#ifndef _SECP256K1_ECDH_ +# define _SECP256K1_ECDH_ + +# include "secp256k1.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/** Compute an EC Diffie-Hellman secret in constant time + * Returns: 1: exponentiation was successful + * 0: scalar was invalid (zero or overflow) + * Args: ctx: pointer to a context object (cannot be NULL) + * Out: result: a 32-byte array which will be populated by an ECDH + * secret computed from the point and scalar + * In: pubkey: a pointer to a secp256k1_pubkey containing an + * initialized public key + * privkey: a 32-byte scalar with which to multiply the point + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( + const secp256k1_context* ctx, + unsigned char *result, + const secp256k1_pubkey *pubkey, + const unsigned char *privkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h new file mode 100644 index 000000000..055379725 --- /dev/null +++ b/src/secp256k1/include/secp256k1_recovery.h @@ -0,0 +1,110 @@ +#ifndef _SECP256K1_RECOVERY_ +# define _SECP256K1_RECOVERY_ + +# include "secp256k1.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/** Opaque data structured that holds a parsed ECDSA signature, + * supporting pubkey recovery. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 65 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage or transmission, use + * the secp256k1_ecdsa_signature_serialize_* and + * secp256k1_ecdsa_signature_parse_* functions. + * + * Furthermore, it is guaranteed that identical signatures (including their + * recoverability) will have identical representation, so they can be + * memcmp'ed. + */ +typedef struct { + unsigned char data[65]; +} secp256k1_ecdsa_recoverable_signature; + +/** Parse a compact ECDSA signature (64 bytes + recovery id). + * + * Returns: 1 when the signature could be parsed, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input64: a pointer to a 64-byte compact signature + * recid: the recovery id (0, 1, 2 or 3) + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact( + const secp256k1_context* ctx, + secp256k1_ecdsa_recoverable_signature* sig, + const unsigned char *input64, + int recid +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Convert a recoverable signature into a normal signature. + * + * Returns: 1 + * Out: sig: a pointer to a normal signature (cannot be NULL). + * In: sigin: a pointer to a recoverable signature (cannot be NULL). + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const secp256k1_ecdsa_recoverable_signature* sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in compact format (64 bytes + recovery id). + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL) + * recid: a pointer to an integer to hold the recovery id (can be NULL). + * In: sig: a pointer to an initialized signature object (cannot be NULL) + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( + const secp256k1_context* ctx, + unsigned char *output64, + int *recid, + const secp256k1_ecdsa_recoverable_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Create a recoverable ECDSA signature. + * + * Returns: 1: signature created + * 0: the nonce generation function failed, or the private key was invalid. + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) + * In: msg32: the 32-byte message hash being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + */ +SECP256K1_API int secp256k1_ecdsa_sign_recoverable( + const secp256k1_context* ctx, + secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Recover an ECDSA public key from a signature. + * + * Returns: 1: public key successfully recovered (which guarantees a correct signature). + * 0: otherwise. + * Args: ctx: pointer to a context object, initialized for verification (cannot be NULL) + * Out: pubkey: pointer to the recovered public key (cannot be NULL) + * In: sig: pointer to initialized signature that supports pubkey recovery (cannot be NULL) + * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *msg32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/secp256k1/include/secp256k1_schnorr.h b/src/secp256k1/include/secp256k1_schnorr.h new file mode 100644 index 000000000..dc32fec1e --- /dev/null +++ b/src/secp256k1/include/secp256k1_schnorr.h @@ -0,0 +1,173 @@ +#ifndef _SECP256K1_SCHNORR_ +# define _SECP256K1_SCHNORR_ + +# include "secp256k1.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/** Create a signature using a custom EC-Schnorr-SHA256 construction. It + * produces non-malleable 64-byte signatures which support public key recovery + * batch validation, and multiparty signing. + * Returns: 1: signature created + * 0: the nonce generation function failed, or the private key was + * invalid. + * Args: ctx: pointer to a context object, initialized for signing + * (cannot be NULL) + * Out: sig64: pointer to a 64-byte array where the signature will be + * placed (cannot be NULL) + * In: msg32: the 32-byte message hash being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp:pointer to a nonce generation function. If NULL, + * secp256k1_nonce_function_default is used + * ndata: pointer to arbitrary data used by the nonce generation + * function (can be NULL) + */ +SECP256K1_API int secp256k1_schnorr_sign( + const secp256k1_context* ctx, + unsigned char *sig64, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Verify a signature created by secp256k1_schnorr_sign. + * Returns: 1: correct signature + * 0: incorrect signature + * Args: ctx: a secp256k1 context object, initialized for verification. + * In: sig64: the 64-byte signature being verified (cannot be NULL) + * msg32: the 32-byte message hash being verified (cannot be NULL) + * pubkey: the public key to verify with (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify( + const secp256k1_context* ctx, + const unsigned char *sig64, + const unsigned char *msg32, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Recover an EC public key from a Schnorr signature created using + * secp256k1_schnorr_sign. + * Returns: 1: public key successfully recovered (which guarantees a correct + * signature). + * 0: otherwise. + * Args: ctx: pointer to a context object, initialized for + * verification (cannot be NULL) + * Out: pubkey: pointer to a pubkey to set to the recovered public key + * (cannot be NULL). + * In: sig64: signature as 64 byte array (cannot be NULL) + * msg32: the 32-byte message hash assumed to be signed (cannot + * be NULL) + */ +SECP256K1_API int secp256k1_schnorr_recover( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *sig64, + const unsigned char *msg32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Generate a nonce pair deterministically for use with + * secp256k1_schnorr_partial_sign. + * Returns: 1: valid nonce pair was generated. + * 0: otherwise (nonce generation function failed) + * Args: ctx: pointer to a context object, initialized for signing + * (cannot be NULL) + * Out: pubnonce: public side of the nonce (cannot be NULL) + * privnonce32: private side of the nonce (32 byte) (cannot be NULL) + * In: msg32: the 32-byte message hash assumed to be signed (cannot + * be NULL) + * sec32: the 32-byte private key (cannot be NULL) + * noncefp: pointer to a nonce generation function. If NULL, + * secp256k1_nonce_function_default is used + * noncedata: pointer to arbitrary data used by the nonce generation + * function (can be NULL) + * + * Do not use the output as a private/public key pair for signing/validation. + */ +SECP256K1_API int secp256k1_schnorr_generate_nonce_pair( + const secp256k1_context* ctx, + secp256k1_pubkey *pubnonce, + unsigned char *privnonce32, + const unsigned char *msg32, + const unsigned char *sec32, + secp256k1_nonce_function noncefp, + const void* noncedata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Produce a partial Schnorr signature, which can be combined using + * secp256k1_schnorr_partial_combine, to end up with a full signature that is + * verifiable using secp256k1_schnorr_verify. + * Returns: 1: signature created successfully. + * 0: no valid signature exists with this combination of keys, nonces + * and message (chance around 1 in 2^128) + * -1: invalid private key, nonce, or public nonces. + * Args: ctx: pointer to context object, initialized for signing (cannot + * be NULL) + * Out: sig64: pointer to 64-byte array to put partial signature in + * In: msg32: pointer to 32-byte message to sign + * sec32: pointer to 32-byte private key + * pubnonce_others: pointer to pubkey containing the sum of the other's + * nonces (see secp256k1_ec_pubkey_combine) + * secnonce32: pointer to 32-byte array containing our nonce + * + * The intended procedure for creating a multiparty signature is: + * - Each signer S[i] with private key x[i] and public key Q[i] runs + * secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of + * private/public nonces. + * - All signers communicate their public nonces to each other (revealing your + * private nonce can lead to discovery of your private key, so it should be + * considered secret). + * - All signers combine all the public nonces they received (excluding their + * own) using secp256k1_ec_pubkey_combine to obtain an + * Rall[i] = sum(R[0..i-1,i+1..n]). + * - All signers produce a partial signature using + * secp256k1_schnorr_partial_sign, passing in their own private key x[i], + * their own private nonce k[i], and the sum of the others' public nonces + * Rall[i]. + * - All signers communicate their partial signatures to each other. + * - Someone combines all partial signatures using + * secp256k1_schnorr_partial_combine, to obtain a full signature. + * - The resulting signature is validatable using secp256k1_schnorr_verify, with + * public key equal to the result of secp256k1_ec_pubkey_combine of the + * signers' public keys (sum(Q[0..n])). + * + * Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine + * function take their arguments in any order, and it is possible to + * pre-combine several inputs already with one call, and add more inputs later + * by calling the function again (they are commutative and associative). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign( + const secp256k1_context* ctx, + unsigned char *sig64, + const unsigned char *msg32, + const unsigned char *sec32, + const secp256k1_pubkey *pubnonce_others, + const unsigned char *secnonce32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); + +/** Combine multiple Schnorr partial signatures. + * Returns: 1: the passed signatures were successfully combined. + * 0: the resulting signature is not valid (chance of 1 in 2^256) + * -1: some inputs were invalid, or the signatures were not created + * using the same set of nonces + * Args: ctx: pointer to a context object + * Out: sig64: pointer to a 64-byte array to place the combined signature + * (cannot be NULL) + * In: sig64sin: pointer to an array of n pointers to 64-byte input + * signatures + * n: the number of signatures to combine (at least 1) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine( + const secp256k1_context* ctx, + unsigned char *sig64, + const unsigned char * const * sig64sin, + size_t n +) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h new file mode 100644 index 000000000..c4c16eb7c --- /dev/null +++ b/src/secp256k1/src/basic-config.h @@ -0,0 +1,32 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_BASIC_CONFIG_ +#define _SECP256K1_BASIC_CONFIG_ + +#ifdef USE_BASIC_CONFIG + +#undef USE_ASM_X86_64 +#undef USE_ENDOMORPHISM +#undef USE_FIELD_10X26 +#undef USE_FIELD_5X52 +#undef USE_FIELD_INV_BUILTIN +#undef USE_FIELD_INV_NUM +#undef USE_NUM_GMP +#undef USE_NUM_NONE +#undef USE_SCALAR_4X64 +#undef USE_SCALAR_8X32 +#undef USE_SCALAR_INV_BUILTIN +#undef USE_SCALAR_INV_NUM + +#define USE_NUM_NONE 1 +#define USE_FIELD_INV_BUILTIN 1 +#define USE_SCALAR_INV_BUILTIN 1 +#define USE_FIELD_10X26 1 +#define USE_SCALAR_8X32 1 + +#endif // USE_BASIC_CONFIG +#endif // _SECP256K1_BASIC_CONFIG_ diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h index db5f68cee..3a71b4aaf 100644 --- a/src/secp256k1/src/bench.h +++ b/src/secp256k1/src/bench.h @@ -20,7 +20,9 @@ static double gettimedouble(void) { void print_number(double x) { double y = x; int c = 0; - if (y < 0.0) y = -y; + if (y < 0.0) { + y = -y; + } while (y < 100.0) { y *= 10.0; c++; @@ -35,13 +37,21 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v double max = 0.0; for (i = 0; i < count; i++) { double begin, total; - if (setup) setup(data); + if (setup != NULL) { + setup(data); + } begin = gettimedouble(); benchmark(data); total = gettimedouble() - begin; - if (teardown) teardown(data); - if (total < min) min = total; - if (total > max) max = total; + if (teardown != NULL) { + teardown(data); + } + if (total < min) { + min = total; + } + if (total > max) { + max = total; + } sum += total; } printf("%s: min ", name); diff --git a/src/secp256k1/src/bench_ecdh.c b/src/secp256k1/src/bench_ecdh.c new file mode 100644 index 000000000..5a7c6376e --- /dev/null +++ b/src/secp256k1/src/bench_ecdh.c @@ -0,0 +1,53 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include + +#include "include/secp256k1.h" +#include "include/secp256k1_ecdh.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_context *ctx; + secp256k1_pubkey point; + unsigned char scalar[32]; +} bench_ecdh_t; + +static void bench_ecdh_setup(void* arg) { + int i; + bench_ecdh_t *data = (bench_ecdh_t*)arg; + const unsigned char point[] = { + 0x03, + 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, + 0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd, + 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb, + 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f + }; + + data->ctx = secp256k1_context_create(0); + for (i = 0; i < 32; i++) { + data->scalar[i] = i + 1; + } + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); +} + +static void bench_ecdh(void* arg) { + int i; + unsigned char res[32]; + bench_ecdh_t *data = (bench_ecdh_t*)arg; + + for (i = 0; i < 20000; i++) { + CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1); + } +} + +int main(void) { + bench_ecdh_t data; + + run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000); + return 0; +} diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c index a960549b9..7809f5f8c 100644 --- a/src/secp256k1/src/bench_internal.c +++ b/src/secp256k1/src/bench_internal.c @@ -13,15 +13,17 @@ #include "field_impl.h" #include "group_impl.h" #include "scalar_impl.h" +#include "ecmult_const_impl.h" #include "ecmult_impl.h" #include "bench.h" +#include "secp256k1.c" typedef struct { - secp256k1_scalar_t scalar_x, scalar_y; - secp256k1_fe_t fe_x, fe_y; - secp256k1_ge_t ge_x, ge_y; - secp256k1_gej_t gej_x, gej_y; - unsigned char data[32]; + secp256k1_scalar scalar_x, scalar_y; + secp256k1_fe fe_x, fe_y; + secp256k1_ge ge_x, ge_y; + secp256k1_gej gej_x, gej_y; + unsigned char data[64]; int wnaf[256]; } bench_inv_t; @@ -51,6 +53,7 @@ void bench_setup(void* arg) { secp256k1_gej_set_ge(&data->gej_x, &data->ge_x); secp256k1_gej_set_ge(&data->gej_y, &data->ge_y); memcpy(data->data, init_x, 32); + memcpy(data->data + 32, init_y, 32); } void bench_scalar_add(void* arg) { @@ -95,8 +98,8 @@ void bench_scalar_split(void* arg) { bench_inv_t *data = (bench_inv_t*)arg; for (i = 0; i < 20000; i++) { - secp256k1_scalar_t l, r; - secp256k1_scalar_split_lambda_var(&l, &r, &data->scalar_x); + secp256k1_scalar l, r; + secp256k1_scalar_split_lambda(&l, &r, &data->scalar_x); secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); } } @@ -193,7 +196,7 @@ void bench_group_double_var(void* arg) { bench_inv_t *data = (bench_inv_t*)arg; for (i = 0; i < 200000; i++) { - secp256k1_gej_double_var(&data->gej_x, &data->gej_x); + secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL); } } @@ -202,7 +205,7 @@ void bench_group_add_var(void* arg) { bench_inv_t *data = (bench_inv_t*)arg; for (i = 0; i < 200000; i++) { - secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y); + secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL); } } @@ -220,7 +223,7 @@ void bench_group_add_affine_var(void* arg) { bench_inv_t *data = (bench_inv_t*)arg; for (i = 0; i < 200000; i++) { - secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y); + secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL); } } @@ -229,7 +232,17 @@ void bench_ecmult_wnaf(void* arg) { bench_inv_t *data = (bench_inv_t*)arg; for (i = 0; i < 20000; i++) { - secp256k1_ecmult_wnaf(data->wnaf, &data->scalar_x, WINDOW_A); + secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_wnaf_const(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A); secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); } } @@ -265,11 +278,27 @@ void bench_rfc6979_hmac_sha256(void* arg) { secp256k1_rfc6979_hmac_sha256_t rng; for (i = 0; i < 20000; i++) { - secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 32, data->data, 32, NULL, 0); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32); } } +void bench_context_verify(void* arg) { + int i; + (void)arg; + for (i = 0; i < 20; i++) { + secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY)); + } +} + +void bench_context_sign(void* arg) { + int i; + (void)arg; + for (i = 0; i < 200; i++) { + secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN)); + } +} + int have_flag(int argc, char** argv, char *flag) { char** argm = argv + argc; @@ -278,7 +307,9 @@ int have_flag(int argc, char** argv, char *flag) { return 1; } while (argv != NULL && argv != argm) { - if (strcmp(*argv, flag) == 0) return 1; + if (strcmp(*argv, flag) == 0) { + return 1; + } argv++; } return 0; @@ -309,10 +340,15 @@ int main(int argc, char **argv) { 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); 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); + if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000); 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); 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); + + if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20); + if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200); + return 0; } diff --git a/src/secp256k1/src/bench_recover.c b/src/secp256k1/src/bench_recover.c index 56faed11a..6489378cc 100644 --- a/src/secp256k1/src/bench_recover.c +++ b/src/secp256k1/src/bench_recover.c @@ -1,15 +1,16 @@ /********************************************************************** - * Copyright (c) 2014 Pieter Wuille * + * Copyright (c) 2014-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ #include "include/secp256k1.h" +#include "include/secp256k1_recovery.h" #include "util.h" #include "bench.h" typedef struct { - secp256k1_context_t *ctx; + secp256k1_context *ctx; unsigned char msg[32]; unsigned char sig[64]; } bench_recover_t; @@ -17,16 +18,20 @@ typedef struct { void bench_recover(void* arg) { int i; bench_recover_t *data = (bench_recover_t*)arg; - unsigned char pubkey[33]; + secp256k1_pubkey pubkey; + unsigned char pubkeyc[33]; for (i = 0; i < 20000; i++) { int j; - int pubkeylen = 33; - CHECK(secp256k1_ecdsa_recover_compact(data->ctx, data->msg, data->sig, pubkey, &pubkeylen, 1, i % 2)); + size_t pubkeylen = 33; + secp256k1_ecdsa_recoverable_signature sig; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2)); + CHECK(secp256k1_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg)); + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); for (j = 0; j < 32; j++) { data->sig[j + 32] = data->msg[j]; /* Move former message to S. */ data->msg[j] = data->sig[j]; /* Move former R to message. */ - data->sig[j] = pubkey[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ + data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ } } } @@ -35,8 +40,12 @@ void bench_recover_setup(void* arg) { int i; bench_recover_t *data = (bench_recover_t*)arg; - for (i = 0; i < 32; i++) data->msg[i] = 1 + i; - for (i = 0; i < 64; i++) data->sig[i] = 65 + i; + for (i = 0; i < 32; i++) { + data->msg[i] = 1 + i; + } + for (i = 0; i < 64; i++) { + data->sig[i] = 65 + i; + } } int main(void) { diff --git a/src/secp256k1/src/bench_schnorr_verify.c b/src/secp256k1/src/bench_schnorr_verify.c new file mode 100644 index 000000000..5f137dda2 --- /dev/null +++ b/src/secp256k1/src/bench_schnorr_verify.c @@ -0,0 +1,73 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "include/secp256k1.h" +#include "include/secp256k1_schnorr.h" +#include "util.h" +#include "bench.h" + +typedef struct { + unsigned char key[32]; + unsigned char sig[64]; + unsigned char pubkey[33]; + size_t pubkeylen; +} benchmark_schnorr_sig_t; + +typedef struct { + secp256k1_context *ctx; + unsigned char msg[32]; + benchmark_schnorr_sig_t sigs[64]; + int numsigs; +} benchmark_schnorr_verify_t; + +static void benchmark_schnorr_init(void* arg) { + int i, k; + benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg; + + for (i = 0; i < 32; i++) { + data->msg[i] = 1 + i; + } + for (k = 0; k < data->numsigs; k++) { + secp256k1_pubkey pubkey; + for (i = 0; i < 32; i++) { + data->sigs[k].key[i] = 33 + i + k; + } + secp256k1_schnorr_sign(data->ctx, data->sigs[k].sig, data->msg, data->sigs[k].key, NULL, NULL); + data->sigs[k].pubkeylen = 33; + CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->sigs[k].key)); + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->sigs[k].pubkey, &data->sigs[k].pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); + } +} + +static void benchmark_schnorr_verify(void* arg) { + int i; + benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg; + + for (i = 0; i < 20000 / data->numsigs; i++) { + secp256k1_pubkey pubkey; + data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->sigs[0].pubkey, data->sigs[0].pubkeylen)); + CHECK(secp256k1_schnorr_verify(data->ctx, data->sigs[0].sig, data->msg, &pubkey) == ((i & 0xFF) == 0)); + data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF); + } +} + + + +int main(void) { + benchmark_schnorr_verify_t data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + data.numsigs = 1; + run_benchmark("schnorr_verify", benchmark_schnorr_verify, benchmark_schnorr_init, NULL, &data, 10, 20000); + + secp256k1_context_destroy(data.ctx); + return 0; +} diff --git a/src/secp256k1/src/bench_sign.c b/src/secp256k1/src/bench_sign.c index 072a37af5..ed7224d75 100644 --- a/src/secp256k1/src/bench_sign.c +++ b/src/secp256k1/src/bench_sign.c @@ -9,7 +9,7 @@ #include "bench.h" typedef struct { - secp256k1_context_t* ctx; + secp256k1_context* ctx; unsigned char msg[32]; unsigned char key[32]; } bench_sign_t; @@ -18,22 +18,28 @@ static void bench_sign_setup(void* arg) { int i; bench_sign_t *data = (bench_sign_t*)arg; - for (i = 0; i < 32; i++) data->msg[i] = i + 1; - for (i = 0; i < 32; i++) data->key[i] = i + 65; + for (i = 0; i < 32; i++) { + data->msg[i] = i + 1; + } + for (i = 0; i < 32; i++) { + data->key[i] = i + 65; + } } static void bench_sign(void* arg) { int i; bench_sign_t *data = (bench_sign_t*)arg; - unsigned char sig[64]; + unsigned char sig[74]; for (i = 0; i < 20000; i++) { + size_t siglen = 74; int j; - int recid = 0; - CHECK(secp256k1_ecdsa_sign_compact(data->ctx, data->msg, sig, data->key, NULL, NULL, &recid)); + secp256k1_ecdsa_signature signature; + CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature)); for (j = 0; j < 32; j++) { - data->msg[j] = sig[j]; /* Move former R to message. */ - data->key[j] = sig[j + 32]; /* Move former S to key. */ + data->msg[j] = sig[j]; + data->key[j] = sig[j + 32]; } } } diff --git a/src/secp256k1/src/bench_verify.c b/src/secp256k1/src/bench_verify.c index c8c82752c..5718320cd 100644 --- a/src/secp256k1/src/bench_verify.c +++ b/src/secp256k1/src/bench_verify.c @@ -12,13 +12,13 @@ #include "bench.h" typedef struct { - secp256k1_context_t *ctx; + secp256k1_context *ctx; unsigned char msg[32]; unsigned char key[32]; unsigned char sig[72]; - int siglen; + size_t siglen; unsigned char pubkey[33]; - int pubkeylen; + size_t pubkeylen; } benchmark_verify_t; static void benchmark_verify(void* arg) { @@ -26,10 +26,14 @@ static void benchmark_verify(void* arg) { benchmark_verify_t* data = (benchmark_verify_t*)arg; for (i = 0; i < 20000; i++) { + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); - CHECK(secp256k1_ecdsa_verify(data->ctx, data->msg, data->sig, data->siglen, data->pubkey, data->pubkeylen) == (i == 0)); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); + CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0)); data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); @@ -38,16 +42,24 @@ static void benchmark_verify(void* arg) { int main(void) { int i; + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; benchmark_verify_t data; data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - for (i = 0; i < 32; i++) data.msg[i] = 1 + i; - for (i = 0; i < 32; i++) data.key[i] = 33 + i; + for (i = 0; i < 32; i++) { + data.msg[i] = 1 + i; + } + for (i = 0; i < 32; i++) { + data.key[i] = 33 + i; + } data.siglen = 72; - secp256k1_ecdsa_sign(data.ctx, data.msg, data.sig, &data.siglen, data.key, NULL, NULL); + CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); + CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key)); data.pubkeylen = 33; - CHECK(secp256k1_ec_pubkey_create(data.ctx, data.pubkey, &data.pubkeylen, data.key, 1)); + CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000); diff --git a/src/secp256k1/src/ecdsa.h b/src/secp256k1/src/ecdsa.h index 4ef78e8af..54ae101b9 100644 --- a/src/secp256k1/src/ecdsa.h +++ b/src/secp256k1/src/ecdsa.h @@ -7,18 +7,15 @@ #ifndef _SECP256K1_ECDSA_ #define _SECP256K1_ECDSA_ +#include + #include "scalar.h" #include "group.h" #include "ecmult.h" -typedef struct { - secp256k1_scalar_t r, s; -} secp256k1_ecdsa_sig_t; - -static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size); -static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a); -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message); -static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid); -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid); +static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *r, secp256k1_scalar *s, const unsigned char *sig, size_t size); +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s); +static 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); +static 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); #endif diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h index ed1d22818..d110b4bb1 100644 --- a/src/secp256k1/src/ecdsa_impl.h +++ b/src/secp256k1/src/ecdsa_impl.h @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ @@ -28,7 +28,7 @@ * sage: '%x' % (EllipticCurve ([F (a), F (b)]).order()) * 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141' */ -static const secp256k1_fe_t secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( +static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL ); @@ -42,82 +42,150 @@ static const secp256k1_fe_t secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CON * sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order()) * '14551231950b75fc4402da1722fc9baee' */ -static const secp256k1_fe_t secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( +static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL ); -static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) { - unsigned char ra[32] = {0}, sa[32] = {0}; - const unsigned char *rp; - const unsigned char *sp; - int lenr; - int lens; - int overflow; - if (sig[0] != 0x30) { +static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) { + int lenleft, b1; + size_t ret = 0; + if (*sigp >= sigend) { + return -1; + } + b1 = *((*sigp)++); + if (b1 == 0xFF) { + /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */ + return -1; + } + if ((b1 & 0x80) == 0) { + /* X.690-0207 8.1.3.4 short form length octets */ + return b1; + } + if (b1 == 0x80) { + /* Indefinite length is not allowed in DER. */ + return -1; + } + /* X.690-207 8.1.3.5 long form length octets */ + lenleft = b1 & 0x7F; + if (lenleft > sigend - *sigp) { + return -1; + } + if (**sigp == 0) { + /* Not the shortest possible length encoding. */ + return -1; + } + if ((size_t)lenleft > sizeof(size_t)) { + /* The resulting length would exceed the range of a size_t, so + * certainly longer than the passed array size. + */ + return -1; + } + while (lenleft > 0) { + if ((ret >> ((sizeof(size_t) - 1) * 8)) != 0) { + } + ret = (ret << 8) | **sigp; + if (ret + lenleft > (size_t)(sigend - *sigp)) { + /* Result exceeds the length of the passed array. */ + return -1; + } + (*sigp)++; + lenleft--; + } + if (ret < 128) { + /* Not the shortest possible length encoding. */ + return -1; + } + return ret; +} + +static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) { + int overflow = 0; + unsigned char ra[32] = {0}; + int rlen; + + if (*sig == sigend || **sig != 0x02) { + /* Not a primitive integer (X.690-0207 8.3.1). */ return 0; } - lenr = sig[3]; - if (5+lenr >= size) { + (*sig)++; + rlen = secp256k1_der_read_len(sig, sigend); + if (rlen <= 0 || (*sig) + rlen > sigend) { + /* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */ return 0; } - lens = sig[lenr+5]; - if (sig[1] != lenr+lens+4) { + if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) { + /* Excessive 0x00 padding. */ return 0; } - if (lenr+lens+6 > size) { + if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) { + /* Excessive 0xFF padding. */ return 0; } - if (sig[2] != 0x02) { - return 0; + if ((**sig & 0x80) == 0x80) { + /* Negative. */ + overflow = 1; } - if (lenr == 0) { - return 0; + while (rlen > 0 && **sig == 0) { + /* Skip leading zero bytes */ + rlen--; + (*sig)++; } - if (sig[lenr+4] != 0x02) { - return 0; + if (rlen > 32) { + overflow = 1; } - if (lens == 0) { - return 0; + if (!overflow) { + memcpy(ra + 32 - rlen, *sig, rlen); + secp256k1_scalar_set_b32(r, ra, &overflow); } - sp = sig + 6 + lenr; - while (lens > 0 && sp[0] == 0) { - lens--; - sp++; - } - if (lens > 32) { - return 0; - } - rp = sig + 4; - while (lenr > 0 && rp[0] == 0) { - lenr--; - rp++; - } - if (lenr > 32) { - return 0; - } - memcpy(ra + 32 - lenr, rp, lenr); - memcpy(sa + 32 - lens, sp, lens); - overflow = 0; - secp256k1_scalar_set_b32(&r->r, ra, &overflow); if (overflow) { - return 0; - } - secp256k1_scalar_set_b32(&r->s, sa, &overflow); - if (overflow) { - return 0; + secp256k1_scalar_set_int(r, 0); } + (*sig) += rlen; return 1; } -static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) { +static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) { + const unsigned char *sigend = sig + size; + int rlen; + if (sig == sigend || *(sig++) != 0x30) { + /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */ + return 0; + } + rlen = secp256k1_der_read_len(&sig, sigend); + if (rlen < 0 || sig + rlen > sigend) { + /* Tuple exceeds bounds */ + return 0; + } + if (sig + rlen != sigend) { + /* Garbage after tuple. */ + return 0; + } + + if (!secp256k1_der_parse_integer(rr, &sig, sigend)) { + return 0; + } + if (!secp256k1_der_parse_integer(rs, &sig, sigend)) { + return 0; + } + + if (sig != sigend) { + /* Trailing garbage inside tuple. */ + return 0; + } + + return 1; +} + +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar* ar, const secp256k1_scalar* as) { unsigned char r[33] = {0}, s[33] = {0}; unsigned char *rp = r, *sp = s; - int lenR = 33, lenS = 33; - secp256k1_scalar_get_b32(&r[1], &a->r); - secp256k1_scalar_get_b32(&s[1], &a->s); + size_t lenR = 33, lenS = 33; + secp256k1_scalar_get_b32(&r[1], ar); + secp256k1_scalar_get_b32(&s[1], as); while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; } while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; } if (*size < 6+lenS+lenR) { + *size = 6 + lenS + lenR; return 0; } *size = 6 + lenS + lenR; @@ -132,26 +200,26 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se return 1; } -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { +static 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) { unsigned char c[32]; - secp256k1_scalar_t sn, u1, u2; - secp256k1_fe_t xr; - secp256k1_gej_t pubkeyj; - secp256k1_gej_t pr; + secp256k1_scalar sn, u1, u2; + secp256k1_fe xr; + secp256k1_gej pubkeyj; + secp256k1_gej pr; - if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { return 0; } - secp256k1_scalar_inverse_var(&sn, &sig->s); + secp256k1_scalar_inverse_var(&sn, sigs); secp256k1_scalar_mul(&u1, &sn, message); - secp256k1_scalar_mul(&u2, &sn, &sig->r); + secp256k1_scalar_mul(&u2, &sn, sigr); secp256k1_gej_set_ge(&pubkeyj, pubkey); secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1); if (secp256k1_gej_is_infinity(&pr)) { return 0; } - secp256k1_scalar_get_b32(c, &sig->r); + secp256k1_scalar_get_b32(c, sigr); secp256k1_fe_set_b32(&xr, c); /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) @@ -171,11 +239,11 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, con * secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. */ if (secp256k1_gej_eq_x_var(&xr, &pr)) { - /* xr.x == xr * xr.z^2 mod p, so the signature is valid. */ + /* xr * pr.z^2 mod p == pr.x, so the signature is valid. */ return 1; } if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) { - /* xr + p >= n, so we can skip testing the second case. */ + /* xr + n >= p, so we can skip testing the second case. */ return 0; } secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe); @@ -186,44 +254,11 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, con return 0; } -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) { - unsigned char brx[32]; - secp256k1_fe_t fx; - secp256k1_ge_t x; - secp256k1_gej_t xj; - secp256k1_scalar_t rn, u1, u2; - secp256k1_gej_t qj; - - if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { - return 0; - } - - secp256k1_scalar_get_b32(brx, &sig->r); - VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */ - if (recid & 2) { - if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { - return 0; - } - secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe); - } - if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) { - return 0; - } - secp256k1_gej_set_ge(&xj, &x); - secp256k1_scalar_inverse_var(&rn, &sig->r); - secp256k1_scalar_mul(&u1, &rn, message); - secp256k1_scalar_negate(&u1, &u1); - secp256k1_scalar_mul(&u2, &rn, &sig->s); - secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); - secp256k1_ge_set_gej_var(pubkey, &qj); - return !secp256k1_gej_is_infinity(&qj); -} - -static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) { +static 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) { unsigned char b[32]; - secp256k1_gej_t rp; - secp256k1_ge_t r; - secp256k1_scalar_t n; + secp256k1_gej rp; + secp256k1_ge r; + secp256k1_scalar n; int overflow = 0; secp256k1_ecmult_gen(ctx, &rp, nonce); @@ -231,28 +266,33 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, s secp256k1_fe_normalize(&r.x); secp256k1_fe_normalize(&r.y); secp256k1_fe_get_b32(b, &r.x); - secp256k1_scalar_set_b32(&sig->r, b, &overflow); - if (secp256k1_scalar_is_zero(&sig->r)) { - /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. */ + secp256k1_scalar_set_b32(sigr, b, &overflow); + if (secp256k1_scalar_is_zero(sigr)) { + /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. + * This branch is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N. + */ secp256k1_gej_clear(&rp); secp256k1_ge_clear(&r); return 0; } if (recid) { + /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log + * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria. + */ *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); } - secp256k1_scalar_mul(&n, &sig->r, seckey); + secp256k1_scalar_mul(&n, sigr, seckey); secp256k1_scalar_add(&n, &n, message); - secp256k1_scalar_inverse(&sig->s, nonce); - secp256k1_scalar_mul(&sig->s, &sig->s, &n); + secp256k1_scalar_inverse(sigs, nonce); + secp256k1_scalar_mul(sigs, sigs, &n); secp256k1_scalar_clear(&n); secp256k1_gej_clear(&rp); secp256k1_ge_clear(&r); - if (secp256k1_scalar_is_zero(&sig->s)) { + if (secp256k1_scalar_is_zero(sigs)) { return 0; } - if (secp256k1_scalar_is_high(&sig->s)) { - secp256k1_scalar_negate(&sig->s, &sig->s); + if (secp256k1_scalar_is_high(sigs)) { + secp256k1_scalar_negate(sigs, sigs); if (recid) { *recid ^= 1; } diff --git a/src/secp256k1/src/eckey.h b/src/secp256k1/src/eckey.h index 53b818485..42739a3be 100644 --- a/src/secp256k1/src/eckey.h +++ b/src/secp256k1/src/eckey.h @@ -7,20 +7,19 @@ #ifndef _SECP256K1_ECKEY_ #define _SECP256K1_ECKEY_ +#include + #include "group.h" #include "scalar.h" #include "ecmult.h" #include "ecmult_gen.h" -static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size); -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed); +static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size); +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed); -static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen); -static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed); - -static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak); -static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak); -static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak); -static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak); +static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); #endif diff --git a/src/secp256k1/src/eckey_impl.h b/src/secp256k1/src/eckey_impl.h index a332bd34e..ce38071ac 100644 --- a/src/secp256k1/src/eckey_impl.h +++ b/src/secp256k1/src/eckey_impl.h @@ -14,12 +14,12 @@ #include "group.h" #include "ecmult_gen.h" -static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size) { +static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) { if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) { - secp256k1_fe_t x; + secp256k1_fe x; return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03); } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) { - secp256k1_fe_t x, y; + secp256k1_fe x, y; if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) { return 0; } @@ -33,7 +33,7 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned cha } } -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed) { +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) { if (secp256k1_ge_is_infinity(elem)) { return 0; } @@ -51,110 +51,7 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char return 1; } -static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen) { - unsigned char c[32] = {0}; - const unsigned char *end = privkey + privkeylen; - int lenb = 0; - int len = 0; - int overflow = 0; - /* sequence header */ - if (end < privkey+1 || *privkey != 0x30) { - return 0; - } - privkey++; - /* sequence length constructor */ - if (end < privkey+1 || !(*privkey & 0x80)) { - return 0; - } - lenb = *privkey & ~0x80; privkey++; - if (lenb < 1 || lenb > 2) { - return 0; - } - if (end < privkey+lenb) { - return 0; - } - /* sequence length */ - len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); - privkey += lenb; - if (end < privkey+len) { - return 0; - } - /* sequence element 0: version number (=1) */ - if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { - return 0; - } - privkey += 3; - /* sequence element 1: octet string, up to 32 bytes */ - if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { - return 0; - } - memcpy(c + 32 - privkey[1], privkey + 2, privkey[1]); - secp256k1_scalar_set_b32(key, c, &overflow); - memset(c, 0, 32); - return !overflow; -} - -static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed) { - secp256k1_gej_t rp; - secp256k1_ge_t r; - int pubkeylen = 0; - secp256k1_ecmult_gen(ctx, &rp, key); - secp256k1_ge_set_gej(&r, &rp); - if (compressed) { - static const unsigned char begin[] = { - 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 - }; - static const unsigned char middle[] = { - 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, - 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,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,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, - 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, - 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, - 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, - 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 - }; - unsigned char *ptr = privkey; - memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); - secp256k1_scalar_get_b32(ptr, key); ptr += 32; - memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 1)) { - return 0; - } - ptr += pubkeylen; - *privkeylen = ptr - privkey; - } else { - static const unsigned char begin[] = { - 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 - }; - static const unsigned char middle[] = { - 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, - 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,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,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, - 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, - 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, - 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, - 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, - 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, - 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 - }; - unsigned char *ptr = privkey; - memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); - secp256k1_scalar_get_b32(ptr, key); ptr += 32; - memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 0)) { - return 0; - } - ptr += pubkeylen; - *privkeylen = ptr - privkey; - } - return 1; -} - -static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) { +static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) { secp256k1_scalar_add(key, key, tweak); if (secp256k1_scalar_is_zero(key)) { return 0; @@ -162,9 +59,9 @@ static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp return 1; } -static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { - secp256k1_gej_t pt; - secp256k1_scalar_t one; +static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) { + secp256k1_gej pt; + secp256k1_scalar one; secp256k1_gej_set_ge(&pt, key); secp256k1_scalar_set_int(&one, 1); secp256k1_ecmult(ctx, &pt, &pt, &one, tweak); @@ -176,7 +73,7 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ct return 1; } -static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) { +static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) { if (secp256k1_scalar_is_zero(tweak)) { return 0; } @@ -185,9 +82,9 @@ static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp return 1; } -static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { - secp256k1_scalar_t zero; - secp256k1_gej_t pt; +static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) { + secp256k1_scalar zero; + secp256k1_gej pt; if (secp256k1_scalar_is_zero(tweak)) { return 0; } diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h index bab9e4ef5..20484134f 100644 --- a/src/secp256k1/src/ecmult.h +++ b/src/secp256k1/src/ecmult.h @@ -12,20 +12,20 @@ typedef struct { /* For accelerating the computation of a*P + b*G: */ - secp256k1_ge_storage_t (*pre_g)[]; /* odd multiples of the generator */ + secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */ #ifdef USE_ENDOMORPHISM - secp256k1_ge_storage_t (*pre_g_128)[]; /* odd multiples of 2^128*generator */ + secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */ #endif -} secp256k1_ecmult_context_t; +} secp256k1_ecmult_context; -static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx); -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx); -static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, - const secp256k1_ecmult_context_t *src); -static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx); -static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx); +static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx); +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb); +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, + const secp256k1_ecmult_context *src, const secp256k1_callback *cb); +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx); +static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx); /** Double multiply: R = na*A + ng*G */ -static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng); +static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng); #endif diff --git a/src/secp256k1/src/ecmult_const.h b/src/secp256k1/src/ecmult_const.h new file mode 100644 index 000000000..2b0097655 --- /dev/null +++ b/src/secp256k1/src/ecmult_const.h @@ -0,0 +1,15 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECMULT_CONST_ +#define _SECP256K1_ECMULT_CONST_ + +#include "scalar.h" +#include "group.h" + +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q); + +#endif diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h new file mode 100644 index 000000000..90ac94770 --- /dev/null +++ b/src/secp256k1/src/ecmult_const_impl.h @@ -0,0 +1,260 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECMULT_CONST_IMPL_ +#define _SECP256K1_ECMULT_CONST_IMPL_ + +#include "scalar.h" +#include "group.h" +#include "ecmult_const.h" +#include "ecmult_impl.h" + +#ifdef USE_ENDOMORPHISM + #define WNAF_BITS 128 +#else + #define WNAF_BITS 256 +#endif +#define WNAF_SIZE(w) ((WNAF_BITS + (w) - 1) / (w)) + +/* This is like `ECMULT_TABLE_GET_GE` but is constant time */ +#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \ + int m; \ + int abs_n = (n) * (((n) > 0) * 2 - 1); \ + int idx_n = abs_n / 2; \ + secp256k1_fe neg_y; \ + VERIFY_CHECK(((n) & 1) == 1); \ + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ + VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \ + VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \ + for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \ + /* This loop is used to avoid secret data in array indices. See + * the comment in ecmult_gen_impl.h for rationale. */ \ + secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \ + secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \ + } \ + (r)->infinity = 0; \ + secp256k1_fe_negate(&neg_y, &(r)->y, 1); \ + secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \ +} while(0) + + +/** Convert a number to WNAF notation. The number becomes represented by sum(2^{wi} * wnaf[i], i=0..return_val) + * with the following guarantees: + * - each wnaf[i] an odd integer between -(1 << w) and (1 << w) + * - each wnaf[i] is nonzero + * - the number of words set is returned; this is always (WNAF_BITS + w - 1) / w + * + * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar + * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.) + * CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003 + * + * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335 + */ +static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) { + int global_sign; + int skew = 0; + int word = 0; + /* 1 2 3 */ + int u_last; + int u; + +#ifdef USE_ENDOMORPHISM + int flip; + int bit; + secp256k1_scalar neg_s; + int not_neg_one; + /* If we are using the endomorphism, we cannot handle even numbers by negating + * them, since we are working with 128-bit numbers whose negations would be 256 + * bits, eliminating the performance advantage. Instead we use a technique from + * Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even) + * or 2 (for odd) to the number we are encoding, then compensating after the + * multiplication. */ + /* Negative 128-bit numbers will be negated, since otherwise they are 256-bit */ + flip = secp256k1_scalar_is_high(&s); + /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */ + bit = flip ^ (s.d[0] & 1); + /* We check for negative one, since adding 2 to it will cause an overflow */ + secp256k1_scalar_negate(&neg_s, &s); + not_neg_one = !secp256k1_scalar_is_one(&neg_s); + secp256k1_scalar_cadd_bit(&s, bit, not_neg_one); + /* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects + * that we added two to it and flipped it. In fact for -1 these operations are + * identical. We only flipped, but since skewing is required (in the sense that + * the skew must be 1 or 2, never zero) and flipping is not, we need to change + * our flags to claim that we only skewed. */ + global_sign = secp256k1_scalar_cond_negate(&s, flip); + global_sign *= not_neg_one * 2 - 1; + skew = 1 << bit; +#else + /* Otherwise, we just negate to force oddness */ + int is_even = secp256k1_scalar_is_even(&s); + global_sign = secp256k1_scalar_cond_negate(&s, is_even); +#endif + + /* 4 */ + u_last = secp256k1_scalar_shr_int(&s, w); + while (word * w < WNAF_BITS) { + int sign; + int even; + + /* 4.1 4.4 */ + u = secp256k1_scalar_shr_int(&s, w); + /* 4.2 */ + even = ((u & 1) == 0); + sign = 2 * (u_last > 0) - 1; + u += sign * even; + u_last -= sign * even * (1 << w); + + /* 4.3, adapted for global sign change */ + wnaf[word++] = u_last * global_sign; + + u_last = u; + } + wnaf[word] = u * global_sign; + + VERIFY_CHECK(secp256k1_scalar_is_zero(&s)); + VERIFY_CHECK(word == WNAF_SIZE(w)); + return skew; +} + + +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) { + secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge tmpa; + secp256k1_fe Z; + +#ifdef USE_ENDOMORPHISM + secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; + int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; + int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; + int skew_1; + int skew_lam; + secp256k1_scalar q_1, q_lam; +#else + int wnaf[1 + WNAF_SIZE(WINDOW_A - 1)]; +#endif + + int i; + secp256k1_scalar sc = *scalar; + + /* build wnaf representation for q. */ +#ifdef USE_ENDOMORPHISM + /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ + secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc); + /* no need for zero correction when using endomorphism since even + * numbers have one added to them anyway */ + skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1); + skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1); +#else + int is_zero = secp256k1_scalar_is_zero(scalar); + /* the wNAF ladder cannot handle zero, so bump this to one .. we will + * correct the result after the fact */ + sc.d[0] += is_zero; + VERIFY_CHECK(!secp256k1_scalar_is_zero(&sc)); + + secp256k1_wnaf_const(wnaf, sc, WINDOW_A - 1); +#endif + + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + */ + secp256k1_gej_set_ge(r, a); + secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r); + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_fe_normalize_weak(&pre_a[i].y); + } +#ifdef USE_ENDOMORPHISM + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); + } +#endif + + /* first loop iteration (separated out so we can directly set r, rather + * than having it start at infinity, get doubled several times, then have + * its new value added to it) */ +#ifdef USE_ENDOMORPHISM + i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); + secp256k1_gej_set_ge(r, &tmpa); + + i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); + secp256k1_gej_add_ge(r, r, &tmpa); +#else + i = wnaf[WNAF_SIZE(WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); + secp256k1_gej_set_ge(r, &tmpa); +#endif + /* remaining loop iterations */ + for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) { + int n; + int j; + for (j = 0; j < WINDOW_A - 1; ++j) { + secp256k1_gej_double_nonzero(r, r, NULL); + } +#ifdef USE_ENDOMORPHISM + n = wnaf_1[i]; + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + VERIFY_CHECK(n != 0); + secp256k1_gej_add_ge(r, r, &tmpa); + + n = wnaf_lam[i]; + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); + VERIFY_CHECK(n != 0); + secp256k1_gej_add_ge(r, r, &tmpa); +#else + n = wnaf[i]; + VERIFY_CHECK(n != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + secp256k1_gej_add_ge(r, r, &tmpa); +#endif + } + + secp256k1_fe_mul(&r->z, &r->z, &Z); + +#ifdef USE_ENDOMORPHISM + { + /* Correct for wNAF skew */ + secp256k1_ge correction = *a; + secp256k1_ge_storage correction_1_stor; + secp256k1_ge_storage correction_lam_stor; + secp256k1_ge_storage a2_stor; + secp256k1_gej tmpj; + secp256k1_gej_set_ge(&tmpj, &correction); + secp256k1_gej_double_var(&tmpj, &tmpj, NULL); + secp256k1_ge_set_gej(&correction, &tmpj); + secp256k1_ge_to_storage(&correction_1_stor, a); + secp256k1_ge_to_storage(&correction_lam_stor, a); + secp256k1_ge_to_storage(&a2_stor, &correction); + + /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */ + secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2); + secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2); + + /* Apply the correction */ + secp256k1_ge_from_storage(&correction, &correction_1_stor); + secp256k1_ge_neg(&correction, &correction); + secp256k1_gej_add_ge(r, r, &correction); + + secp256k1_ge_from_storage(&correction, &correction_lam_stor); + secp256k1_ge_neg(&correction, &correction); + secp256k1_ge_mul_lambda(&correction, &correction); + secp256k1_gej_add_ge(r, r, &correction); + } +#else + /* correct for zero */ + r->infinity |= is_zero; +#endif +} + +#endif diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h index 3745633c4..eb2cc9ead 100644 --- a/src/secp256k1/src/ecmult_gen.h +++ b/src/secp256k1/src/ecmult_gen.h @@ -23,21 +23,21 @@ typedef struct { * None of the resulting prec group elements have a known scalar, and neither do any of * the intermediate sums while computing a*G. */ - secp256k1_ge_storage_t (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */ - secp256k1_scalar_t blind; - secp256k1_gej_t initial; -} secp256k1_ecmult_gen_context_t; + secp256k1_ge_storage (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */ + secp256k1_scalar blind; + secp256k1_gej initial; +} secp256k1_ecmult_gen_context; -static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t* ctx); -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t* ctx); -static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, - const secp256k1_ecmult_gen_context_t* src); -static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t* ctx); -static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx); +static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx); +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb); +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, + const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb); +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx); +static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx); /** Multiply with the generator: R = a*G */ -static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t* ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *a); +static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a); -static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32); +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32); #endif diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h index 4697753ac..b63c4d866 100644 --- a/src/secp256k1/src/ecmult_gen_impl.h +++ b/src/secp256k1/src/ecmult_gen_impl.h @@ -11,22 +11,26 @@ #include "group.h" #include "ecmult_gen.h" #include "hash_impl.h" - -static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t *ctx) { +#ifdef USE_ECMULT_STATIC_PRECOMPUTATION +#include "ecmult_static_context.h" +#endif +static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) { ctx->prec = NULL; } -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *ctx) { - secp256k1_ge_t prec[1024]; - secp256k1_gej_t gj; - secp256k1_gej_t nums_gej; +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + secp256k1_ge prec[1024]; + secp256k1_gej gj; + secp256k1_gej nums_gej; int i, j; +#endif if (ctx->prec != NULL) { return; } - - ctx->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*ctx->prec)); +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec)); /* get the generator */ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); @@ -34,77 +38,93 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *c /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ { static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; - secp256k1_fe_t nums_x; - secp256k1_ge_t nums_ge; - VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32)); - VERIFY_CHECK(secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0)); + secp256k1_fe nums_x; + secp256k1_ge nums_ge; + int r; + r = secp256k1_fe_set_b32(&nums_x, nums_b32); + (void)r; + VERIFY_CHECK(r); + r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0); + (void)r; + VERIFY_CHECK(r); secp256k1_gej_set_ge(&nums_gej, &nums_ge); /* Add G to make the bits in x uniformly distributed. */ - secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g); + secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL); } /* compute prec. */ { - secp256k1_gej_t precj[1024]; /* Jacobian versions of prec. */ - secp256k1_gej_t gbase; - secp256k1_gej_t numsbase; + secp256k1_gej precj[1024]; /* Jacobian versions of prec. */ + secp256k1_gej gbase; + secp256k1_gej numsbase; gbase = gj; /* 16^j * G */ numsbase = nums_gej; /* 2^j * nums. */ for (j = 0; j < 64; j++) { /* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */ precj[j*16] = numsbase; for (i = 1; i < 16; i++) { - secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase); + secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL); } /* Multiply gbase by 16. */ for (i = 0; i < 4; i++) { - secp256k1_gej_double_var(&gbase, &gbase); + secp256k1_gej_double_var(&gbase, &gbase, NULL); } /* Multiply numbase by 2. */ - secp256k1_gej_double_var(&numsbase, &numsbase); + secp256k1_gej_double_var(&numsbase, &numsbase, NULL); if (j == 62) { /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ secp256k1_gej_neg(&numsbase, &numsbase); - secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej); + secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); } } - secp256k1_ge_set_all_gej_var(1024, prec, precj); + secp256k1_ge_set_all_gej_var(1024, prec, precj, cb); } for (j = 0; j < 64; j++) { for (i = 0; i < 16; i++) { secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]); } } +#else + (void)cb; + ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context; +#endif secp256k1_ecmult_gen_blind(ctx, NULL); } -static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx) { +static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) { return ctx->prec != NULL; } -static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, - const secp256k1_ecmult_gen_context_t *src) { +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, + const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) { if (src->prec == NULL) { dst->prec = NULL; } else { - dst->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*dst->prec)); +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec)); memcpy(dst->prec, src->prec, sizeof(*dst->prec)); +#else + (void)cb; + dst->prec = src->prec; +#endif dst->initial = src->initial; dst->blind = src->blind; } } -static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t *ctx) { +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION free(ctx->prec); +#endif secp256k1_scalar_clear(&ctx->blind); secp256k1_gej_clear(&ctx->initial); ctx->prec = NULL; } -static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *gn) { - secp256k1_ge_t add; - secp256k1_ge_storage_t adds; - secp256k1_scalar_t gnb; +static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) { + secp256k1_ge add; + secp256k1_ge_storage adds; + secp256k1_scalar gnb; int bits; int i, j; memset(&adds, 0, sizeof(adds)); @@ -136,14 +156,15 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t *ctx, secp } /* Setup blinding values for secp256k1_ecmult_gen. */ -static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32) { - secp256k1_scalar_t b; - secp256k1_gej_t gb; - secp256k1_fe_t s; +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) { + secp256k1_scalar b; + secp256k1_gej gb; + secp256k1_fe s; unsigned char nonce32[32]; secp256k1_rfc6979_hmac_sha256_t rng; int retry; - if (!seed32) { + unsigned char keydata[64] = {0}; + if (seed32 == NULL) { /* When seed is NULL, reset the initial point and blinding value. */ secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g); secp256k1_gej_neg(&ctx->initial, &ctx->initial); @@ -155,13 +176,18 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons * and guards against weak or adversarial seeds. This is a simpler and safer interface than * asking the caller for blinding values directly and expecting them to retry on failure. */ - secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed32 ? seed32 : nonce32, 32, nonce32, 32, NULL, 0); + memcpy(keydata, nonce32, 32); + if (seed32 != NULL) { + memcpy(keydata + 32, seed32, 32); + } + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32); + memset(keydata, 0, sizeof(keydata)); /* Retry for out of range results to achieve uniformity. */ do { secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); retry = !secp256k1_fe_set_b32(&s, nonce32); retry |= secp256k1_fe_is_zero(&s); - } while (retry); + } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */ /* Randomize the projection to defend against multiplier sidechannels. */ secp256k1_gej_rescale(&ctx->initial, &s); secp256k1_fe_clear(&s); @@ -170,7 +196,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons secp256k1_scalar_set_b32(&b, nonce32, &retry); /* A blinding value of 0 works, but would undermine the projection hardening. */ retry |= secp256k1_scalar_is_zero(&b); - } while (retry); + } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */ secp256k1_rfc6979_hmac_sha256_finalize(&rng); memset(nonce32, 0, 32); secp256k1_ecmult_gen(ctx, &gb, &b); diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h index 1b2856f83..e6e5f4718 100644 --- a/src/secp256k1/src/ecmult_impl.h +++ b/src/secp256k1/src/ecmult_impl.h @@ -24,62 +24,107 @@ #define WINDOW_G 16 #endif -/** Fill a table 'pre' with precomputed odd multiples of a. W determines the size of the table. - * pre will contains the values [1*a,3*a,5*a,...,(2^(w-1)-1)*a], so it needs place for - * 2^(w-2) entries. - * - * There are two versions of this function: - * - secp256k1_ecmult_precomp_wnaf_gej, which operates on group elements in jacobian notation, - * fast to precompute, but slower to use in later additions. - * - secp256k1_ecmult_precomp_wnaf_ge, which operates on group elements in affine notations, - * (much) slower to precompute, but a bit faster to use in later additions. - * To compute a*P + b*G, we use the jacobian version for P, and the affine version for G, as - * G is constant, so it only needs to be done once in advance. - */ -static void secp256k1_ecmult_table_precomp_gej_var(secp256k1_gej_t *pre, const secp256k1_gej_t *a, int w) { - secp256k1_gej_t d; - int i; - pre[0] = *a; - secp256k1_gej_double_var(&d, &pre[0]); - for (i = 1; i < (1 << (w-2)); i++) { - secp256k1_gej_add_var(&pre[i], &d, &pre[i-1]); - } -} - -static void secp256k1_ecmult_table_precomp_ge_storage_var(secp256k1_ge_storage_t *pre, const secp256k1_gej_t *a, int w) { - secp256k1_gej_t d; - int i; - const int table_size = 1 << (w-2); - secp256k1_gej_t *prej = (secp256k1_gej_t *)checked_malloc(sizeof(secp256k1_gej_t) * table_size); - secp256k1_ge_t *prea = (secp256k1_ge_t *)checked_malloc(sizeof(secp256k1_ge_t) * table_size); - prej[0] = *a; - secp256k1_gej_double_var(&d, a); - for (i = 1; i < table_size; i++) { - secp256k1_gej_add_var(&prej[i], &d, &prej[i-1]); - } - secp256k1_ge_set_all_gej_var(table_size, prea, prej); - for (i = 0; i < table_size; i++) { - secp256k1_ge_to_storage(&pre[i], &prea[i]); - } - free(prej); - free(prea); -} - /** The number of entries a table with precomputed multiples needs to have. */ #define ECMULT_TABLE_SIZE(w) (1 << ((w)-2)) +/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain + * the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will + * contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z. + * Prej's Z values are undefined, except for the last value. + */ +static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, secp256k1_fe *zr, const secp256k1_gej *a) { + secp256k1_gej d; + secp256k1_ge a_ge, d_ge; + int i; + + VERIFY_CHECK(!a->infinity); + + secp256k1_gej_double_var(&d, a, NULL); + + /* + * Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate + * of 'd', and scale the 1P starting value's x/y coordinates without changing its z. + */ + d_ge.x = d.x; + d_ge.y = d.y; + d_ge.infinity = 0; + + secp256k1_ge_set_gej_zinv(&a_ge, a, &d.z); + prej[0].x = a_ge.x; + prej[0].y = a_ge.y; + prej[0].z = a->z; + prej[0].infinity = 0; + + zr[0] = d.z; + for (i = 1; i < n; i++) { + secp256k1_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]); + } + + /* + * Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only + * the final point's z coordinate is actually used though, so just update that. + */ + secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z); +} + +/** Fill a table 'pre' with precomputed odd multiples of a. + * + * There are two versions of this function: + * - secp256k1_ecmult_odd_multiples_table_globalz_windowa which brings its + * resulting point set to a single constant Z denominator, stores the X and Y + * coordinates as ge_storage points in pre, and stores the global Z in rz. + * It only operates on tables sized for WINDOW_A wnaf multiples. + * - secp256k1_ecmult_odd_multiples_table_storage_var, which converts its + * resulting point set to actually affine points, and stores those in pre. + * It operates on tables of any size, but uses heap-allocated temporaries. + * + * To compute a*P + b*G, we compute a table for P using the first function, + * and for G using the second (which requires an inverse, but it only needs to + * happen once). + */ +static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) { + secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)]; + + /* Compute the odd multiples in Jacobian form. */ + secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a); + /* Bring them to the same Z denominator. */ + secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr); +} + +static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge_storage *pre, const secp256k1_gej *a, const secp256k1_callback *cb) { + secp256k1_gej *prej = (secp256k1_gej*)checked_malloc(cb, sizeof(secp256k1_gej) * n); + secp256k1_ge *prea = (secp256k1_ge*)checked_malloc(cb, sizeof(secp256k1_ge) * n); + secp256k1_fe *zr = (secp256k1_fe*)checked_malloc(cb, sizeof(secp256k1_fe) * n); + int i; + + /* Compute the odd multiples in Jacobian form. */ + secp256k1_ecmult_odd_multiples_table(n, prej, zr, a); + /* Convert them in batch to affine coordinates. */ + secp256k1_ge_set_table_gej_var(n, prea, prej, zr); + /* Convert them to compact storage form. */ + for (i = 0; i < n; i++) { + secp256k1_ge_to_storage(&pre[i], &prea[i]); + } + + free(prea); + free(prej); + free(zr); +} + /** The following two macro retrieves a particular odd multiple from a table * of precomputed multiples. */ -#define ECMULT_TABLE_GET_GEJ(r,pre,n,w) do { \ +#define ECMULT_TABLE_GET_GE(r,pre,n,w) do { \ VERIFY_CHECK(((n) & 1) == 1); \ VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ if ((n) > 0) { \ *(r) = (pre)[((n)-1)/2]; \ } else { \ - secp256k1_gej_neg((r), &(pre)[(-(n)-1)/2]); \ + secp256k1_ge_neg((r), &(pre)[(-(n)-1)/2]); \ } \ } while(0) + #define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \ VERIFY_CHECK(((n) & 1) == 1); \ VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ @@ -92,15 +137,15 @@ static void secp256k1_ecmult_table_precomp_ge_storage_var(secp256k1_ge_storage_t } \ } while(0) -static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx) { +static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) { ctx->pre_g = NULL; #ifdef USE_ENDOMORPHISM ctx->pre_g_128 = NULL; #endif } -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) { - secp256k1_gej_t gj; +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) { + secp256k1_gej gj; if (ctx->pre_g != NULL) { return; @@ -109,35 +154,35 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) { /* get the generator */ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); - ctx->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); /* precompute the tables with odd multiples */ - secp256k1_ecmult_table_precomp_ge_storage_var(*ctx->pre_g, &gj, WINDOW_G); + secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb); #ifdef USE_ENDOMORPHISM { - secp256k1_gej_t g_128j; + secp256k1_gej g_128j; int i; - ctx->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + ctx->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); /* calculate 2^128*generator */ g_128j = gj; for (i = 0; i < 128; i++) { - secp256k1_gej_double_var(&g_128j, &g_128j); + secp256k1_gej_double_var(&g_128j, &g_128j, NULL); } - secp256k1_ecmult_table_precomp_ge_storage_var(*ctx->pre_g_128, &g_128j, WINDOW_G); + secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j, cb); } #endif } -static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, - const secp256k1_ecmult_context_t *src) { +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, + const secp256k1_ecmult_context *src, const secp256k1_callback *cb) { if (src->pre_g == NULL) { dst->pre_g = NULL; } else { size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); - dst->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(size); + dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); memcpy(dst->pre_g, src->pre_g, size); } #ifdef USE_ENDOMORPHISM @@ -145,17 +190,17 @@ static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, dst->pre_g_128 = NULL; } else { size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); - dst->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(size); + dst->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); memcpy(dst->pre_g_128, src->pre_g_128, size); } #endif } -static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx) { +static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx) { return ctx->pre_g != NULL; } -static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx) { +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) { free(ctx->pre_g); #ifdef USE_ENDOMORPHISM free(ctx->pre_g_128); @@ -168,54 +213,68 @@ static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx) { * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) * - two non-zero entries in wnaf are separated by at least w-1 zeroes. * - the number of set values in wnaf is returned. This number is at most 256, and at most one more - * - than the number of bits in the (absolute value) of the input. + * than the number of bits in the (absolute value) of the input. */ -static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w) { - secp256k1_scalar_t s = *a; - int set_bits = 0; +static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, int w) { + secp256k1_scalar s = *a; + int last_set_bit = -1; int bit = 0; int sign = 1; + int carry = 0; + + VERIFY_CHECK(wnaf != NULL); + VERIFY_CHECK(0 <= len && len <= 256); + VERIFY_CHECK(a != NULL); + VERIFY_CHECK(2 <= w && w <= 31); + + memset(wnaf, 0, len * sizeof(wnaf[0])); if (secp256k1_scalar_get_bits(&s, 255, 1)) { secp256k1_scalar_negate(&s, &s); sign = -1; } - while (bit < 256) { + while (bit < len) { int now; int word; - if (secp256k1_scalar_get_bits(&s, bit, 1) == 0) { + if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) { bit++; continue; } - while (set_bits < bit) { - wnaf[set_bits++] = 0; - } + now = w; - if (bit + now > 256) { - now = 256 - bit; - } - word = secp256k1_scalar_get_bits_var(&s, bit, now); - if (word & (1 << (w-1))) { - secp256k1_scalar_add_bit(&s, bit + w); - wnaf[set_bits++] = sign * (word - (1 << w)); - } else { - wnaf[set_bits++] = sign * word; + if (now > len - bit) { + now = len - bit; } + + word = secp256k1_scalar_get_bits_var(&s, bit, now) + carry; + + carry = (word >> (w-1)) & 1; + word -= carry << w; + + wnaf[bit] = sign * word; + last_set_bit = bit; + bit += now; } - return set_bits; +#ifdef VERIFY + CHECK(carry == 0); + while (bit < 256) { + CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0); + } +#endif + return last_set_bit + 1; } -static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng) { - secp256k1_gej_t tmpj; - secp256k1_gej_t pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_ge_t tmpa; +static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { + secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge tmpa; + secp256k1_fe Z; #ifdef USE_ENDOMORPHISM - secp256k1_gej_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_scalar_t na_1, na_lam; + secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_scalar na_1, na_lam; /* Splitted G factors. */ - secp256k1_scalar_t ng_1, ng_128; + secp256k1_scalar ng_1, ng_128; int wnaf_na_1[130]; int wnaf_na_lam[130]; int bits_na_1; @@ -227,7 +286,7 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge #else int wnaf_na[256]; int bits_na; - int wnaf_ng[257]; + int wnaf_ng[256]; int bits_ng; #endif int i; @@ -235,11 +294,11 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge #ifdef USE_ENDOMORPHISM /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ - secp256k1_scalar_split_lambda_var(&na_1, &na_lam, na); + secp256k1_scalar_split_lambda(&na_1, &na_lam, na); /* build wnaf representation for na_1 and na_lam. */ - bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A); - bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A); + bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, 130, &na_1, WINDOW_A); + bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, 130, &na_lam, WINDOW_A); VERIFY_CHECK(bits_na_1 <= 130); VERIFY_CHECK(bits_na_lam <= 130); bits = bits_na_1; @@ -248,24 +307,33 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge } #else /* build wnaf representation for na. */ - bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A); + bits_na = secp256k1_ecmult_wnaf(wnaf_na, 256, na, WINDOW_A); bits = bits_na; #endif - /* calculate odd multiples of a */ - secp256k1_ecmult_table_precomp_gej_var(pre_a, a, WINDOW_A); + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + * The exception is the precomputed G table points, which are actually + * affine. Compared to the base used for other points, they have a Z ratio + * of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same + * isomorphism to efficiently add with a known Z inverse. + */ + secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, a); #ifdef USE_ENDOMORPHISM for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - secp256k1_gej_mul_lambda(&pre_a_lam[i], &pre_a[i]); + secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); } /* 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) */ secp256k1_scalar_split_128(&ng_1, &ng_128, ng); /* Build wnaf representation for ng_1 and ng_128 */ - bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G); - bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G); + bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G); + bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G); if (bits_ng_1 > bits) { bits = bits_ng_1; } @@ -273,7 +341,7 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge bits = bits_ng_128; } #else - bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G); + bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G); if (bits_ng > bits) { bits = bits_ng; } @@ -281,37 +349,41 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge secp256k1_gej_set_infinity(r); - for (i = bits-1; i >= 0; i--) { + for (i = bits - 1; i >= 0; i--) { int n; - secp256k1_gej_double_var(r, r); + secp256k1_gej_double_var(r, r, NULL); #ifdef USE_ENDOMORPHISM if (i < bits_na_1 && (n = wnaf_na_1[i])) { - ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A); - secp256k1_gej_add_var(r, r, &tmpj); + ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); } if (i < bits_na_lam && (n = wnaf_na_lam[i])) { - ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_lam, n, WINDOW_A); - secp256k1_gej_add_var(r, r, &tmpj); + ECMULT_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); } if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); - secp256k1_gej_add_ge_var(r, r, &tmpa); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); } if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G); - secp256k1_gej_add_ge_var(r, r, &tmpa); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); } #else if (i < bits_na && (n = wnaf_na[i])) { - ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A); - secp256k1_gej_add_var(r, r, &tmpj); + ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); } if (i < bits_ng && (n = wnaf_ng[i])) { ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); - secp256k1_gej_add_ge_var(r, r, &tmpa); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); } #endif } + + if (!r->infinity) { + secp256k1_fe_mul(&r->z, &r->z, &Z); + } } #endif diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h index 41b280892..2d52af5e3 100644 --- a/src/secp256k1/src/field.h +++ b/src/secp256k1/src/field.h @@ -10,7 +10,7 @@ /** Field element module. * * Field elements can be represented in several ways, but code accessing - * it (and implementations) need to take certain properaties into account: + * it (and implementations) need to take certain properties into account: * - Each field element can be normalized or not. * - Each field element has a magnitude, which represents how far away * its representation is away from normalization. Normalized elements @@ -31,89 +31,91 @@ #endif /** Normalize a field element. */ -static void secp256k1_fe_normalize(secp256k1_fe_t *r); +static void secp256k1_fe_normalize(secp256k1_fe *r); /** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */ -static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r); +static void secp256k1_fe_normalize_weak(secp256k1_fe *r); /** Normalize a field element, without constant-time guarantee. */ -static void secp256k1_fe_normalize_var(secp256k1_fe_t *r); +static void secp256k1_fe_normalize_var(secp256k1_fe *r); /** Verify whether a field element represents zero i.e. would normalize to a zero value. The field * implementation may optionally normalize the input, but this should not be relied upon. */ -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r); +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r); /** Verify whether a field element represents zero i.e. would normalize to a zero value. The field * implementation may optionally normalize the input, but this should not be relied upon. */ -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r); +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r); /** Set a field element equal to a small integer. Resulting field element is normalized. */ -static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a); +static void secp256k1_fe_set_int(secp256k1_fe *r, int a); /** Verify whether a field element is zero. Requires the input to be normalized. */ -static int secp256k1_fe_is_zero(const secp256k1_fe_t *a); +static int secp256k1_fe_is_zero(const secp256k1_fe *a); /** Check the "oddness" of a field element. Requires the input to be normalized. */ -static int secp256k1_fe_is_odd(const secp256k1_fe_t *a); +static int secp256k1_fe_is_odd(const secp256k1_fe *a); /** Compare two field elements. Requires magnitude-1 inputs. */ -static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b); +static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); /** Compare two field elements. Requires both inputs to be normalized */ -static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b); +static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); -/** Set a field element equal to 32-byte big endian value. If succesful, the resulting field element is normalized. */ -static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a); +/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */ +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a); +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); /** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input * as an argument. The magnitude of the output is one higher. */ -static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m); +static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); /** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that * small integer. */ -static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a); +static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); /** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ -static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); /** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. * The output magnitude is 1 (but not guaranteed to be normalized). */ -static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b); +static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); /** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. * The output magnitude is 1 (but not guaranteed to be normalized). */ -static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); -/** Sets a field element to be the (modular) square root (if any exist) of another. Requires the - * input's magnitude to be at most 8. The output magnitude is 1 (but not guaranteed to be - * normalized). Return value indicates whether a square root was found. */ -static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a); +/** If a has a square root, it is computed in r and 1 is returned. If a does not + * have a square root, the root of its negation is computed and 0 is returned. + * The input's magnitude can be at most 8. The output magnitude is 1 (but not + * guaranteed to be normalized). The result in r will always be a square + * itself. */ +static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a); /** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ -static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a); /** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ -static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); /** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be * at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and * outputs must not overlap in memory. */ -static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a); /** Convert a field element to the storage type. */ -static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t*); +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); /** Convert a field element back from the storage type. */ -static void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t*); +static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ -static void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag); +static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag); /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ -static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag); +static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); #endif diff --git a/src/secp256k1/src/field_10x26.h b/src/secp256k1/src/field_10x26.h index 44bce6525..61ee1e096 100644 --- a/src/secp256k1/src/field_10x26.h +++ b/src/secp256k1/src/field_10x26.h @@ -16,20 +16,20 @@ typedef struct { int magnitude; int normalized; #endif -} secp256k1_fe_t; +} secp256k1_fe; /* Unpacks a constant into a overlapping multi-limbed FE element. */ #define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ (d0) & 0x3FFFFFFUL, \ - ((d0) >> 26) | ((d1) & 0xFFFFFUL) << 6, \ - ((d1) >> 20) | ((d2) & 0x3FFFUL) << 12, \ - ((d2) >> 14) | ((d3) & 0xFFUL) << 18, \ - ((d3) >> 8) | ((d4) & 0x3) << 24, \ - ((d4) >> 2) & 0x3FFFFFFUL, \ - ((d4) >> 28) | ((d5) & 0x3FFFFFUL) << 4, \ - ((d5) >> 22) | ((d6) & 0xFFFF) << 10, \ - ((d6) >> 16) | ((d7) & 0x3FF) << 16, \ - ((d7) >> 10) \ + (((uint32_t)d0) >> 26) | (((uint32_t)(d1) & 0xFFFFFUL) << 6), \ + (((uint32_t)d1) >> 20) | (((uint32_t)(d2) & 0x3FFFUL) << 12), \ + (((uint32_t)d2) >> 14) | (((uint32_t)(d3) & 0xFFUL) << 18), \ + (((uint32_t)d3) >> 8) | (((uint32_t)(d4) & 0x3UL) << 24), \ + (((uint32_t)d4) >> 2) & 0x3FFFFFFUL, \ + (((uint32_t)d4) >> 28) | (((uint32_t)(d5) & 0x3FFFFFUL) << 4), \ + (((uint32_t)d5) >> 22) | (((uint32_t)(d6) & 0xFFFFUL) << 10), \ + (((uint32_t)d6) >> 16) | (((uint32_t)(d7) & 0x3FFUL) << 16), \ + (((uint32_t)d7) >> 10) \ } #ifdef VERIFY @@ -40,8 +40,8 @@ typedef struct { typedef struct { uint32_t n[8]; -} secp256k1_fe_storage_t; +} secp256k1_fe_storage; #define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }} - +#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] #endif diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h index 871b91f91..212cc5396 100644 --- a/src/secp256k1/src/field_10x26_impl.h +++ b/src/secp256k1/src/field_10x26_impl.h @@ -14,7 +14,7 @@ #include "field.h" #ifdef VERIFY -static void secp256k1_fe_verify(const secp256k1_fe_t *a) { +static void secp256k1_fe_verify(const secp256k1_fe *a) { const uint32_t *d = a->n; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; r &= (d[0] <= 0x3FFFFFFUL * m); @@ -41,12 +41,12 @@ static void secp256k1_fe_verify(const secp256k1_fe_t *a) { VERIFY_CHECK(r == 1); } #else -static void secp256k1_fe_verify(const secp256k1_fe_t *a) { +static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; } #endif -static void secp256k1_fe_normalize(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -101,7 +101,7 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) { #endif } -static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -132,7 +132,7 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { #endif } -static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize_var(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -188,7 +188,7 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { #endif } -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -217,7 +217,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; uint32_t z0, z1; uint32_t x; @@ -252,7 +252,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { t9 &= 0x03FFFFFUL; t1 += (x << 6); - t1 += (t0 >> 26); t0 = z0; + t1 += (t0 >> 26); t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; @@ -269,7 +269,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { r->n[0] = a; 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; #ifdef VERIFY @@ -279,7 +279,7 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { #endif } -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { const uint32_t *t = a->n; #ifdef VERIFY VERIFY_CHECK(a->normalized); @@ -288,7 +288,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; } -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); secp256k1_fe_verify(a); @@ -296,7 +296,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { int i; #ifdef VERIFY a->magnitude = 0; @@ -307,7 +307,7 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { } } -static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { +static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { int i; #ifdef VERIFY VERIFY_CHECK(a->normalized); @@ -326,7 +326,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { int i; r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; @@ -350,7 +350,7 @@ static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { int i; #ifdef VERIFY VERIFY_CHECK(a->normalized); @@ -368,7 +368,7 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { } } -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) { +SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= m); secp256k1_fe_verify(a); @@ -390,7 +390,7 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp25 #endif } -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; @@ -408,7 +408,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { #endif } -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { #ifdef VERIFY secp256k1_fe_verify(a); #endif @@ -1039,7 +1039,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t } -static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) { +static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= 8); VERIFY_CHECK(b->magnitude <= 8); @@ -1055,7 +1055,7 @@ static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const s #endif } -static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= 8); secp256k1_fe_verify(a); @@ -1068,7 +1068,7 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { #endif } -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { +static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint32_t mask0, mask1; mask0 = flag + ~((uint32_t)0); mask1 = ~mask0; @@ -1083,12 +1083,14 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); #ifdef VERIFY - r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1); - r->normalized = (r->normalized & mask0) | (a->normalized & mask1); + if (a->magnitude > r->magnitude) { + r->magnitude = a->magnitude; + } + r->normalized &= a->normalized; #endif } -static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) { +static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { uint32_t mask0, mask1; mask0 = flag + ~((uint32_t)0); mask1 = ~mask0; @@ -1102,7 +1104,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); } -static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); #endif @@ -1116,7 +1118,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_f r->n[7] = a->n[8] >> 16 | a->n[9] << 10; } -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) { +static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { r->n[0] = a->n[0] & 0x3FFFFFFUL; r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL); r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL); diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h index 4513d36f4..8e69a560d 100644 --- a/src/secp256k1/src/field_5x52.h +++ b/src/secp256k1/src/field_5x52.h @@ -16,15 +16,15 @@ typedef struct { int magnitude; int normalized; #endif -} secp256k1_fe_t; +} secp256k1_fe; /* Unpacks a constant into a overlapping multi-limbed FE element. */ #define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ - (d0) | ((uint64_t)(d1) & 0xFFFFFUL) << 32, \ - ((d1) >> 20) | ((uint64_t)(d2)) << 12 | ((uint64_t)(d3) & 0xFFUL) << 44, \ - ((d3) >> 8) | ((uint64_t)(d4) & 0xFFFFFFFUL) << 24, \ - ((d4) >> 28) | ((uint64_t)(d5)) << 4 | ((uint64_t)(d6) & 0xFFFFUL) << 36, \ - ((d6) >> 16) | ((uint64_t)(d7)) << 16 \ + (d0) | (((uint64_t)(d1) & 0xFFFFFUL) << 32), \ + ((uint64_t)(d1) >> 20) | (((uint64_t)(d2)) << 12) | (((uint64_t)(d3) & 0xFFUL) << 44), \ + ((uint64_t)(d3) >> 8) | (((uint64_t)(d4) & 0xFFFFFFFUL) << 24), \ + ((uint64_t)(d4) >> 28) | (((uint64_t)(d5)) << 4) | (((uint64_t)(d6) & 0xFFFFUL) << 36), \ + ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \ } #ifdef VERIFY @@ -35,13 +35,13 @@ typedef struct { typedef struct { uint64_t n[4]; -} secp256k1_fe_storage_t; +} secp256k1_fe_storage; #define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \ - (d0) | ((uint64_t)(d1)) << 32, \ - (d2) | ((uint64_t)(d3)) << 32, \ - (d4) | ((uint64_t)(d5)) << 32, \ - (d6) | ((uint64_t)(d7)) << 32 \ + (d0) | (((uint64_t)(d1)) << 32), \ + (d2) | (((uint64_t)(d3)) << 32), \ + (d4) | (((uint64_t)(d5)) << 32), \ + (d6) | (((uint64_t)(d7)) << 32) \ }} #endif diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h index bda4c3dfc..b31e24ab8 100644 --- a/src/secp256k1/src/field_5x52_impl.h +++ b/src/secp256k1/src/field_5x52_impl.h @@ -31,7 +31,7 @@ */ #ifdef VERIFY -static void secp256k1_fe_verify(const secp256k1_fe_t *a) { +static void secp256k1_fe_verify(const secp256k1_fe *a) { const uint64_t *d = a->n; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ @@ -51,12 +51,12 @@ static void secp256k1_fe_verify(const secp256k1_fe_t *a) { VERIFY_CHECK(r == 1); } #else -static void secp256k1_fe_verify(const secp256k1_fe_t *a) { +static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; } #endif -static void secp256k1_fe_normalize(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -99,7 +99,7 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) { #endif } -static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -123,7 +123,7 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { #endif } -static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize_var(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -167,7 +167,7 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { #endif } -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ @@ -190,7 +190,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { uint64_t t0, t1, t2, t3, t4; uint64_t z0, z1; uint64_t x; @@ -219,7 +219,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { t4 &= 0x0FFFFFFFFFFFFULL; - t1 += (t0 >> 52); t0 = z0; + t1 += (t0 >> 52); t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; @@ -231,7 +231,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; #ifdef VERIFY @@ -241,7 +241,7 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { #endif } -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { const uint64_t *t = a->n; #ifdef VERIFY VERIFY_CHECK(a->normalized); @@ -250,7 +250,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; } -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); secp256k1_fe_verify(a); @@ -258,7 +258,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { int i; #ifdef VERIFY a->magnitude = 0; @@ -269,7 +269,7 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { } } -static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { +static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { int i; #ifdef VERIFY VERIFY_CHECK(a->normalized); @@ -288,7 +288,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { int i; r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; for (i=0; i<32; i++) { @@ -311,7 +311,7 @@ static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { int i; #ifdef VERIFY VERIFY_CHECK(a->normalized); @@ -329,7 +329,7 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { } } -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) { +SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= m); secp256k1_fe_verify(a); @@ -346,7 +346,7 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp25 #endif } -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; @@ -359,7 +359,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { #endif } -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { #ifdef VERIFY secp256k1_fe_verify(a); #endif @@ -375,7 +375,7 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1 #endif } -static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) { +static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= 8); VERIFY_CHECK(b->magnitude <= 8); @@ -391,7 +391,7 @@ static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const s #endif } -static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= 8); secp256k1_fe_verify(a); @@ -404,7 +404,7 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { #endif } -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { +static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint64_t mask0, mask1; mask0 = flag + ~((uint64_t)0); mask1 = ~mask0; @@ -414,12 +414,14 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); #ifdef VERIFY - r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1); - r->normalized = (r->normalized & mask0) | (a->normalized & mask1); + if (a->magnitude > r->magnitude) { + r->magnitude = a->magnitude; + } + r->normalized &= a->normalized; #endif } -static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) { +static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { uint64_t mask0, mask1; mask0 = flag + ~((uint64_t)0); mask1 = ~mask0; @@ -429,7 +431,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); } -static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); #endif @@ -439,7 +441,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_f r->n[3] = a->n[3] >> 36 | a->n[4] << 16; } -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) { +static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL; r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL); r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL); diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h index e6ec11e8f..77f4aae2f 100644 --- a/src/secp256k1/src/field_impl.h +++ b/src/secp256k1/src/field_impl.h @@ -21,15 +21,24 @@ #error "Please select field implementation" #endif -SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { - secp256k1_fe_t na; +SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe na; secp256k1_fe_negate(&na, a, 1); secp256k1_fe_add(&na, b); return secp256k1_fe_normalizes_to_zero_var(&na); } -static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { - secp256k1_fe_t x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; +static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) { + /** Given that p is congruent to 3 mod 4, we can compute the square root of + * a mod p as the (p+1)/4'th power of a. + * + * As (p+1)/4 is an even number, it will have the same result for a and for + * (-a). Only one of these two numbers actually has a square root however, + * so we test at the end by squaring and comparing to the input. + * Also because (p+1)/4 is an even number, the computed square root is + * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). + */ + secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; int j; /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in @@ -117,8 +126,8 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { return secp256k1_fe_equal_var(&t1, a); } -static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) { - secp256k1_fe_t x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; +static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) { + secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; int j; /** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in @@ -207,11 +216,15 @@ static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) { secp256k1_fe_mul(r, a, &t1); } -static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) { #if defined(USE_FIELD_INV_BUILTIN) secp256k1_fe_inv(r, a); #elif defined(USE_FIELD_INV_NUM) - secp256k1_num_t n, m; + secp256k1_num n, m; + static const secp256k1_fe negone = SECP256K1_FE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xFFFFFC2EUL + ); /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ static const unsigned char prime[32] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, @@ -220,21 +233,28 @@ static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F }; unsigned char b[32]; - secp256k1_fe_t c = *a; + int res; + secp256k1_fe c = *a; secp256k1_fe_normalize_var(&c); secp256k1_fe_get_b32(b, &c); secp256k1_num_set_bin(&n, b, 32); secp256k1_num_set_bin(&m, prime, 32); secp256k1_num_mod_inverse(&n, &n, &m); secp256k1_num_get_bin(b, 32, &n); - VERIFY_CHECK(secp256k1_fe_set_b32(r, b)); + res = secp256k1_fe_set_b32(r, b); + (void)res; + VERIFY_CHECK(res); + /* Verify the result is the (unique) valid inverse using non-GMP code. */ + secp256k1_fe_mul(&c, &c, r); + secp256k1_fe_add(&c, &negone); + CHECK(secp256k1_fe_normalizes_to_zero_var(&c)); #else #error "Please select field inverse implementation" #endif } -static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a) { - secp256k1_fe_t u; +static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a) { + secp256k1_fe u; size_t i; if (len < 1) { return; @@ -252,7 +272,7 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp25 secp256k1_fe_inv_var(&u, &r[--i]); while (i > 0) { - int j = i--; + size_t j = i--; secp256k1_fe_mul(&r[j], &r[i], &u); secp256k1_fe_mul(&u, &u, &a[j]); } diff --git a/src/secp256k1/src/gen_context.c b/src/secp256k1/src/gen_context.c new file mode 100644 index 000000000..1835fd491 --- /dev/null +++ b/src/secp256k1/src/gen_context.c @@ -0,0 +1,74 @@ +/********************************************************************** + * Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#define USE_BASIC_CONFIG 1 + +#include "basic-config.h" +#include "include/secp256k1.h" +#include "field_impl.h" +#include "scalar_impl.h" +#include "group_impl.h" +#include "ecmult_gen_impl.h" + +static void default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} + +static const secp256k1_callback default_error_callback = { + default_error_callback_fn, + NULL +}; + +int main(int argc, char **argv) { + secp256k1_ecmult_gen_context ctx; + int inner; + int outer; + FILE* fp; + + (void)argc; + (void)argv; + + fp = fopen("src/ecmult_static_context.h","w"); + if (fp == NULL) { + fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n"); + return -1; + } + + fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); + fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); + fprintf(fp, "#include \"group.h\"\n"); + fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n"); + fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n"); + + secp256k1_ecmult_gen_context_init(&ctx); + secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback); + for(outer = 0; outer != 64; outer++) { + fprintf(fp,"{\n"); + for(inner = 0; inner != 16; inner++) { + 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])); + if (inner != 15) { + fprintf(fp,",\n"); + } else { + fprintf(fp,"\n"); + } + } + if (outer != 63) { + fprintf(fp,"},\n"); + } else { + fprintf(fp,"}\n"); + } + } + fprintf(fp,"};\n"); + secp256k1_ecmult_gen_context_clear(&ctx); + + fprintf(fp, "#undef SC\n"); + fprintf(fp, "#endif\n"); + fclose(fp); + + return 0; +} diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h index 0b08b3b99..ebfe1ca70 100644 --- a/src/secp256k1/src/group.h +++ b/src/secp256k1/src/group.h @@ -12,110 +12,130 @@ /** A group element of the secp256k1 curve, in affine coordinates. */ typedef struct { - secp256k1_fe_t x; - secp256k1_fe_t y; + secp256k1_fe x; + secp256k1_fe y; int infinity; /* whether this represents the point at infinity */ -} secp256k1_ge_t; +} secp256k1_ge; #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} #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} /** A group element of the secp256k1 curve, in jacobian coordinates. */ typedef struct { - secp256k1_fe_t x; /* actual X: x/z^2 */ - secp256k1_fe_t y; /* actual Y: y/z^3 */ - secp256k1_fe_t z; + secp256k1_fe x; /* actual X: x/z^2 */ + secp256k1_fe y; /* actual Y: y/z^3 */ + secp256k1_fe z; int infinity; /* whether this represents the point at infinity */ -} secp256k1_gej_t; +} secp256k1_gej; #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} #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} typedef struct { - secp256k1_fe_storage_t x; - secp256k1_fe_storage_t y; -} secp256k1_ge_storage_t; + secp256k1_fe_storage x; + secp256k1_fe_storage y; +} secp256k1_ge_storage; #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))} -/** Set a group element equal to the point at infinity */ -static void secp256k1_ge_set_infinity(secp256k1_ge_t *r); +#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) /** Set a group element equal to the point with given X and Y coordinates */ -static void secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y); +static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y); + +/** Set a group element (affine) equal to the point with the given X coordinate + * and a Y coordinate that is a quadratic residue modulo p. The return value + * is true iff a coordinate with the given X coordinate exists. + */ +static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x); /** Set a group element (affine) equal to the point with the given X coordinate, and given oddness * for Y. Return value indicates whether the result is valid. */ -static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd); +static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd); /** Check whether a group element is the point at infinity. */ -static int secp256k1_ge_is_infinity(const secp256k1_ge_t *a); +static int secp256k1_ge_is_infinity(const secp256k1_ge *a); /** Check whether a group element is valid (i.e., on the curve). */ -static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a); +static int secp256k1_ge_is_valid_var(const secp256k1_ge *a); -static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a); +static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a); /** Set a group element equal to another which is given in jacobian coordinates */ -static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a); +static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a); /** Set a batch of group elements equal to the inputs given in jacobian coordinates */ -static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a); +static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb); +/** Set a batch of group elements equal to the inputs given in jacobian + * coordinates (with known z-ratios). zr must contain the known z-ratios such + * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */ +static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr); + +/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to + * the same global z "denominator". zr must contain the known z-ratios such + * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y + * coordinates of the result are stored in r, the common z coordinate is + * stored in globalz. */ +static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr); /** Set a group element (jacobian) equal to the point at infinity. */ -static void secp256k1_gej_set_infinity(secp256k1_gej_t *r); - -/** Set a group element (jacobian) equal to the point with given X and Y coordinates. */ -static void secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y); +static void secp256k1_gej_set_infinity(secp256k1_gej *r); /** Set a group element (jacobian) equal to another which is given in affine coordinates. */ -static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a); +static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a); /** Compare the X coordinate of a group element (jacobian). */ -static int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a); +static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a); /** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ -static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a); +static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a); /** Check whether a group element is the point at infinity. */ -static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a); +static int secp256k1_gej_is_infinity(const secp256k1_gej *a); -/** Set r equal to the double of a. */ -static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a); +/** 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). + * a may not be zero. Constant time. */ +static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); -/** Set r equal to the sum of a and b. */ -static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b); +/** 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). */ +static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); + +/** 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). */ +static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr); /** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */ -static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b); +static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b); /** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time - guarantee, and b is allowed to be infinity. */ -static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b); + 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). */ +static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr); + +/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */ +static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv); #ifdef USE_ENDOMORPHISM /** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ -static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a); +static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a); #endif -/** Clear a secp256k1_gej_t to prevent leaking sensitive information. */ -static void secp256k1_gej_clear(secp256k1_gej_t *r); +/** Clear a secp256k1_gej to prevent leaking sensitive information. */ +static void secp256k1_gej_clear(secp256k1_gej *r); -/** Clear a secp256k1_ge_t to prevent leaking sensitive information. */ -static void secp256k1_ge_clear(secp256k1_ge_t *r); +/** Clear a secp256k1_ge to prevent leaking sensitive information. */ +static void secp256k1_ge_clear(secp256k1_ge *r); /** Convert a group element to the storage type. */ -static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t*); +static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a); /** Convert a group element back from the storage type. */ -static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_storage_t*); +static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a); /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ -static void secp256k1_ge_storage_cmov(secp256k1_ge_storage_t *r, const secp256k1_ge_storage_t *a, int flag); +static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag); /** Rescale a jacobian point by b which must be non-zero. Constant-time. */ -static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *b); +static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); #endif diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h index 0f64576fb..42e2f6e6e 100644 --- a/src/secp256k1/src/group_impl.h +++ b/src/secp256k1/src/group_impl.h @@ -16,35 +16,41 @@ /** Generator for secp256k1, value 'g' defined in * "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ -static const secp256k1_ge_t secp256k1_ge_const_g = SECP256K1_GE_CONST( +static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( 0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL, 0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL, 0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL, 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL ); -static void secp256k1_ge_set_infinity(secp256k1_ge_t *r) { - r->infinity = 1; +static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { + secp256k1_fe zi2; + secp256k1_fe zi3; + secp256k1_fe_sqr(&zi2, zi); + secp256k1_fe_mul(&zi3, &zi2, zi); + secp256k1_fe_mul(&r->x, &a->x, &zi2); + secp256k1_fe_mul(&r->y, &a->y, &zi3); + r->infinity = a->infinity; } -static void secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) { +static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) { r->infinity = 0; r->x = *x; r->y = *y; } -static int secp256k1_ge_is_infinity(const secp256k1_ge_t *a) { +static int secp256k1_ge_is_infinity(const secp256k1_ge *a) { return a->infinity; } -static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a) { +static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) { *r = *a; secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); } -static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) { - secp256k1_fe_t z2, z3; +static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { + secp256k1_fe z2, z3; r->infinity = a->infinity; secp256k1_fe_inv(&a->z, &a->z); secp256k1_fe_sqr(&z2, &a->z); @@ -56,8 +62,8 @@ static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) { r->y = a->y; } -static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) { - secp256k1_fe_t z2, z3; +static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { + secp256k1_fe z2, z3; r->infinity = a->infinity; if (a->infinity) { return; @@ -72,19 +78,19 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) { r->y = a->y; } -static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a) { - secp256k1_fe_t *az; - secp256k1_fe_t *azi; +static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb) { + secp256k1_fe *az; + secp256k1_fe *azi; size_t i; size_t count = 0; - az = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * len); + az = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * len); for (i = 0; i < len; i++) { if (!a[i].infinity) { az[count++] = a[i].z; } } - azi = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * count); + azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count); secp256k1_fe_inv_all_var(count, azi, az); free(az); @@ -92,53 +98,86 @@ static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const se for (i = 0; i < len; i++) { r[i].infinity = a[i].infinity; if (!a[i].infinity) { - secp256k1_fe_t zi2, zi3; - secp256k1_fe_t *zi = &azi[count++]; - secp256k1_fe_sqr(&zi2, zi); - secp256k1_fe_mul(&zi3, &zi2, zi); - secp256k1_fe_mul(&r[i].x, &a[i].x, &zi2); - secp256k1_fe_mul(&r[i].y, &a[i].y, &zi3); + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]); } } free(azi); } -static void secp256k1_gej_set_infinity(secp256k1_gej_t *r) { +static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr) { + size_t i = len - 1; + secp256k1_fe zi; + + if (len > 0) { + /* Compute the inverse of the last z coordinate, and use it to compute the last affine output. */ + secp256k1_fe_inv(&zi, &a[i].z); + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi); + + /* Work out way backwards, using the z-ratios to scale the x/y values. */ + while (i > 0) { + secp256k1_fe_mul(&zi, &zi, &zr[i]); + i--; + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi); + } + } +} + +static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr) { + size_t i = len - 1; + secp256k1_fe zs; + + if (len > 0) { + /* The z of the final point gives us the "global Z" for the table. */ + r[i].x = a[i].x; + r[i].y = a[i].y; + *globalz = a[i].z; + r[i].infinity = 0; + zs = zr[i]; + + /* Work our way backwards, using the z-ratios to scale the x/y values. */ + while (i > 0) { + if (i != len - 1) { + secp256k1_fe_mul(&zs, &zs, &zr[i]); + } + i--; + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zs); + } + } +} + +static void secp256k1_gej_set_infinity(secp256k1_gej *r) { r->infinity = 1; secp256k1_fe_set_int(&r->x, 0); secp256k1_fe_set_int(&r->y, 0); secp256k1_fe_set_int(&r->z, 0); } -static void secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) { - r->infinity = 0; - r->x = *x; - r->y = *y; - secp256k1_fe_set_int(&r->z, 1); -} - -static void secp256k1_gej_clear(secp256k1_gej_t *r) { +static void secp256k1_gej_clear(secp256k1_gej *r) { r->infinity = 0; secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); secp256k1_fe_clear(&r->z); } -static void secp256k1_ge_clear(secp256k1_ge_t *r) { +static void secp256k1_ge_clear(secp256k1_ge *r) { r->infinity = 0; secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); } -static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd) { - secp256k1_fe_t x2, x3, c; +static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x) { + secp256k1_fe x2, x3, c; r->x = *x; secp256k1_fe_sqr(&x2, x); secp256k1_fe_mul(&x3, x, &x2); r->infinity = 0; secp256k1_fe_set_int(&c, 7); secp256k1_fe_add(&c, &x3); - if (!secp256k1_fe_sqrt_var(&r->y, &c)) { + return secp256k1_fe_sqrt_var(&r->y, &c); +} + +static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { + if (!secp256k1_ge_set_xquad_var(r, x)) { return 0; } secp256k1_fe_normalize_var(&r->y); @@ -146,24 +185,25 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, i secp256k1_fe_negate(&r->y, &r->y, 1); } return 1; + } -static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a) { +static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { r->infinity = a->infinity; r->x = a->x; r->y = a->y; secp256k1_fe_set_int(&r->z, 1); } -static int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a) { - secp256k1_fe_t r, r2; +static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) { + secp256k1_fe r, r2; VERIFY_CHECK(!a->infinity); secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); r2 = a->x; secp256k1_fe_normalize_weak(&r2); return secp256k1_fe_equal_var(&r, &r2); } -static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) { +static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) { r->infinity = a->infinity; r->x = a->x; r->y = a->y; @@ -172,12 +212,12 @@ static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) { secp256k1_fe_negate(&r->y, &r->y, 1); } -static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a) { +static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { return a->infinity; } -static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) { - secp256k1_fe_t y2, x3, z2, z6; +static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) { + secp256k1_fe y2, x3, z2, z6; if (a->infinity) { return 0; } @@ -196,8 +236,8 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) { return secp256k1_fe_equal_var(&y2, &x3); } -static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a) { - secp256k1_fe_t y2, x3, c; +static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { + secp256k1_fe y2, x3, c; if (a->infinity) { return 0; } @@ -210,18 +250,27 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a) { return secp256k1_fe_equal_var(&y2, &x3); } -static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a) { +static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate */ - secp256k1_fe_t t1,t2,t3,t4; + secp256k1_fe t1,t2,t3,t4; /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, * 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 * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. */ r->infinity = a->infinity; if (r->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } return; } + if (rzr != NULL) { + *rzr = a->y; + secp256k1_fe_normalize_weak(rzr); + secp256k1_fe_mul_int(rzr, 2); + } + secp256k1_fe_mul(&r->z, &a->z, &a->y); secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */ secp256k1_fe_sqr(&t1, &a->x); @@ -244,17 +293,29 @@ static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t * secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */ } -static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b) { +static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { + VERIFY_CHECK(!secp256k1_gej_is_infinity(a)); + secp256k1_gej_double_var(r, a, rzr); +} + +static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) { /* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */ - secp256k1_fe_t z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + if (a->infinity) { + VERIFY_CHECK(rzr == NULL); *r = *b; return; } + if (b->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } *r = *a; return; } + r->infinity = 0; secp256k1_fe_sqr(&z22, &b->z); secp256k1_fe_sqr(&z12, &a->z); @@ -266,8 +327,11 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); if (secp256k1_fe_normalizes_to_zero_var(&h)) { if (secp256k1_fe_normalizes_to_zero_var(&i)) { - secp256k1_gej_double_var(r, a); + secp256k1_gej_double_var(r, a, rzr); } else { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 0); + } r->infinity = 1; } return; @@ -275,7 +339,11 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, secp256k1_fe_sqr(&i2, &i); secp256k1_fe_sqr(&h2, &h); secp256k1_fe_mul(&h3, &h, &h2); - secp256k1_fe_mul(&r->z, &a->z, &b->z); secp256k1_fe_mul(&r->z, &r->z, &h); + secp256k1_fe_mul(&h, &h, &b->z); + if (rzr != NULL) { + *rzr = h; + } + secp256k1_fe_mul(&r->z, &a->z, &h); secp256k1_fe_mul(&t, &u1, &h2); 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); secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); @@ -283,21 +351,23 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, secp256k1_fe_add(&r->y, &h3); } -static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) { +static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) { /* 8 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ - secp256k1_fe_t z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + secp256k1_fe z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; if (a->infinity) { - r->infinity = b->infinity; - r->x = b->x; - r->y = b->y; - secp256k1_fe_set_int(&r->z, 1); + VERIFY_CHECK(rzr == NULL); + secp256k1_gej_set_ge(r, b); return; } if (b->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } *r = *a; return; } r->infinity = 0; + secp256k1_fe_sqr(&z12, &a->z); u1 = a->x; secp256k1_fe_normalize_weak(&u1); secp256k1_fe_mul(&u2, &b->x, &z12); @@ -307,7 +377,69 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t * secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); if (secp256k1_fe_normalizes_to_zero_var(&h)) { if (secp256k1_fe_normalizes_to_zero_var(&i)) { - secp256k1_gej_double_var(r, a); + secp256k1_gej_double_var(r, a, rzr); + } else { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 0); + } + r->infinity = 1; + } + return; + } + secp256k1_fe_sqr(&i2, &i); + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_mul(&h3, &h, &h2); + if (rzr != NULL) { + *rzr = h; + } + secp256k1_fe_mul(&r->z, &a->z, &h); + secp256k1_fe_mul(&t, &u1, &h2); + 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); + secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); + secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); + secp256k1_fe_add(&r->y, &h3); +} + +static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) { + /* 9 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ + secp256k1_fe az, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + + if (b->infinity) { + *r = *a; + return; + } + if (a->infinity) { + secp256k1_fe bzinv2, bzinv3; + r->infinity = b->infinity; + secp256k1_fe_sqr(&bzinv2, bzinv); + secp256k1_fe_mul(&bzinv3, &bzinv2, bzinv); + secp256k1_fe_mul(&r->x, &b->x, &bzinv2); + secp256k1_fe_mul(&r->y, &b->y, &bzinv3); + secp256k1_fe_set_int(&r->z, 1); + return; + } + r->infinity = 0; + + /** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to + * secp256k1's isomorphism we can multiply the Z coordinates on both sides + * by bzinv, and get: (rx,ry,rz*bzinv) = (ax,ay,az*bzinv) + (bx,by,1). + * This means that (rx,ry,rz) can be calculated as + * (ax,ay,az*bzinv) + (bx,by,1), when not applying the bzinv factor to rz. + * The variable az below holds the modified Z coordinate for a, which is used + * for the computation of rx and ry, but not for rz. + */ + secp256k1_fe_mul(&az, &a->z, bzinv); + + secp256k1_fe_sqr(&z12, &az); + u1 = a->x; secp256k1_fe_normalize_weak(&u1); + secp256k1_fe_mul(&u2, &b->x, &z12); + s1 = a->y; secp256k1_fe_normalize_weak(&s1); + secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az); + secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { + secp256k1_gej_double_var(r, a, NULL); } else { r->infinity = 1; } @@ -324,11 +456,13 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t * secp256k1_fe_add(&r->y, &h3); } -static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) { - /* Operations: 7 mul, 5 sqr, 5 normalize, 17 mul_int/add/negate/cmov */ - static const secp256k1_fe_t fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_fe_t zz, u1, u2, s1, s2, z, t, m, n, q, rr; - int infinity; + +static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) { + /* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */ + static const secp256k1_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; + secp256k1_fe m_alt, rr_alt; + int infinity, degenerate; VERIFY_CHECK(!b->infinity); VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); @@ -352,53 +486,102 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c * Y3 = 4*(R*(3*Q-2*R^2)-M^4) * Z3 = 2*M*Z * (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.) + * + * This formula has the benefit of being the same for both addition + * of distinct points and doubling. However, it breaks down in the + * case that either point is infinity, or that y1 = -y2. We handle + * these cases in the following ways: + * + * - If b is infinity we simply bail by means of a VERIFY_CHECK. + * + * - If a is infinity, we detect this, and at the end of the + * computation replace the result (which will be meaningless, + * but we compute to be constant-time) with b.x : b.y : 1. + * + * - If a = -b, we have y1 = -y2, which is a degenerate case. + * But here the answer is infinity, so we simply set the + * infinity flag of the result, overriding the computed values + * without even needing to cmov. + * + * - If y1 = -y2 but x1 != x2, which does occur thanks to certain + * properties of our curve (specifically, 1 has nontrivial cube + * roots in our field, and the curve equation has no x coefficient) + * then the answer is not infinity but also not given by the above + * equation. In this case, we cmov in place an alternate expression + * for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these + * expressions for lambda are defined, they are equal, and can be + * obtained from each other by multiplication by (y1 + y2)/(y1 + y2) + * then substitution of x^3 + 7 for y^2 (using the curve equation). + * For all pairs of nonzero points (a, b) at least one is defined, + * so this covers everything. */ secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */ u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */ secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ - secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z2^2 (1) */ + secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */ secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ - z = a->z; /* z = Z = Z1*Z2 (8) */ t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */ m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */ - secp256k1_fe_sqr(&n, &m); /* n = M^2 (1) */ - secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*M^2 (1) */ - secp256k1_fe_sqr(&n, &n); /* n = M^4 (1) */ secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */ - secp256k1_fe_mul(&t, &u1, &u2); secp256k1_fe_negate(&t, &t, 1); /* t = -U1*U2 (2) */ - secp256k1_fe_add(&rr, &t); /* rr = R = T^2-U1*U2 (3) */ - secp256k1_fe_sqr(&t, &rr); /* t = R^2 (1) */ - secp256k1_fe_mul(&r->z, &m, &z); /* r->z = M*Z (1) */ - infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity); - secp256k1_fe_mul_int(&r->z, 2 * (1 - a->infinity)); /* r->z = Z3 = 2*M*Z (2) */ - r->x = t; /* r->x = R^2 (1) */ - secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */ - secp256k1_fe_add(&r->x, &q); /* r->x = R^2-Q (3) */ - secp256k1_fe_normalize(&r->x); - secp256k1_fe_mul_int(&q, 3); /* q = -3*Q (6) */ - secp256k1_fe_mul_int(&t, 2); /* t = 2*R^2 (2) */ - secp256k1_fe_add(&t, &q); /* t = 2*R^2-3*Q (8) */ - secp256k1_fe_mul(&t, &t, &rr); /* t = R*(2*R^2-3*Q) (1) */ - secp256k1_fe_add(&t, &n); /* t = R*(2*R^2-3*Q)+M^4 (2) */ - secp256k1_fe_negate(&r->y, &t, 2); /* r->y = R*(3*Q-2*R^2)-M^4 (3) */ - secp256k1_fe_normalize_weak(&r->y); - secp256k1_fe_mul_int(&r->x, 4 * (1 - a->infinity)); /* r->x = X3 = 4*(R^2-Q) */ - secp256k1_fe_mul_int(&r->y, 4 * (1 - a->infinity)); /* r->y = Y3 = 4*R*(3*Q-2*R^2)-4*M^4 (4) */ + secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */ + secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */ + secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */ + /** If lambda = R/M = 0/0 we have a problem (except in the "trivial" + * case that Z = z1z2 = 0, and this is special-cased later on). */ + degenerate = secp256k1_fe_normalizes_to_zero(&m) & + secp256k1_fe_normalizes_to_zero(&rr); + /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. + * This means either x1 == beta*x2 or beta*x1 == x2, where beta is + * a nontrivial cube root of one. In either case, an alternate + * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2), + * so we set R/M equal to this. */ + rr_alt = s1; + secp256k1_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */ + secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */ - /** In case a->infinity == 1, the above code results in r->x, r->y, and r->z all equal to 0. - * Replace r with b->x, b->y, 1 in that case. - */ + secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); + secp256k1_fe_cmov(&m_alt, &m, !degenerate); + /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0. + * From here on out Ralt and Malt represent the numerator + * and denominator of lambda; R and M represent the explicit + * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ + secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */ + secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*Malt^2 (1) */ + /* These two lines use the observation that either M == Malt or M == 0, + * so M^3 * Malt is either Malt^4 (which is computed by squaring), or + * zero (which is "computed" by cmov). So the cost is one squaring + * versus two multiplications. */ + secp256k1_fe_sqr(&n, &n); + secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */ + secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ + secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */ + infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity); + secp256k1_fe_mul_int(&r->z, 2); /* r->z = Z3 = 2*Malt*Z (2) */ + secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */ + secp256k1_fe_add(&t, &q); /* t = Ralt^2-Q (3) */ + secp256k1_fe_normalize_weak(&t); + r->x = t; /* r->x = Ralt^2-Q (1) */ + secp256k1_fe_mul_int(&t, 2); /* t = 2*x3 (2) */ + secp256k1_fe_add(&t, &q); /* t = 2*x3 - Q: (4) */ + secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*x3 - Q) (1) */ + secp256k1_fe_add(&t, &n); /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */ + secp256k1_fe_negate(&r->y, &t, 3); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */ + secp256k1_fe_normalize_weak(&r->y); + secp256k1_fe_mul_int(&r->x, 4); /* r->x = X3 = 4*(Ralt^2-Q) */ + secp256k1_fe_mul_int(&r->y, 4); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */ + + /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */ secp256k1_fe_cmov(&r->x, &b->x, a->infinity); secp256k1_fe_cmov(&r->y, &b->y, a->infinity); secp256k1_fe_cmov(&r->z, &fe_1, a->infinity); r->infinity = infinity; } -static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *s) { +static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { /* Operations: 4 mul, 1 sqr */ - secp256k1_fe_t zz; + secp256k1_fe zz; VERIFY_CHECK(!secp256k1_fe_is_zero(s)); secp256k1_fe_sqr(&zz, s); secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ @@ -407,8 +590,8 @@ static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *s) { secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ } -static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t *a) { - secp256k1_fe_t x, y; +static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) { + secp256k1_fe x, y; VERIFY_CHECK(!a->infinity); x = a->x; secp256k1_fe_normalize(&x); @@ -418,20 +601,20 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_g secp256k1_fe_to_storage(&r->y, &y); } -static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_storage_t *a) { +static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a) { secp256k1_fe_from_storage(&r->x, &a->x); secp256k1_fe_from_storage(&r->y, &a->y); r->infinity = 0; } -static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage_t *r, const secp256k1_ge_storage_t *a, int flag) { +static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) { secp256k1_fe_storage_cmov(&r->x, &a->x, flag); secp256k1_fe_storage_cmov(&r->y, &a->y, flag); } #ifdef USE_ENDOMORPHISM -static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a) { - static const secp256k1_fe_t beta = SECP256K1_FE_CONST( +static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { + static const secp256k1_fe beta = SECP256K1_FE_CONST( 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul ); diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h index 843423d7f..0ff01e63f 100644 --- a/src/secp256k1/src/hash.h +++ b/src/secp256k1/src/hash.h @@ -34,7 +34,7 @@ typedef struct { int retry; } secp256k1_rfc6979_hmac_sha256_t; -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen, const unsigned char *msg, size_t msglen, const unsigned char *rnd, size_t rndlen); +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen); static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen); static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng); diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h index 9828827bc..ae55df6d8 100644 --- a/src/secp256k1/src/hash_impl.h +++ b/src/secp256k1/src/hash_impl.h @@ -202,7 +202,7 @@ static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsign } -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen, const unsigned char *msg, size_t msglen, const unsigned char *rnd, size_t rndlen) { +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen) { secp256k1_hmac_sha256_t hmac; static const unsigned char zero[1] = {0x00}; static const unsigned char one[1] = {0x01}; @@ -215,11 +215,6 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, zero, 1); secp256k1_hmac_sha256_write(&hmac, key, keylen); - secp256k1_hmac_sha256_write(&hmac, msg, msglen); - if (rnd && rndlen) { - /* RFC6979 3.6 "Additional data". */ - secp256k1_hmac_sha256_write(&hmac, rnd, rndlen); - } secp256k1_hmac_sha256_finalize(&hmac, rng->k); secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); @@ -230,11 +225,6 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, one, 1); secp256k1_hmac_sha256_write(&hmac, key, keylen); - secp256k1_hmac_sha256_write(&hmac, msg, msglen); - if (rnd && rndlen) { - /* RFC6979 3.6 "Additional data". */ - secp256k1_hmac_sha256_write(&hmac, rnd, rndlen); - } secp256k1_hmac_sha256_finalize(&hmac, rng->k); secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); diff --git a/src/secp256k1/src/modules/ecdh/Makefile.am.include b/src/secp256k1/src/modules/ecdh/Makefile.am.include new file mode 100644 index 000000000..670b9c115 --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_ecdh.h +noinst_HEADERS += src/modules/ecdh/main_impl.h +noinst_HEADERS += src/modules/ecdh/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_ecdh +bench_ecdh_SOURCES = src/bench_ecdh.c +bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) +endif diff --git a/src/secp256k1/src/modules/ecdh/main_impl.h b/src/secp256k1/src/modules/ecdh/main_impl.h new file mode 100644 index 000000000..c23e4f82f --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/main_impl.h @@ -0,0 +1,54 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_ECDH_MAIN_ +#define _SECP256K1_MODULE_ECDH_MAIN_ + +#include "include/secp256k1_ecdh.h" +#include "ecmult_const_impl.h" + +int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) { + int ret = 0; + int overflow = 0; + secp256k1_gej res; + secp256k1_ge pt; + secp256k1_scalar s; + ARG_CHECK(result != NULL); + ARG_CHECK(point != NULL); + ARG_CHECK(scalar != NULL); + (void)ctx; + + secp256k1_pubkey_load(ctx, &pt, point); + secp256k1_scalar_set_b32(&s, scalar, &overflow); + if (overflow || secp256k1_scalar_is_zero(&s)) { + ret = 0; + } else { + unsigned char x[32]; + unsigned char y[1]; + secp256k1_sha256_t sha; + + secp256k1_ecmult_const(&res, &pt, &s); + secp256k1_ge_set_gej(&pt, &res); + /* Compute a hash of the point in compressed form + * Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not + * expect its output to be secret and has a timing sidechannel. */ + secp256k1_fe_normalize(&pt.x); + secp256k1_fe_normalize(&pt.y); + secp256k1_fe_get_b32(x, &pt.x); + y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y); + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, y, sizeof(y)); + secp256k1_sha256_write(&sha, x, sizeof(x)); + secp256k1_sha256_finalize(&sha, result); + ret = 1; + } + + secp256k1_scalar_clear(&s); + return ret; +} + +#endif diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h new file mode 100644 index 000000000..7badc9033 --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/tests_impl.h @@ -0,0 +1,75 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_ECDH_TESTS_ +#define _SECP256K1_MODULE_ECDH_TESTS_ + +void test_ecdh_generator_basepoint(void) { + unsigned char s_one[32] = { 0 }; + secp256k1_pubkey point[2]; + int i; + + s_one[31] = 1; + /* Check against pubkey creation when the basepoint is the generator */ + for (i = 0; i < 100; ++i) { + secp256k1_sha256_t sha; + unsigned char s_b32[32]; + unsigned char output_ecdh[32]; + unsigned char output_ser[32]; + unsigned char point_ser[33]; + size_t point_ser_len = sizeof(point_ser); + secp256k1_scalar s; + + random_scalar_order(&s); + secp256k1_scalar_get_b32(s_b32, &s); + + /* compute using ECDH function */ + CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1); + CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1); + /* compute "explicitly" */ + CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); + CHECK(point_ser_len == sizeof(point_ser)); + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, point_ser, point_ser_len); + secp256k1_sha256_finalize(&sha, output_ser); + /* compare */ + CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0); + } +} + +void test_bad_scalar(void) { + unsigned char s_zero[32] = { 0 }; + unsigned char s_overflow[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + unsigned char s_rand[32] = { 0 }; + unsigned char output[32]; + secp256k1_scalar rand; + secp256k1_pubkey point; + + /* Create random point */ + random_scalar_order(&rand); + secp256k1_scalar_get_b32(s_rand, &rand); + CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1); + + /* Try to multiply it by bad values */ + CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0); + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0); + /* ...and a good one */ + s_overflow[31] -= 1; + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1); +} + +void run_ecdh_tests(void) { + test_ecdh_generator_basepoint(); + test_bad_scalar(); +} + +#endif diff --git a/src/secp256k1/src/modules/recovery/Makefile.am.include b/src/secp256k1/src/modules/recovery/Makefile.am.include new file mode 100644 index 000000000..5de3ea33e --- /dev/null +++ b/src/secp256k1/src/modules/recovery/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_recovery.h +noinst_HEADERS += src/modules/recovery/main_impl.h +noinst_HEADERS += src/modules/recovery/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_recover +bench_recover_SOURCES = src/bench_recover.c +bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) +endif diff --git a/src/secp256k1/src/modules/recovery/main_impl.h b/src/secp256k1/src/modules/recovery/main_impl.h new file mode 100644 index 000000000..ec42f4bb6 --- /dev/null +++ b/src/secp256k1/src/modules/recovery/main_impl.h @@ -0,0 +1,193 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_RECOVERY_MAIN_ +#define _SECP256K1_MODULE_RECOVERY_MAIN_ + +#include "include/secp256k1_recovery.h" + +static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) { + (void)ctx; + if (sizeof(secp256k1_scalar) == 32) { + /* When the secp256k1_scalar type is exactly 32 byte, use its + * representation inside secp256k1_ecdsa_signature, as conversion is very fast. + * Note that secp256k1_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + secp256k1_scalar_set_b32(r, &sig->data[0], NULL); + secp256k1_scalar_set_b32(s, &sig->data[32], NULL); + } + *recid = sig->data[64]; +} + +static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s, int recid) { + if (sizeof(secp256k1_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + secp256k1_scalar_get_b32(&sig->data[0], r); + secp256k1_scalar_get_b32(&sig->data[32], s); + } + sig->data[64] = recid; +} + +int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) { + secp256k1_scalar r, s; + int ret = 1; + int overflow = 0; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + ARG_CHECK(recid >= 0 && recid <= 3); + + secp256k1_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig) { + secp256k1_scalar r, s; + + (void)ctx; + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(recid != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig); + secp256k1_scalar_get_b32(&output64[0], &r); + secp256k1_scalar_get_b32(&output64[32], &s); + return 1; +} + +int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const secp256k1_ecdsa_recoverable_signature* sigin) { + secp256k1_scalar r, s; + int recid; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin); + secp256k1_ecdsa_signature_save(sig, &r, &s); + return 1; +} + +static 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) { + unsigned char brx[32]; + secp256k1_fe fx; + secp256k1_ge x; + secp256k1_gej xj; + secp256k1_scalar rn, u1, u2; + secp256k1_gej qj; + int r; + + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { + return 0; + } + + secp256k1_scalar_get_b32(brx, sigr); + r = secp256k1_fe_set_b32(&fx, brx); + (void)r; + VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */ + if (recid & 2) { + if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { + return 0; + } + secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe); + } + if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) { + return 0; + } + secp256k1_gej_set_ge(&xj, &x); + secp256k1_scalar_inverse_var(&rn, sigr); + secp256k1_scalar_mul(&u1, &rn, message); + secp256k1_scalar_negate(&u1, &u1); + secp256k1_scalar_mul(&u2, &rn, sigs); + secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); + secp256k1_ge_set_gej_var(pubkey, &qj); + return !secp256k1_gej_is_infinity(&qj); +} + +int 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) { + secp256k1_scalar r, s; + secp256k1_scalar sec, non, msg; + int recid; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + /* Fail if the secret key is invalid. */ + if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + unsigned int count = 0; + secp256k1_scalar_set_b32(&msg, msg32, NULL); + while (1) { + unsigned char nonce32[32]; + ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&non, nonce32, &overflow); + memset(nonce32, 0, 32); + if (!secp256k1_scalar_is_zero(&non) && !overflow) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) { + break; + } + } + count++; + } + secp256k1_scalar_clear(&msg); + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + } + if (ret) { + secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid); + } else { + memset(signature, 0, sizeof(*signature)); + } + return ret; +} + +int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32) { + secp256k1_ge q; + secp256k1_scalar r, s; + secp256k1_scalar m; + int recid; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature); + ARG_CHECK(recid >= 0 && recid < 4); + secp256k1_scalar_set_b32(&m, msg32, NULL); + if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) { + secp256k1_pubkey_save(pubkey, &q); + return 1; + } else { + memset(pubkey, 0, sizeof(*pubkey)); + return 0; + } +} + +#endif diff --git a/src/secp256k1/src/modules/recovery/tests_impl.h b/src/secp256k1/src/modules/recovery/tests_impl.h new file mode 100644 index 000000000..8932d5f0a --- /dev/null +++ b/src/secp256k1/src/modules/recovery/tests_impl.h @@ -0,0 +1,250 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_ +#define _SECP256K1_MODULE_RECOVERY_TESTS_ + +void test_ecdsa_recovery_end_to_end(void) { + unsigned char extra[32] = {0x00}; + unsigned char privkey[32]; + unsigned char message[32]; + secp256k1_ecdsa_signature signature[5]; + secp256k1_ecdsa_recoverable_signature rsignature[5]; + unsigned char sig[74]; + secp256k1_pubkey pubkey; + secp256k1_pubkey recpubkey; + int recid = 0; + + /* Generate a random key and message. */ + { + secp256k1_scalar msg, key; + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_scalar_get_b32(privkey, &key); + secp256k1_scalar_get_b32(message, &msg); + } + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Serialize/parse compact and verify/recover. */ + extra[0] = 0; + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1); + extra[31] = 1; + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1); + extra[31] = 0; + extra[0] = 1; + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(memcmp(&signature[4], &signature[0], 64) == 0); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); + memset(&rsignature[4], 0, sizeof(rsignature[4])); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); + /* Parse compact (with recovery id) and recover. */ + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1); + CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + /* Serialize/destroy/parse signature and verify again. */ + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); + sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0); + /* Recover again */ + CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 || + memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); +} + +/* Tests several edge cases. */ +void test_ecdsa_recovery_edge_cases(void) { + const unsigned char msg32[32] = { + 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', + 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', + 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', + 's', 's', 'a', 'g', 'e', '.', '.', '.' + }; + const unsigned char sig64[64] = { + /* Generated by signing the above message with nonce 'This is the nonce we will use...' + * and secret key 0 (which is not valid), resulting in recid 0. */ + 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, + 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, + 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, + 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, + 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, + 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, + 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, + 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 + }; + secp256k1_pubkey pubkey; + /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ + const unsigned char sigb64[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + secp256k1_pubkey pubkeyb; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + int recid; + + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0)); + CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1)); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2)); + CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3)); + CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + + for (recid = 0; recid < 4; recid++) { + int i; + int recid2; + /* (4,4) encoded in DER. */ + unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; + unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; + unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; + unsigned char sigbderalt1[39] = { + 0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt2[39] = { + 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + unsigned char sigbderalt3[40] = { + 0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt4[40] = { + 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + /* (order + r,4) encoded in DER. */ + unsigned char sigbderlong[40] = { + 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, + 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, + 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 + }; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); + for (recid2 = 0; recid2 < 4; recid2++) { + secp256k1_pubkey pubkey2b; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1); + /* Verifying with (order + r,4) should always fail. */ + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + } + /* DER parsing tests. */ + /* Zero length r/s. */ + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); + /* Leading zeros. */ + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); + sigbderalt3[4] = 1; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + sigbderalt4[7] = 1; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + /* Damage signature. */ + sigbder[7]++; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + sigbder[7]--; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0); + for(i = 0; i < 8; i++) { + int c; + unsigned char orig = sigbder[i]; + /*Try every single-byte change.*/ + for (c = 0; c < 256; c++) { + if (c == orig ) { + continue; + } + sigbder[i] = c; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + } + sigbder[i] = orig; + } + } + + /* Test r/s equal to zero */ + { + /* (1,1) encoded in DER. */ + unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; + unsigned char sigc64[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + secp256k1_pubkey pubkeyc; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1); + sigcder[4] = 0; + sigc64[31] = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); + sigcder[4] = 1; + sigcder[7] = 0; + sigc64[31] = 1; + sigc64[63] = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); + } +} + +void run_recovery_tests(void) { + int i; + for (i = 0; i < 64*count; i++) { + test_ecdsa_recovery_end_to_end(); + } + test_ecdsa_recovery_edge_cases(); +} + +#endif diff --git a/src/secp256k1/src/modules/schnorr/Makefile.am.include b/src/secp256k1/src/modules/schnorr/Makefile.am.include new file mode 100644 index 000000000..b3bfa7d5c --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/Makefile.am.include @@ -0,0 +1,10 @@ +include_HEADERS += include/secp256k1_schnorr.h +noinst_HEADERS += src/modules/schnorr/main_impl.h +noinst_HEADERS += src/modules/schnorr/schnorr.h +noinst_HEADERS += src/modules/schnorr/schnorr_impl.h +noinst_HEADERS += src/modules/schnorr/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_schnorr_verify +bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c +bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS) +endif diff --git a/src/secp256k1/src/modules/schnorr/main_impl.h b/src/secp256k1/src/modules/schnorr/main_impl.h new file mode 100644 index 000000000..fa176a176 --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/main_impl.h @@ -0,0 +1,164 @@ +/********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORR_MAIN +#define SECP256K1_MODULE_SCHNORR_MAIN + +#include "include/secp256k1_schnorr.h" +#include "modules/schnorr/schnorr_impl.h" + +static void secp256k1_schnorr_msghash_sha256(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) { + secp256k1_sha256_t sha; + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, r32, 32); + secp256k1_sha256_write(&sha, msg32, 32); + secp256k1_sha256_finalize(&sha, h32); +} + +static const unsigned char secp256k1_schnorr_algo16[17] = "Schnorr+SHA256 "; + +int secp256k1_schnorr_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { + secp256k1_scalar sec, non; + int ret = 0; + int overflow = 0; + unsigned int count = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(seckey != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + secp256k1_scalar_set_b32(&sec, seckey, NULL); + while (1) { + unsigned char nonce32[32]; + ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&non, nonce32, &overflow); + memset(nonce32, 0, 32); + if (!secp256k1_scalar_is_zero(&non) && !overflow) { + if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, NULL, secp256k1_schnorr_msghash_sha256, msg32)) { + break; + } + } + count++; + } + if (!ret) { + memset(sig64, 0, 64); + } + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + return ret; +} + +int secp256k1_schnorr_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { + secp256k1_ge q; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_pubkey_load(ctx, &q, pubkey); + return secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32); +} + +int secp256k1_schnorr_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *sig64, const unsigned char *msg32) { + secp256k1_ge q; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(pubkey != NULL); + + if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32)) { + secp256k1_pubkey_save(pubkey, &q); + return 1; + } else { + memset(pubkey, 0, sizeof(*pubkey)); + return 0; + } +} + +int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, unsigned char *privnonce32, const unsigned char *sec32, const unsigned char *msg32, secp256k1_nonce_function noncefp, const void* noncedata) { + int count = 0; + int ret = 1; + secp256k1_gej Qj; + secp256k1_ge Q; + secp256k1_scalar sec; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sec32 != NULL); + ARG_CHECK(pubnonce != NULL); + ARG_CHECK(privnonce32 != NULL); + + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + do { + int overflow; + ret = noncefp(privnonce32, sec32, msg32, secp256k1_schnorr_algo16, (void*)noncedata, count++); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&sec, privnonce32, &overflow); + if (overflow || secp256k1_scalar_is_zero(&sec)) { + continue; + } + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sec); + secp256k1_ge_set_gej(&Q, &Qj); + + secp256k1_pubkey_save(pubnonce, &Q); + break; + } while(1); + + secp256k1_scalar_clear(&sec); + if (!ret) { + memset(pubnonce, 0, sizeof(*pubnonce)); + } + return ret; +} + +int secp256k1_schnorr_partial_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *sec32, const secp256k1_pubkey *pubnonce_others, const unsigned char *secnonce32) { + int overflow = 0; + secp256k1_scalar sec, non; + secp256k1_ge pubnon; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(sec32 != NULL); + ARG_CHECK(secnonce32 != NULL); + ARG_CHECK(pubnonce_others != NULL); + + secp256k1_scalar_set_b32(&sec, sec32, &overflow); + if (overflow || secp256k1_scalar_is_zero(&sec)) { + return -1; + } + secp256k1_scalar_set_b32(&non, secnonce32, &overflow); + if (overflow || secp256k1_scalar_is_zero(&non)) { + return -1; + } + secp256k1_pubkey_load(ctx, &pubnon, pubnonce_others); + return secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, &pubnon, secp256k1_schnorr_msghash_sha256, msg32); +} + +int secp256k1_schnorr_partial_combine(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char * const *sig64sin, size_t n) { + ARG_CHECK(sig64 != NULL); + ARG_CHECK(n >= 1); + ARG_CHECK(sig64sin != NULL); + return secp256k1_schnorr_sig_combine(sig64, n, sig64sin); +} + +#endif diff --git a/src/secp256k1/src/modules/schnorr/schnorr.h b/src/secp256k1/src/modules/schnorr/schnorr.h new file mode 100644 index 000000000..de18147bd --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/schnorr.h @@ -0,0 +1,20 @@ +/*********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php. * + ***********************************************************************/ + +#ifndef _SECP256K1_MODULE_SCHNORR_H_ +#define _SECP256K1_MODULE_SCHNORR_H_ + +#include "scalar.h" +#include "group.h" + +typedef void (*secp256k1_schnorr_msghash)(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32); + +static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32); +static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32); +static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32); +static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins); + +#endif diff --git a/src/secp256k1/src/modules/schnorr/schnorr_impl.h b/src/secp256k1/src/modules/schnorr/schnorr_impl.h new file mode 100644 index 000000000..e13ab6db7 --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/schnorr_impl.h @@ -0,0 +1,207 @@ +/*********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php. * + ***********************************************************************/ + +#ifndef _SECP256K1_SCHNORR_IMPL_H_ +#define _SECP256K1_SCHNORR_IMPL_H_ + +#include + +#include "schnorr.h" +#include "num.h" +#include "field.h" +#include "group.h" +#include "ecmult.h" +#include "ecmult_gen.h" + +/** + * Custom Schnorr-based signature scheme. They support multiparty signing, public key + * recovery and batch validation. + * + * Rationale for verifying R's y coordinate: + * In order to support batch validation and public key recovery, the full R point must + * be known to verifiers, rather than just its x coordinate. In order to not risk + * being more strict in batch validation than normal validation, validators must be + * required to reject signatures with incorrect y coordinate. This is only possible + * by including a (relatively slow) field inverse, or a field square root. However, + * batch validation offers potentially much higher benefits than this cost. + * + * Rationale for having an implicit y coordinate oddness: + * If we commit to having the full R point known to verifiers, there are two mechanism. + * Either include its oddness in the signature, or give it an implicit fixed value. + * As the R y coordinate can be flipped by a simple negation of the nonce, we choose the + * latter, as it comes with nearly zero impact on signing or validation performance, and + * saves a byte in the signature. + * + * Signing: + * Inputs: 32-byte message m, 32-byte scalar key x (!=0), 32-byte scalar nonce k (!=0) + * + * Compute point R = k * G. Reject nonce if R's y coordinate is odd (or negate nonce). + * Compute 32-byte r, the serialization of R's x coordinate. + * Compute scalar h = Hash(r || m). Reject nonce if h == 0 or h >= order. + * Compute scalar s = k - h * x. + * The signature is (r, s). + * + * + * Verification: + * Inputs: 32-byte message m, public key point Q, signature: (32-byte r, scalar s) + * + * Signature is invalid if s >= order. + * Signature is invalid if r >= p. + * Compute scalar h = Hash(r || m). Signature is invalid if h == 0 or h >= order. + * Option 1 (faster for single verification): + * Compute point R = h * Q + s * G. Signature is invalid if R is infinity or R's y coordinate is odd. + * Signature is valid if the serialization of R's x coordinate equals r. + * Option 2 (allows batch validation and pubkey recovery): + * Decompress x coordinate r into point R, with odd y coordinate. Fail if R is not on the curve. + * Signature is valid if R + h * Q + s * G == 0. + */ + +static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { + secp256k1_gej Rj; + secp256k1_ge Ra; + unsigned char h32[32]; + secp256k1_scalar h, s; + int overflow; + secp256k1_scalar n; + + if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) { + return 0; + } + n = *nonce; + + secp256k1_ecmult_gen(ctx, &Rj, &n); + if (pubnonce != NULL) { + secp256k1_gej_add_ge(&Rj, &Rj, pubnonce); + } + secp256k1_ge_set_gej(&Ra, &Rj); + secp256k1_fe_normalize(&Ra.y); + if (secp256k1_fe_is_odd(&Ra.y)) { + /* R's y coordinate is odd, which is not allowed (see rationale above). + Force it to be even by negating the nonce. Note that this even works + for multiparty signing, as the R point is known to all participants, + which can all decide to flip the sign in unison, resulting in the + overall R point to be negated too. */ + secp256k1_scalar_negate(&n, &n); + } + secp256k1_fe_normalize(&Ra.x); + secp256k1_fe_get_b32(sig64, &Ra.x); + hash(h32, sig64, msg32); + overflow = 0; + secp256k1_scalar_set_b32(&h, h32, &overflow); + if (overflow || secp256k1_scalar_is_zero(&h)) { + secp256k1_scalar_clear(&n); + return 0; + } + secp256k1_scalar_mul(&s, &h, key); + secp256k1_scalar_negate(&s, &s); + secp256k1_scalar_add(&s, &s, &n); + secp256k1_scalar_clear(&n); + secp256k1_scalar_get_b32(sig64 + 32, &s); + return 1; +} + +static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { + secp256k1_gej Qj, Rj; + secp256k1_ge Ra; + secp256k1_fe Rx; + secp256k1_scalar h, s; + unsigned char hh[32]; + int overflow; + + if (secp256k1_ge_is_infinity(pubkey)) { + return 0; + } + hash(hh, sig64, msg32); + overflow = 0; + secp256k1_scalar_set_b32(&h, hh, &overflow); + if (overflow || secp256k1_scalar_is_zero(&h)) { + return 0; + } + overflow = 0; + secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); + if (overflow) { + return 0; + } + if (!secp256k1_fe_set_b32(&Rx, sig64)) { + return 0; + } + secp256k1_gej_set_ge(&Qj, pubkey); + secp256k1_ecmult(ctx, &Rj, &Qj, &h, &s); + if (secp256k1_gej_is_infinity(&Rj)) { + return 0; + } + secp256k1_ge_set_gej_var(&Ra, &Rj); + secp256k1_fe_normalize_var(&Ra.y); + if (secp256k1_fe_is_odd(&Ra.y)) { + return 0; + } + return secp256k1_fe_equal_var(&Rx, &Ra.x); +} + +static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { + secp256k1_gej Qj, Rj; + secp256k1_ge Ra; + secp256k1_fe Rx; + secp256k1_scalar h, s; + unsigned char hh[32]; + int overflow; + + hash(hh, sig64, msg32); + overflow = 0; + secp256k1_scalar_set_b32(&h, hh, &overflow); + if (overflow || secp256k1_scalar_is_zero(&h)) { + return 0; + } + overflow = 0; + secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); + if (overflow) { + return 0; + } + if (!secp256k1_fe_set_b32(&Rx, sig64)) { + return 0; + } + if (!secp256k1_ge_set_xo_var(&Ra, &Rx, 0)) { + return 0; + } + secp256k1_gej_set_ge(&Rj, &Ra); + secp256k1_scalar_inverse_var(&h, &h); + secp256k1_scalar_negate(&s, &s); + secp256k1_scalar_mul(&s, &s, &h); + secp256k1_ecmult(ctx, &Qj, &Rj, &h, &s); + if (secp256k1_gej_is_infinity(&Qj)) { + return 0; + } + secp256k1_ge_set_gej(pubkey, &Qj); + return 1; +} + +static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins) { + secp256k1_scalar s = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + size_t i; + for (i = 0; i < n; i++) { + secp256k1_scalar si; + int overflow; + secp256k1_scalar_set_b32(&si, sig64ins[i] + 32, &overflow); + if (overflow) { + return -1; + } + if (i) { + if (memcmp(sig64ins[i - 1], sig64ins[i], 32) != 0) { + return -1; + } + } + secp256k1_scalar_add(&s, &s, &si); + } + if (secp256k1_scalar_is_zero(&s)) { + return 0; + } + memcpy(sig64, sig64ins[0], 32); + secp256k1_scalar_get_b32(sig64 + 32, &s); + secp256k1_scalar_clear(&s); + return 1; +} + +#endif diff --git a/src/secp256k1/src/modules/schnorr/tests_impl.h b/src/secp256k1/src/modules/schnorr/tests_impl.h new file mode 100644 index 000000000..5bd14a03e --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/tests_impl.h @@ -0,0 +1,175 @@ +/********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORR_TESTS +#define SECP256K1_MODULE_SCHNORR_TESTS + +#include "include/secp256k1_schnorr.h" + +void test_schnorr_end_to_end(void) { + unsigned char privkey[32]; + unsigned char message[32]; + unsigned char schnorr_signature[64]; + secp256k1_pubkey pubkey, recpubkey; + + /* Generate a random key and message. */ + { + secp256k1_scalar key; + random_scalar_order_test(&key); + secp256k1_scalar_get_b32(privkey, &key); + secp256k1_rand256_test(message); + } + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Schnorr sign. */ + CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1); + CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) == 1); + CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + /* Destroy signature and verify again. */ + schnorr_signature[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255); + CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 0); + CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) != 1 || + memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); +} + +/** Horribly broken hash function. Do not use for anything but tests. */ +void test_schnorr_hash(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) { + int i; + for (i = 0; i < 32; i++) { + h32[i] = r32[i] ^ msg32[i]; + } +} + +void test_schnorr_sign_verify(void) { + unsigned char msg32[32]; + unsigned char sig64[3][64]; + secp256k1_gej pubkeyj[3]; + secp256k1_ge pubkey[3]; + secp256k1_scalar nonce[3], key[3]; + int i = 0; + int k; + + secp256k1_rand256_test(msg32); + + for (k = 0; k < 3; k++) { + random_scalar_order_test(&key[k]); + + do { + random_scalar_order_test(&nonce[k]); + if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64[k], &key[k], &nonce[k], NULL, &test_schnorr_hash, msg32)) { + break; + } + } while(1); + + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj[k], &key[k]); + secp256k1_ge_set_gej_var(&pubkey[k], &pubkeyj[k]); + CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32)); + + for (i = 0; i < 4; i++) { + int pos = secp256k1_rand_bits(6); + int mod = 1 + secp256k1_rand_int(255); + sig64[k][pos] ^= mod; + CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32) == 0); + sig64[k][pos] ^= mod; + } + } +} + +void test_schnorr_threshold(void) { + unsigned char msg[32]; + unsigned char sec[5][32]; + secp256k1_pubkey pub[5]; + unsigned char nonce[5][32]; + secp256k1_pubkey pubnonce[5]; + unsigned char sig[5][64]; + const unsigned char* sigs[5]; + unsigned char allsig[64]; + const secp256k1_pubkey* pubs[5]; + secp256k1_pubkey allpub; + int n, i; + int damage; + int ret = 0; + + damage = secp256k1_rand_bits(1) ? (1 + secp256k1_rand_int(4)) : 0; + secp256k1_rand256_test(msg); + n = 2 + secp256k1_rand_int(4); + for (i = 0; i < n; i++) { + do { + secp256k1_rand256_test(sec[i]); + } while (!secp256k1_ec_seckey_verify(ctx, sec[i])); + CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i])); + CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL)); + pubs[i] = &pub[i]; + } + if (damage == 1) { + nonce[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); + } else if (damage == 2) { + sec[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); + } + for (i = 0; i < n; i++) { + secp256k1_pubkey allpubnonce; + const secp256k1_pubkey *pubnonces[4]; + int j; + for (j = 0; j < i; j++) { + pubnonces[j] = &pubnonce[j]; + } + for (j = i + 1; j < n; j++) { + pubnonces[j - 1] = &pubnonce[j]; + } + CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1)); + ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1; + sigs[i] = sig[i]; + } + if (damage == 3) { + sig[secp256k1_rand_int(n)][secp256k1_rand_bits(6)] ^= 1 + secp256k1_rand_int(255); + } + ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2; + if ((ret & 1) == 0) { + ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4; + } + if (damage == 4) { + allsig[secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); + } + if ((ret & 7) == 0) { + ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8; + } + CHECK((ret == 0) == (damage == 0)); +} + +void test_schnorr_recovery(void) { + unsigned char msg32[32]; + unsigned char sig64[64]; + secp256k1_ge Q; + + secp256k1_rand256_test(msg32); + secp256k1_rand256_test(sig64); + secp256k1_rand256_test(sig64 + 32); + if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1) { + CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1); + } +} + +void run_schnorr_tests(void) { + int i; + for (i = 0; i < 32*count; i++) { + test_schnorr_end_to_end(); + } + for (i = 0; i < 32 * count; i++) { + test_schnorr_sign_verify(); + } + for (i = 0; i < 16 * count; i++) { + test_schnorr_recovery(); + } + for (i = 0; i < 10 * count; i++) { + test_schnorr_threshold(); + } +} + +#endif diff --git a/src/secp256k1/src/num.h b/src/secp256k1/src/num.h index 339b6bb6e..ebfa71eb4 100644 --- a/src/secp256k1/src/num.h +++ b/src/secp256k1/src/num.h @@ -20,48 +20,48 @@ #endif /** Copy a number. */ -static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a); +static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a); /** Convert a number's absolute value to a binary big-endian string. * There must be enough place. */ -static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a); +static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a); /** Set a number to the value of a binary big-endian string. */ -static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen); +static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen); /** Compute a modular inverse. The input must be less than the modulus. */ -static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m); +static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m); /** Compare the absolute value of two numbers. */ -static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b); +static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b); /** Test whether two number are equal (including sign). */ -static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b); +static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b); /** Add two (signed) numbers. */ -static void secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); /** Subtract two (signed) numbers. */ -static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); /** Multiply two (signed) numbers. */ -static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); /** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1, even if r was negative. */ -static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m); +static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m); /** Right-shift the passed number by bits bits. */ -static void secp256k1_num_shift(secp256k1_num_t *r, int bits); +static void secp256k1_num_shift(secp256k1_num *r, int bits); /** Check whether a number is zero. */ -static int secp256k1_num_is_zero(const secp256k1_num_t *a); +static int secp256k1_num_is_zero(const secp256k1_num *a); /** Check whether a number is strictly negative. */ -static int secp256k1_num_is_neg(const secp256k1_num_t *a); +static int secp256k1_num_is_neg(const secp256k1_num *a); /** Change a number's sign. */ -static void secp256k1_num_negate(secp256k1_num_t *r); +static void secp256k1_num_negate(secp256k1_num *r); #endif diff --git a/src/secp256k1/src/num_gmp.h b/src/secp256k1/src/num_gmp.h index baa1f2bf2..7dd813088 100644 --- a/src/secp256k1/src/num_gmp.h +++ b/src/secp256k1/src/num_gmp.h @@ -15,6 +15,6 @@ typedef struct { mp_limb_t data[2*NUM_LIMBS]; int neg; int limbs; -} secp256k1_num_t; +} secp256k1_num; #endif diff --git a/src/secp256k1/src/num_gmp_impl.h b/src/secp256k1/src/num_gmp_impl.h index dbbc458d5..7b6a89719 100644 --- a/src/secp256k1/src/num_gmp_impl.h +++ b/src/secp256k1/src/num_gmp_impl.h @@ -15,18 +15,18 @@ #include "num.h" #ifdef VERIFY -static void secp256k1_num_sanity(const secp256k1_num_t *a) { +static void secp256k1_num_sanity(const secp256k1_num *a) { VERIFY_CHECK(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0)); } #else #define secp256k1_num_sanity(a) do { } while(0) #endif -static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) { +static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a) { *r = *a; } -static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) { +static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a) { unsigned char tmp[65]; int len = 0; int shift = 0; @@ -42,7 +42,7 @@ static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const sec memset(tmp, 0, sizeof(tmp)); } -static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) { +static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen) { int len; VERIFY_CHECK(alen > 0); VERIFY_CHECK(alen <= 64); @@ -59,7 +59,7 @@ static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, un } } -static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_add_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs); r->limbs = a->limbs; if (c != 0) { @@ -68,8 +68,9 @@ static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, } } -static void secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_sub_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs); + (void)c; VERIFY_CHECK(c == 0); r->limbs = a->limbs; while (r->limbs > 1 && r->data[r->limbs-1]==0) { @@ -77,7 +78,7 @@ static void secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, } } -static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) { +static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m) { secp256k1_num_sanity(r); secp256k1_num_sanity(m); @@ -97,7 +98,7 @@ static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) { } } -static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) { +static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m) { int i; mp_limb_t g[NUM_LIMBS+1]; mp_limb_t u[NUM_LIMBS+1]; @@ -125,6 +126,7 @@ static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t } sn = NUM_LIMBS+1; gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs); + (void)gn; VERIFY_CHECK(gn == 1); VERIFY_CHECK(g[0] == 1); r->neg = a->neg ^ m->neg; @@ -142,15 +144,15 @@ static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t memset(v, 0, sizeof(v)); } -static int secp256k1_num_is_zero(const secp256k1_num_t *a) { +static int secp256k1_num_is_zero(const secp256k1_num *a) { return (a->limbs == 1 && a->data[0] == 0); } -static int secp256k1_num_is_neg(const secp256k1_num_t *a) { +static int secp256k1_num_is_neg(const secp256k1_num *a) { return (a->limbs > 1 || a->data[0] != 0) && a->neg; } -static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) { +static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b) { if (a->limbs > b->limbs) { return 1; } @@ -160,7 +162,7 @@ static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) return mpn_cmp(a->data, b->data, a->limbs); } -static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b) { +static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b) { if (a->limbs > b->limbs) { return 0; } @@ -173,7 +175,7 @@ static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b) return mpn_cmp(a->data, b->data, a->limbs) == 0; } -static void secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, int bneg) { +static void secp256k1_num_subadd(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b, int bneg) { if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */ r->neg = a->neg; if (a->limbs >= b->limbs) { @@ -192,19 +194,19 @@ static void secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, c } } -static void secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { secp256k1_num_sanity(a); secp256k1_num_sanity(b); secp256k1_num_subadd(r, a, b, 0); } -static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { secp256k1_num_sanity(a); secp256k1_num_sanity(b); secp256k1_num_subadd(r, a, b, 1); } -static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { mp_limb_t tmp[2*NUM_LIMBS+1]; secp256k1_num_sanity(a); secp256k1_num_sanity(b); @@ -231,13 +233,13 @@ static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, cons memset(tmp, 0, sizeof(tmp)); } -static void secp256k1_num_shift(secp256k1_num_t *r, int bits) { - int i; +static void secp256k1_num_shift(secp256k1_num *r, int bits) { if (bits % GMP_NUMB_BITS) { /* Shift within limbs. */ mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS); } if (bits >= GMP_NUMB_BITS) { + int i; /* Shift full limbs. */ for (i = 0; i < r->limbs; i++) { int index = i + (bits / GMP_NUMB_BITS); @@ -253,7 +255,7 @@ static void secp256k1_num_shift(secp256k1_num_t *r, int bits) { } } -static void secp256k1_num_negate(secp256k1_num_t *r) { +static void secp256k1_num_negate(secp256k1_num *r) { r->neg ^= 1; } diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h index f5d09f8d4..b590ccd6d 100644 --- a/src/secp256k1/src/scalar.h +++ b/src/secp256k1/src/scalar.h @@ -22,72 +22,83 @@ #endif /** Clear a scalar to prevent the leak of sensitive data. */ -static void secp256k1_scalar_clear(secp256k1_scalar_t *r); +static void secp256k1_scalar_clear(secp256k1_scalar *r); /** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */ -static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count); +static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count); /** Access bits from a scalar. Not constant time. */ -static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count); +static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count); /** Set a scalar from a big endian byte array. */ -static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *bin, int *overflow); +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *bin, int *overflow); /** Set a scalar to an unsigned integer. */ -static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v); +static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v); /** Convert a scalar to a byte array. */ -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a); +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a); /** Add two scalars together (modulo the group order). Returns whether it overflowed. */ -static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); -/** Add a power of two to a scalar. The result is not allowed to overflow. */ -static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit); +/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */ +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag); /** Multiply two scalars (modulo the group order). */ -static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); + +/** Shift a scalar right by some amount strictly between 0 and 16, returning + * the low bits that were shifted off */ +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n); /** Compute the square of a scalar (modulo the group order). */ -static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a); /** Compute the inverse of a scalar (modulo the group order). */ -static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a); /** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */ -static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *a); /** Compute the complement of a scalar (modulo the group order). */ -static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a); /** Check whether a scalar equals zero. */ -static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a); +static int secp256k1_scalar_is_zero(const secp256k1_scalar *a); /** Check whether a scalar equals one. */ -static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a); +static int secp256k1_scalar_is_one(const secp256k1_scalar *a); + +/** Check whether a scalar, considered as an nonnegative integer, is even. */ +static int secp256k1_scalar_is_even(const secp256k1_scalar *a); /** Check whether a scalar is higher than the group order divided by 2. */ -static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a); +static int secp256k1_scalar_is_high(const secp256k1_scalar *a); + +/** Conditionally negate a number, in constant time. + * Returns -1 if the number was negated, 1 otherwise */ +static int secp256k1_scalar_cond_negate(secp256k1_scalar *a, int flag); #ifndef USE_NUM_NONE /** Convert a scalar to a number. */ -static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a); /** Get the order of the group as a number. */ -static void secp256k1_scalar_order_get_num(secp256k1_num_t *r); +static void secp256k1_scalar_order_get_num(secp256k1_num *r); #endif /** Compare two scalars. */ -static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); +static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b); #ifdef USE_ENDOMORPHISM /** Find r1 and r2 such that r1+r2*2^128 = a. */ -static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a); +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); /** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */ -static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a); +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); #endif /** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ -static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift); +static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); #endif diff --git a/src/secp256k1/src/scalar_4x64.h b/src/secp256k1/src/scalar_4x64.h index 82899aa7b..cff406038 100644 --- a/src/secp256k1/src/scalar_4x64.h +++ b/src/secp256k1/src/scalar_4x64.h @@ -12,7 +12,7 @@ /** A scalar modulo the group order of the secp256k1 curve. */ typedef struct { uint64_t d[4]; -} secp256k1_scalar_t; +} secp256k1_scalar; #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)}} diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h index ff365292f..aa2703dd2 100644 --- a/src/secp256k1/src/scalar_4x64_impl.h +++ b/src/secp256k1/src/scalar_4x64_impl.h @@ -24,26 +24,26 @@ #define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) #define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL) -SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) { +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { r->d[0] = 0; r->d[1] = 0; r->d[2] = 0; r->d[3] = 0; } -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) { +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { r->d[0] = v; r->d[1] = 0; r->d[2] = 0; r->d[3] = 0; } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1); } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { VERIFY_CHECK(count < 32); VERIFY_CHECK(offset + count <= 256); if ((offset + count - 1) >> 6 == offset >> 6) { @@ -54,7 +54,7 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256 } } -SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { int yes = 0; int no = 0; no |= (a->d[3] < SECP256K1_N_3); /* No need for a > check. */ @@ -66,7 +66,7 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal return yes; } -SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsigned int overflow) { +SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) { uint128_t t; VERIFY_CHECK(overflow <= 1); t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; @@ -80,7 +80,7 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsig return overflow; } -static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { int overflow; uint128_t t = (uint128_t)a->d[0] + b->d[0]; r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; @@ -96,9 +96,10 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t return overflow; } -static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { uint128_t t; VERIFY_CHECK(bit < 256); + bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); @@ -113,7 +114,7 @@ static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { #endif } -static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) { +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { int over; 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; 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; @@ -125,18 +126,18 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char } } -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) { +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { 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]; 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]; 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]; 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]; } -SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; } -static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0); uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1; r->d[0] = t & nonzero; t >>= 64; @@ -148,11 +149,11 @@ static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scala r->d[3] = t & nonzero; } -SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; } -static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { int yes = 0; int no = 0; no |= (a->d[3] < SECP256K1_N_H_3); @@ -164,6 +165,22 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { return yes; } +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ + uint64_t mask = !flag - 1; + uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; + uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + r->d[0] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); + r->d[1] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); + r->d[2] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); + r->d[3] = t & nonzero; + return 2 * (mask == 0) - 1; +} + /* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ /** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ @@ -250,7 +267,7 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { VERIFY_CHECK(c2 == 0); \ } -static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l) { +static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) { #ifdef USE_ASM_X86_64 /* Reduce 512 bits into 385. */ uint64_t m0, m1, m2, m3, m4, m5, m6; @@ -559,7 +576,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); } -static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, const secp256k1_scalar *b) { #ifdef USE_ASM_X86_64 const uint64_t *pb = b->d; __asm__ __volatile__( @@ -721,12 +738,12 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar_t *a, extract(l[5]); muladd_fast(a->d[3], b->d[3]); extract_fast(l[6]); - VERIFY_CHECK(c1 <= 0); + VERIFY_CHECK(c1 == 0); l[7] = c0; #endif } -static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a) { +static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar *a) { #ifdef USE_ASM_X86_64 __asm__ __volatile__( /* Preload */ @@ -871,19 +888,32 @@ static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a) #undef extract #undef extract_fast -static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { uint64_t l[8]; secp256k1_scalar_mul_512(l, a, b); secp256k1_scalar_reduce_512(r, l); } -static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = r->d[0] & ((1 << n) - 1); + r->d[0] = (r->d[0] >> n) + (r->d[1] << (64 - n)); + r->d[1] = (r->d[1] >> n) + (r->d[2] << (64 - n)); + r->d[2] = (r->d[2] >> n) + (r->d[3] << (64 - n)); + r->d[3] = (r->d[3] >> n); + return ret; +} + +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { uint64_t l[8]; secp256k1_scalar_sqr_512(l, a); secp256k1_scalar_reduce_512(r, l); } -static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { +#ifdef USE_ENDOMORPHISM +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { r1->d[0] = a->d[0]; r1->d[1] = a->d[1]; r1->d[2] = 0; @@ -893,12 +923,13 @@ static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_ r2->d[2] = 0; r2->d[3] = 0; } +#endif -SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { 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; } -SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) { +SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { uint64_t l[8]; unsigned int shiftlimbs; unsigned int shiftlow; @@ -912,9 +943,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t * r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; - if ((l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1) { - secp256k1_scalar_add_bit(r, 0); - } + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); } #endif diff --git a/src/secp256k1/src/scalar_8x32.h b/src/secp256k1/src/scalar_8x32.h index f17017e24..1319664f6 100644 --- a/src/secp256k1/src/scalar_8x32.h +++ b/src/secp256k1/src/scalar_8x32.h @@ -12,7 +12,7 @@ /** A scalar modulo the group order of the secp256k1 curve. */ typedef struct { uint32_t d[8]; -} secp256k1_scalar_t; +} secp256k1_scalar; #define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h index 22b31d411..aae4f35c0 100644 --- a/src/secp256k1/src/scalar_8x32_impl.h +++ b/src/secp256k1/src/scalar_8x32_impl.h @@ -34,7 +34,7 @@ #define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL) #define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL) -SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) { +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { r->d[0] = 0; r->d[1] = 0; r->d[2] = 0; @@ -45,7 +45,7 @@ SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) { r->d[7] = 0; } -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) { +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { r->d[0] = v; r->d[1] = 0; r->d[2] = 0; @@ -56,12 +56,12 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, uns r->d[7] = 0; } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1); } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { VERIFY_CHECK(count < 32); VERIFY_CHECK(offset + count <= 256); if ((offset + count - 1) >> 5 == offset >> 5) { @@ -72,7 +72,7 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256 } } -SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { int yes = 0; int no = 0; no |= (a->d[7] < SECP256K1_N_7); /* No need for a > check. */ @@ -90,7 +90,7 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal return yes; } -SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint32_t overflow) { +SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_t overflow) { uint64_t t; VERIFY_CHECK(overflow <= 1); t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; @@ -112,7 +112,7 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint3 return overflow; } -static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { int overflow; uint64_t t = (uint64_t)a->d[0] + b->d[0]; r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; @@ -136,9 +136,10 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t return overflow; } -static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { uint64_t t; VERIFY_CHECK(bit < 256); + bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F)); @@ -161,7 +162,7 @@ static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { #endif } -static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) { +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { int over; r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24; r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24; @@ -177,7 +178,7 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char } } -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) { +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7]; bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6]; bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5]; @@ -188,11 +189,11 @@ static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_ bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; } -SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { 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; } -static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0); uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1; r->d[0] = t & nonzero; t >>= 32; @@ -212,11 +213,11 @@ static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scala r->d[7] = t & nonzero; } -SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { 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; } -static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { int yes = 0; int no = 0; no |= (a->d[7] < SECP256K1_N_H_7); @@ -234,6 +235,31 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { return yes; } +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ + uint32_t mask = !flag - 1; + uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0); + uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + r->d[0] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); + r->d[1] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); + r->d[2] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); + r->d[3] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[4] ^ mask) + (SECP256K1_N_4 & mask); + r->d[4] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[5] ^ mask) + (SECP256K1_N_5 & mask); + r->d[5] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[6] ^ mask) + (SECP256K1_N_6 & mask); + r->d[6] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask); + r->d[7] = t & nonzero; + return 2 * (mask == 0) - 1; +} + + /* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ /** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ @@ -320,7 +346,7 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { VERIFY_CHECK(c2 == 0); \ } -static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l) { +static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint32_t *l) { uint64_t c; 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]; uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12; @@ -462,7 +488,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); } -static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, const secp256k1_scalar *b) { /* 96 bit accumulator. */ uint32_t c0 = 0, c1 = 0, c2 = 0; @@ -550,7 +576,7 @@ static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar_t *a, c l[15] = c0; } -static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar_t *a) { +static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar *a) { /* 96 bit accumulator. */ uint32_t c0 = 0, c1 = 0, c2 = 0; @@ -618,20 +644,36 @@ static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar_t *a) { #undef extract #undef extract_fast -static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { uint32_t l[16]; secp256k1_scalar_mul_512(l, a, b); secp256k1_scalar_reduce_512(r, l); } -static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = r->d[0] & ((1 << n) - 1); + r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n)); + r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n)); + r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n)); + r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n)); + r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - n)); + r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n)); + r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n)); + r->d[7] = (r->d[7] >> n); + return ret; +} + +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { uint32_t l[16]; secp256k1_scalar_sqr_512(l, a); secp256k1_scalar_reduce_512(r, l); } #ifdef USE_ENDOMORPHISM -static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { r1->d[0] = a->d[0]; r1->d[1] = a->d[1]; r1->d[2] = a->d[2]; @@ -651,11 +693,11 @@ static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_ } #endif -SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { 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; } -SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) { +SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { uint32_t l[16]; unsigned int shiftlimbs; unsigned int shiftlow; @@ -673,9 +715,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t * r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0; - if ((l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1) { - secp256k1_scalar_add_bit(r, 0); - } + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); } #endif diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h index 33824983e..88ea97de8 100644 --- a/src/secp256k1/src/scalar_impl.h +++ b/src/secp256k1/src/scalar_impl.h @@ -25,14 +25,14 @@ #endif #ifndef USE_NUM_NONE -static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a) { +static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a) { unsigned char c[32]; secp256k1_scalar_get_b32(c, a); secp256k1_num_set_bin(r, c, 32); } /** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */ -static void secp256k1_scalar_order_get_num(secp256k1_num_t *r) { +static void secp256k1_scalar_order_get_num(secp256k1_num *r) { static const unsigned char order[32] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, @@ -43,11 +43,11 @@ static void secp256k1_scalar_order_get_num(secp256k1_num_t *r) { } #endif -static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) { - secp256k1_scalar_t *t; +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { + secp256k1_scalar *t; int i; /* First compute x ^ (2^N - 1) for some values of N. */ - secp256k1_scalar_t x2, x3, x4, x6, x7, x8, x15, x30, x60, x120, x127; + secp256k1_scalar x2, x3, x4, x6, x7, x8, x15, x30, x60, x120, x127; secp256k1_scalar_sqr(&x2, x); secp256k1_scalar_mul(&x2, &x2, x); @@ -234,18 +234,27 @@ static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scal secp256k1_scalar_mul(r, t, &x6); /* 111111 */ } -static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) { +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + /* d[0] is present and is the lowest word for all representations */ + return !(a->d[0] & 1); +} + +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { #if defined(USE_SCALAR_INV_BUILTIN) secp256k1_scalar_inverse(r, x); #elif defined(USE_SCALAR_INV_NUM) unsigned char b[32]; - secp256k1_num_t n, m; - secp256k1_scalar_get_b32(b, x); + secp256k1_num n, m; + secp256k1_scalar t = *x; + secp256k1_scalar_get_b32(b, &t); secp256k1_num_set_bin(&n, b, 32); secp256k1_scalar_order_get_num(&m); secp256k1_num_mod_inverse(&n, &n, &m); secp256k1_num_get_bin(b, 32, &n); secp256k1_scalar_set_b32(r, b, NULL); + /* Verify that the inverse was computed correctly, without GMP code. */ + secp256k1_scalar_mul(&t, &t, r); + CHECK(secp256k1_scalar_is_one(&t)); #else #error "Please select scalar inverse implementation" #endif @@ -290,30 +299,31 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_ * The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order). */ -static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { - secp256k1_scalar_t c1, c2; - static const secp256k1_scalar_t minus_lambda = SECP256K1_SCALAR_CONST( +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + secp256k1_scalar c1, c2; + static const secp256k1_scalar minus_lambda = SECP256K1_SCALAR_CONST( 0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL, 0xA880B9FCUL, 0x8EC739C2UL, 0xE0CFC810UL, 0xB51283CFUL ); - static const secp256k1_scalar_t minus_b1 = SECP256K1_SCALAR_CONST( + static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST( 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL ); - static const secp256k1_scalar_t minus_b2 = SECP256K1_SCALAR_CONST( + static const secp256k1_scalar minus_b2 = SECP256K1_SCALAR_CONST( 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL ); - static const secp256k1_scalar_t g1 = SECP256K1_SCALAR_CONST( + static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST( 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL, 0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL ); - static const secp256k1_scalar_t g2 = SECP256K1_SCALAR_CONST( + static const secp256k1_scalar g2 = SECP256K1_SCALAR_CONST( 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL, 0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL ); VERIFY_CHECK(r1 != a); VERIFY_CHECK(r2 != a); + /* these _var calls are constant time since the shift amount is constant */ secp256k1_scalar_mul_shift_var(&c1, a, &g1, 272); secp256k1_scalar_mul_shift_var(&c2, a, &g2, 272); secp256k1_scalar_mul(&c1, &c1, &minus_b1); diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c index d6192dc4e..62d192bae 100644 --- a/src/secp256k1/src/secp256k1.c +++ b/src/secp256k1/src/secp256k1.c @@ -14,81 +14,328 @@ #include "scalar_impl.h" #include "group_impl.h" #include "ecmult_impl.h" +#include "ecmult_const_impl.h" #include "ecmult_gen_impl.h" #include "ecdsa_impl.h" #include "eckey_impl.h" #include "hash_impl.h" -struct secp256k1_context_struct { - secp256k1_ecmult_context_t ecmult_ctx; - secp256k1_ecmult_gen_context_t ecmult_gen_ctx; +#define ARG_CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + secp256k1_callback_call(&ctx->illegal_callback, #cond); \ + return 0; \ + } \ +} while(0) + +static void default_illegal_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); + abort(); +} + +static const secp256k1_callback default_illegal_callback = { + default_illegal_callback_fn, + NULL }; -secp256k1_context_t* secp256k1_context_create(int flags) { - secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t)); +static void default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} + +static const secp256k1_callback default_error_callback = { + default_error_callback_fn, + NULL +}; + + +struct secp256k1_context_struct { + secp256k1_ecmult_context ecmult_ctx; + secp256k1_ecmult_gen_context ecmult_gen_ctx; + secp256k1_callback illegal_callback; + secp256k1_callback error_callback; +}; + +secp256k1_context* secp256k1_context_create(unsigned int flags) { + secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context)); + ret->illegal_callback = default_illegal_callback; + ret->error_callback = default_error_callback; + + if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { + secp256k1_callback_call(&ret->illegal_callback, + "Invalid flags"); + free(ret); + return NULL; + } secp256k1_ecmult_context_init(&ret->ecmult_ctx); secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx); - if (flags & SECP256K1_CONTEXT_SIGN) { - secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx); + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) { + secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback); } - if (flags & SECP256K1_CONTEXT_VERIFY) { - secp256k1_ecmult_context_build(&ret->ecmult_ctx); + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) { + secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback); } return ret; } -secp256k1_context_t* secp256k1_context_clone(const secp256k1_context_t* ctx) { - secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t)); - secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx); - secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx); +secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { + secp256k1_context* ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_context)); + ret->illegal_callback = ctx->illegal_callback; + ret->error_callback = ctx->error_callback; + secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback); + secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback); return ret; } -void secp256k1_context_destroy(secp256k1_context_t* ctx) { - secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); - secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); +void secp256k1_context_destroy(secp256k1_context* ctx) { + if (ctx != NULL) { + secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); + secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); - free(ctx); + free(ctx); + } } -int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) { - secp256k1_ge_t q; - secp256k1_ecdsa_sig_t s; - secp256k1_scalar_t m; - int ret = -3; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig != NULL); - DEBUG_CHECK(pubkey != NULL); +void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + if (fun == NULL) { + fun = default_illegal_callback_fn; + } + ctx->illegal_callback.fn = fun; + ctx->illegal_callback.data = data; +} + +void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + if (fun == NULL) { + fun = default_error_callback_fn; + } + ctx->error_callback.fn = fun; + ctx->error_callback.data = data; +} + +static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { + if (sizeof(secp256k1_ge_storage) == 64) { + /* When the secp256k1_ge_storage type is exactly 64 byte, use its + * representation inside secp256k1_pubkey, as conversion is very fast. + * Note that secp256k1_pubkey_save must use the same representation. */ + secp256k1_ge_storage s; + memcpy(&s, &pubkey->data[0], 64); + secp256k1_ge_from_storage(ge, &s); + } else { + /* Otherwise, fall back to 32-byte big endian for X and Y. */ + secp256k1_fe x, y; + secp256k1_fe_set_b32(&x, pubkey->data); + secp256k1_fe_set_b32(&y, pubkey->data + 32); + secp256k1_ge_set_xy(ge, &x, &y); + } + ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); + return 1; +} + +static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { + if (sizeof(secp256k1_ge_storage) == 64) { + secp256k1_ge_storage s; + secp256k1_ge_to_storage(&s, ge); + memcpy(&pubkey->data[0], &s, 64); + } else { + VERIFY_CHECK(!secp256k1_ge_is_infinity(ge)); + secp256k1_fe_normalize_var(&ge->x); + secp256k1_fe_normalize_var(&ge->y); + secp256k1_fe_get_b32(pubkey->data, &ge->x); + secp256k1_fe_get_b32(pubkey->data + 32, &ge->y); + } +} + +int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { + secp256k1_ge Q; + + (void)ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(input != NULL); + if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) { + return 0; + } + secp256k1_pubkey_save(pubkey, &Q); + secp256k1_ge_clear(&Q); + return 1; +} + +int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags) { + secp256k1_ge Q; + size_t len; + int ret = 0; + + (void)ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65)); + len = *outputlen; + *outputlen = 0; + ARG_CHECK(output != NULL); + memset(output, 0, len); + ARG_CHECK(pubkey != NULL); + ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); + if (secp256k1_pubkey_load(ctx, &Q, pubkey)) { + ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); + if (ret) { + *outputlen = len; + } + } + return ret; +} + +static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) { + (void)ctx; + if (sizeof(secp256k1_scalar) == 32) { + /* When the secp256k1_scalar type is exactly 32 byte, use its + * representation inside secp256k1_ecdsa_signature, as conversion is very fast. + * Note that secp256k1_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + secp256k1_scalar_set_b32(r, &sig->data[0], NULL); + secp256k1_scalar_set_b32(s, &sig->data[32], NULL); + } +} + +static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s) { + if (sizeof(secp256k1_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + secp256k1_scalar_get_b32(&sig->data[0], r); + secp256k1_scalar_get_b32(&sig->data[32], s); + } +} + +int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + secp256k1_scalar r, s; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(input != NULL); + + if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) { + secp256k1_ecdsa_signature_save(sig, &r, &s); + return 1; + } else { + memset(sig, 0, sizeof(*sig)); + return 0; + } +} + +int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input64) { + secp256k1_scalar r, s; + int ret = 1; + int overflow = 0; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + + secp256k1_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + secp256k1_ecdsa_signature_save(sig, &r, &s); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) { + secp256k1_scalar r, s; + + (void)ctx; + ARG_CHECK(output != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s); +} + +int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) { + secp256k1_scalar r, s; + + (void)ctx; + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + secp256k1_scalar_get_b32(&output64[0], &r); + secp256k1_scalar_get_b32(&output64[32], &s); + return 1; +} + +int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) { + secp256k1_scalar r, s; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin); + ret = secp256k1_scalar_is_high(&s); + if (sigout != NULL) { + if (ret) { + secp256k1_scalar_negate(&s, &s); + } + secp256k1_ecdsa_signature_save(sigout, &r, &s); + } + + return ret; +} + +int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { + secp256k1_ge q; + secp256k1_scalar r, s; + secp256k1_scalar m; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(pubkey != NULL); secp256k1_scalar_set_b32(&m, msg32, NULL); - - if (secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) { - if (secp256k1_ecdsa_sig_parse(&s, sig, siglen)) { - if (secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &s, &q, &m)) { - /* success is 1, all other values are fail */ - ret = 1; - } else { - ret = 0; - } - } else { - ret = -2; - } - } else { - ret = -1; - } - - return ret; + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + return (!secp256k1_scalar_is_high(&s) && + secp256k1_pubkey_load(ctx, &q, pubkey) && + secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m)); } -static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { +static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + unsigned char keydata[112]; + int keylen = 64; secp256k1_rfc6979_hmac_sha256_t rng; unsigned int i; - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key32, 32, msg32, 32, (const unsigned char*)data, data != NULL ? 32 : 0); + /* We feed a byte array to the PRNG as input, consisting of: + * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d. + * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. + * - optionally 16 extra bytes with the algorithm name. + * Because the arguments have distinct fixed lengths it is not possible for + * different argument mixtures to emulate each other and result in the same + * nonces. + */ + memcpy(keydata, key32, 32); + memcpy(keydata + 32, msg32, 32); + if (data != NULL) { + memcpy(keydata + 64, data, 32); + keylen = 96; + } + if (algo16 != NULL) { + memcpy(keydata + keylen, algo16, 16); + keylen += 16; + } + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, keylen); + memset(keydata, 0, sizeof(keydata)); for (i = 0; i <= counter; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); } @@ -96,21 +343,19 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m return 1; } -const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; -const secp256k1_nonce_function_t secp256k1_nonce_function_default = nonce_function_rfc6979; +const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; +const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979; -int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) { - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t sec, non, msg; +int 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) { + secp256k1_scalar r, s; + secp256k1_scalar sec, non, msg; int ret = 0; int overflow = 0; - unsigned int count = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(signature != NULL); - DEBUG_CHECK(signaturelen != NULL); - DEBUG_CHECK(seckey != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); if (noncefp == NULL) { noncefp = secp256k1_nonce_function_default; } @@ -118,186 +363,87 @@ int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *ms secp256k1_scalar_set_b32(&sec, seckey, &overflow); /* Fail if the secret key is invalid. */ if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + unsigned int count = 0; secp256k1_scalar_set_b32(&msg, msg32, NULL); while (1) { unsigned char nonce32[32]; - ret = noncefp(nonce32, msg32, seckey, count, noncedata); + ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); if (!ret) { break; } secp256k1_scalar_set_b32(&non, nonce32, &overflow); memset(nonce32, 0, 32); - if (!secp256k1_scalar_is_zero(&non) && !overflow) { - if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, NULL)) { + if (!overflow && !secp256k1_scalar_is_zero(&non)) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) { break; } } count++; } - if (ret) { - ret = secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig); - } secp256k1_scalar_clear(&msg); secp256k1_scalar_clear(&non); secp256k1_scalar_clear(&sec); } - if (!ret) { - *signaturelen = 0; + if (ret) { + secp256k1_ecdsa_signature_save(signature, &r, &s); + } else { + memset(signature, 0, sizeof(*signature)); } return ret; } -int secp256k1_ecdsa_sign_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata, int *recid) { - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t sec, non, msg; - int ret = 0; - int overflow = 0; - unsigned int count = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig64 != NULL); - DEBUG_CHECK(seckey != NULL); - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; - } - - secp256k1_scalar_set_b32(&sec, seckey, &overflow); - /* Fail if the secret key is invalid. */ - if (!overflow && !secp256k1_scalar_is_zero(&sec)) { - secp256k1_scalar_set_b32(&msg, msg32, NULL); - while (1) { - unsigned char nonce32[32]; - ret = noncefp(nonce32, msg32, seckey, count, noncedata); - if (!ret) { - break; - } - secp256k1_scalar_set_b32(&non, nonce32, &overflow); - memset(nonce32, 0, 32); - if (!secp256k1_scalar_is_zero(&non) && !overflow) { - if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, recid)) { - break; - } - } - count++; - } - if (ret) { - secp256k1_scalar_get_b32(sig64, &sig.r); - secp256k1_scalar_get_b32(sig64 + 32, &sig.s); - } - secp256k1_scalar_clear(&msg); - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); - } - if (!ret) { - memset(sig64, 0, 64); - } - return ret; -} - -int secp256k1_ecdsa_recover_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) { - secp256k1_ge_t q; - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t m; - int ret = 0; - int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig64 != NULL); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - DEBUG_CHECK(recid >= 0 && recid <= 3); - - secp256k1_scalar_set_b32(&sig.r, sig64, &overflow); - if (!overflow) { - secp256k1_scalar_set_b32(&sig.s, sig64 + 32, &overflow); - if (!overflow) { - secp256k1_scalar_set_b32(&m, msg32, NULL); - - if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &sig, &q, &m, recid)) { - ret = secp256k1_eckey_pubkey_serialize(&q, pubkey, pubkeylen, compressed); - } - } - } - return ret; -} - -int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) { - secp256k1_scalar_t sec; +int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) { + secp256k1_scalar sec; int ret; int overflow; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(seckey != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); (void)ctx; secp256k1_scalar_set_b32(&sec, seckey, &overflow); - ret = !secp256k1_scalar_is_zero(&sec) && !overflow; + ret = !overflow && !secp256k1_scalar_is_zero(&sec); secp256k1_scalar_clear(&sec); return ret; } -int secp256k1_ec_pubkey_verify(const secp256k1_context_t* ctx, const unsigned char *pubkey, int pubkeylen) { - secp256k1_ge_t q; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(pubkey != NULL); - (void)ctx; - - return secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen); -} - -int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) { - secp256k1_gej_t pj; - secp256k1_ge_t p; - secp256k1_scalar_t sec; +int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) { + secp256k1_gej pj; + secp256k1_ge p; + secp256k1_scalar sec; int overflow; int ret = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - DEBUG_CHECK(seckey != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey != NULL); secp256k1_scalar_set_b32(&sec, seckey, &overflow); - if (!overflow) { + ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec)); + if (ret) { secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); - secp256k1_scalar_clear(&sec); secp256k1_ge_set_gej(&p, &pj); - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, compressed); - } - if (!ret) { - *pubkeylen = 0; + secp256k1_pubkey_save(pubkey, &p); } + secp256k1_scalar_clear(&sec); return ret; } -int secp256k1_ec_pubkey_decompress(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen) { - secp256k1_ge_t p; - int ret = 0; - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - (void)ctx; - - if (secp256k1_eckey_pubkey_parse(&p, pubkey, *pubkeylen)) { - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, 0); - } - return ret; -} - -int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) { - secp256k1_scalar_t term; - secp256k1_scalar_t sec; +int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_scalar term; + secp256k1_scalar sec; int ret = 0; int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(tweak != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); (void)ctx; secp256k1_scalar_set_b32(&term, tweak, &overflow); secp256k1_scalar_set_b32(&sec, seckey, NULL); - ret = secp256k1_eckey_privkey_tweak_add(&sec, &term) && !overflow; + ret = !overflow && secp256k1_eckey_privkey_tweak_add(&sec, &term); + memset(seckey, 0, 32); if (ret) { secp256k1_scalar_get_b32(seckey, &sec); } @@ -307,45 +453,44 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char return ret; } -int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { - secp256k1_ge_t p; - secp256k1_scalar_t term; +int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { + secp256k1_ge p; + secp256k1_scalar term; int ret = 0; int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(tweak != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak != NULL); secp256k1_scalar_set_b32(&term, tweak, &overflow); - if (!overflow) { - ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); - if (ret) { - ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term); - } - if (ret) { - int oldlen = pubkeylen; - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); - VERIFY_CHECK(pubkeylen == oldlen); + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + if (secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) { + secp256k1_pubkey_save(pubkey, &p); + } else { + ret = 0; } } return ret; } -int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) { - secp256k1_scalar_t factor; - secp256k1_scalar_t sec; +int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_scalar factor; + secp256k1_scalar sec; int ret = 0; int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(tweak != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); (void)ctx; secp256k1_scalar_set_b32(&factor, tweak, &overflow); secp256k1_scalar_set_b32(&sec, seckey, NULL); - ret = secp256k1_eckey_privkey_tweak_mul(&sec, &factor) && !overflow; + ret = !overflow && secp256k1_eckey_privkey_tweak_mul(&sec, &factor); + memset(seckey, 0, 32); if (ret) { secp256k1_scalar_get_b32(seckey, &sec); } @@ -355,65 +500,69 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char return ret; } -int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { - secp256k1_ge_t p; - secp256k1_scalar_t factor; +int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { + secp256k1_ge p; + secp256k1_scalar factor; int ret = 0; int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(tweak != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak != NULL); secp256k1_scalar_set_b32(&factor, tweak, &overflow); - if (!overflow) { - ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); - if (ret) { - ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor); - } - if (ret) { - int oldlen = pubkeylen; - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); - VERIFY_CHECK(pubkeylen == oldlen); - } - } - - return ret; -} - -int secp256k1_ec_privkey_export(const secp256k1_context_t* ctx, const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) { - secp256k1_scalar_t key; - int ret = 0; - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(privkey != NULL); - DEBUG_CHECK(privkeylen != NULL); - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - - secp256k1_scalar_set_b32(&key, seckey, NULL); - ret = secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, privkeylen, &key, compressed); - secp256k1_scalar_clear(&key); - return ret; -} - -int secp256k1_ec_privkey_import(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *privkey, int privkeylen) { - secp256k1_scalar_t key; - int ret = 0; - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(privkey != NULL); - (void)ctx; - - ret = secp256k1_eckey_privkey_parse(&key, privkey, privkeylen); + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); if (ret) { - secp256k1_scalar_get_b32(seckey, &key); + if (secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor)) { + secp256k1_pubkey_save(pubkey, &p); + } else { + ret = 0; + } } - secp256k1_scalar_clear(&key); + return ret; } -int secp256k1_context_randomize(secp256k1_context_t* ctx, const unsigned char *seed32) { - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); +int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); return 1; } + +int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, const secp256k1_pubkey * const *pubnonces, size_t n) { + size_t i; + secp256k1_gej Qj; + secp256k1_ge Q; + + ARG_CHECK(pubnonce != NULL); + memset(pubnonce, 0, sizeof(*pubnonce)); + ARG_CHECK(n >= 1); + ARG_CHECK(pubnonces != NULL); + + secp256k1_gej_set_infinity(&Qj); + + for (i = 0; i < n; i++) { + secp256k1_pubkey_load(ctx, &Q, pubnonces[i]); + secp256k1_gej_add_ge(&Qj, &Qj, &Q); + } + if (secp256k1_gej_is_infinity(&Qj)) { + return 0; + } + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(pubnonce, &Q); + return 1; +} + +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORR +# include "modules/schnorr/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/main_impl.h" +#endif diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h index 041bb92c4..f8efa93c7 100644 --- a/src/secp256k1/src/testrand.h +++ b/src/secp256k1/src/testrand.h @@ -16,13 +16,23 @@ /** Seed the pseudorandom number generator for testing. */ SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16); -/** Generate a pseudorandom 32-bit number. */ +/** Generate a pseudorandom number in the range [0..2**32-1]. */ static uint32_t secp256k1_rand32(void); +/** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or + * more. */ +static uint32_t secp256k1_rand_bits(int bits); + +/** Generate a pseudorandom number in the range [0..range-1]. */ +static uint32_t secp256k1_rand_int(uint32_t range); + /** Generate a pseudorandom 32-byte array. */ static void secp256k1_rand256(unsigned char *b32); /** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ static void secp256k1_rand256_test(unsigned char *b32); +/** Generate pseudorandom bytes with long sequences of zero and one bits. */ +static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len); + #endif diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h index 21c69f1c5..15c7b9f12 100644 --- a/src/secp256k1/src/testrand_impl.h +++ b/src/secp256k1/src/testrand_impl.h @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ @@ -16,9 +16,11 @@ static secp256k1_rfc6979_hmac_sha256_t secp256k1_test_rng; static uint32_t secp256k1_test_rng_precomputed[8]; static int secp256k1_test_rng_precomputed_used = 8; +static uint64_t secp256k1_test_rng_integer; +static int secp256k1_test_rng_integer_bits_left = 0; SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16) { - secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, (const unsigned char*)"TestRNG", 7, seed16, 16, NULL, 0); + secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16); } SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { @@ -29,32 +31,80 @@ SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++]; } +static uint32_t secp256k1_rand_bits(int bits) { + uint32_t ret; + if (secp256k1_test_rng_integer_bits_left < bits) { + secp256k1_test_rng_integer |= (((uint64_t)secp256k1_rand32()) << secp256k1_test_rng_integer_bits_left); + secp256k1_test_rng_integer_bits_left += 32; + } + ret = secp256k1_test_rng_integer; + secp256k1_test_rng_integer >>= bits; + secp256k1_test_rng_integer_bits_left -= bits; + ret &= ((~((uint32_t)0)) >> (32 - bits)); + return ret; +} + +static uint32_t secp256k1_rand_int(uint32_t range) { + /* We want a uniform integer between 0 and range-1, inclusive. + * B is the smallest number such that range <= 2**B. + * two mechanisms implemented here: + * - generate B bits numbers until one below range is found, and return it + * - find the largest multiple M of range that is <= 2**(B+A), generate B+A + * bits numbers until one below M is found, and return it modulo range + * The second mechanism consumes A more bits of entropy in every iteration, + * but may need fewer iterations due to M being closer to 2**(B+A) then + * range is to 2**B. The array below (indexed by B) contains a 0 when the + * first mechanism is to be used, and the number A otherwise. + */ + 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}; + uint32_t trange, mult; + int bits = 0; + if (range <= 1) { + return 0; + } + trange = range - 1; + while (trange > 0) { + trange >>= 1; + bits++; + } + if (addbits[bits]) { + bits = bits + addbits[bits]; + mult = ((~((uint32_t)0)) >> (32 - bits)) / range; + trange = range * mult; + } else { + trange = range; + mult = 1; + } + while(1) { + uint32_t x = secp256k1_rand_bits(bits); + if (x < trange) { + return (mult == 1) ? x : (x % range); + } + } +} + static void secp256k1_rand256(unsigned char *b32) { secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32); } -static void secp256k1_rand256_test(unsigned char *b32) { - int bits=0; - uint64_t ent = 0; - int entleft = 0; - memset(b32, 0, 32); - while (bits < 256) { +static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len) { + size_t bits = 0; + memset(bytes, 0, len); + while (bits < len * 8) { int now; uint32_t val; - if (entleft < 12) { - ent |= ((uint64_t)secp256k1_rand32()) << entleft; - entleft += 32; - } - now = 1 + ((ent % 64)*((ent >> 6) % 32)+16)/31; - val = 1 & (ent >> 11); - ent >>= 12; - entleft -= 12; - while (now > 0 && bits < 256) { - b32[bits / 8] |= val << (bits % 8); + now = 1 + (secp256k1_rand_bits(6) * secp256k1_rand_bits(5) + 16) / 31; + val = secp256k1_rand_bits(1); + while (now > 0 && bits < len * 8) { + bytes[bits / 8] |= val << (bits % 8); now--; bits++; } } } +static void secp256k1_rand256_test(unsigned char *b32) { + secp256k1_rand_bytes_test(b32, 32); +} + #endif diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c index d0e05057f..687a5f2fd 100644 --- a/src/secp256k1/src/tests.c +++ b/src/secp256k1/src/tests.c @@ -14,6 +14,7 @@ #include #include "secp256k1.c" +#include "include/secp256k1.h" #include "testrand_impl.h" #ifdef ENABLE_OPENSSL_TESTS @@ -23,10 +24,40 @@ #include "openssl/obj_mac.h" #endif -static int count = 64; -static secp256k1_context_t *ctx = NULL; +#include "contrib/lax_der_parsing.c" +#include "contrib/lax_der_privatekey_parsing.c" -void random_field_element_test(secp256k1_fe_t *fe) { +#if !defined(VG_CHECK) +# if defined(VALGRIND) +# include +# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) +# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) +# else +# define VG_UNDEF(x,y) +# define VG_CHECK(x,y) +# endif +#endif + +static int count = 64; +static secp256k1_context *ctx = NULL; + +static void counting_illegal_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts. */ + int32_t *p; + (void)str; + p = data; + (*p)++; +} + +static void uncounting_illegal_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts (backwards). */ + int32_t *p; + (void)str; + p = data; + (*p)--; +} + +void random_field_element_test(secp256k1_fe *fe) { do { unsigned char b32[32]; secp256k1_rand256_test(b32); @@ -36,9 +67,9 @@ void random_field_element_test(secp256k1_fe_t *fe) { } while(1); } -void random_field_element_magnitude(secp256k1_fe_t *fe) { - secp256k1_fe_t zero; - int n = secp256k1_rand32() % 9; +void random_field_element_magnitude(secp256k1_fe *fe) { + secp256k1_fe zero; + int n = secp256k1_rand_int(9); secp256k1_fe_normalize(fe); if (n == 0) { return; @@ -47,23 +78,22 @@ void random_field_element_magnitude(secp256k1_fe_t *fe) { secp256k1_fe_negate(&zero, &zero, 0); secp256k1_fe_mul_int(&zero, n - 1); secp256k1_fe_add(fe, &zero); -#ifdef VERIFY - CHECK(fe->magnitude == n); -#endif + VERIFY_CHECK(fe->magnitude == n); } -void random_group_element_test(secp256k1_ge_t *ge) { - secp256k1_fe_t fe; +void random_group_element_test(secp256k1_ge *ge) { + secp256k1_fe fe; do { random_field_element_test(&fe); - if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand32() & 1)) { + if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand_bits(1))) { + secp256k1_fe_normalize(&ge->y); break; } } while(1); } -void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge_t *ge) { - secp256k1_fe_t z2, z3; +void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { + secp256k1_fe z2, z3; do { random_field_element_test(&gej->z); if (!secp256k1_fe_is_zero(&gej->z)) { @@ -77,7 +107,7 @@ void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge gej->infinity = ge->infinity; } -void random_scalar_order_test(secp256k1_scalar_t *num) { +void random_scalar_order_test(secp256k1_scalar *num) { do { unsigned char b32[32]; int overflow = 0; @@ -90,7 +120,7 @@ void random_scalar_order_test(secp256k1_scalar_t *num) { } while(1); } -void random_scalar_order(secp256k1_scalar_t *num) { +void random_scalar_order(secp256k1_scalar *num) { do { unsigned char b32[32]; int overflow = 0; @@ -104,19 +134,31 @@ void random_scalar_order(secp256k1_scalar_t *num) { } void run_context_tests(void) { - secp256k1_context_t *none = secp256k1_context_create(0); - secp256k1_context_t *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - secp256k1_context_t *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + unsigned char ctmp[32]; + int32_t ecount; + int32_t ecount2; + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - secp256k1_gej_t pubj; - secp256k1_ge_t pub; - secp256k1_scalar_t msg, key, nonce; - secp256k1_ecdsa_sig_t sig; + secp256k1_gej pubj; + secp256k1_ge pub; + secp256k1_scalar msg, key, nonce; + secp256k1_scalar sigr, sigs; + + ecount = 0; + ecount2 = 10; + secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2); + secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL); + CHECK(vrfy->error_callback.fn != sign->error_callback.fn); /*** clone and destroy all of them to make sure cloning was complete ***/ { - secp256k1_context_t *ctx_tmp; + secp256k1_context *ctx_tmp; ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_destroy(ctx_tmp); ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_destroy(ctx_tmp); @@ -124,30 +166,74 @@ void run_context_tests(void) { ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp); } + /* Verify that the error callback makes it across the clone. */ + CHECK(vrfy->error_callback.fn != sign->error_callback.fn); + /* And that it resets back to default. */ + secp256k1_context_set_error_callback(sign, NULL, NULL); + CHECK(vrfy->error_callback.fn == sign->error_callback.fn); + /*** attempt to use them ***/ random_scalar_order_test(&msg); random_scalar_order_test(&key); secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); + /* Verify context-type checking illegal-argument errors. */ + memset(ctmp, 1, 32); + CHECK(secp256k1_ec_pubkey_create(vrfy, &pubkey, ctmp) == 0); + CHECK(ecount == 1); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(sign, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ecdsa_sign(vrfy, &sig, ctmp, ctmp, NULL, NULL) == 0); + CHECK(ecount == 2); + VG_UNDEF(&sig, sizeof(sig)); + CHECK(secp256k1_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1); + VG_CHECK(&sig, sizeof(sig)); + CHECK(ecount2 == 10); + CHECK(secp256k1_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 0); + CHECK(ecount2 == 11); + CHECK(secp256k1_ecdsa_verify(vrfy, &sig, ctmp, &pubkey) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 0); + CHECK(ecount2 == 12); + CHECK(secp256k1_ec_pubkey_tweak_add(vrfy, &pubkey, ctmp) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0); + CHECK(ecount2 == 13); + CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_context_randomize(sign, NULL) == 1); + CHECK(ecount2 == 13); + secp256k1_context_set_illegal_callback(vrfy, NULL, NULL); + secp256k1_context_set_illegal_callback(sign, NULL, NULL); + + /* This shouldn't leak memory, due to already-set tests. */ + secp256k1_ecmult_gen_context_build(&sign->ecmult_gen_ctx, NULL); + secp256k1_ecmult_context_build(&vrfy->ecmult_ctx, NULL); + /* obtain a working nonce */ do { random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); /* try signing */ - CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); - CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); /* try verifying */ - CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sig, &pub, &msg)); - CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sig, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg)); /* cleanup */ secp256k1_context_destroy(none); secp256k1_context_destroy(sign); secp256k1_context_destroy(vrfy); secp256k1_context_destroy(both); + /* Defined as no-op. */ + secp256k1_context_destroy(NULL); } /***** HASH TESTS *****/ @@ -178,7 +264,7 @@ void run_sha256_tests(void) { secp256k1_sha256_finalize(&hasher, out); CHECK(memcmp(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand32() % strlen(inputs[i]); + int split = secp256k1_rand_int(strlen(inputs[i])); secp256k1_sha256_initialize(&hasher); secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); @@ -222,7 +308,7 @@ void run_hmac_sha256_tests(void) { secp256k1_hmac_sha256_finalize(&hasher, out); CHECK(memcmp(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand32() % strlen(inputs[i]); + int split = secp256k1_rand_int(strlen(inputs[i])); secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); @@ -233,16 +319,14 @@ void run_hmac_sha256_tests(void) { } void run_rfc6979_hmac_sha256_tests(void) { - static const unsigned char key1[32] = {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}; - static const unsigned char msg1[32] = {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}; + 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}; static const unsigned char out1[3][32] = { {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}, {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}, {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} }; - static const unsigned char key2[32] = {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}; - static const unsigned char msg2[32] = {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}; + 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}; static const unsigned char out2[3][32] = { {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}, {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}, @@ -251,24 +335,23 @@ void run_rfc6979_hmac_sha256_tests(void) { secp256k1_rfc6979_hmac_sha256_t rng; unsigned char out[32]; - unsigned char zero[1] = {0}; int i; - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32, NULL, 1); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); CHECK(memcmp(out, out1[i], 32) == 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32, zero, 1); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); CHECK(memcmp(out, out1[i], 32) != 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 32, msg2, 32, zero, 0); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); CHECK(memcmp(out, out2[i], 32) == 0); @@ -276,30 +359,102 @@ void run_rfc6979_hmac_sha256_tests(void) { secp256k1_rfc6979_hmac_sha256_finalize(&rng); } +/***** RANDOM TESTS *****/ + +void test_rand_bits(int rand32, int bits) { + /* (1-1/2^B)^rounds[B] < 1/10^9, so rounds is the number of iterations to + * get a false negative chance below once in a billion */ + static const unsigned int rounds[7] = {1, 30, 73, 156, 322, 653, 1316}; + /* We try multiplying the results with various odd numbers, which shouldn't + * influence the uniform distribution modulo a power of 2. */ + static const uint32_t mults[6] = {1, 3, 21, 289, 0x9999, 0x80402011}; + /* We only select up to 6 bits from the output to analyse */ + unsigned int usebits = bits > 6 ? 6 : bits; + unsigned int maxshift = bits - usebits; + /* For each of the maxshift+1 usebits-bit sequences inside a bits-bit + number, track all observed outcomes, one per bit in a uint64_t. */ + uint64_t x[6][27] = {{0}}; + unsigned int i, shift, m; + /* Multiply the output of all rand calls with the odd number m, which + should not change the uniformity of its distribution. */ + for (i = 0; i < rounds[usebits]; i++) { + uint32_t r = (rand32 ? secp256k1_rand32() : secp256k1_rand_bits(bits)); + CHECK((((uint64_t)r) >> bits) == 0); + for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { + uint32_t rm = r * mults[m]; + for (shift = 0; shift <= maxshift; shift++) { + x[m][shift] |= (((uint64_t)1) << ((rm >> shift) & ((1 << usebits) - 1))); + } + } + } + for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { + for (shift = 0; shift <= maxshift; shift++) { + /* Test that the lower usebits bits of x[shift] are 1 */ + CHECK(((~x[m][shift]) << (64 - (1 << usebits))) == 0); + } + } +} + +/* Subrange must be a whole divisor of range, and at most 64 */ +void test_rand_int(uint32_t range, uint32_t subrange) { + /* (1-1/subrange)^rounds < 1/10^9 */ + int rounds = (subrange * 2073) / 100; + int i; + uint64_t x = 0; + CHECK((range % subrange) == 0); + for (i = 0; i < rounds; i++) { + uint32_t r = secp256k1_rand_int(range); + CHECK(r < range); + r = r % subrange; + x |= (((uint64_t)1) << r); + } + /* Test that the lower subrange bits of x are 1. */ + CHECK(((~x) << (64 - subrange)) == 0); +} + +void run_rand_bits(void) { + size_t b; + test_rand_bits(1, 32); + for (b = 1; b <= 32; b++) { + test_rand_bits(0, b); + } +} + +void run_rand_int(void) { + static const uint32_t ms[] = {1, 3, 17, 1000, 13771, 999999, 33554432}; + static const uint32_t ss[] = {1, 3, 6, 9, 13, 31, 64}; + unsigned int m, s; + for (m = 0; m < sizeof(ms) / sizeof(ms[0]); m++) { + for (s = 0; s < sizeof(ss) / sizeof(ss[0]); s++) { + test_rand_int(ms[m] * ss[s], ss[s]); + } + } +} + /***** NUM TESTS *****/ #ifndef USE_NUM_NONE -void random_num_negate(secp256k1_num_t *num) { - if (secp256k1_rand32() & 1) { +void random_num_negate(secp256k1_num *num) { + if (secp256k1_rand_bits(1)) { secp256k1_num_negate(num); } } -void random_num_order_test(secp256k1_num_t *num) { - secp256k1_scalar_t sc; +void random_num_order_test(secp256k1_num *num) { + secp256k1_scalar sc; random_scalar_order_test(&sc); secp256k1_scalar_get_num(num, &sc); } -void random_num_order(secp256k1_num_t *num) { - secp256k1_scalar_t sc; +void random_num_order(secp256k1_num *num) { + secp256k1_scalar sc; random_scalar_order(&sc); secp256k1_scalar_get_num(num, &sc); } void test_num_negate(void) { - secp256k1_num_t n1; - secp256k1_num_t n2; + secp256k1_num n1; + secp256k1_num n2; random_num_order_test(&n1); /* n1 = R */ random_num_negate(&n1); secp256k1_num_copy(&n2, &n1); /* n2 = R */ @@ -318,16 +473,15 @@ void test_num_negate(void) { } void test_num_add_sub(void) { - secp256k1_num_t n1; - secp256k1_num_t n2; - secp256k1_num_t n1p2, n2p1, n1m2, n2m1; - int r = secp256k1_rand32(); + secp256k1_num n1; + secp256k1_num n2; + secp256k1_num n1p2, n2p1, n1m2, n2m1; random_num_order_test(&n1); /* n1 = R1 */ - if (r & 1) { + if (secp256k1_rand_bits(1)) { random_num_negate(&n1); } random_num_order_test(&n2); /* n2 = R2 */ - if (r & 2) { + if (secp256k1_rand_bits(1)) { random_num_negate(&n2); } secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */ @@ -358,12 +512,12 @@ void run_num_smalltests(void) { /***** SCALAR TESTS *****/ void scalar_test(void) { - secp256k1_scalar_t s; - secp256k1_scalar_t s1; - secp256k1_scalar_t s2; + secp256k1_scalar s; + secp256k1_scalar s1; + secp256k1_scalar s2; #ifndef USE_NUM_NONE - secp256k1_num_t snum, s1num, s2num; - secp256k1_num_t order, half_order; + secp256k1_num snum, s1num, s2num; + secp256k1_num order, half_order; #endif unsigned char c[32]; @@ -390,10 +544,10 @@ void scalar_test(void) { { int i; /* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */ - secp256k1_scalar_t n; + secp256k1_scalar n; secp256k1_scalar_set_int(&n, 0); for (i = 0; i < 256; i += 4) { - secp256k1_scalar_t t; + secp256k1_scalar t; int j; secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4)); for (j = 0; j < 4; j++) { @@ -406,13 +560,13 @@ void scalar_test(void) { { /* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */ - secp256k1_scalar_t n; + secp256k1_scalar n; int i = 0; secp256k1_scalar_set_int(&n, 0); while (i < 256) { - secp256k1_scalar_t t; + secp256k1_scalar t; int j; - int now = (secp256k1_rand32() % 15) + 1; + int now = secp256k1_rand_int(15) + 1; if (now + i > 256) { now = 256 - i; } @@ -429,9 +583,9 @@ void scalar_test(void) { #ifndef USE_NUM_NONE { /* Test that adding the scalars together is equal to adding their numbers together modulo the order. */ - secp256k1_num_t rnum; - secp256k1_num_t r2num; - secp256k1_scalar_t r; + secp256k1_num rnum; + secp256k1_num r2num; + secp256k1_scalar r; secp256k1_num_add(&rnum, &snum, &s2num); secp256k1_num_mod(&rnum, &order); secp256k1_scalar_add(&r, &s, &s2); @@ -440,10 +594,10 @@ void scalar_test(void) { } { - /* Test that multipying the scalars is equal to multiplying their numbers modulo the order. */ - secp256k1_scalar_t r; - secp256k1_num_t r2num; - secp256k1_num_t rnum; + /* Test that multiplying the scalars is equal to multiplying their numbers modulo the order. */ + secp256k1_scalar r; + secp256k1_num r2num; + secp256k1_num rnum; secp256k1_num_mul(&rnum, &snum, &s2num); secp256k1_num_mod(&rnum, &order); secp256k1_scalar_mul(&r, &s, &s2); @@ -457,9 +611,9 @@ void scalar_test(void) { } { - secp256k1_scalar_t neg; - secp256k1_num_t negnum; - secp256k1_num_t negnum2; + secp256k1_scalar neg; + secp256k1_num negnum; + secp256k1_num negnum2; /* Check that comparison with zero matches comparison with zero on the number. */ CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s)); /* Check that comparison with the half order is equal to testing for high scalar. */ @@ -484,12 +638,12 @@ void scalar_test(void) { { /* Test secp256k1_scalar_mul_shift_var. */ - secp256k1_scalar_t r; - secp256k1_num_t one; - secp256k1_num_t rnum; - secp256k1_num_t rnum2; + secp256k1_scalar r; + secp256k1_num one; + secp256k1_num rnum; + secp256k1_num rnum2; unsigned char cone[1] = {0x01}; - unsigned int shift = 256 + (secp256k1_rand32() % 257); + unsigned int shift = 256 + secp256k1_rand_int(257); secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift); secp256k1_num_mul(&rnum, &s1num, &s2num); secp256k1_num_shift(&rnum, shift - 1); @@ -499,15 +653,29 @@ void scalar_test(void) { secp256k1_scalar_get_num(&rnum2, &r); CHECK(secp256k1_num_eq(&rnum, &rnum2)); } + + { + /* test secp256k1_scalar_shr_int */ + secp256k1_scalar r; + int i; + random_scalar_order_test(&r); + for (i = 0; i < 100; ++i) { + int low; + int shift = 1 + secp256k1_rand_int(15); + int expected = r.d[0] % (1 << shift); + low = secp256k1_scalar_shr_int(&r, shift); + CHECK(expected == low); + } + } #endif { /* Test that scalar inverses are equal to the inverse of their number modulo the order. */ if (!secp256k1_scalar_is_zero(&s)) { - secp256k1_scalar_t inv; + secp256k1_scalar inv; #ifndef USE_NUM_NONE - secp256k1_num_t invnum; - secp256k1_num_t invnum2; + secp256k1_num invnum; + secp256k1_num invnum2; #endif secp256k1_scalar_inverse(&inv, &s); #ifndef USE_NUM_NONE @@ -526,18 +694,18 @@ void scalar_test(void) { { /* Test commutativity of add. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_add(&r1, &s1, &s2); secp256k1_scalar_add(&r2, &s2, &s1); CHECK(secp256k1_scalar_eq(&r1, &r2)); } { - secp256k1_scalar_t r1, r2; - secp256k1_scalar_t b; + secp256k1_scalar r1, r2; + secp256k1_scalar b; int i; /* Test add_bit. */ - int bit = secp256k1_rand32() % 256; + int bit = secp256k1_rand_bits(8); secp256k1_scalar_set_int(&b, 1); CHECK(secp256k1_scalar_is_one(&b)); for (i = 0; i < bit; i++) { @@ -547,14 +715,17 @@ void scalar_test(void) { r2 = s1; if (!secp256k1_scalar_add(&r1, &r1, &b)) { /* No overflow happened. */ - secp256k1_scalar_add_bit(&r2, bit); + secp256k1_scalar_cadd_bit(&r2, bit, 1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + /* cadd is a noop when flag is zero */ + secp256k1_scalar_cadd_bit(&r2, bit, 0); CHECK(secp256k1_scalar_eq(&r1, &r2)); } } { /* Test commutativity of mul. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_mul(&r1, &s1, &s2); secp256k1_scalar_mul(&r2, &s2, &s1); CHECK(secp256k1_scalar_eq(&r1, &r2)); @@ -562,7 +733,7 @@ void scalar_test(void) { { /* Test associativity of add. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_add(&r1, &s1, &s2); secp256k1_scalar_add(&r1, &r1, &s); secp256k1_scalar_add(&r2, &s2, &s); @@ -572,7 +743,7 @@ void scalar_test(void) { { /* Test associativity of mul. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_mul(&r1, &s1, &s2); secp256k1_scalar_mul(&r1, &r1, &s); secp256k1_scalar_mul(&r2, &s2, &s); @@ -582,7 +753,7 @@ void scalar_test(void) { { /* Test distributitivity of mul over add. */ - secp256k1_scalar_t r1, r2, t; + secp256k1_scalar r1, r2, t; secp256k1_scalar_add(&r1, &s1, &s2); secp256k1_scalar_mul(&r1, &r1, &s); secp256k1_scalar_mul(&r2, &s1, &s); @@ -593,7 +764,7 @@ void scalar_test(void) { { /* Test square. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_sqr(&r1, &s1); secp256k1_scalar_mul(&r2, &s1, &s1); CHECK(secp256k1_scalar_eq(&r1, &r2)); @@ -601,7 +772,7 @@ void scalar_test(void) { { /* Test multiplicative identity. */ - secp256k1_scalar_t r1, v1; + secp256k1_scalar r1, v1; secp256k1_scalar_set_int(&v1,1); secp256k1_scalar_mul(&r1, &s1, &v1); CHECK(secp256k1_scalar_eq(&r1, &s1)); @@ -609,7 +780,7 @@ void scalar_test(void) { { /* Test additive identity. */ - secp256k1_scalar_t r1, v0; + secp256k1_scalar r1, v0; secp256k1_scalar_set_int(&v0,0); secp256k1_scalar_add(&r1, &s1, &v0); CHECK(secp256k1_scalar_eq(&r1, &s1)); @@ -617,7 +788,7 @@ void scalar_test(void) { { /* Test zero product property. */ - secp256k1_scalar_t r1, v0; + secp256k1_scalar r1, v0; secp256k1_scalar_set_int(&v0,0); secp256k1_scalar_mul(&r1, &s1, &v0); CHECK(secp256k1_scalar_eq(&r1, &v0)); @@ -633,7 +804,7 @@ void run_scalar_tests(void) { { /* (-1)+1 should be zero. */ - secp256k1_scalar_t s, o; + secp256k1_scalar s, o; secp256k1_scalar_set_int(&s, 1); CHECK(secp256k1_scalar_is_one(&s)); secp256k1_scalar_negate(&o, &s); @@ -646,8 +817,8 @@ void run_scalar_tests(void) { #ifndef USE_NUM_NONE { /* A scalar with value of the curve order should be 0. */ - secp256k1_num_t order; - secp256k1_scalar_t zero; + secp256k1_num order; + secp256k1_scalar zero; unsigned char bin[32]; int overflow = 0; secp256k1_scalar_order_get_num(&order); @@ -657,11 +828,589 @@ void run_scalar_tests(void) { CHECK(secp256k1_scalar_is_zero(&zero)); } #endif + + { + /* Does check_overflow check catch all ones? */ + static const secp256k1_scalar overflowed = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + CHECK(secp256k1_scalar_check_overflow(&overflowed)); + } + + { + /* Static test vectors. + * These were reduced from ~10^12 random vectors based on comparison-decision + * and edge-case coverage on 32-bit and 64-bit implementations. + * The responses were generated with Sage 5.9. + */ + secp256k1_scalar x; + secp256k1_scalar y; + secp256k1_scalar z; + secp256k1_scalar zz; + secp256k1_scalar one; + secp256k1_scalar r1; + secp256k1_scalar r2; +#if defined(USE_SCALAR_INV_NUM) + secp256k1_scalar zzv; +#endif + int overflow; + unsigned char chal[32][2][32] = { + {{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff}}, + {{0xef, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1e, 0xf8, 0xff, 0xff, 0xff, 0xfd, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xe0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, + 0xf3, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xfc, 0x9f, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x0f, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0xf8, 0xff, 0x0f, 0xc0, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x00, 0xf8, 0xff, 0x03, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0xc0, 0xff, 0x0f, 0xfc, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x8f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0x7f}, + {0xff, 0xcf, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, + 0xbf, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x01, 0xfc, 0xff, 0x01, 0x00, 0xfe, 0xff}, + {0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0xff, + 0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x3f, + 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x0f, 0x7e, 0x00, 0x00}}, + {{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x1f, 0x00, 0x00, 0xfe, 0x07, 0x00}, + {0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60}}, + {{0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, + 0x80, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x00, 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, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0xff, 0xff, 0xcf, 0xff, 0x1f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00}, + {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x80, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x1f, 0x00, 0xfe}}, + {{0xff, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0x03, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x7f, 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}, + {0x7f, 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, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xc0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff}}, + {{0x7f, 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}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7e, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0xc0, 0xf1, 0x7f, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, + 0x00, 0x00, 0xfc, 0xff, 0xff, 0x01, 0xff, 0xff}}, + {{0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x03, 0xe0, 0x01, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xf0, 0x07, 0x00, 0x3c, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x07, 0xe0, 0xff, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x80, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0xff, 0x1f, + 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0xfe, 0xff}}, + {{0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, + 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, + 0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}} + }; + unsigned char res[32][2][32] = { + {{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9, + 0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1, + 0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6, + 0x20, 0x1e, 0x86, 0xd0, 0x95, 0xf6, 0x92, 0x35}, + {0xdc, 0x90, 0x7a, 0x07, 0x2e, 0x1e, 0x44, 0x6d, + 0xf8, 0x15, 0x24, 0x5b, 0x5a, 0x96, 0x37, 0x9c, + 0x37, 0x7b, 0x0d, 0xac, 0x1b, 0x65, 0x58, 0x49, + 0x43, 0xb7, 0x31, 0xbb, 0xa7, 0xf4, 0x97, 0x15}}, + {{0xf1, 0xf7, 0x3a, 0x50, 0xe6, 0x10, 0xba, 0x22, + 0x43, 0x4d, 0x1f, 0x1f, 0x7c, 0x27, 0xca, 0x9c, + 0xb8, 0xb6, 0xa0, 0xfc, 0xd8, 0xc0, 0x05, 0x2f, + 0xf7, 0x08, 0xe1, 0x76, 0xdd, 0xd0, 0x80, 0xc8}, + {0xe3, 0x80, 0x80, 0xb8, 0xdb, 0xe3, 0xa9, 0x77, + 0x00, 0xb0, 0xf5, 0x2e, 0x27, 0xe2, 0x68, 0xc4, + 0x88, 0xe8, 0x04, 0xc1, 0x12, 0xbf, 0x78, 0x59, + 0xe6, 0xa9, 0x7c, 0xe1, 0x81, 0xdd, 0xb9, 0xd5}}, + {{0x96, 0xe2, 0xee, 0x01, 0xa6, 0x80, 0x31, 0xef, + 0x5c, 0xd0, 0x19, 0xb4, 0x7d, 0x5f, 0x79, 0xab, + 0xa1, 0x97, 0xd3, 0x7e, 0x33, 0xbb, 0x86, 0x55, + 0x60, 0x20, 0x10, 0x0d, 0x94, 0x2d, 0x11, 0x7c}, + {0xcc, 0xab, 0xe0, 0xe8, 0x98, 0x65, 0x12, 0x96, + 0x38, 0x5a, 0x1a, 0xf2, 0x85, 0x23, 0x59, 0x5f, + 0xf9, 0xf3, 0xc2, 0x81, 0x70, 0x92, 0x65, 0x12, + 0x9c, 0x65, 0x1e, 0x96, 0x00, 0xef, 0xe7, 0x63}}, + {{0xac, 0x1e, 0x62, 0xc2, 0x59, 0xfc, 0x4e, 0x5c, + 0x83, 0xb0, 0xd0, 0x6f, 0xce, 0x19, 0xf6, 0xbf, + 0xa4, 0xb0, 0xe0, 0x53, 0x66, 0x1f, 0xbf, 0xc9, + 0x33, 0x47, 0x37, 0xa9, 0x3d, 0x5d, 0xb0, 0x48}, + {0x86, 0xb9, 0x2a, 0x7f, 0x8e, 0xa8, 0x60, 0x42, + 0x26, 0x6d, 0x6e, 0x1c, 0xa2, 0xec, 0xe0, 0xe5, + 0x3e, 0x0a, 0x33, 0xbb, 0x61, 0x4c, 0x9f, 0x3c, + 0xd1, 0xdf, 0x49, 0x33, 0xcd, 0x72, 0x78, 0x18}}, + {{0xf7, 0xd3, 0xcd, 0x49, 0x5c, 0x13, 0x22, 0xfb, + 0x2e, 0xb2, 0x2f, 0x27, 0xf5, 0x8a, 0x5d, 0x74, + 0xc1, 0x58, 0xc5, 0xc2, 0x2d, 0x9f, 0x52, 0xc6, + 0x63, 0x9f, 0xba, 0x05, 0x76, 0x45, 0x7a, 0x63}, + {0x8a, 0xfa, 0x55, 0x4d, 0xdd, 0xa3, 0xb2, 0xc3, + 0x44, 0xfd, 0xec, 0x72, 0xde, 0xef, 0xc0, 0x99, + 0xf5, 0x9f, 0xe2, 0x52, 0xb4, 0x05, 0x32, 0x58, + 0x57, 0xc1, 0x8f, 0xea, 0xc3, 0x24, 0x5b, 0x94}}, + {{0x05, 0x83, 0xee, 0xdd, 0x64, 0xf0, 0x14, 0x3b, + 0xa0, 0x14, 0x4a, 0x3a, 0x41, 0x82, 0x7c, 0xa7, + 0x2c, 0xaa, 0xb1, 0x76, 0xbb, 0x59, 0x64, 0x5f, + 0x52, 0xad, 0x25, 0x29, 0x9d, 0x8f, 0x0b, 0xb0}, + {0x7e, 0xe3, 0x7c, 0xca, 0xcd, 0x4f, 0xb0, 0x6d, + 0x7a, 0xb2, 0x3e, 0xa0, 0x08, 0xb9, 0xa8, 0x2d, + 0xc2, 0xf4, 0x99, 0x66, 0xcc, 0xac, 0xd8, 0xb9, + 0x72, 0x2a, 0x4a, 0x3e, 0x0f, 0x7b, 0xbf, 0xf4}}, + {{0x8c, 0x9c, 0x78, 0x2b, 0x39, 0x61, 0x7e, 0xf7, + 0x65, 0x37, 0x66, 0x09, 0x38, 0xb9, 0x6f, 0x70, + 0x78, 0x87, 0xff, 0xcf, 0x93, 0xca, 0x85, 0x06, + 0x44, 0x84, 0xa7, 0xfe, 0xd3, 0xa4, 0xe3, 0x7e}, + {0xa2, 0x56, 0x49, 0x23, 0x54, 0xa5, 0x50, 0xe9, + 0x5f, 0xf0, 0x4d, 0xe7, 0xdc, 0x38, 0x32, 0x79, + 0x4f, 0x1c, 0xb7, 0xe4, 0xbb, 0xf8, 0xbb, 0x2e, + 0x40, 0x41, 0x4b, 0xcc, 0xe3, 0x1e, 0x16, 0x36}}, + {{0x0c, 0x1e, 0xd7, 0x09, 0x25, 0x40, 0x97, 0xcb, + 0x5c, 0x46, 0xa8, 0xda, 0xef, 0x25, 0xd5, 0xe5, + 0x92, 0x4d, 0xcf, 0xa3, 0xc4, 0x5d, 0x35, 0x4a, + 0xe4, 0x61, 0x92, 0xf3, 0xbf, 0x0e, 0xcd, 0xbe}, + {0xe4, 0xaf, 0x0a, 0xb3, 0x30, 0x8b, 0x9b, 0x48, + 0x49, 0x43, 0xc7, 0x64, 0x60, 0x4a, 0x2b, 0x9e, + 0x95, 0x5f, 0x56, 0xe8, 0x35, 0xdc, 0xeb, 0xdc, + 0xc7, 0xc4, 0xfe, 0x30, 0x40, 0xc7, 0xbf, 0xa4}}, + {{0xd4, 0xa0, 0xf5, 0x81, 0x49, 0x6b, 0xb6, 0x8b, + 0x0a, 0x69, 0xf9, 0xfe, 0xa8, 0x32, 0xe5, 0xe0, + 0xa5, 0xcd, 0x02, 0x53, 0xf9, 0x2c, 0xe3, 0x53, + 0x83, 0x36, 0xc6, 0x02, 0xb5, 0xeb, 0x64, 0xb8}, + {0x1d, 0x42, 0xb9, 0xf9, 0xe9, 0xe3, 0x93, 0x2c, + 0x4c, 0xee, 0x6c, 0x5a, 0x47, 0x9e, 0x62, 0x01, + 0x6b, 0x04, 0xfe, 0xa4, 0x30, 0x2b, 0x0d, 0x4f, + 0x71, 0x10, 0xd3, 0x55, 0xca, 0xf3, 0x5e, 0x80}}, + {{0x77, 0x05, 0xf6, 0x0c, 0x15, 0x9b, 0x45, 0xe7, + 0xb9, 0x11, 0xb8, 0xf5, 0xd6, 0xda, 0x73, 0x0c, + 0xda, 0x92, 0xea, 0xd0, 0x9d, 0xd0, 0x18, 0x92, + 0xce, 0x9a, 0xaa, 0xee, 0x0f, 0xef, 0xde, 0x30}, + {0xf1, 0xf1, 0xd6, 0x9b, 0x51, 0xd7, 0x77, 0x62, + 0x52, 0x10, 0xb8, 0x7a, 0x84, 0x9d, 0x15, 0x4e, + 0x07, 0xdc, 0x1e, 0x75, 0x0d, 0x0c, 0x3b, 0xdb, + 0x74, 0x58, 0x62, 0x02, 0x90, 0x54, 0x8b, 0x43}}, + {{0xa6, 0xfe, 0x0b, 0x87, 0x80, 0x43, 0x67, 0x25, + 0x57, 0x5d, 0xec, 0x40, 0x50, 0x08, 0xd5, 0x5d, + 0x43, 0xd7, 0xe0, 0xaa, 0xe0, 0x13, 0xb6, 0xb0, + 0xc0, 0xd4, 0xe5, 0x0d, 0x45, 0x83, 0xd6, 0x13}, + {0x40, 0x45, 0x0a, 0x92, 0x31, 0xea, 0x8c, 0x60, + 0x8c, 0x1f, 0xd8, 0x76, 0x45, 0xb9, 0x29, 0x00, + 0x26, 0x32, 0xd8, 0xa6, 0x96, 0x88, 0xe2, 0xc4, + 0x8b, 0xdb, 0x7f, 0x17, 0x87, 0xcc, 0xc8, 0xf2}}, + {{0xc2, 0x56, 0xe2, 0xb6, 0x1a, 0x81, 0xe7, 0x31, + 0x63, 0x2e, 0xbb, 0x0d, 0x2f, 0x81, 0x67, 0xd4, + 0x22, 0xe2, 0x38, 0x02, 0x25, 0x97, 0xc7, 0x88, + 0x6e, 0xdf, 0xbe, 0x2a, 0xa5, 0x73, 0x63, 0xaa}, + {0x50, 0x45, 0xe2, 0xc3, 0xbd, 0x89, 0xfc, 0x57, + 0xbd, 0x3c, 0xa3, 0x98, 0x7e, 0x7f, 0x36, 0x38, + 0x92, 0x39, 0x1f, 0x0f, 0x81, 0x1a, 0x06, 0x51, + 0x1f, 0x8d, 0x6a, 0xff, 0x47, 0x16, 0x06, 0x9c}}, + {{0x33, 0x95, 0xa2, 0x6f, 0x27, 0x5f, 0x9c, 0x9c, + 0x64, 0x45, 0xcb, 0xd1, 0x3c, 0xee, 0x5e, 0x5f, + 0x48, 0xa6, 0xaf, 0xe3, 0x79, 0xcf, 0xb1, 0xe2, + 0xbf, 0x55, 0x0e, 0xa2, 0x3b, 0x62, 0xf0, 0xe4}, + {0x14, 0xe8, 0x06, 0xe3, 0xbe, 0x7e, 0x67, 0x01, + 0xc5, 0x21, 0x67, 0xd8, 0x54, 0xb5, 0x7f, 0xa4, + 0xf9, 0x75, 0x70, 0x1c, 0xfd, 0x79, 0xdb, 0x86, + 0xad, 0x37, 0x85, 0x83, 0x56, 0x4e, 0xf0, 0xbf}}, + {{0xbc, 0xa6, 0xe0, 0x56, 0x4e, 0xef, 0xfa, 0xf5, + 0x1d, 0x5d, 0x3f, 0x2a, 0x5b, 0x19, 0xab, 0x51, + 0xc5, 0x8b, 0xdd, 0x98, 0x28, 0x35, 0x2f, 0xc3, + 0x81, 0x4f, 0x5c, 0xe5, 0x70, 0xb9, 0xeb, 0x62}, + {0xc4, 0x6d, 0x26, 0xb0, 0x17, 0x6b, 0xfe, 0x6c, + 0x12, 0xf8, 0xe7, 0xc1, 0xf5, 0x2f, 0xfa, 0x91, + 0x13, 0x27, 0xbd, 0x73, 0xcc, 0x33, 0x31, 0x1c, + 0x39, 0xe3, 0x27, 0x6a, 0x95, 0xcf, 0xc5, 0xfb}}, + {{0x30, 0xb2, 0x99, 0x84, 0xf0, 0x18, 0x2a, 0x6e, + 0x1e, 0x27, 0xed, 0xa2, 0x29, 0x99, 0x41, 0x56, + 0xe8, 0xd4, 0x0d, 0xef, 0x99, 0x9c, 0xf3, 0x58, + 0x29, 0x55, 0x1a, 0xc0, 0x68, 0xd6, 0x74, 0xa4}, + {0x07, 0x9c, 0xe7, 0xec, 0xf5, 0x36, 0x73, 0x41, + 0xa3, 0x1c, 0xe5, 0x93, 0x97, 0x6a, 0xfd, 0xf7, + 0x53, 0x18, 0xab, 0xaf, 0xeb, 0x85, 0xbd, 0x92, + 0x90, 0xab, 0x3c, 0xbf, 0x30, 0x82, 0xad, 0xf6}}, + {{0xc6, 0x87, 0x8a, 0x2a, 0xea, 0xc0, 0xa9, 0xec, + 0x6d, 0xd3, 0xdc, 0x32, 0x23, 0xce, 0x62, 0x19, + 0xa4, 0x7e, 0xa8, 0xdd, 0x1c, 0x33, 0xae, 0xd3, + 0x4f, 0x62, 0x9f, 0x52, 0xe7, 0x65, 0x46, 0xf4}, + {0x97, 0x51, 0x27, 0x67, 0x2d, 0xa2, 0x82, 0x87, + 0x98, 0xd3, 0xb6, 0x14, 0x7f, 0x51, 0xd3, 0x9a, + 0x0b, 0xd0, 0x76, 0x81, 0xb2, 0x4f, 0x58, 0x92, + 0xa4, 0x86, 0xa1, 0xa7, 0x09, 0x1d, 0xef, 0x9b}}, + {{0xb3, 0x0f, 0x2b, 0x69, 0x0d, 0x06, 0x90, 0x64, + 0xbd, 0x43, 0x4c, 0x10, 0xe8, 0x98, 0x1c, 0xa3, + 0xe1, 0x68, 0xe9, 0x79, 0x6c, 0x29, 0x51, 0x3f, + 0x41, 0xdc, 0xdf, 0x1f, 0xf3, 0x60, 0xbe, 0x33}, + {0xa1, 0x5f, 0xf7, 0x1d, 0xb4, 0x3e, 0x9b, 0x3c, + 0xe7, 0xbd, 0xb6, 0x06, 0xd5, 0x60, 0x06, 0x6d, + 0x50, 0xd2, 0xf4, 0x1a, 0x31, 0x08, 0xf2, 0xea, + 0x8e, 0xef, 0x5f, 0x7d, 0xb6, 0xd0, 0xc0, 0x27}}, + {{0x62, 0x9a, 0xd9, 0xbb, 0x38, 0x36, 0xce, 0xf7, + 0x5d, 0x2f, 0x13, 0xec, 0xc8, 0x2d, 0x02, 0x8a, + 0x2e, 0x72, 0xf0, 0xe5, 0x15, 0x9d, 0x72, 0xae, + 0xfc, 0xb3, 0x4f, 0x02, 0xea, 0xe1, 0x09, 0xfe}, + {0x00, 0x00, 0x00, 0x00, 0xfa, 0x0a, 0x3d, 0xbc, + 0xad, 0x16, 0x0c, 0xb6, 0xe7, 0x7c, 0x8b, 0x39, + 0x9a, 0x43, 0xbb, 0xe3, 0xc2, 0x55, 0x15, 0x14, + 0x75, 0xac, 0x90, 0x9b, 0x7f, 0x9a, 0x92, 0x00}}, + {{0x8b, 0xac, 0x70, 0x86, 0x29, 0x8f, 0x00, 0x23, + 0x7b, 0x45, 0x30, 0xaa, 0xb8, 0x4c, 0xc7, 0x8d, + 0x4e, 0x47, 0x85, 0xc6, 0x19, 0xe3, 0x96, 0xc2, + 0x9a, 0xa0, 0x12, 0xed, 0x6f, 0xd7, 0x76, 0x16}, + {0x45, 0xaf, 0x7e, 0x33, 0xc7, 0x7f, 0x10, 0x6c, + 0x7c, 0x9f, 0x29, 0xc1, 0xa8, 0x7e, 0x15, 0x84, + 0xe7, 0x7d, 0xc0, 0x6d, 0xab, 0x71, 0x5d, 0xd0, + 0x6b, 0x9f, 0x97, 0xab, 0xcb, 0x51, 0x0c, 0x9f}}, + {{0x9e, 0xc3, 0x92, 0xb4, 0x04, 0x9f, 0xc8, 0xbb, + 0xdd, 0x9e, 0xc6, 0x05, 0xfd, 0x65, 0xec, 0x94, + 0x7f, 0x2c, 0x16, 0xc4, 0x40, 0xac, 0x63, 0x7b, + 0x7d, 0xb8, 0x0c, 0xe4, 0x5b, 0xe3, 0xa7, 0x0e}, + {0x43, 0xf4, 0x44, 0xe8, 0xcc, 0xc8, 0xd4, 0x54, + 0x33, 0x37, 0x50, 0xf2, 0x87, 0x42, 0x2e, 0x00, + 0x49, 0x60, 0x62, 0x02, 0xfd, 0x1a, 0x7c, 0xdb, + 0x29, 0x6c, 0x6d, 0x54, 0x53, 0x08, 0xd1, 0xc8}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0x28, 0x56, 0xac, 0x0e, 0x4f, 0x98, 0x09, 0xf0, + 0x49, 0xfa, 0x7f, 0x84, 0xac, 0x7e, 0x50, 0x5b, + 0x17, 0x43, 0x14, 0x89, 0x9c, 0x53, 0xa8, 0x94, + 0x30, 0xf2, 0x11, 0x4d, 0x92, 0x14, 0x27, 0xe8}, + {0x39, 0x7a, 0x84, 0x56, 0x79, 0x9d, 0xec, 0x26, + 0x2c, 0x53, 0xc1, 0x94, 0xc9, 0x8d, 0x9e, 0x9d, + 0x32, 0x1f, 0xdd, 0x84, 0x04, 0xe8, 0xe2, 0x0a, + 0x6b, 0xbe, 0xbb, 0x42, 0x40, 0x67, 0x30, 0x6c}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x73, 0x2f, 0xc9, 0xbe, 0xbd}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0x1c, 0xc4, 0xf7, 0xda, 0x0f, 0x65, 0xca, 0x39, + 0x70, 0x52, 0x92, 0x8e, 0xc3, 0xc8, 0x15, 0xea, + 0x7f, 0x10, 0x9e, 0x77, 0x4b, 0x6e, 0x2d, 0xdf, + 0xe8, 0x30, 0x9d, 0xda, 0xe8, 0x9a, 0x65, 0xae}, + {0x02, 0xb0, 0x16, 0xb1, 0x1d, 0xc8, 0x57, 0x7b, + 0xa2, 0x3a, 0xa2, 0xa3, 0x38, 0x5c, 0x8f, 0xeb, + 0x66, 0x37, 0x91, 0xa8, 0x5f, 0xef, 0x04, 0xf6, + 0x59, 0x75, 0xe1, 0xee, 0x92, 0xf6, 0x0e, 0x30}}, + {{0x8d, 0x76, 0x14, 0xa4, 0x14, 0x06, 0x9f, 0x9a, + 0xdf, 0x4a, 0x85, 0xa7, 0x6b, 0xbf, 0x29, 0x6f, + 0xbc, 0x34, 0x87, 0x5d, 0xeb, 0xbb, 0x2e, 0xa9, + 0xc9, 0x1f, 0x58, 0xd6, 0x9a, 0x82, 0xa0, 0x56}, + {0xd4, 0xb9, 0xdb, 0x88, 0x1d, 0x04, 0xe9, 0x93, + 0x8d, 0x3f, 0x20, 0xd5, 0x86, 0xa8, 0x83, 0x07, + 0xdb, 0x09, 0xd8, 0x22, 0x1f, 0x7f, 0xf1, 0x71, + 0xc8, 0xe7, 0x5d, 0x47, 0xaf, 0x8b, 0x72, 0xe9}}, + {{0x83, 0xb9, 0x39, 0xb2, 0xa4, 0xdf, 0x46, 0x87, + 0xc2, 0xb8, 0xf1, 0xe6, 0x4c, 0xd1, 0xe2, 0xa9, + 0xe4, 0x70, 0x30, 0x34, 0xbc, 0x52, 0x7c, 0x55, + 0xa6, 0xec, 0x80, 0xa4, 0xe5, 0xd2, 0xdc, 0x73}, + {0x08, 0xf1, 0x03, 0xcf, 0x16, 0x73, 0xe8, 0x7d, + 0xb6, 0x7e, 0x9b, 0xc0, 0xb4, 0xc2, 0xa5, 0x86, + 0x02, 0x77, 0xd5, 0x27, 0x86, 0xa5, 0x15, 0xfb, + 0xae, 0x9b, 0x8c, 0xa9, 0xf9, 0xf8, 0xa8, 0x4a}}, + {{0x8b, 0x00, 0x49, 0xdb, 0xfa, 0xf0, 0x1b, 0xa2, + 0xed, 0x8a, 0x9a, 0x7a, 0x36, 0x78, 0x4a, 0xc7, + 0xf7, 0xad, 0x39, 0xd0, 0x6c, 0x65, 0x7a, 0x41, + 0xce, 0xd6, 0xd6, 0x4c, 0x20, 0x21, 0x6b, 0xc7}, + {0xc6, 0xca, 0x78, 0x1d, 0x32, 0x6c, 0x6c, 0x06, + 0x91, 0xf2, 0x1a, 0xe8, 0x43, 0x16, 0xea, 0x04, + 0x3c, 0x1f, 0x07, 0x85, 0xf7, 0x09, 0x22, 0x08, + 0xba, 0x13, 0xfd, 0x78, 0x1e, 0x3f, 0x6f, 0x62}}, + {{0x25, 0x9b, 0x7c, 0xb0, 0xac, 0x72, 0x6f, 0xb2, + 0xe3, 0x53, 0x84, 0x7a, 0x1a, 0x9a, 0x98, 0x9b, + 0x44, 0xd3, 0x59, 0xd0, 0x8e, 0x57, 0x41, 0x40, + 0x78, 0xa7, 0x30, 0x2f, 0x4c, 0x9c, 0xb9, 0x68}, + {0xb7, 0x75, 0x03, 0x63, 0x61, 0xc2, 0x48, 0x6e, + 0x12, 0x3d, 0xbf, 0x4b, 0x27, 0xdf, 0xb1, 0x7a, + 0xff, 0x4e, 0x31, 0x07, 0x83, 0xf4, 0x62, 0x5b, + 0x19, 0xa5, 0xac, 0xa0, 0x32, 0x58, 0x0d, 0xa7}}, + {{0x43, 0x4f, 0x10, 0xa4, 0xca, 0xdb, 0x38, 0x67, + 0xfa, 0xae, 0x96, 0xb5, 0x6d, 0x97, 0xff, 0x1f, + 0xb6, 0x83, 0x43, 0xd3, 0xa0, 0x2d, 0x70, 0x7a, + 0x64, 0x05, 0x4c, 0xa7, 0xc1, 0xa5, 0x21, 0x51}, + {0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2, + 0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38, + 0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34, + 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}} + }; + secp256k1_scalar_set_int(&one, 1); + for (i = 0; i < 32; i++) { + secp256k1_scalar_set_b32(&x, chal[i][0], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&y, chal[i][1], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&r1, res[i][0], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&r2, res[i][1], &overflow); + CHECK(!overflow); + secp256k1_scalar_mul(&z, &x, &y); + CHECK(!secp256k1_scalar_check_overflow(&z)); + CHECK(secp256k1_scalar_eq(&r1, &z)); + if (!secp256k1_scalar_is_zero(&y)) { + secp256k1_scalar_inverse(&zz, &y); + CHECK(!secp256k1_scalar_check_overflow(&zz)); +#if defined(USE_SCALAR_INV_NUM) + secp256k1_scalar_inverse_var(&zzv, &y); + CHECK(secp256k1_scalar_eq(&zzv, &zz)); +#endif + secp256k1_scalar_mul(&z, &z, &zz); + CHECK(!secp256k1_scalar_check_overflow(&z)); + CHECK(secp256k1_scalar_eq(&x, &z)); + secp256k1_scalar_mul(&zz, &zz, &y); + CHECK(!secp256k1_scalar_check_overflow(&zz)); + CHECK(secp256k1_scalar_eq(&one, &zz)); + } + secp256k1_scalar_mul(&z, &x, &x); + CHECK(!secp256k1_scalar_check_overflow(&z)); + secp256k1_scalar_sqr(&zz, &x); + CHECK(!secp256k1_scalar_check_overflow(&zz)); + CHECK(secp256k1_scalar_eq(&zz, &z)); + CHECK(secp256k1_scalar_eq(&r2, &zz)); + } + } } /***** FIELD TESTS *****/ -void random_fe(secp256k1_fe_t *x) { +void random_fe(secp256k1_fe *x) { unsigned char bin[32]; do { secp256k1_rand256(bin); @@ -671,7 +1420,17 @@ void random_fe(secp256k1_fe_t *x) { } while(1); } -void random_fe_non_zero(secp256k1_fe_t *nz) { +void random_fe_test(secp256k1_fe *x) { + unsigned char bin[32]; + do { + secp256k1_rand256_test(bin); + if (secp256k1_fe_set_b32(x, bin)) { + return; + } + } while(1); +} + +void random_fe_non_zero(secp256k1_fe *nz) { int tries = 10; while (--tries >= 0) { random_fe(nz); @@ -684,25 +1443,25 @@ void random_fe_non_zero(secp256k1_fe_t *nz) { CHECK(tries >= 0); } -void random_fe_non_square(secp256k1_fe_t *ns) { - secp256k1_fe_t r; +void random_fe_non_square(secp256k1_fe *ns) { + secp256k1_fe r; random_fe_non_zero(ns); if (secp256k1_fe_sqrt_var(&r, ns)) { secp256k1_fe_negate(ns, ns, 1); } } -int check_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { - secp256k1_fe_t an = *a; - secp256k1_fe_t bn = *b; +int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe an = *a; + secp256k1_fe bn = *b; secp256k1_fe_normalize_weak(&an); secp256k1_fe_normalize_var(&bn); return secp256k1_fe_equal_var(&an, &bn); } -int check_fe_inverse(const secp256k1_fe_t *a, const secp256k1_fe_t *ai) { - secp256k1_fe_t x; - secp256k1_fe_t one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); +int check_fe_inverse(const secp256k1_fe *a, const secp256k1_fe *ai) { + secp256k1_fe x; + secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); secp256k1_fe_mul(&x, a, ai); return check_fe_equal(&x, &one); } @@ -714,17 +1473,17 @@ void run_field_convert(void) { 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40 }; - static const secp256k1_fe_storage_t fes = SECP256K1_FE_STORAGE_CONST( + static const secp256k1_fe_storage fes = SECP256K1_FE_STORAGE_CONST( 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL ); - static const secp256k1_fe_t fe = SECP256K1_FE_CONST( + static const secp256k1_fe fe = SECP256K1_FE_CONST( 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL ); - secp256k1_fe_t fe2; + secp256k1_fe fe2; unsigned char b322[32]; - secp256k1_fe_storage_t fes2; + secp256k1_fe_storage fes2; /* Check conversions to fe. */ CHECK(secp256k1_fe_set_b32(&fe2, b32)); CHECK(secp256k1_fe_equal_var(&fe, &fe2)); @@ -737,15 +1496,24 @@ void run_field_convert(void) { CHECK(memcmp(&fes2, &fes, sizeof(fes)) == 0); } +int fe_memcmp(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe t = *b; +#ifdef VERIFY + t.magnitude = a->magnitude; + t.normalized = a->normalized; +#endif + return memcmp(a, &t, sizeof(secp256k1_fe)); +} + void run_field_misc(void) { - secp256k1_fe_t x; - secp256k1_fe_t y; - secp256k1_fe_t z; - secp256k1_fe_t q; - secp256k1_fe_t fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); - int i; + secp256k1_fe x; + secp256k1_fe y; + secp256k1_fe z; + secp256k1_fe q; + secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); + int i, j; for (i = 0; i < 5*count; i++) { - secp256k1_fe_storage_t xs, ys, zs; + secp256k1_fe_storage xs, ys, zs; random_fe(&x); random_fe_non_zero(&y); /* Test the fe equality and comparison operations. */ @@ -756,14 +1524,27 @@ void run_field_misc(void) { /* Test fe conditional move; z is not normalized here. */ q = x; secp256k1_fe_cmov(&x, &z, 0); + VERIFY_CHECK(!x.normalized && x.magnitude == z.magnitude); secp256k1_fe_cmov(&x, &x, 1); - CHECK(memcmp(&x, &z, sizeof(x)) != 0); - CHECK(memcmp(&x, &q, sizeof(x)) == 0); + CHECK(fe_memcmp(&x, &z) != 0); + CHECK(fe_memcmp(&x, &q) == 0); secp256k1_fe_cmov(&q, &z, 1); - CHECK(memcmp(&q, &z, sizeof(q)) == 0); - /* Test storage conversion and conditional moves. */ - secp256k1_fe_normalize(&z); + VERIFY_CHECK(!q.normalized && q.magnitude == z.magnitude); + CHECK(fe_memcmp(&q, &z) == 0); + secp256k1_fe_normalize_var(&x); + secp256k1_fe_normalize_var(&z); CHECK(!secp256k1_fe_equal_var(&x, &z)); + secp256k1_fe_normalize_var(&q); + secp256k1_fe_cmov(&q, &z, (i&1)); + VERIFY_CHECK(q.normalized && q.magnitude == 1); + for (j = 0; j < 6; j++) { + secp256k1_fe_negate(&z, &z, j+1); + secp256k1_fe_normalize_var(&q); + secp256k1_fe_cmov(&q, &z, (j&1)); + VERIFY_CHECK(!q.normalized && q.magnitude == (j+2)); + } + secp256k1_fe_normalize_var(&z); + /* Test storage conversion and conditional moves. */ secp256k1_fe_to_storage(&xs, &x); secp256k1_fe_to_storage(&ys, &y); secp256k1_fe_to_storage(&zs, &z); @@ -797,7 +1578,7 @@ void run_field_misc(void) { } void run_field_inv(void) { - secp256k1_fe_t x, xi, xii; + secp256k1_fe x, xi, xii; int i; for (i = 0; i < 10*count; i++) { random_fe_non_zero(&x); @@ -809,7 +1590,7 @@ void run_field_inv(void) { } void run_field_inv_var(void) { - secp256k1_fe_t x, xi, xii; + secp256k1_fe x, xi, xii; int i; for (i = 0; i < 10*count; i++) { random_fe_non_zero(&x); @@ -821,13 +1602,13 @@ void run_field_inv_var(void) { } void run_field_inv_all_var(void) { - secp256k1_fe_t x[16], xi[16], xii[16]; + secp256k1_fe x[16], xi[16], xii[16]; int i; /* Check it's safe to call for 0 elements */ secp256k1_fe_inv_all_var(0, xi, x); for (i = 0; i < count; i++) { size_t j; - size_t len = (secp256k1_rand32() & 15) + 1; + size_t len = secp256k1_rand_int(15) + 1; for (j = 0; j < len; j++) { random_fe_non_zero(&x[j]); } @@ -843,7 +1624,7 @@ void run_field_inv_all_var(void) { } void run_sqr(void) { - secp256k1_fe_t x, s; + secp256k1_fe x, s; { int i; @@ -858,8 +1639,8 @@ void run_sqr(void) { } } -void test_sqrt(const secp256k1_fe_t *a, const secp256k1_fe_t *k) { - secp256k1_fe_t r1, r2; +void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { + secp256k1_fe r1, r2; int v = secp256k1_fe_sqrt_var(&r1, a); CHECK((v == 0) == (k == NULL)); @@ -873,7 +1654,7 @@ void test_sqrt(const secp256k1_fe_t *a, const secp256k1_fe_t *k) { } void run_sqrt(void) { - secp256k1_fe_t ns, x, s, t; + secp256k1_fe ns, x, s, t; int i; /* Check sqrt(0) is 0 */ @@ -908,19 +1689,19 @@ void run_sqrt(void) { /***** GROUP TESTS *****/ -void ge_equals_ge(const secp256k1_ge_t *a, const secp256k1_ge_t *b) { +void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { CHECK(a->infinity == b->infinity); if (a->infinity) { return; } CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); - CHECK(secp256k1_fe_equal_var(&b->y, &b->y)); + CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); } /* This compares jacobian points including their Z, not just their geometric meaning. */ -int gej_xyz_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) { - secp256k1_gej_t a2; - secp256k1_gej_t b2; +int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { + secp256k1_gej a2; + secp256k1_gej b2; int ret = 1; ret &= a->infinity == b->infinity; if (ret && !a->infinity) { @@ -939,9 +1720,9 @@ int gej_xyz_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) { return ret; } -void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) { - secp256k1_fe_t z2s; - secp256k1_fe_t u1, u2, s1, s2; +void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { + secp256k1_fe z2s; + secp256k1_fe u1, u2, s1, s2; CHECK(a->infinity == b->infinity); if (a->infinity) { return; @@ -958,21 +1739,39 @@ void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) { void test_ge(void) { int i, i1; +#ifdef USE_ENDOMORPHISM + int runs = 6; +#else int runs = 4; +#endif /* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4). * The second in each pair of identical points uses a random Z coordinate in the Jacobian form. * All magnitudes are randomized. - * All 17*17 combinations of points are added to eachother, using all applicable methods. + * All 17*17 combinations of points are added to each other, using all applicable methods. + * + * When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well. */ - secp256k1_ge_t *ge = (secp256k1_ge_t *)malloc(sizeof(secp256k1_ge_t) * (1 + 4 * runs)); - secp256k1_gej_t *gej = (secp256k1_gej_t *)malloc(sizeof(secp256k1_gej_t) * (1 + 4 * runs)); + secp256k1_ge *ge = (secp256k1_ge *)malloc(sizeof(secp256k1_ge) * (1 + 4 * runs)); + secp256k1_gej *gej = (secp256k1_gej *)malloc(sizeof(secp256k1_gej) * (1 + 4 * runs)); + secp256k1_fe *zinv = (secp256k1_fe *)malloc(sizeof(secp256k1_fe) * (1 + 4 * runs)); + secp256k1_fe zf; + secp256k1_fe zfi2, zfi3; + secp256k1_gej_set_infinity(&gej[0]); secp256k1_ge_clear(&ge[0]); secp256k1_ge_set_gej_var(&ge[0], &gej[0]); for (i = 0; i < runs; i++) { int j; - secp256k1_ge_t g; + secp256k1_ge g; random_group_element_test(&g); +#ifdef USE_ENDOMORPHISM + if (i >= runs - 2) { + secp256k1_ge_mul_lambda(&g, &ge[1]); + } + if (i >= runs - 1) { + secp256k1_ge_mul_lambda(&g, &g); + } +#endif ge[1 + 4 * i] = g; ge[2 + 4 * i] = g; secp256k1_ge_neg(&ge[3 + 4 * i], &g); @@ -990,18 +1789,65 @@ void test_ge(void) { } } + /* Compute z inverses. */ + { + secp256k1_fe *zs = malloc(sizeof(secp256k1_fe) * (1 + 4 * runs)); + for (i = 0; i < 4 * runs + 1; i++) { + if (i == 0) { + /* The point at infinity does not have a meaningful z inverse. Any should do. */ + do { + random_field_element_test(&zs[i]); + } while(secp256k1_fe_is_zero(&zs[i])); + } else { + zs[i] = gej[i].z; + } + } + secp256k1_fe_inv_all_var(4 * runs + 1, zinv, zs); + free(zs); + } + + /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */ + do { + random_field_element_test(&zf); + } while(secp256k1_fe_is_zero(&zf)); + random_field_element_magnitude(&zf); + secp256k1_fe_inv_var(&zfi3, &zf); + secp256k1_fe_sqr(&zfi2, &zfi3); + secp256k1_fe_mul(&zfi3, &zfi3, &zfi2); + for (i1 = 0; i1 < 1 + 4 * runs; i1++) { int i2; for (i2 = 0; i2 < 1 + 4 * runs; i2++) { /* Compute reference result using gej + gej (var). */ - secp256k1_gej_t refj, resj; - secp256k1_ge_t ref; - secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2]); + secp256k1_gej refj, resj; + secp256k1_ge ref; + secp256k1_fe zr; + secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); + /* Check Z ratio. */ + if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&refj)) { + secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(secp256k1_fe_equal_var(&zrz, &refj.z)); + } secp256k1_ge_set_gej_var(&ref, &refj); - /* Test gej + ge (var). */ - secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2]); + /* Test gej + ge with Z ratio result (var). */ + secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); ge_equals_gej(&ref, &resj); + if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&resj)) { + secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(secp256k1_fe_equal_var(&zrz, &resj.z)); + } + + /* Test gej + ge (var, with additional Z factor). */ + { + secp256k1_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */ + secp256k1_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2); + secp256k1_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3); + random_field_element_magnitude(&ge2_zfi.x); + random_field_element_magnitude(&ge2_zfi.y); + secp256k1_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf); + ge_equals_gej(&ref, &resj); + } /* Test gej + ge (const). */ if (i2 != 0) { @@ -1012,10 +1858,15 @@ void test_ge(void) { /* Test doubling (var). */ if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) { - /* Normal doubling. */ - secp256k1_gej_double_var(&resj, &gej[i1]); + secp256k1_fe zr2; + /* Normal doubling with Z ratio result. */ + secp256k1_gej_double_var(&resj, &gej[i1], &zr2); ge_equals_gej(&ref, &resj); - secp256k1_gej_double_var(&resj, &gej[i2]); + /* Check Z ratio. */ + secp256k1_fe_mul(&zr2, &zr2, &gej[i1].z); + CHECK(secp256k1_fe_equal_var(&zr2, &resj.z)); + /* Normal doubling. */ + secp256k1_gej_double_var(&resj, &gej[i2], NULL); ge_equals_gej(&ref, &resj); } @@ -1040,41 +1891,121 @@ void test_ge(void) { /* Test adding all points together in random order equals infinity. */ { - secp256k1_gej_t sum = SECP256K1_GEJ_CONST_INFINITY; - secp256k1_gej_t *gej_shuffled = (secp256k1_gej_t *)malloc((4 * runs + 1) * sizeof(secp256k1_gej_t)); + secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY; + secp256k1_gej *gej_shuffled = (secp256k1_gej *)malloc((4 * runs + 1) * sizeof(secp256k1_gej)); for (i = 0; i < 4 * runs + 1; i++) { gej_shuffled[i] = gej[i]; } for (i = 0; i < 4 * runs + 1; i++) { - int swap = i + secp256k1_rand32() % (4 * runs + 1 - i); + int swap = i + secp256k1_rand_int(4 * runs + 1 - i); if (swap != i) { - secp256k1_gej_t t = gej_shuffled[i]; + secp256k1_gej t = gej_shuffled[i]; gej_shuffled[i] = gej_shuffled[swap]; gej_shuffled[swap] = t; } } for (i = 0; i < 4 * runs + 1; i++) { - secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i]); + secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i], NULL); } CHECK(secp256k1_gej_is_infinity(&sum)); free(gej_shuffled); } - /* Test batch gej -> ge conversion. */ + /* Test batch gej -> ge conversion with and without known z ratios. */ { - secp256k1_ge_t *ge_set_all = (secp256k1_ge_t *)malloc((4 * runs + 1) * sizeof(secp256k1_ge_t)); - secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej); + secp256k1_fe *zr = (secp256k1_fe *)malloc((4 * runs + 1) * sizeof(secp256k1_fe)); + secp256k1_ge *ge_set_table = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge)); + secp256k1_ge *ge_set_all = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge)); for (i = 0; i < 4 * runs + 1; i++) { - secp256k1_fe_t s; + /* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */ + if (i < 4 * runs) { + secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z); + } + } + secp256k1_ge_set_table_gej_var(4 * runs + 1, ge_set_table, gej, zr); + secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej, &ctx->error_callback); + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_fe s; random_fe_non_zero(&s); secp256k1_gej_rescale(&gej[i], &s); + ge_equals_gej(&ge_set_table[i], &gej[i]); ge_equals_gej(&ge_set_all[i], &gej[i]); } + free(ge_set_table); free(ge_set_all); + free(zr); } free(ge); free(gej); + free(zinv); +} + +void test_add_neg_y_diff_x(void) { + /* The point of this test is to check that we can add two points + * whose y-coordinates are negatives of each other but whose x + * coordinates differ. If the x-coordinates were the same, these + * points would be negatives of each other and their sum is + * infinity. This is cool because it "covers up" any degeneracy + * in the addition algorithm that would cause the xy coordinates + * of the sum to be wrong (since infinity has no xy coordinates). + * HOWEVER, if the x-coordinates are different, infinity is the + * wrong answer, and such degeneracies are exposed. This is the + * root of https://github.com/bitcoin/secp256k1/issues/257 which + * this test is a regression test for. + * + * These points were generated in sage as + * # secp256k1 params + * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) + * C = EllipticCurve ([F (0), F (7)]) + * G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) + * N = FiniteField(G.order()) + * + * # endomorphism values (lambda is 1^{1/3} in N, beta is 1^{1/3} in F) + * x = polygen(N) + * lam = (1 - x^3).roots()[1][0] + * + * # random "bad pair" + * P = C.random_element() + * Q = -int(lam) * P + * print " P: %x %x" % P.xy() + * print " Q: %x %x" % Q.xy() + * print "P + Q: %x %x" % (P + Q).xy() + */ + secp256k1_gej aj = SECP256K1_GEJ_CONST( + 0x8d24cd95, 0x0a355af1, 0x3c543505, 0x44238d30, + 0x0643d79f, 0x05a59614, 0x2f8ec030, 0xd58977cb, + 0x001e337a, 0x38093dcd, 0x6c0f386d, 0x0b1293a8, + 0x4d72c879, 0xd7681924, 0x44e6d2f3, 0x9190117d + ); + secp256k1_gej bj = SECP256K1_GEJ_CONST( + 0xc7b74206, 0x1f788cd9, 0xabd0937d, 0x164a0d86, + 0x95f6ff75, 0xf19a4ce9, 0xd013bd7b, 0xbf92d2a7, + 0xffe1cc85, 0xc7f6c232, 0x93f0c792, 0xf4ed6c57, + 0xb28d3786, 0x2897e6db, 0xbb192d0b, 0x6e6feab2 + ); + secp256k1_gej sumj = SECP256K1_GEJ_CONST( + 0x671a63c0, 0x3efdad4c, 0x389a7798, 0x24356027, + 0xb3d69010, 0x278625c3, 0x5c86d390, 0x184a8f7a, + 0x5f6409c2, 0x2ce01f2b, 0x511fd375, 0x25071d08, + 0xda651801, 0x70e95caf, 0x8f0d893c, 0xbed8fbbe + ); + secp256k1_ge b; + secp256k1_gej resj; + secp256k1_ge res; + secp256k1_ge_set_gej(&b, &bj); + + secp256k1_gej_add_var(&resj, &aj, &bj, NULL); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); + + secp256k1_gej_add_ge(&resj, &aj, &b); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); + + secp256k1_gej_add_ge_var(&resj, &aj, &b, NULL); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); } void run_ge(void) { @@ -1082,36 +2013,125 @@ void run_ge(void) { for (i = 0; i < count * 32; i++) { test_ge(); } + test_add_neg_y_diff_x(); +} + +void test_ec_combine(void) { + secp256k1_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_pubkey data[6]; + const secp256k1_pubkey* d[6]; + secp256k1_pubkey sd; + secp256k1_pubkey sd2; + secp256k1_gej Qj; + secp256k1_ge Q; + int i; + for (i = 1; i <= 6; i++) { + secp256k1_scalar s; + random_scalar_order_test(&s); + secp256k1_scalar_add(&sum, &sum, &s); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &s); + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(&data[i - 1], &Q); + d[i - 1] = &data[i - 1]; + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sum); + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(&sd, &Q); + CHECK(secp256k1_ec_pubkey_combine(ctx, &sd2, d, i) == 1); + CHECK(memcmp(&sd, &sd2, sizeof(sd)) == 0); + } +} + +void run_ec_combine(void) { + int i; + for (i = 0; i < count * 8; i++) { + test_ec_combine(); + } +} + +void test_group_decompress(const secp256k1_fe* x) { + /* The input itself, normalized. */ + secp256k1_fe fex = *x; + secp256k1_fe tmp; + /* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */ + secp256k1_ge ge_quad, ge_even, ge_odd; + /* Return values of the above calls. */ + int res_quad, res_even, res_odd; + + secp256k1_fe_normalize_var(&fex); + + res_quad = secp256k1_ge_set_xquad_var(&ge_quad, &fex); + res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0); + res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1); + + CHECK(res_quad == res_even); + CHECK(res_quad == res_odd); + + if (res_quad) { + secp256k1_fe_normalize_var(&ge_quad.x); + secp256k1_fe_normalize_var(&ge_odd.x); + secp256k1_fe_normalize_var(&ge_even.x); + secp256k1_fe_normalize_var(&ge_quad.y); + secp256k1_fe_normalize_var(&ge_odd.y); + secp256k1_fe_normalize_var(&ge_even.y); + + /* No infinity allowed. */ + CHECK(!ge_quad.infinity); + CHECK(!ge_even.infinity); + CHECK(!ge_odd.infinity); + + /* Check that the x coordinates check out. */ + CHECK(secp256k1_fe_equal_var(&ge_quad.x, x)); + CHECK(secp256k1_fe_equal_var(&ge_even.x, x)); + CHECK(secp256k1_fe_equal_var(&ge_odd.x, x)); + + /* Check that the Y coordinate result in ge_quad is a square. */ + CHECK(secp256k1_fe_sqrt_var(&tmp, &ge_quad.y)); + secp256k1_fe_sqr(&tmp, &tmp); + CHECK(secp256k1_fe_equal_var(&tmp, &ge_quad.y)); + + /* Check odd/even Y in ge_odd, ge_even. */ + CHECK(secp256k1_fe_is_odd(&ge_odd.y)); + CHECK(!secp256k1_fe_is_odd(&ge_even.y)); + } +} + +void run_group_decompress(void) { + int i; + for (i = 0; i < count * 4; i++) { + secp256k1_fe fe; + random_fe_test(&fe); + test_group_decompress(&fe); + } } /***** ECMULT TESTS *****/ void run_ecmult_chain(void) { /* random starting point A (on the curve) */ - secp256k1_gej_t a = SECP256K1_GEJ_CONST( + secp256k1_gej a = SECP256K1_GEJ_CONST( 0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3, 0x727fd8bc, 0x04d3362c, 0x6c7bf458, 0xe2846004, 0xa357ae91, 0x5c4a6528, 0x1309edf2, 0x0504740f, 0x0eb33439, 0x90216b4f, 0x81063cb6, 0x5f2f7e0f ); /* two random initial factors xn and gn */ - secp256k1_scalar_t xn = SECP256K1_SCALAR_CONST( + secp256k1_scalar xn = SECP256K1_SCALAR_CONST( 0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c, 0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407 ); - secp256k1_scalar_t gn = SECP256K1_SCALAR_CONST( + secp256k1_scalar gn = SECP256K1_SCALAR_CONST( 0xa1e58d22, 0x553dcd42, 0xb2398062, 0x5d4c57a9, 0x6e9323d4, 0x2b3152e5, 0xca2c3990, 0xedc7c9de ); /* two small multipliers to be applied to xn and gn in every iteration: */ - static const secp256k1_scalar_t xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); - static const secp256k1_scalar_t gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); + static const secp256k1_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); + static const secp256k1_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); /* accumulators with the resulting coefficients to A and G */ - secp256k1_scalar_t ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_scalar_t ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_scalar ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); /* actual points */ - secp256k1_gej_t x = a; - secp256k1_gej_t x2; + secp256k1_gej x; + secp256k1_gej x2; int i; /* the point being computed */ @@ -1131,7 +2151,7 @@ void run_ecmult_chain(void) { /* verify */ if (i == 19999) { /* expected result after 19999 iterations */ - secp256k1_gej_t rp = SECP256K1_GEJ_CONST( + secp256k1_gej rp = SECP256K1_GEJ_CONST( 0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE, 0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830, 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D, @@ -1139,30 +2159,32 @@ void run_ecmult_chain(void) { ); secp256k1_gej_neg(&rp, &rp); - secp256k1_gej_add_var(&rp, &rp, &x); + secp256k1_gej_add_var(&rp, &rp, &x, NULL); CHECK(secp256k1_gej_is_infinity(&rp)); } } /* redo the computation, but directly with the resulting ae and ge coefficients: */ secp256k1_ecmult(&ctx->ecmult_ctx, &x2, &a, &ae, &ge); secp256k1_gej_neg(&x2, &x2); - secp256k1_gej_add_var(&x2, &x2, &x); + secp256k1_gej_add_var(&x2, &x2, &x, NULL); CHECK(secp256k1_gej_is_infinity(&x2)); } -void test_point_times_order(const secp256k1_gej_t *point) { +void test_point_times_order(const secp256k1_gej *point) { /* X * (point + G) + (order-X) * (pointer + G) = 0 */ - secp256k1_scalar_t x; - secp256k1_scalar_t nx; - secp256k1_gej_t res1, res2; - secp256k1_ge_t res3; + secp256k1_scalar x; + secp256k1_scalar nx; + secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_gej res1, res2; + secp256k1_ge res3; unsigned char pub[65]; - int psize = 65; + size_t psize = 65; random_scalar_order_test(&x); secp256k1_scalar_negate(&nx, &x); secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &x, &x); /* calc res1 = x * point + x * G; */ secp256k1_ecmult(&ctx->ecmult_ctx, &res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ - secp256k1_gej_add_var(&res1, &res1, &res2); + secp256k1_gej_add_var(&res1, &res1, &res2, NULL); CHECK(secp256k1_gej_is_infinity(&res1)); CHECK(secp256k1_gej_is_valid_var(&res1) == 0); secp256k1_ge_set_gej(&res3, &res1); @@ -1171,19 +2193,29 @@ void test_point_times_order(const secp256k1_gej_t *point) { CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0); psize = 65; CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); + /* check zero/one edge cases */ + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &zero); + secp256k1_ge_set_gej(&res3, &res1); + CHECK(secp256k1_ge_is_infinity(&res3)); + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &one, &zero); + secp256k1_ge_set_gej(&res3, &res1); + ge_equals_gej(&res3, point); + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &one); + secp256k1_ge_set_gej(&res3, &res1); + ge_equals_ge(&res3, &secp256k1_ge_const_g); } void run_point_times_order(void) { int i; - secp256k1_fe_t x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); - static const secp256k1_fe_t xr = SECP256K1_FE_CONST( + secp256k1_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); + static const secp256k1_fe xr = SECP256K1_FE_CONST( 0x7603CB59, 0xB0EF6C63, 0xFE608479, 0x2A0C378C, 0xDB3233A8, 0x0F8A9A09, 0xA877DEAD, 0x31B38C45 ); for (i = 0; i < 500; i++) { - secp256k1_ge_t p; + secp256k1_ge p; if (secp256k1_ge_set_xo_var(&p, &x, 1)) { - secp256k1_gej_t j; + secp256k1_gej j; CHECK(secp256k1_ge_is_valid_var(&p)); secp256k1_gej_set_ge(&j, &p); CHECK(secp256k1_gej_is_valid_var(&j)); @@ -1195,15 +2227,118 @@ void run_point_times_order(void) { CHECK(secp256k1_fe_equal_var(&x, &xr)); } -void test_wnaf(const secp256k1_scalar_t *number, int w) { - secp256k1_scalar_t x, two, t; +void ecmult_const_random_mult(void) { + /* random starting point A (on the curve) */ + secp256k1_ge a = SECP256K1_GE_CONST( + 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b, + 0xa97f9263, 0xb1e88044, 0x93351325, 0x91bc450a, + 0x535c59f7, 0x325e5d2b, 0xc391fbe8, 0x3c12787c, + 0x337e4a98, 0xe82a9011, 0x0123ba37, 0xdd769c7d + ); + /* random initial factor xn */ + secp256k1_scalar xn = SECP256K1_SCALAR_CONST( + 0x649d4f77, 0xc4242df7, 0x7f2079c9, 0x14530327, + 0xa31b876a, 0xd2d8ce2a, 0x2236d5c6, 0xd7b2029b + ); + /* expected xn * A (from sage) */ + secp256k1_ge expected_b = SECP256K1_GE_CONST( + 0x23773684, 0x4d209dc7, 0x098a786f, 0x20d06fcd, + 0x070a38bf, 0xc11ac651, 0x03004319, 0x1e2a8786, + 0xed8c3b8e, 0xc06dd57b, 0xd06ea66e, 0x45492b0f, + 0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956 + ); + secp256k1_gej b; + secp256k1_ecmult_const(&b, &a, &xn); + + CHECK(secp256k1_ge_is_valid_var(&a)); + ge_equals_gej(&expected_b, &b); +} + +void ecmult_const_commutativity(void) { + secp256k1_scalar a; + secp256k1_scalar b; + secp256k1_gej res1; + secp256k1_gej res2; + secp256k1_ge mid1; + secp256k1_ge mid2; + random_scalar_order_test(&a); + random_scalar_order_test(&b); + + secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a); + secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b); + secp256k1_ge_set_gej(&mid1, &res1); + secp256k1_ge_set_gej(&mid2, &res2); + secp256k1_ecmult_const(&res1, &mid1, &b); + secp256k1_ecmult_const(&res2, &mid2, &a); + secp256k1_ge_set_gej(&mid1, &res1); + secp256k1_ge_set_gej(&mid2, &res2); + ge_equals_ge(&mid1, &mid2); +} + +void ecmult_const_mult_zero_one(void) { + secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_scalar negone; + secp256k1_gej res1; + secp256k1_ge res2; + secp256k1_ge point; + secp256k1_scalar_negate(&negone, &one); + + random_group_element_test(&point); + secp256k1_ecmult_const(&res1, &point, &zero); + secp256k1_ge_set_gej(&res2, &res1); + CHECK(secp256k1_ge_is_infinity(&res2)); + secp256k1_ecmult_const(&res1, &point, &one); + secp256k1_ge_set_gej(&res2, &res1); + ge_equals_ge(&res2, &point); + secp256k1_ecmult_const(&res1, &point, &negone); + secp256k1_gej_neg(&res1, &res1); + secp256k1_ge_set_gej(&res2, &res1); + ge_equals_ge(&res2, &point); +} + +void ecmult_const_chain_multiply(void) { + /* Check known result (randomly generated test problem from sage) */ + const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST( + 0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d, + 0xcd83d307, 0x827bed62, 0x05fad0ce, 0x18fae63b + ); + const secp256k1_gej expected_point = SECP256K1_GEJ_CONST( + 0x5494c15d, 0x32099706, 0xc2395f94, 0x348745fd, + 0x757ce30e, 0x4e8c90fb, 0xa2bad184, 0xf883c69f, + 0x5d195d20, 0xe191bf7f, 0x1be3e55f, 0x56a80196, + 0x6071ad01, 0xf1462f66, 0xc997fa94, 0xdb858435 + ); + secp256k1_gej point; + secp256k1_ge res; + int i; + + secp256k1_gej_set_ge(&point, &secp256k1_ge_const_g); + for (i = 0; i < 100; ++i) { + secp256k1_ge tmp; + secp256k1_ge_set_gej(&tmp, &point); + secp256k1_ecmult_const(&point, &tmp, &scalar); + } + secp256k1_ge_set_gej(&res, &point); + ge_equals_gej(&res, &expected_point); +} + +void run_ecmult_const_tests(void) { + ecmult_const_mult_zero_one(); + ecmult_const_random_mult(); + ecmult_const_commutativity(); + ecmult_const_chain_multiply(); +} + +void test_wnaf(const secp256k1_scalar *number, int w) { + secp256k1_scalar x, two, t; int wnaf[256]; int zeroes = -1; int i; int bits; secp256k1_scalar_set_int(&x, 0); secp256k1_scalar_set_int(&two, 2); - bits = secp256k1_ecmult_wnaf(wnaf, number, w); + bits = secp256k1_ecmult_wnaf(wnaf, 256, number, w); CHECK(bits <= 256); for (i = bits-1; i >= 0; i--) { int v = wnaf[i]; @@ -1229,20 +2364,95 @@ void test_wnaf(const secp256k1_scalar_t *number, int w) { CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */ } +void test_constant_wnaf_negate(const secp256k1_scalar *number) { + secp256k1_scalar neg1 = *number; + secp256k1_scalar neg2 = *number; + int sign1 = 1; + int sign2 = 1; + + if (!secp256k1_scalar_get_bits(&neg1, 0, 1)) { + secp256k1_scalar_negate(&neg1, &neg1); + sign1 = -1; + } + sign2 = secp256k1_scalar_cond_negate(&neg2, secp256k1_scalar_is_even(&neg2)); + CHECK(sign1 == sign2); + CHECK(secp256k1_scalar_eq(&neg1, &neg2)); +} + +void test_constant_wnaf(const secp256k1_scalar *number, int w) { + secp256k1_scalar x, shift; + int wnaf[256] = {0}; + int i; +#ifdef USE_ENDOMORPHISM + int skew; +#endif + secp256k1_scalar num = *number; + + secp256k1_scalar_set_int(&x, 0); + secp256k1_scalar_set_int(&shift, 1 << w); + /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */ +#ifdef USE_ENDOMORPHISM + for (i = 0; i < 16; ++i) { + secp256k1_scalar_shr_int(&num, 8); + } + skew = secp256k1_wnaf_const(wnaf, num, w); +#else + secp256k1_wnaf_const(wnaf, num, w); +#endif + + for (i = WNAF_SIZE(w); i >= 0; --i) { + secp256k1_scalar t; + int v = wnaf[i]; + CHECK(v != 0); /* check nonzero */ + CHECK(v & 1); /* check parity */ + CHECK(v > -(1 << w)); /* check range above */ + CHECK(v < (1 << w)); /* check range below */ + + secp256k1_scalar_mul(&x, &x, &shift); + if (v >= 0) { + secp256k1_scalar_set_int(&t, v); + } else { + secp256k1_scalar_set_int(&t, -v); + secp256k1_scalar_negate(&t, &t); + } + secp256k1_scalar_add(&x, &x, &t); + } +#ifdef USE_ENDOMORPHISM + /* Skew num because when encoding 128-bit numbers as odd we use an offset */ + secp256k1_scalar_cadd_bit(&num, skew == 2, 1); +#endif + CHECK(secp256k1_scalar_eq(&x, &num)); +} + void run_wnaf(void) { int i; - secp256k1_scalar_t n; + secp256k1_scalar n = {{0}}; + + /* Sanity check: 1 and 2 are the smallest odd and even numbers and should + * have easier-to-diagnose failure modes */ + n.d[0] = 1; + test_constant_wnaf(&n, 4); + n.d[0] = 2; + test_constant_wnaf(&n, 4); + /* Random tests */ for (i = 0; i < count; i++) { random_scalar_order(&n); test_wnaf(&n, 4+(i%10)); + test_constant_wnaf_negate(&n); + test_constant_wnaf(&n, 4 + (i % 10)); } + secp256k1_scalar_set_int(&n, 0); + CHECK(secp256k1_scalar_cond_negate(&n, 1) == -1); + CHECK(secp256k1_scalar_is_zero(&n)); + CHECK(secp256k1_scalar_cond_negate(&n, 0) == 1); + CHECK(secp256k1_scalar_is_zero(&n)); } void test_ecmult_constants(void) { /* Test ecmult_gen() for [0..36) and [order-36..0). */ - secp256k1_scalar_t x; - secp256k1_gej_t r; - secp256k1_ge_t ng; + secp256k1_scalar x; + secp256k1_gej r; + secp256k1_ge ng; int i; int j; secp256k1_ge_neg(&ng, &secp256k1_ge_const_g); @@ -1276,14 +2486,14 @@ void run_ecmult_constants(void) { } void test_ecmult_gen_blind(void) { - /* Test ecmult_gen() blinding and confirm that the blinding changes, the affline points match, and the z's don't match. */ - secp256k1_scalar_t key; - secp256k1_scalar_t b; + /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ + secp256k1_scalar key; + secp256k1_scalar b; unsigned char seed32[32]; - secp256k1_gej_t pgej; - secp256k1_gej_t pgej2; - secp256k1_gej_t i; - secp256k1_ge_t pge; + secp256k1_gej pgej; + secp256k1_gej pgej2; + secp256k1_gej i; + secp256k1_ge pge; random_scalar_order_test(&key); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key); secp256k1_rand256(seed32); @@ -1300,8 +2510,8 @@ void test_ecmult_gen_blind(void) { void test_ecmult_gen_blind_reset(void) { /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ - secp256k1_scalar_t b; - secp256k1_gej_t initial; + secp256k1_scalar b; + secp256k1_gej initial; secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); b = ctx->ecmult_gen_ctx.blind; initial = ctx->ecmult_gen_ctx.initial; @@ -1318,35 +2528,702 @@ void run_ecmult_gen_blind(void) { } } +#ifdef USE_ENDOMORPHISM +/***** ENDOMORPHISH TESTS *****/ +void test_scalar_split(void) { + secp256k1_scalar full; + secp256k1_scalar s1, slam; + const unsigned char zero[32] = {0}; + unsigned char tmp[32]; -void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *key, const secp256k1_scalar_t *msg, int *recid) { - secp256k1_scalar_t nonce; + random_scalar_order_test(&full); + secp256k1_scalar_split_lambda(&s1, &slam, &full); + + /* check that both are <= 128 bits in size */ + if (secp256k1_scalar_is_high(&s1)) { + secp256k1_scalar_negate(&s1, &s1); + } + if (secp256k1_scalar_is_high(&slam)) { + secp256k1_scalar_negate(&slam, &slam); + } + + secp256k1_scalar_get_b32(tmp, &s1); + CHECK(memcmp(zero, tmp, 16) == 0); + secp256k1_scalar_get_b32(tmp, &slam); + CHECK(memcmp(zero, tmp, 16) == 0); +} + +void run_endomorphism_tests(void) { + test_scalar_split(); +} +#endif + +void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { + unsigned char pubkeyc[65]; + secp256k1_pubkey pubkey; + secp256k1_ge ge; + size_t pubkeyclen; + int32_t ecount; + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) { + /* Smaller sizes are tested exhaustively elsewhere. */ + int32_t i; + memcpy(&pubkeyc[1], input, 64); + VG_UNDEF(&pubkeyc[pubkeyclen], 65 - pubkeyclen); + for (i = 0; i < 256; i++) { + /* Try all type bytes. */ + int xpass; + int ypass; + int ysign; + pubkeyc[0] = i; + /* What sign does this point have? */ + ysign = (input[63] & 1) + 2; + /* For the current type (i) do we expect parsing to work? Handled all of compressed/uncompressed/hybrid. */ + xpass = xvalid && (pubkeyclen == 33) && ((i & 254) == 2); + /* Do we expect a parse and re-serialize as uncompressed to give a matching y? */ + ypass = xvalid && yvalid && ((i & 4) == ((pubkeyclen == 65) << 2)) && + ((i == 4) || ((i & 251) == ysign)) && ((pubkeyclen == 33) || (pubkeyclen == 65)); + if (xpass || ypass) { + /* These cases must parse. */ + unsigned char pubkeyo[65]; + size_t outl; + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + ecount = 0; + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + VG_UNDEF(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + VG_CHECK(pubkeyo, outl); + CHECK(outl == 33); + CHECK(memcmp(&pubkeyo[1], &pubkeyc[1], 32) == 0); + CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0])); + if (ypass) { + /* This test isn't always done because we decode with alternative signs, so the y won't match. */ + CHECK(pubkeyo[0] == ysign); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + secp256k1_pubkey_save(&pubkey, &ge); + VG_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + VG_UNDEF(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + VG_CHECK(pubkeyo, outl); + CHECK(outl == 65); + CHECK(pubkeyo[0] == 4); + CHECK(memcmp(&pubkeyo[1], input, 64) == 0); + } + CHECK(ecount == 0); + } else { + /* These cases must fail to parse. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + } + } + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); +} + +void run_ec_pubkey_parse_test(void) { +#define SECP256K1_EC_PARSE_TEST_NVALID (12) + const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = { + { + /* Point with leading and trailing zeros in x and y serialization. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x64, 0xef, 0xa1, 0x7b, 0x77, 0x61, 0xe1, 0xe4, 0x27, 0x06, 0x98, 0x9f, 0xb4, 0x83, + 0xb8, 0xd2, 0xd4, 0x9b, 0xf7, 0x8f, 0xae, 0x98, 0x03, 0xf0, 0x99, 0xb8, 0x34, 0xed, 0xeb, 0x00 + }, + { + /* Point with x equal to a 3rd root of unity.*/ + 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10, 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9, + 0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95, 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with largest x. (1/2) */ + 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, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0x0e, 0x99, 0x4b, 0x14, 0xea, 0x72, 0xf8, 0xc3, 0xeb, 0x95, 0xc7, 0x1e, 0xf6, 0x92, 0x57, 0x5e, + 0x77, 0x50, 0x58, 0x33, 0x2d, 0x7e, 0x52, 0xd0, 0x99, 0x5c, 0xf8, 0x03, 0x88, 0x71, 0xb6, 0x7d, + }, + { + /* Point with largest x. (2/2) */ + 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, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0xf1, 0x66, 0xb4, 0xeb, 0x15, 0x8d, 0x07, 0x3c, 0x14, 0x6a, 0x38, 0xe1, 0x09, 0x6d, 0xa8, 0xa1, + 0x88, 0xaf, 0xa7, 0xcc, 0xd2, 0x81, 0xad, 0x2f, 0x66, 0xa3, 0x07, 0xfb, 0x77, 0x8e, 0x45, 0xb2, + }, + { + /* Point with smallest x. (1/2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with smallest x. (2/2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* Point with largest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 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, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 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, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 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, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with smallest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Point with smallest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Point with smallest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + } + }; +#define SECP256K1_EC_PARSE_TEST_NXVALID (4) + const unsigned char onlyxvalid[SECP256K1_EC_PARSE_TEST_NXVALID][64] = { + { + /* Valid if y overflow ignored (y = 1 mod p). (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 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, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 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, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (3/3)*/ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 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, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* x on curve, y is from y^2 = x^3 + 8. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 + } + }; +#define SECP256K1_EC_PARSE_TEST_NINVALID (7) + const unsigned char invalid[SECP256K1_EC_PARSE_TEST_NINVALID][64] = { + { + /* x is third root of -8, y is -1 * (x^3+7); also on the curve for y^2 = x^3 + 9. */ + 0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, + 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 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, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 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, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 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, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0xf4, 0x84, 0x14, 0x5c, 0xb0, 0x14, 0x9b, 0x82, 0x5d, 0xff, 0x41, 0x2f, 0xa0, 0x52, 0xa8, 0x3f, + 0xcb, 0x72, 0xdb, 0x61, 0xd5, 0x6f, 0x37, 0x70, 0xce, 0x06, 0x6b, 0x73, 0x49, 0xa2, 0xaa, 0x28, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 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, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0x0b, 0x7b, 0xeb, 0xa3, 0x4f, 0xeb, 0x64, 0x7d, 0xa2, 0x00, 0xbe, 0xd0, 0x5f, 0xad, 0x57, 0xc0, + 0x34, 0x8d, 0x24, 0x9e, 0x2a, 0x90, 0xc8, 0x8f, 0x31, 0xf9, 0x94, 0x8b, 0xb6, 0x5d, 0x52, 0x07, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8f, 0x53, 0x7e, 0xef, 0xdf, 0xc1, 0x60, 0x6a, 0x07, 0x27, 0xcd, 0x69, 0xb4, 0xa7, 0x33, 0x3d, + 0x38, 0xed, 0x44, 0xe3, 0x93, 0x2a, 0x71, 0x79, 0xee, 0xcb, 0x4b, 0x6f, 0xba, 0x93, 0x60, 0xdc, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0xac, 0x81, 0x10, 0x20, 0x3e, 0x9f, 0x95, 0xf8, 0xd8, 0x32, 0x96, 0x4b, 0x58, 0xcc, 0xc2, + 0xc7, 0x12, 0xbb, 0x1c, 0x6c, 0xd5, 0x8e, 0x86, 0x11, 0x34, 0xb4, 0x8f, 0x45, 0x6c, 0x9b, 0x53 + } + }; + const unsigned char pubkeyc[66] = { + /* Serialization of G. */ + 0x04, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, + 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, + 0x98, 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, + 0xA8, 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, + 0xB8, 0x00 + }; + unsigned char sout[65]; + unsigned char shortkey[2]; + secp256k1_ge ge; + secp256k1_pubkey pubkey; + size_t len; + int32_t i; + int32_t ecount; + int32_t ecount2; + ecount = 0; + /* Nothing should be reading this far into pubkeyc. */ + VG_UNDEF(&pubkeyc[65], 1); + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + /* Zero length claimed, fail, zeroize, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(shortkey, 2); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 0) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* Length one claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 256 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + shortkey[0] = i; + VG_UNDEF(&shortkey[1], 1); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 1) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + /* Length two claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 65536 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + shortkey[0] = i & 255; + shortkey[1] = i >> 8; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 2) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */ + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 33) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */ + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, pubkeyc, 65) == 0); + CHECK(ecount == 2); + /* NULL input string. Illegal arg and zeroize output. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, NULL, 65) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 1); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 2); + /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 64) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 66) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* Valid parse. */ + memset(&pubkey, 0, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + VG_UNDEF(&ge, sizeof(ge)); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); + VG_CHECK(&ge.x, sizeof(ge.x)); + VG_CHECK(&ge.y, sizeof(ge.y)); + VG_CHECK(&ge.infinity, sizeof(ge.infinity)); + ge_equals_ge(&secp256k1_ge_const_g, &ge); + CHECK(ecount == 0); + /* secp256k1_ec_pubkey_serialize illegal args. */ + ecount = 0; + len = 65; + CHECK(secp256k1_ec_pubkey_serialize(ctx, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); + CHECK(ecount == 1); + CHECK(len == 0); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); + CHECK(ecount == 2); + len = 65; + VG_UNDEF(sout, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0); + VG_CHECK(sout, 65); + CHECK(ecount == 3); + CHECK(len == 0); + len = 65; + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, ~0) == 0); + CHECK(ecount == 4); + CHECK(len == 0); + len = 65; + VG_UNDEF(sout, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + VG_CHECK(sout, 65); + CHECK(ecount == 4); + CHECK(len == 65); + /* Multiple illegal args. Should still set arg error only once. */ + ecount = 0; + ecount2 = 11; + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); + CHECK(ecount == 1); + /* Does the illegal arg callback actually change the behavior? */ + secp256k1_context_set_illegal_callback(ctx, uncounting_illegal_callback_fn, &ecount2); + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); + CHECK(ecount == 1); + CHECK(ecount2 == 10); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); + /* Try a bunch of prefabbed points with all possible encodings. */ + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) { + ec_pubkey_parse_pointtest(valid[i], 1, 1); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NXVALID; i++) { + ec_pubkey_parse_pointtest(onlyxvalid[i], 1, 0); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NINVALID; i++) { + ec_pubkey_parse_pointtest(invalid[i], 0, 0); + } +} + +void run_eckey_edge_case_test(void) { + const unsigned char orderc[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + const unsigned char zeros[sizeof(secp256k1_pubkey)] = {0x00}; + unsigned char ctmp[33]; + unsigned char ctmp2[33]; + secp256k1_pubkey pubkey; + secp256k1_pubkey pubkey2; + secp256k1_pubkey pubkey_one; + secp256k1_pubkey pubkey_negone; + const secp256k1_pubkey *pubkeys[3]; + size_t len; + int32_t ecount; + /* Group order is too large, reject. */ + CHECK(secp256k1_ec_seckey_verify(ctx, orderc) == 0); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, orderc) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* Maximum value is too large, reject. */ + memset(ctmp, 255, 32); + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* Zero is too small, reject. */ + memset(ctmp, 0, 32); + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* One must be accepted. */ + ctmp[31] = 0x01; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + pubkey_one = pubkey; + /* Group order + 1 is too large, reject. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x42; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* -1 must be accepted. */ + ctmp[31] = 0x40; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + pubkey_negone = pubkey; + /* Tweak of zero leaves the value changed. */ + memset(ctmp2, 0, 32); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1); + CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); + memcpy(&pubkey2, &pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Multiply tweak of zero zeroizes the output. */ + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Overflowing key tweak zeroizes. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, orderc) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Private key tweaks results in a key of zero. */ + ctmp2[31] = 1; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0); + CHECK(memcmp(zeros, ctmp2, 32) == 0); + ctmp2[31] = 1; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Tweak computation wraps and results in a key of 1. */ + ctmp2[31] = 2; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 1); + CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); + ctmp2[31] = 2; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + ctmp2[31] = 1; + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Tweak mul * 2 = 1+1. */ + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + ctmp2[31] = 2; + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Test argument errors. */ + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + CHECK(ecount == 0); + /* Zeroize pubkey on parse error. */ + memset(&pubkey, 0, 32); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + memset(&pubkey2, 0, 32); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0); + CHECK(ecount == 2); + CHECK(memcmp(&pubkey2, zeros, sizeof(pubkey2)) == 0); + /* Plain argument errors. */ + ecount = 0; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_ec_seckey_verify(ctx, NULL) == 0); + CHECK(ecount == 1); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 1; + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + CHECK(secp256k1_ec_pubkey_create(ctx, NULL, ctmp) == 0); + CHECK(ecount == 1); + memset(&pubkey, 1, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* secp256k1_ec_pubkey_combine tests. */ + ecount = 0; + pubkeys[0] = &pubkey_one; + VG_UNDEF(&pubkeys[0], sizeof(secp256k1_pubkey *)); + VG_UNDEF(&pubkeys[1], sizeof(secp256k1_pubkey *)); + VG_UNDEF(&pubkeys[2], sizeof(secp256k1_pubkey *)); + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 0) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_combine(ctx, NULL, pubkeys, 1) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 2); + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, NULL, 1) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 3); + pubkeys[0] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 1) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); + CHECK(memcmp(ctmp, ctmp2, 33) == 0); + /* Result is infinity. */ + pubkeys[0] = &pubkey_one; + pubkeys[1] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 3); + /* Passes through infinity but comes out one. */ + pubkeys[2] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 3) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); + CHECK(memcmp(ctmp, ctmp2, 33) == 0); + /* Adds to two. */ + pubkeys[1] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); +} + +void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { + secp256k1_scalar nonce; do { random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sig, key, msg, &nonce, recid)); + } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); } void test_ecdsa_sign_verify(void) { - secp256k1_gej_t pubj; - secp256k1_ge_t pub; - secp256k1_scalar_t one; - secp256k1_scalar_t msg, key; - secp256k1_ecdsa_sig_t sig; + secp256k1_gej pubj; + secp256k1_ge pub; + secp256k1_scalar one; + secp256k1_scalar msg, key; + secp256k1_scalar sigr, sigs; int recid; int getrec; random_scalar_order_test(&msg); random_scalar_order_test(&key); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); - getrec = secp256k1_rand32()&1; - random_sign(&sig, &key, &msg, getrec?&recid:NULL); + getrec = secp256k1_rand_bits(1); + random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL); if (getrec) { CHECK(recid >= 0 && recid < 4); } - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); secp256k1_scalar_set_int(&one, 1); secp256k1_scalar_add(&msg, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg)); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); } void run_ecdsa_sign_verify(void) { @@ -1357,22 +3234,23 @@ void run_ecdsa_sign_verify(void) { } /** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */ -static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { +static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { (void)msg32; (void)key32; + (void)algo16; memcpy(nonce32, data, 32); return (counter == 0); } -static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { +static 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) { /* Dummy nonce generator that has a fatal error on the first counter value. */ if (counter == 0) { return 0; } - return nonce_function_rfc6979(nonce32, msg32, key32, counter - 1, data); + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 1); } -static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { +static 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) { /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */ if (counter < 3) { memset(nonce32, counter==0 ? 0 : 255, 32); @@ -1394,17 +3272,17 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char } return 1; } - /* Retry rate of 6979 is negligible esp. as we only call this in determinstic tests. */ + /* Retry rate of 6979 is negligible esp. as we only call this in deterministic tests. */ /* If someone does fine a case where it retries for secp256k1, we'd like to know. */ if (counter > 5) { return 0; } - return nonce_function_rfc6979(nonce32, msg32, key32, counter - 5, data); + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5); } -int is_empty_compact_signature(const unsigned char *sig64) { - static const unsigned char res[64] = {0}; - return memcmp(sig64, res, 64) == 0; +int is_empty_signature(const secp256k1_ecdsa_signature *sig) { + static const unsigned char res[sizeof(secp256k1_ecdsa_signature)] = {0}; + return memcmp(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0; } void test_ecdsa_end_to_end(void) { @@ -1412,26 +3290,19 @@ void test_ecdsa_end_to_end(void) { unsigned char privkey[32]; unsigned char message[32]; unsigned char privkey2[32]; - unsigned char csignature[64]; - unsigned char signature[72]; - unsigned char signature2[72]; - unsigned char signature3[72]; - unsigned char signature4[72]; - unsigned char pubkey[65]; - unsigned char recpubkey[65]; + secp256k1_ecdsa_signature signature[6]; + secp256k1_scalar r, s; + unsigned char sig[74]; + size_t siglen = 74; + unsigned char pubkeyc[65]; + size_t pubkeyclen = 65; + secp256k1_pubkey pubkey; unsigned char seckey[300]; - int signaturelen = 72; - int signaturelen2 = 72; - int signaturelen3 = 72; - int signaturelen4 = 72; - int recid = 0; - int recpubkeylen = 0; - int pubkeylen = 65; - int seckeylen = 300; + size_t seckeylen = 300; /* Generate a random key and message. */ { - secp256k1_scalar_t msg, key; + secp256k1_scalar msg, key; random_scalar_order_test(&msg); random_scalar_order_test(&key); secp256k1_scalar_get_b32(privkey, &key); @@ -1440,117 +3311,120 @@ void test_ecdsa_end_to_end(void) { /* Construct and verify corresponding public key. */ CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, pubkey, &pubkeylen, privkey, (secp256k1_rand32() & 3) != 0) == 1); - if (secp256k1_rand32() & 1) { - CHECK(secp256k1_ec_pubkey_decompress(ctx, pubkey, &pubkeylen)); - } - CHECK(secp256k1_ec_pubkey_verify(ctx, pubkey, pubkeylen)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Verify exporting and importing public key. */ + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); + memset(&pubkey, 0, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); /* Verify private key import and export. */ - CHECK(secp256k1_ec_privkey_export(ctx, privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1); - CHECK(secp256k1_ec_privkey_import(ctx, privkey2, seckey, seckeylen) == 1); + CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1)); + CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1); CHECK(memcmp(privkey, privkey2, 32) == 0); /* Optionally tweak the keys using addition. */ - if (secp256k1_rand32() % 3 == 0) { + if (secp256k1_rand_int(3) == 0) { int ret1; int ret2; unsigned char rnd[32]; - unsigned char pubkey2[65]; - int pubkeylen2 = 65; + secp256k1_pubkey pubkey2; secp256k1_rand256_test(rnd); ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_add(ctx, pubkey, pubkeylen, rnd); + ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd); CHECK(ret1 == ret2); if (ret1 == 0) { return; } - CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); - CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Optionally tweak the keys using multiplication. */ - if (secp256k1_rand32() % 3 == 0) { + if (secp256k1_rand_int(3) == 0) { int ret1; int ret2; unsigned char rnd[32]; - unsigned char pubkey2[65]; - int pubkeylen2 = 65; + secp256k1_pubkey pubkey2; secp256k1_rand256_test(rnd); ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, pubkey, pubkeylen, rnd); + ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd); CHECK(ret1 == ret2); if (ret1 == 0) { return; } - CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); - CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Sign. */ - CHECK(secp256k1_ecdsa_sign(ctx, message, signature, &signaturelen, privkey, NULL, NULL) == 1); - CHECK(signaturelen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, message, signature2, &signaturelen2, privkey, NULL, extra) == 1); - CHECK(signaturelen2 > 0); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[1], message, privkey, NULL, extra) == 1); extra[31] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, message, signature3, &signaturelen3, privkey, NULL, extra) == 1); - CHECK(signaturelen3 > 0); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[2], message, privkey, NULL, extra) == 1); extra[31] = 0; extra[0] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, message, signature4, &signaturelen4, privkey, NULL, extra) == 1); - CHECK(signaturelen3 > 0); - CHECK((signaturelen != signaturelen2) || (memcmp(signature, signature2, signaturelen) != 0)); - CHECK((signaturelen != signaturelen3) || (memcmp(signature, signature3, signaturelen) != 0)); - CHECK((signaturelen3 != signaturelen2) || (memcmp(signature3, signature2, signaturelen3) != 0)); - CHECK((signaturelen4 != signaturelen3) || (memcmp(signature4, signature3, signaturelen4) != 0)); - CHECK((signaturelen4 != signaturelen2) || (memcmp(signature4, signature2, signaturelen4) != 0)); - CHECK((signaturelen4 != signaturelen) || (memcmp(signature4, signature, signaturelen4) != 0)); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[3], message, privkey, NULL, extra) == 1); + CHECK(memcmp(&signature[0], &signature[4], sizeof(signature[0])) == 0); + CHECK(memcmp(&signature[0], &signature[1], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[0], &signature[2], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[0], &signature[3], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[1], &signature[2], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[1], &signature[3], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[2], &signature[3], sizeof(signature[0])) != 0); /* Verify. */ - CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature2, signaturelen2, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature3, signaturelen3, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature4, signaturelen4, pubkey, pubkeylen) == 1); - /* Destroy signature and verify again. */ - signature[signaturelen - 1 - secp256k1_rand32() % 20] += 1 + (secp256k1_rand32() % 255); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) != 1); - - /* Compact sign. */ - CHECK(secp256k1_ecdsa_sign_compact(ctx, message, csignature, privkey, NULL, NULL, &recid) == 1); - CHECK(!is_empty_compact_signature(csignature)); - /* Recover. */ - CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1); - CHECK(recpubkeylen == pubkeylen); - CHECK(memcmp(pubkey, recpubkey, pubkeylen) == 0); - /* Destroy signature and verify again. */ - csignature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); - CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) != 1 || - memcmp(pubkey, recpubkey, pubkeylen) != 0); - CHECK(recpubkeylen == pubkeylen); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1); + /* Test lower-S form, malleate, verify and fail, test again, malleate again */ + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[0])); + secp256k1_ecdsa_signature_load(ctx, &r, &s, &signature[0]); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0); + CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + CHECK(memcmp(&signature[5], &signature[0], 64) == 0); + /* Serialize/parse DER and verify again */ + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + memset(&signature[0], 0, sizeof(signature[0])); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); + /* Serialize/destroy/parse DER and verify again. */ + siglen = 74; + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + sig[secp256k1_rand_int(siglen)] += 1 + secp256k1_rand_int(255); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 || + secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0); } void test_random_pubkeys(void) { - secp256k1_ge_t elem; - secp256k1_ge_t elem2; + secp256k1_ge elem; + secp256k1_ge elem2; unsigned char in[65]; /* Generate some randomly sized pubkeys. */ - uint32_t r = secp256k1_rand32(); - int len = (r & 3) == 0 ? 65 : 33; - r>>=2; - if ((r & 3) == 0) { - len = (r & 252) >> 3; + size_t len = secp256k1_rand_bits(2) == 0 ? 65 : 33; + if (secp256k1_rand_bits(2) == 0) { + len = secp256k1_rand_bits(6); } - r>>=8; if (len == 65) { - in[0] = (r & 2) ? 4 : (r & 1? 6 : 7); + in[0] = secp256k1_rand_bits(1) ? 4 : (secp256k1_rand_bits(1) ? 6 : 7); } else { - in[0] = (r & 1) ? 2 : 3; + in[0] = secp256k1_rand_bits(1) ? 2 : 3; } - r>>=2; - if ((r & 7) == 0) { - in[0] = (r & 2040) >> 3; + if (secp256k1_rand_bits(3) == 0) { + in[0] = secp256k1_rand_bits(8); } - r>>=11; if (len > 1) { secp256k1_rand256(&in[1]); } @@ -1561,7 +3435,7 @@ void test_random_pubkeys(void) { unsigned char out[65]; unsigned char firstb; int res; - int size = len; + size_t size = len; firstb = in[0]; /* If the pubkey can be parsed, it should round-trip... */ CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33)); @@ -1577,7 +3451,7 @@ void test_random_pubkeys(void) { CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); ge_equals_ge(&elem,&elem2); /* Check that the X9.62 hybrid type is checked. */ - in[0] = (r & 1) ? 6 : 7; + in[0] = secp256k1_rand_bits(1) ? 6 : 7; res = secp256k1_eckey_pubkey_parse(&elem2, in, size); if (firstb == 2 || firstb == 3) { if (in[0] == firstb + 4) { @@ -1608,185 +3482,505 @@ void run_ecdsa_end_to_end(void) { } } -/* Tests several edge cases. */ -void test_ecdsa_edge_cases(void) { - const unsigned char msg32[32] = { - 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', - 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', - 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', - 's', 's', 'a', 'g', 'e', '.', '.', '.' +int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { + static const unsigned char zeroes[32] = {0}; + static const unsigned char max_scalar[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40 }; - const unsigned char sig64[64] = { - /* Generated by signing the above message with nonce 'This is the nonce we will use...' - * and secret key 0 (which is not valid), resulting in recid 0. */ - 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, - 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, - 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, - 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, - 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, - 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, - 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, - 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 - }; - unsigned char pubkey[65]; - int t; - int pubkeylen = 65; - /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ - const unsigned char sigb64[64] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - }; - unsigned char pubkeyb[33]; - int pubkeyblen = 33; - int recid; - CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 0)); - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 1)); - CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 2)); - CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 3)); + int ret = 0; - for (recid = 0; recid < 4; recid++) { - int i; - int recid2; - /* (4,4) encoded in DER. */ - unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; - unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; - unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; - unsigned char sigbderalt1[39] = { - 0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, - }; - unsigned char sigbderalt2[39] = { - 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - }; - unsigned char sigbderalt3[40] = { - 0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, - }; - unsigned char sigbderalt4[40] = { - 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - }; - /* (order + r,4) encoded in DER. */ - unsigned char sigbderlong[40] = { - 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, - 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, - 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 - }; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkeyb, &pubkeyblen, 1, recid)); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1); - for (recid2 = 0; recid2 < 4; recid2++) { - unsigned char pubkey2b[33]; - int pubkey2blen = 33; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkey2b, &pubkey2blen, 1, recid2)); - /* Verifying with (order + r,4) should always fail. */ - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderlong, sizeof(sigbderlong), pubkey2b, pubkey2blen) != 1); + secp256k1_ecdsa_signature sig_der; + unsigned char roundtrip_der[2048]; + unsigned char compact_der[64]; + size_t len_der = 2048; + int parsed_der = 0, valid_der = 0, roundtrips_der = 0; + + secp256k1_ecdsa_signature sig_der_lax; + unsigned char roundtrip_der_lax[2048]; + unsigned char compact_der_lax[64]; + size_t len_der_lax = 2048; + int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0; + +#ifdef ENABLE_OPENSSL_TESTS + ECDSA_SIG *sig_openssl; + const unsigned char *sigptr; + unsigned char roundtrip_openssl[2048]; + int len_openssl = 2048; + int parsed_openssl, valid_openssl = 0, roundtrips_openssl = 0; +#endif + + parsed_der = secp256k1_ecdsa_signature_parse_der(ctx, &sig_der, sig, siglen); + if (parsed_der) { + ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der, &sig_der)) << 0; + valid_der = (memcmp(compact_der, zeroes, 32) != 0) && (memcmp(compact_der + 32, zeroes, 32) != 0); + } + if (valid_der) { + ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der, &len_der, &sig_der)) << 1; + roundtrips_der = (len_der == siglen) && memcmp(roundtrip_der, sig, siglen) == 0; + } + + parsed_der_lax = ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen); + if (parsed_der_lax) { + ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10; + valid_der_lax = (memcmp(compact_der_lax, zeroes, 32) != 0) && (memcmp(compact_der_lax + 32, zeroes, 32) != 0); + } + if (valid_der_lax) { + ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; + roundtrips_der_lax = (len_der_lax == siglen) && memcmp(roundtrip_der_lax, sig, siglen) == 0; + } + + if (certainly_der) { + ret |= (!parsed_der) << 2; + } + if (certainly_not_der) { + ret |= (parsed_der) << 17; + } + if (valid_der) { + ret |= (!roundtrips_der) << 3; + } + + if (valid_der) { + ret |= (!roundtrips_der_lax) << 12; + ret |= (len_der != len_der_lax) << 13; + ret |= (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0) << 14; + } + ret |= (roundtrips_der != roundtrips_der_lax) << 15; + if (parsed_der) { + ret |= (!parsed_der_lax) << 16; + } + +#ifdef ENABLE_OPENSSL_TESTS + sig_openssl = ECDSA_SIG_new(); + sigptr = sig; + parsed_openssl = (d2i_ECDSA_SIG(&sig_openssl, &sigptr, siglen) != NULL); + if (parsed_openssl) { + 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; + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(sig_openssl->r, tmp + 32 - BN_num_bytes(sig_openssl->r)); + valid_openssl = memcmp(tmp, max_scalar, 32) < 0; } - /* DER parsing tests. */ - /* Zero length r/s. */ - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zr, sizeof(sigcder_zr), pubkeyb, pubkeyblen) == -2); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zs, sizeof(sigcder_zs), pubkeyb, pubkeyblen) == -2); - /* Leading zeros. */ - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt1, sizeof(sigbderalt1), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt2, sizeof(sigbderalt2), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == 1); - sigbderalt3[4] = 1; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == -2); - sigbderalt4[7] = 1; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == -2); - /* Damage signature. */ - sigbder[7]++; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0); - sigbder[7]--; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, 6, pubkeyb, pubkeyblen) == -2); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder)-1, pubkeyb, pubkeyblen) == -2); - for(i = 0; i < 8; i++) { - int c; - unsigned char orig = sigbder[i]; - /*Try every single-byte change.*/ - for (c = 0; c < 256; c++) { - if (c == orig ) { - continue; - } - sigbder[i] = c; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == - (i==4 || i==7) ? 0 : -2 ); - } - sigbder[i] = orig; + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(sig_openssl->s, tmp + 32 - BN_num_bytes(sig_openssl->s)); + valid_openssl = memcmp(tmp, max_scalar, 32) < 0; } } + len_openssl = i2d_ECDSA_SIG(sig_openssl, NULL); + if (len_openssl <= 2048) { + unsigned char *ptr = roundtrip_openssl; + CHECK(i2d_ECDSA_SIG(sig_openssl, &ptr) == len_openssl); + roundtrips_openssl = valid_openssl && ((size_t)len_openssl == siglen) && (memcmp(roundtrip_openssl, sig, siglen) == 0); + } else { + len_openssl = 0; + } + ECDSA_SIG_free(sig_openssl); + + ret |= (parsed_der && !parsed_openssl) << 4; + ret |= (valid_der && !valid_openssl) << 5; + ret |= (roundtrips_openssl && !parsed_der) << 6; + ret |= (roundtrips_der != roundtrips_openssl) << 7; + if (roundtrips_openssl) { + ret |= (len_der != (size_t)len_openssl) << 8; + ret |= (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0) << 9; + } +#endif + return ret; +} + +static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) { + size_t i; + for (i = 0; i < ptrlen; i++) { + int shift = ptrlen - 1 - i; + if (shift >= 4) { + ptr[i] = 0; + } else { + ptr[i] = (val >> shift) & 0xFF; + } + } +} + +static void damage_array(unsigned char *sig, size_t *len) { + int pos; + int action = secp256k1_rand_bits(3); + if (action < 1) { + /* Delete a byte. */ + pos = secp256k1_rand_int(*len); + memmove(sig + pos, sig + pos + 1, *len - pos - 1); + (*len)--; + return; + } else if (action < 2) { + /* Insert a byte. */ + pos = secp256k1_rand_int(1 + *len); + memmove(sig + pos + 1, sig + pos, *len - pos); + sig[pos] = secp256k1_rand_bits(8); + (*len)++; + return; + } else if (action < 4) { + /* Modify a byte. */ + sig[secp256k1_rand_int(*len)] += 1 + secp256k1_rand_int(255); + return; + } else { /* action < 8 */ + /* Modify a bit. */ + sig[secp256k1_rand_int(*len)] ^= 1 << secp256k1_rand_bits(3); + return; + } +} + +static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly_der, int* certainly_not_der) { + int der; + int nlow[2], nlen[2], nlenlen[2], nhbit[2], nhbyte[2], nzlen[2]; + size_t tlen, elen, glen; + int indet; + int n; + + *len = 0; + der = secp256k1_rand_bits(2) == 0; + *certainly_der = der; + *certainly_not_der = 0; + indet = der ? 0 : secp256k1_rand_int(10) == 0; + + for (n = 0; n < 2; 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) */ + nlow[n] = der ? 1 : (secp256k1_rand_bits(3) != 0); + /* The length of the number in bytes (the first byte of which will always be nonzero) */ + nlen[n] = nlow[n] ? secp256k1_rand_int(33) : 32 + secp256k1_rand_int(200) * secp256k1_rand_int(8) / 8; + CHECK(nlen[n] <= 232); + /* The top bit of the number. */ + nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_rand_bits(1)); + /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */ + nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_rand_bits(7) : 1 + secp256k1_rand_int(127)); + /* 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) */ + 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); + if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) { + *certainly_not_der = 1; + } + CHECK(nlen[n] + nzlen[n] <= 300); + /* The length of the length descriptor for the number. 0 means short encoding, anything else is long encoding. */ + nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2); + if (!der) { + /* nlenlen[n] max 127 bytes */ + int add = secp256k1_rand_int(127 - nlenlen[n]) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + nlenlen[n] += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + CHECK(nlen[n] + nzlen[n] + nlenlen[n] <= 427); + } + + /* The total length of the data to go, so far */ + tlen = 2 + nlenlen[0] + nlen[0] + nzlen[0] + 2 + nlenlen[1] + nlen[1] + nzlen[1]; + CHECK(tlen <= 856); + + /* The length of the garbage inside the tuple. */ + elen = (der || indet) ? 0 : secp256k1_rand_int(980 - tlen) * secp256k1_rand_int(8) / 8; + if (elen != 0) { + *certainly_not_der = 1; + } + tlen += elen; + CHECK(tlen <= 980); + + /* The length of the garbage after the end of the tuple. */ + glen = der ? 0 : secp256k1_rand_int(990 - tlen) * secp256k1_rand_int(8) / 8; + if (glen != 0) { + *certainly_not_der = 1; + } + CHECK(tlen + glen <= 990); + + /* Write the tuple header. */ + sig[(*len)++] = 0x30; + if (indet) { + /* Indeterminate length */ + sig[(*len)++] = 0x80; + *certainly_not_der = 1; + } else { + int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2); + if (!der) { + int add = secp256k1_rand_int(127 - tlenlen) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + tlenlen += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + if (tlenlen == 0) { + /* Short length notation */ + sig[(*len)++] = tlen; + } else { + /* Long length notation */ + sig[(*len)++] = 128 + tlenlen; + assign_big_endian(sig + *len, tlenlen, tlen); + *len += tlenlen; + } + tlen += tlenlen; + } + tlen += 2; + CHECK(tlen + glen <= 1119); + + for (n = 0; n < 2; n++) { + /* Write the integer header. */ + sig[(*len)++] = 0x02; + if (nlenlen[n] == 0) { + /* Short length notation */ + sig[(*len)++] = nlen[n] + nzlen[n]; + } else { + /* Long length notation. */ + sig[(*len)++] = 128 + nlenlen[n]; + assign_big_endian(sig + *len, nlenlen[n], nlen[n] + nzlen[n]); + *len += nlenlen[n]; + } + /* Write zero padding */ + while (nzlen[n] > 0) { + sig[(*len)++] = 0x00; + nzlen[n]--; + } + if (nlen[n] == 32 && !nlow[n]) { + /* Special extra 16 0xFF bytes in "high" 32-byte numbers */ + int i; + for (i = 0; i < 16; i++) { + sig[(*len)++] = 0xFF; + } + nlen[n] -= 16; + } + /* Write first byte of number */ + if (nlen[n] > 0) { + sig[(*len)++] = nhbyte[n]; + nlen[n]--; + } + /* Generate remaining random bytes of number */ + secp256k1_rand_bytes_test(sig + *len, nlen[n]); + *len += nlen[n]; + nlen[n] = 0; + } + + /* Generate random garbage inside tuple. */ + secp256k1_rand_bytes_test(sig + *len, elen); + *len += elen; + + /* Generate end-of-contents bytes. */ + if (indet) { + sig[(*len)++] = 0; + sig[(*len)++] = 0; + tlen += 2; + } + CHECK(tlen + glen <= 1121); + + /* Generate random garbage outside tuple. */ + secp256k1_rand_bytes_test(sig + *len, glen); + *len += glen; + tlen += glen; + CHECK(tlen <= 1121); + CHECK(tlen == *len); +} + +void run_ecdsa_der_parse(void) { + int i,j; + for (i = 0; i < 200 * count; i++) { + unsigned char buffer[2048]; + size_t buflen = 0; + int certainly_der = 0; + int certainly_not_der = 0; + random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der); + for (j = 0; j < 16; j++) { + int ret = 0; + if (j > 0) { + damage_array(buffer, &buflen); + /* We don't know anything anymore about the DERness of the result */ + certainly_der = 0; + certainly_not_der = 0; + } + ret = test_ecdsa_der_parse(buffer, buflen, certainly_der, certainly_not_der); + if (ret != 0) { + size_t k; + fprintf(stderr, "Failure %x on ", ret); + for (k = 0; k < buflen; k++) { + fprintf(stderr, "%02x ", buffer[k]); + } + fprintf(stderr, "\n"); + } + CHECK(ret == 0); + } + } +} + +/* Tests several edge cases. */ +void test_ecdsa_edge_cases(void) { + int t; + secp256k1_ecdsa_signature sig; /* Test the case where ECDSA recomputes a point that is infinity. */ { - secp256k1_gej_t keyj; - secp256k1_ge_t key; - secp256k1_scalar_t msg; - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_set_int(&sig.s, 1); - secp256k1_scalar_negate(&sig.s, &sig.s); - secp256k1_scalar_inverse(&sig.s, &sig.s); - secp256k1_scalar_set_int(&sig.r, 1); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sig.r); + secp256k1_gej keyj; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_negate(&ss, &ss); + secp256k1_scalar_inverse(&ss, &ss); + secp256k1_scalar_set_int(&sr, 1); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr); secp256k1_ge_set_gej(&key, &keyj); - msg = sig.s; - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &key, &msg) == 0); + msg = ss; + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); } - /* Test r/s equal to zero */ + /* Verify signature with r of zero fails. */ { - /* (1,1) encoded in DER. */ - unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; - unsigned char sigc64[64] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + const unsigned char pubkey_mods_zero[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x41 }; - unsigned char pubkeyc[65]; - int pubkeyclen = 65; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1); - sigcder[4] = 0; - sigc64[31] = 0; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); - sigcder[4] = 1; - sigcder[7] = 0; - sigc64[31] = 1; - sigc64[63] = 0; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 0); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey_mods_zero, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); } - /*Signature where s would be zero.*/ + /* Verify signature with s of zero fails. */ { - const unsigned char nonce[32] = { + const unsigned char pubkey[33] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01 + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 0); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 1); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with message 0 passes. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02 + }; + const unsigned char pubkey2[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x43 + }; + secp256k1_ge key; + secp256k1_ge key2; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 2); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 2); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_set_int(&ss, 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message 1 passes. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x14, 0x4e, 0x5a, 0x58, 0xef, 0x5b, 0x22, + 0x6f, 0xd2, 0xe2, 0x07, 0x6a, 0x77, 0xcf, 0x05, + 0xb4, 0x1d, 0xe7, 0x4a, 0x30, 0x98, 0x27, 0x8c, + 0x93, 0xe6, 0xe6, 0x3c, 0x0b, 0xc4, 0x73, 0x76, + 0x25 + }; + const unsigned char pubkey2[33] = { + 0x02, 0x8a, 0xd5, 0x37, 0xed, 0x73, 0xd9, 0x40, + 0x1d, 0xa0, 0x33, 0xd2, 0xdc, 0xf0, 0xaf, 0xae, + 0x34, 0xcf, 0x5f, 0x96, 0x4c, 0x73, 0x28, 0x0f, + 0x92, 0xc0, 0xf6, 0x9d, 0xd9, 0xb2, 0x09, 0x10, + 0x62 + }; + const unsigned char csr[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xeb + }; + secp256k1_ge key; + secp256k1_ge key2; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 1); + secp256k1_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_set_int(&ss, 2); + secp256k1_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message -1 passes. */ + { + const unsigned char pubkey[33] = { + 0x03, 0xaf, 0x97, 0xff, 0x7d, 0x3a, 0xf6, 0xa0, + 0x02, 0x94, 0xbd, 0x9f, 0x4b, 0x2e, 0xd7, 0x52, + 0x28, 0xdb, 0x49, 0x2a, 0x65, 0xcb, 0x1e, 0x27, + 0x57, 0x9c, 0xba, 0x74, 0x20, 0xd5, 0x1d, 0x20, + 0xf1 + }; + const unsigned char csr[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xee + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 1); + secp256k1_scalar_negate(&msg, &msg); + secp256k1_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + secp256k1_scalar_set_int(&ss, 3); + secp256k1_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Signature where s would be zero. */ + { + secp256k1_pubkey pubkey; + size_t siglen; + int32_t ecount; + unsigned char signature[72]; + static const unsigned char nonce[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1810,21 +4004,72 @@ void test_ecdsa_edge_cases(void) { 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, }; - unsigned char sig[72]; - int siglen = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 0); - CHECK(siglen == 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 0); - CHECK(siglen == 0); + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); msg[31] = 0xaa; + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, key) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, NULL, msg, &pubkey) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, NULL, &pubkey) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, NULL) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1); + CHECK(ecount == 6); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 7); + /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */ + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 0); + CHECK(ecount == 8); siglen = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 1); - CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 1); - CHECK(siglen > 0); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig) == 0); + CHECK(ecount == 9); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig) == 0); + CHECK(ecount == 10); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL) == 0); + CHECK(ecount == 11); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1); + CHECK(ecount == 11); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, NULL, signature, siglen) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, NULL, siglen) == 0); + CHECK(ecount == 13); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, signature, siglen) == 1); + CHECK(ecount == 13); siglen = 10; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) != 1); - CHECK(siglen == 0); + /* Too little room for a signature does not fail via ARGCHECK. */ + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0); + CHECK(ecount == 13); + ecount = 0; + CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, NULL, &sig) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, &sig) == 1); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, NULL, signature) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, NULL) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 1); + CHECK(ecount == 5); + memset(signature, 255, 64); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 0); + CHECK(ecount == 5); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); } /* Nonce function corner cases. */ @@ -1833,65 +4078,43 @@ void test_ecdsa_edge_cases(void) { int i; unsigned char key[32]; unsigned char msg[32]; - unsigned char sig[72]; - unsigned char sig2[72]; - secp256k1_ecdsa_sig_t s[512]; - int siglen = 72; - int siglen2 = 72; - int recid2; + secp256k1_ecdsa_signature sig2; + secp256k1_scalar sr[512], ss; const unsigned char *extra; extra = t == 0 ? NULL : zero; memset(msg, 0, 32); msg[31] = 1; /* High key results in signature failure. */ memset(key, 0xFF, 32); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0); - CHECK(siglen == 0); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); /* Zero key results in signature failure. */ memset(key, 0, 32); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0); - CHECK(siglen == 0); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); /* Nonce function failure results in signature failure. */ key[31] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_fail, extra) == 0); - CHECK(siglen == 0); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_fail, extra, &recid) == 0); - CHECK(is_empty_compact_signature(sig)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_fail, extra) == 0); + CHECK(is_empty_signature(&sig)); /* The retry loop successfully makes its way to the first good value. */ - siglen = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_retry, extra) == 1); - CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, nonce_function_rfc6979, extra) == 1); - CHECK(siglen > 0); - CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_retry, extra, &recid) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, nonce_function_rfc6979, extra, &recid2) == 1); - CHECK(!is_empty_compact_signature(sig2)); - CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); - /* The default nonce function is determinstic. */ - siglen = 72; - siglen2 = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 1); - CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); - CHECK(siglen2 > 0); - CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, NULL, extra, &recid) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, NULL, extra, &recid2) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_retry, extra) == 1); + CHECK(!is_empty_signature(&sig)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); + /* The default nonce function is deterministic. */ + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); /* The default nonce function changes output with different messages. */ for(i = 0; i < 256; i++) { int j; - siglen2 = 72; msg[0] = i; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); for (j = 0; j < i; j++) { - CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r)); + CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); } } msg[0] = 0; @@ -1899,17 +4122,45 @@ void test_ecdsa_edge_cases(void) { /* The default nonce function changes output with different keys. */ for(i = 256; i < 512; i++) { int j; - siglen2 = 72; key[0] = i - 256; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); - CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); for (j = 0; j < i; j++) { - CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r)); + CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); } } key[0] = 0; } + { + /* Check that optional nonce arguments do not have equivalent effect. */ + const unsigned char zeros[32] = {0}; + unsigned char nonce[32]; + unsigned char nonce2[32]; + unsigned char nonce3[32]; + unsigned char nonce4[32]; + VG_UNDEF(nonce,32); + VG_UNDEF(nonce2,32); + VG_UNDEF(nonce3,32); + VG_UNDEF(nonce4,32); + CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1); + VG_CHECK(nonce,32); + CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1); + VG_CHECK(nonce2,32); + CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1); + VG_CHECK(nonce3,32); + CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1); + VG_CHECK(nonce4,32); + CHECK(memcmp(nonce, nonce2, 32) != 0); + CHECK(memcmp(nonce, nonce3, 32) != 0); + CHECK(memcmp(nonce, nonce4, 32) != 0); + CHECK(memcmp(nonce2, nonce3, 32) != 0); + CHECK(memcmp(nonce2, nonce4, 32) != 0); + CHECK(memcmp(nonce3, nonce4, 32) != 0); + } + + /* Privkey export where pubkey is the point at infinity. */ { unsigned char privkey[300]; @@ -1919,9 +4170,10 @@ void test_ecdsa_edge_cases(void) { 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, }; - int outlen = 300; - CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 0)); - CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 1)); + size_t outlen = 300; + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0)); + outlen = 300; + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1)); } } @@ -1930,46 +4182,48 @@ void run_ecdsa_edge_cases(void) { } #ifdef ENABLE_OPENSSL_TESTS -EC_KEY *get_openssl_key(const secp256k1_scalar_t *key) { +EC_KEY *get_openssl_key(const unsigned char *key32) { unsigned char privkey[300]; - int privkeylen; + size_t privkeylen; const unsigned char* pbegin = privkey; - int compr = secp256k1_rand32() & 1; + int compr = secp256k1_rand_bits(1); EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); - CHECK(secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, &privkeylen, key, compr)); + CHECK(ec_privkey_export_der(ctx, privkey, &privkeylen, key32, compr)); CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen)); CHECK(EC_KEY_check_key(ec_key)); return ec_key; } void test_ecdsa_openssl(void) { - secp256k1_gej_t qj; - secp256k1_ge_t q; - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t one; - secp256k1_scalar_t msg2; - secp256k1_scalar_t key, msg; + secp256k1_gej qj; + secp256k1_ge q; + secp256k1_scalar sigr, sigs; + secp256k1_scalar one; + secp256k1_scalar msg2; + secp256k1_scalar key, msg; EC_KEY *ec_key; unsigned int sigsize = 80; - int secp_sigsize = 80; + size_t secp_sigsize = 80; unsigned char message[32]; unsigned char signature[80]; + unsigned char key32[32]; secp256k1_rand256_test(message); secp256k1_scalar_set_b32(&msg, message, NULL); random_scalar_order_test(&key); + secp256k1_scalar_get_b32(key32, &key); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &qj, &key); secp256k1_ge_set_gej(&q, &qj); - ec_key = get_openssl_key(&key); - CHECK(ec_key); + ec_key = get_openssl_key(key32); + CHECK(ec_key != NULL); CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); - CHECK(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg)); + CHECK(secp256k1_ecdsa_sig_parse(&sigr, &sigs, signature, sigsize)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg)); secp256k1_scalar_set_int(&one, 1); secp256k1_scalar_add(&msg2, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg2)); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg2)); - random_sign(&sig, &key, &msg, NULL); - CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sig)); + random_sign(&sigr, &sigs, &key, &msg, NULL); + CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sigr, &sigs)); CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1); EC_KEY_free(ec_key); @@ -1983,6 +4237,18 @@ void run_ecdsa_openssl(void) { } #endif +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORR +# include "modules/schnorr/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/tests_impl.h" +#endif + int main(int argc, char **argv) { unsigned char seed16[16] = {0}; unsigned char run32[32] = {0}; @@ -2007,7 +4273,7 @@ int main(int argc, char **argv) { } } else { FILE *frand = fopen("/dev/urandom", "r"); - if (!frand || !fread(&seed16, sizeof(seed16), 1, frand)) { + if ((frand == NULL) || !fread(&seed16, sizeof(seed16), 1, frand)) { uint64_t t = time(NULL) * (uint64_t)1337; seed16[0] ^= t; seed16[1] ^= t >> 8; @@ -2028,12 +4294,14 @@ int main(int argc, char **argv) { /* initialize */ run_context_tests(); ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - if (secp256k1_rand32() & 1) { + if (secp256k1_rand_bits(1)) { secp256k1_rand256(run32); - CHECK(secp256k1_context_randomize(ctx, secp256k1_rand32() & 1 ? run32 : NULL)); + CHECK(secp256k1_context_randomize(ctx, secp256k1_rand_bits(1) ? run32 : NULL)); } + run_rand_bits(); + run_rand_int(); + run_sha256_tests(); run_hmac_sha256_tests(); run_rfc6979_hmac_sha256_tests(); @@ -2057,6 +4325,7 @@ int main(int argc, char **argv) { /* group tests */ run_ge(); + run_group_decompress(); /* ecmult tests */ run_wnaf(); @@ -2064,9 +4333,28 @@ int main(int argc, char **argv) { run_ecmult_chain(); run_ecmult_constants(); run_ecmult_gen_blind(); + run_ecmult_const_tests(); + run_ec_combine(); + + /* endomorphism tests */ +#ifdef USE_ENDOMORPHISM + run_endomorphism_tests(); +#endif + + /* EC point parser test */ + run_ec_pubkey_parse_test(); + + /* EC key edge cases */ + run_eckey_edge_case_test(); + +#ifdef ENABLE_MODULE_ECDH + /* ecdh tests */ + run_ecdh_tests(); +#endif /* ecdsa tests */ run_random_pubkeys(); + run_ecdsa_der_parse(); run_ecdsa_sign_verify(); run_ecdsa_end_to_end(); run_ecdsa_edge_cases(); @@ -2074,10 +4362,22 @@ int main(int argc, char **argv) { run_ecdsa_openssl(); #endif +#ifdef ENABLE_MODULE_SCHNORR + /* Schnorr tests */ + run_schnorr_tests(); +#endif + +#ifdef ENABLE_MODULE_RECOVERY + /* ECDSA pubkey recovery tests */ + run_recovery_tests(); +#endif + secp256k1_rand256(run32); 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]); /* shutdown */ secp256k1_context_destroy(ctx); + + printf("no problems found\n"); return 0; } diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h index ae98639f7..4eef4ded4 100644 --- a/src/secp256k1/src/util.h +++ b/src/secp256k1/src/util.h @@ -15,6 +15,15 @@ #include #include +typedef struct { + void (*fn)(const char *text, void* data); + const void* data; +} secp256k1_callback; + +static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * const cb, const char * const text) { + cb->fn(text, (void*)cb->data); +} + #ifdef DETERMINISTIC #define TEST_FAILURE(msg) do { \ fprintf(stderr, "%s\n", msg); \ @@ -47,23 +56,20 @@ } while(0) #endif -/* Like assert(), but safe to use on expressions with side effects. */ -#ifndef NDEBUG -#define DEBUG_CHECK CHECK -#else -#define DEBUG_CHECK(cond) do { (void)(cond); } while(0) -#endif - -/* Like DEBUG_CHECK(), but when VERIFY is defined instead of NDEBUG not defined. */ +/* Like assert(), but when VERIFY is defined, and side-effect safe. */ #ifdef VERIFY #define VERIFY_CHECK CHECK +#define VERIFY_SETUP(stmt) do { stmt; } while(0) #else #define VERIFY_CHECK(cond) do { (void)(cond); } while(0) +#define VERIFY_SETUP(stmt) #endif -static SECP256K1_INLINE void *checked_malloc(size_t size) { +static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { void *ret = malloc(size); - CHECK(ret != NULL); + if (ret == NULL) { + secp256k1_callback_call(cb, "Out of memory"); + } return ret; } diff --git a/src/serialize.h b/src/serialize.h index 53d8af142..5c2db9d33 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -20,7 +20,7 @@ #include #include -class CScript; +#include "prevector.h" static const unsigned int MAX_SIZE = 0x02000000; @@ -49,26 +49,26 @@ inline T* NCONST_PTR(const T* val) * @note These functions avoid the undefined case of indexing into an empty * vector, as well as that of indexing after the end of the vector. */ -template -inline T* begin_ptr(std::vector& v) +template +inline typename V::value_type* begin_ptr(V& v) { return v.empty() ? NULL : &v[0]; } /** Get begin pointer of vector (const version) */ -template -inline const T* begin_ptr(const std::vector& v) +template +inline const typename V::value_type* begin_ptr(const V& v) { return v.empty() ? NULL : &v[0]; } /** Get end pointer of vector (non-const version) */ -template -inline T* end_ptr(std::vector& v) +template +inline typename V::value_type* end_ptr(V& v) { return v.empty() ? NULL : (&v[0] + v.size()); } /** Get end pointer of vector (const version) */ -template -inline const T* end_ptr(const std::vector& v) +template +inline const typename V::value_type* end_ptr(const V& v) { return v.empty() ? NULL : (&v[0] + v.size()); } @@ -391,6 +391,12 @@ public: pbegin = (char*)begin_ptr(v); pend = (char*)end_ptr(v); } + template + explicit CFlatData(prevector &v) + { + pbegin = (char*)begin_ptr(v); + pend = (char*)end_ptr(v); + } char* begin() { return pbegin; } const char* begin() const { return pbegin; } char* end() { return pend; } @@ -485,6 +491,20 @@ template unsigned int GetSerializeSize(const std::basic_string& s template void Serialize(Stream& os, const std::basic_string& str, int, int=0); template void Unserialize(Stream& is, std::basic_string& str, int, int=0); +/** + * prevector + * prevectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. + */ +template unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const unsigned char&); +template unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const V&); +template inline unsigned int GetSerializeSize(const prevector& v, int nType, int nVersion); +template void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const unsigned char&); +template void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const V&); +template inline void Serialize(Stream& os, const prevector& v, int nType, int nVersion); +template void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const unsigned char&); +template void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const V&); +template inline void Unserialize(Stream& is, prevector& v, int nType, int nVersion); + /** * vector * vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. @@ -499,13 +519,6 @@ template void Unserialize_impl(Stream& template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const V&); template inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion); -/** - * others derived from vector - */ -extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion); -template void Serialize(Stream& os, const CScript& v, int nType, int nVersion); -template void Unserialize(Stream& is, CScript& v, int nType, int nVersion); - /** * pair */ @@ -587,6 +600,96 @@ void Unserialize(Stream& is, std::basic_string& str, int, int) +/** + * prevector + */ +template +unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const unsigned char&) +{ + return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); +} + +template +unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const V&) +{ + unsigned int nSize = GetSizeOfCompactSize(v.size()); + for (typename prevector::const_iterator vi = v.begin(); vi != v.end(); ++vi) + nSize += GetSerializeSize((*vi), nType, nVersion); + return nSize; +} + +template +inline unsigned int GetSerializeSize(const prevector& v, int nType, int nVersion) +{ + return GetSerializeSize_impl(v, nType, nVersion, T()); +} + + +template +void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const unsigned char&) +{ + WriteCompactSize(os, v.size()); + if (!v.empty()) + os.write((char*)&v[0], v.size() * sizeof(T)); +} + +template +void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const V&) +{ + WriteCompactSize(os, v.size()); + for (typename prevector::const_iterator vi = v.begin(); vi != v.end(); ++vi) + ::Serialize(os, (*vi), nType, nVersion); +} + +template +inline void Serialize(Stream& os, const prevector& v, int nType, int nVersion) +{ + Serialize_impl(os, v, nType, nVersion, T()); +} + + +template +void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const unsigned char&) +{ + // Limit size per read so bogus size value won't cause out of memory + v.clear(); + unsigned int nSize = ReadCompactSize(is); + unsigned int i = 0; + while (i < nSize) + { + unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); + v.resize(i + blk); + is.read((char*)&v[i], blk * sizeof(T)); + i += blk; + } +} + +template +void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const V&) +{ + v.clear(); + unsigned int nSize = ReadCompactSize(is); + unsigned int i = 0; + unsigned int nMid = 0; + while (nMid < nSize) + { + nMid += 5000000 / sizeof(T); + if (nMid > nSize) + nMid = nSize; + v.resize(nMid); + for (; i < nMid; i++) + Unserialize(is, v[i], nType, nVersion); + } +} + +template +inline void Unserialize(Stream& is, prevector& v, int nType, int nVersion) +{ + Unserialize_impl(is, v, nType, nVersion, T()); +} + + + /** * vector */ @@ -677,28 +780,6 @@ inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersio -/** - * others derived from vector - */ -inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion) -{ - return GetSerializeSize((const std::vector&)v, nType, nVersion); -} - -template -void Serialize(Stream& os, const CScript& v, int nType, int nVersion) -{ - Serialize(os, (const std::vector&)v, nType, nVersion); -} - -template -void Unserialize(Stream& is, CScript& v, int nType, int nVersion) -{ - Unserialize(is, (std::vector&)v, nType, nVersion); -} - - - /** * pair */ diff --git a/src/streams.h b/src/streams.h index 8610e4d18..0fc6135a6 100644 --- a/src/streams.h +++ b/src/streams.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h index 5e7bb66ea..1ec40fe83 100644 --- a/src/support/allocators/secure.h +++ b/src/support/allocators/secure.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/support/allocators/zeroafterfree.h b/src/support/allocators/zeroafterfree.h index 41e23392e..28a940ad1 100644 --- a/src/support/allocators/zeroafterfree.h +++ b/src/support/allocators/zeroafterfree.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/support/pagelocker.cpp b/src/support/pagelocker.cpp index 440e0a519..7cea2d88c 100644 --- a/src/support/pagelocker.cpp +++ b/src/support/pagelocker.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/support/pagelocker.h b/src/support/pagelocker.h index 88b95cce7..6b3979e55 100644 --- a/src/support/pagelocker.h +++ b/src/support/pagelocker.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/sync.cpp b/src/sync.cpp index 1837e8d53..641ed2c8c 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2012 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -56,11 +56,24 @@ private: }; typedef std::vector > LockStack; +typedef std::map, LockStack> LockOrders; +typedef std::set > InvLockOrders; -static boost::mutex dd_mutex; -static std::map, LockStack> lockorders; -static boost::thread_specific_ptr lockstack; +struct LockData { + // Very ugly hack: as the global constructs and destructors run single + // threaded, we use this boolean to know whether LockData still exists, + // as DeleteLock can get called by global CCriticalSection destructors + // after LockData disappears. + bool available; + LockData() : available(true) {} + ~LockData() { available = false; } + LockOrders lockorders; + InvLockOrders invlockorders; + boost::mutex dd_mutex; +} static lockdata; + +boost::thread_specific_ptr lockstack; static void potential_deadlock_detected(const std::pair& mismatch, const LockStack& s1, const LockStack& s2) { @@ -117,7 +130,7 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) if (lockstack.get() == NULL) lockstack.reset(new LockStack); - dd_mutex.lock(); + boost::unique_lock lock(lockdata.dd_mutex); (*lockstack).push_back(std::make_pair(c, locklocation)); @@ -127,23 +140,21 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) break; std::pair p1 = std::make_pair(i.first, c); - if (lockorders.count(p1)) + if (lockdata.lockorders.count(p1)) continue; - lockorders[p1] = (*lockstack); + lockdata.lockorders[p1] = (*lockstack); std::pair p2 = std::make_pair(c, i.first); - if (lockorders.count(p2)) - potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]); + lockdata.invlockorders.insert(p2); + if (lockdata.lockorders.count(p2)) + potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]); } } - dd_mutex.unlock(); } static void pop_lock() { - dd_mutex.lock(); (*lockstack).pop_back(); - dd_mutex.unlock(); } void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) @@ -173,4 +184,26 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, abort(); } +void DeleteLock(void* cs) +{ + if (!lockdata.available) { + // We're already shutting down. + return; + } + boost::unique_lock lock(lockdata.dd_mutex); + std::pair item = std::make_pair(cs, (void*)0); + LockOrders::iterator it = lockdata.lockorders.lower_bound(item); + while (it != lockdata.lockorders.end() && it->first.first == cs) { + std::pair invitem = std::make_pair(it->first.second, it->first.first); + lockdata.invlockorders.erase(invitem); + lockdata.lockorders.erase(it++); + } + InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item); + while (invit != lockdata.invlockorders.end() && invit->first == cs) { + std::pair invinvitem = std::make_pair(invit->second, invit->first); + lockdata.lockorders.erase(invinvitem); + lockdata.invlockorders.erase(invit++); + } +} + #endif /* DEBUG_LOCKORDER */ diff --git a/src/sync.h b/src/sync.h index 68a944308..0c58fb6b4 100644 --- a/src/sync.h +++ b/src/sync.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -71,30 +71,39 @@ public: } }; -/** - * Wrapped boost mutex: supports recursive locking, but no waiting - * TODO: We should move away from using the recursive lock by default. - */ -typedef AnnotatedMixin CCriticalSection; - -/** Wrapped boost mutex: supports waiting but not recursive locking */ -typedef AnnotatedMixin CWaitableCriticalSection; - -/** Just a typedef for boost::condition_variable, can be wrapped later if desired */ -typedef boost::condition_variable CConditionVariable; - #ifdef DEBUG_LOCKORDER void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); void LeaveCritical(); std::string LocksHeld(); void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs); +void DeleteLock(void* cs); #else void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} void static inline LeaveCritical() {} void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {} +void static inline DeleteLock(void* cs) {} #endif #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) +/** + * Wrapped boost mutex: supports recursive locking, but no waiting + * TODO: We should move away from using the recursive lock by default. + */ +class CCriticalSection : public AnnotatedMixin +{ +public: + ~CCriticalSection() { + DeleteLock((void*)this); + } +}; + +typedef CCriticalSection CDynamicCriticalSection; +/** Wrapped boost mutex: supports waiting but not recursive locking */ +typedef AnnotatedMixin CWaitableCriticalSection; + +/** Just a typedef for boost::condition_variable, can be wrapped later if desired */ +typedef boost::condition_variable CConditionVariable; + #ifdef DEBUG_LOCKCONTENTION void PrintLockContention(const char* pszName, const char* pszFile, int nLine); #endif diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp index e3a32968e..003e5d40a 100644 --- a/src/test/Checkpoints_tests.cpp +++ b/src/test/Checkpoints_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index da296a046..95342498f 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) CNode dummyNode1(INVALID_SOCKET, addr1, "", true); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); // Should get banned - SendMessages(&dummyNode1, false); + SendMessages(&dummyNode1); BOOST_CHECK(CNode::IsBanned(addr1)); BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned @@ -57,11 +57,11 @@ BOOST_AUTO_TEST_CASE(DoS_banning) CNode dummyNode2(INVALID_SOCKET, addr2, "", true); dummyNode2.nVersion = 1; Misbehaving(dummyNode2.GetId(), 50); - SendMessages(&dummyNode2, false); + SendMessages(&dummyNode2); BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet... BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be Misbehaving(dummyNode2.GetId(), 50); - SendMessages(&dummyNode2, false); + SendMessages(&dummyNode2); BOOST_CHECK(CNode::IsBanned(addr2)); } @@ -73,13 +73,13 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) CNode dummyNode1(INVALID_SOCKET, addr1, "", true); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); - SendMessages(&dummyNode1, false); + SendMessages(&dummyNode1); BOOST_CHECK(!CNode::IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 10); - SendMessages(&dummyNode1, false); + SendMessages(&dummyNode1); BOOST_CHECK(!CNode::IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 1); - SendMessages(&dummyNode1, false); + SendMessages(&dummyNode1); BOOST_CHECK(CNode::IsBanned(addr1)); mapArgs.erase("-banscore"); } @@ -95,7 +95,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) dummyNode.nVersion = 1; Misbehaving(dummyNode.GetId(), 100); - SendMessages(&dummyNode, false); + SendMessages(&dummyNode); BOOST_CHECK(CNode::IsBanned(addr)); SetMockTime(nStartTime+60*60); diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp index 0c2ade48d..dad191c68 100644 --- a/src/test/accounting_tests.cpp +++ b/src/test/accounting_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2014 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333333; ae.strOtherAccount = "b"; ae.strComment = ""; - walletdb.WriteAccountingEntry(ae); + pwalletMain->AddAccountingEntry(ae, walletdb); wtx.mapValue["comment"] = "z"; pwalletMain->AddToWallet(wtx, false, &walletdb); @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333336; ae.strOtherAccount = "c"; - walletdb.WriteAccountingEntry(ae); + pwalletMain->AddAccountingEntry(ae, walletdb); GetResults(walletdb, results); @@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333330; ae.strOtherAccount = "d"; ae.nOrderPos = pwalletMain->IncOrderPosNext(); - walletdb.WriteAccountingEntry(ae); + pwalletMain->AddAccountingEntry(ae, walletdb); GetResults(walletdb, results); @@ -121,7 +121,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333334; ae.strOtherAccount = "e"; ae.nOrderPos = -1; - walletdb.WriteAccountingEntry(ae); + pwalletMain->AddAccountingEntry(ae, walletdb); GetResults(walletdb, results); diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index cfcdd9abb..767b653e4 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "addrman.h" @@ -6,11 +6,49 @@ #include #include +#include "hash.h" #include "random.h" using namespace std; -class CAddrManTest : public CAddrMan{}; +class CAddrManTest : public CAddrMan +{ + uint64_t state; + +public: + CAddrManTest() + { + state = 1; + } + + //! Ensure that bucket placement is always the same for testing purposes. + void MakeDeterministic() + { + nKey.SetNull(); + seed_insecure_rand(true); + } + + int RandomInt(int nMax) + { + state = (CHashWriter(SER_GETHASH, 0) << state).GetHash().GetCheapHash(); + return (unsigned int)(state % nMax); + } + + CAddrInfo* Find(const CNetAddr& addr, int* pnId = NULL) + { + return CAddrMan::Find(addr, pnId); + } + + CAddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = NULL) + { + return CAddrMan::Create(addr, addrSource, pnId); + } + + void Delete(int nId) + { + CAddrMan::Delete(nId); + } +}; BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup) @@ -21,7 +59,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple) // Set addrman addr placement to be deterministic. addrman.MakeDeterministic(); - CNetAddr source = CNetAddr("252.2.2.2:8333"); + CNetAddr source = CNetAddr("252.2.2.2"); // Test 1: Does Addrman respond correctly when empty. BOOST_CHECK(addrman.size() == 0); @@ -29,26 +67,26 @@ BOOST_AUTO_TEST_CASE(addrman_simple) BOOST_CHECK(addr_null.ToString() == "[::]:0"); // Test 2: Does Addrman::Add work as expected. - CService addr1 = CService("250.1.1.1:8333"); + CService addr1 = CService("250.1.1.1", 8333); addrman.Add(CAddress(addr1), source); BOOST_CHECK(addrman.size() == 1); CAddrInfo addr_ret1 = addrman.Select(); BOOST_CHECK(addr_ret1.ToString() == "250.1.1.1:8333"); - // Test 3: Does IP address deduplication work correctly. + // Test 3: Does IP address deduplication work correctly. // Expected dup IP should not be added. - CService addr1_dup = CService("250.1.1.1:8333"); + CService addr1_dup = CService("250.1.1.1", 8333); addrman.Add(CAddress(addr1_dup), source); BOOST_CHECK(addrman.size() == 1); // Test 5: New table has one addr and we add a diff addr we should // have two addrs. - CService addr2 = CService("250.1.1.2:8333"); + CService addr2 = CService("250.1.1.2", 8333); addrman.Add(CAddress(addr2), source); BOOST_CHECK(addrman.size() == 2); - // Test 6: AddrMan::Clear() should empty the new table. + // Test 6: AddrMan::Clear() should empty the new table. addrman.Clear(); BOOST_CHECK(addrman.size() == 0); CAddrInfo addr_null2 = addrman.Select(); @@ -62,16 +100,16 @@ BOOST_AUTO_TEST_CASE(addrman_ports) // Set addrman addr placement to be deterministic. addrman.MakeDeterministic(); - CNetAddr source = CNetAddr("252.2.2.2:8333"); + CNetAddr source = CNetAddr("252.2.2.2"); BOOST_CHECK(addrman.size() == 0); // Test 7; Addr with same IP but diff port does not replace existing addr. - CService addr1 = CService("250.1.1.1:8333"); + CService addr1 = CService("250.1.1.1", 8333); addrman.Add(CAddress(addr1), source); BOOST_CHECK(addrman.size() == 1); - CService addr1_port = CService("250.1.1.1:8334"); + CService addr1_port = CService("250.1.1.1", 8334); addrman.Add(CAddress(addr1_port), source); BOOST_CHECK(addrman.size() == 1); CAddrInfo addr_ret2 = addrman.Select(); @@ -94,10 +132,10 @@ BOOST_AUTO_TEST_CASE(addrman_select) // Set addrman addr placement to be deterministic. addrman.MakeDeterministic(); - CNetAddr source = CNetAddr("252.2.2.2:8333"); + CNetAddr source = CNetAddr("252.2.2.2"); // Test 9: Select from new with 1 addr in new. - CService addr1 = CService("250.1.1.1:8333"); + CService addr1 = CService("250.1.1.1", 8333); addrman.Add(CAddress(addr1), source); BOOST_CHECK(addrman.size() == 1); @@ -105,7 +143,6 @@ BOOST_AUTO_TEST_CASE(addrman_select) CAddrInfo addr_ret1 = addrman.Select(newOnly); BOOST_CHECK(addr_ret1.ToString() == "250.1.1.1:8333"); - // Test 10: move addr to tried, select from new expected nothing returned. addrman.Good(CAddress(addr1)); BOOST_CHECK(addrman.size() == 1); @@ -114,6 +151,39 @@ BOOST_AUTO_TEST_CASE(addrman_select) CAddrInfo addr_ret3 = addrman.Select(); BOOST_CHECK(addr_ret3.ToString() == "250.1.1.1:8333"); + + BOOST_CHECK(addrman.size() == 1); + + + // Add three addresses to new table. + CService addr2 = CService("250.3.1.1", 8333); + CService addr3 = CService("250.3.2.2", 9999); + CService addr4 = CService("250.3.3.3", 9999); + + addrman.Add(CAddress(addr2), CService("250.3.1.1", 8333)); + addrman.Add(CAddress(addr3), CService("250.3.1.1", 8333)); + addrman.Add(CAddress(addr4), CService("250.4.1.1", 8333)); + + // Add three addresses to tried table. + CService addr5 = CService("250.4.4.4", 8333); + CService addr6 = CService("250.4.5.5", 7777); + CService addr7 = CService("250.4.6.6", 8333); + + addrman.Add(CAddress(addr5), CService("250.3.1.1", 8333)); + addrman.Good(CAddress(addr5)); + addrman.Add(CAddress(addr6), CService("250.3.1.1", 8333)); + addrman.Good(CAddress(addr6)); + addrman.Add(CAddress(addr7), CService("250.1.1.3", 8333)); + addrman.Good(CAddress(addr7)); + + // Test 11: 6 addrs + 1 addr from last test = 7. + BOOST_CHECK(addrman.size() == 7); + + // Test 12: Select pulls from new and tried regardless of port number. + BOOST_CHECK(addrman.Select().ToString() == "250.4.6.6:8333"); + BOOST_CHECK(addrman.Select().ToString() == "250.3.2.2:9999"); + BOOST_CHECK(addrman.Select().ToString() == "250.3.3.3:9999"); + BOOST_CHECK(addrman.Select().ToString() == "250.4.4.4:8333"); } BOOST_AUTO_TEST_CASE(addrman_new_collisions) @@ -123,26 +193,26 @@ BOOST_AUTO_TEST_CASE(addrman_new_collisions) // Set addrman addr placement to be deterministic. addrman.MakeDeterministic(); - CNetAddr source = CNetAddr("252.2.2.2:8333"); + CNetAddr source = CNetAddr("252.2.2.2"); BOOST_CHECK(addrman.size() == 0); - for (unsigned int i = 1; i < 4; i++){ - CService addr = CService("250.1.1."+boost::to_string(i)); + for (unsigned int i = 1; i < 18; i++) { + CService addr = CService("250.1.1." + boost::to_string(i)); addrman.Add(CAddress(addr), source); - //Test 11: No collision in new table yet. + //Test 13: No collision in new table yet. BOOST_CHECK(addrman.size() == i); } - //Test 12: new table collision! - CService addr1 = CService("250.1.1.4"); + //Test 14: new table collision! + CService addr1 = CService("250.1.1.18"); addrman.Add(CAddress(addr1), source); - BOOST_CHECK(addrman.size() == 3); + BOOST_CHECK(addrman.size() == 17); - CService addr2 = CService("250.1.1.5"); + CService addr2 = CService("250.1.1.19"); addrman.Add(CAddress(addr2), source); - BOOST_CHECK(addrman.size() == 4); + BOOST_CHECK(addrman.size() == 18); } BOOST_AUTO_TEST_CASE(addrman_tried_collisions) @@ -152,29 +222,300 @@ BOOST_AUTO_TEST_CASE(addrman_tried_collisions) // Set addrman addr placement to be deterministic. addrman.MakeDeterministic(); - CNetAddr source = CNetAddr("252.2.2.2:8333"); + CNetAddr source = CNetAddr("252.2.2.2"); BOOST_CHECK(addrman.size() == 0); - for (unsigned int i = 1; i < 75; i++){ - CService addr = CService("250.1.1."+boost::to_string(i)); + for (unsigned int i = 1; i < 80; i++) { + CService addr = CService("250.1.1." + boost::to_string(i)); addrman.Add(CAddress(addr), source); addrman.Good(CAddress(addr)); - //Test 13: No collision in tried table yet. + //Test 15: No collision in tried table yet. BOOST_TEST_MESSAGE(addrman.size()); BOOST_CHECK(addrman.size() == i); } - //Test 14: tried table collision! - CService addr1 = CService("250.1.1.76"); + //Test 16: tried table collision! + CService addr1 = CService("250.1.1.80"); addrman.Add(CAddress(addr1), source); - BOOST_CHECK(addrman.size() == 74); + BOOST_CHECK(addrman.size() == 79); - CService addr2 = CService("250.1.1.77"); + CService addr2 = CService("250.1.1.81"); addrman.Add(CAddress(addr2), source); - BOOST_CHECK(addrman.size() == 75); + BOOST_CHECK(addrman.size() == 80); +} + +BOOST_AUTO_TEST_CASE(addrman_find) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + BOOST_CHECK(addrman.size() == 0); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CAddress addr2 = CAddress(CService("250.1.2.1", 9999)); + CAddress addr3 = CAddress(CService("251.255.2.1", 8333)); + + CNetAddr source1 = CNetAddr("250.1.2.1"); + CNetAddr source2 = CNetAddr("250.1.2.2"); + + addrman.Add(addr1, source1); + addrman.Add(addr2, source2); + addrman.Add(addr3, source1); + + // Test 17: ensure Find returns an IP matching what we searched on. + CAddrInfo* info1 = addrman.Find(addr1); + BOOST_CHECK(info1); + if (info1) + BOOST_CHECK(info1->ToString() == "250.1.2.1:8333"); + + // Test 18; Find does not discriminate by port number. + CAddrInfo* info2 = addrman.Find(addr2); + BOOST_CHECK(info2); + if (info2) + BOOST_CHECK(info2->ToString() == info1->ToString()); + + // Test 19: Find returns another IP matching what we searched on. + CAddrInfo* info3 = addrman.Find(addr3); + BOOST_CHECK(info3); + if (info3) + BOOST_CHECK(info3->ToString() == "251.255.2.1:8333"); +} + +BOOST_AUTO_TEST_CASE(addrman_create) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + BOOST_CHECK(addrman.size() == 0); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CNetAddr source1 = CNetAddr("250.1.2.1"); + + int nId; + CAddrInfo* pinfo = addrman.Create(addr1, source1, &nId); + + // Test 20: The result should be the same as the input addr. + BOOST_CHECK(pinfo->ToString() == "250.1.2.1:8333"); + + CAddrInfo* info2 = addrman.Find(addr1); + BOOST_CHECK(info2->ToString() == "250.1.2.1:8333"); } +BOOST_AUTO_TEST_CASE(addrman_delete) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + BOOST_CHECK(addrman.size() == 0); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CNetAddr source1 = CNetAddr("250.1.2.1"); + + int nId; + addrman.Create(addr1, source1, &nId); + + // Test 21: Delete should actually delete the addr. + BOOST_CHECK(addrman.size() == 1); + addrman.Delete(nId); + BOOST_CHECK(addrman.size() == 0); + CAddrInfo* info2 = addrman.Find(addr1); + BOOST_CHECK(info2 == NULL); +} + +BOOST_AUTO_TEST_CASE(addrman_getaddr) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + // Test 22: Sanity check, GetAddr should never return anything if addrman + // is empty. + BOOST_CHECK(addrman.size() == 0); + vector vAddr1 = addrman.GetAddr(); + BOOST_CHECK(vAddr1.size() == 0); + + CAddress addr1 = CAddress(CService("250.250.2.1", 8333)); + addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false + CAddress addr2 = CAddress(CService("250.251.2.2", 9999)); + addr2.nTime = GetAdjustedTime(); + CAddress addr3 = CAddress(CService("251.252.2.3", 8333)); + addr3.nTime = GetAdjustedTime(); + CAddress addr4 = CAddress(CService("252.253.3.4", 8333)); + addr4.nTime = GetAdjustedTime(); + CAddress addr5 = CAddress(CService("252.254.4.5", 8333)); + addr5.nTime = GetAdjustedTime(); + CNetAddr source1 = CNetAddr("250.1.2.1"); + CNetAddr source2 = CNetAddr("250.2.3.3"); + + // Test 23: Ensure GetAddr works with new addresses. + addrman.Add(addr1, source1); + addrman.Add(addr2, source2); + addrman.Add(addr3, source1); + addrman.Add(addr4, source2); + addrman.Add(addr5, source1); + + // GetAddr returns 23% of addresses, 23% of 5 is 1 rounded down. + BOOST_CHECK(addrman.GetAddr().size() == 1); + + // Test 24: Ensure GetAddr works with new and tried addresses. + addrman.Good(CAddress(addr1)); + addrman.Good(CAddress(addr2)); + BOOST_CHECK(addrman.GetAddr().size() == 1); + + // Test 25: Ensure GetAddr still returns 23% when addrman has many addrs. + for (unsigned int i = 1; i < (8 * 256); i++) { + int octet1 = i % 256; + int octet2 = (i / 256) % 256; + int octet3 = (i / (256 * 2)) % 256; + string strAddr = boost::to_string(octet1) + "." + boost::to_string(octet2) + "." + boost::to_string(octet3) + ".23"; + CAddress addr = CAddress(CService(strAddr)); + + // Ensure that for all addrs in addrman, isTerrible == false. + addr.nTime = GetAdjustedTime(); + addrman.Add(addr, CNetAddr(strAddr)); + if (i % 8 == 0) + addrman.Good(addr); + } + vector vAddr = addrman.GetAddr(); + + size_t percent23 = (addrman.size() * 23) / 100; + BOOST_CHECK(vAddr.size() == percent23); + BOOST_CHECK(vAddr.size() == 461); + // (Addrman.size() < number of addresses added) due to address collisons. + BOOST_CHECK(addrman.size() == 2007); +} + + +BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CAddress addr1 = CAddress(CService("250.1.1.1", 8333)); + CAddress addr2 = CAddress(CService("250.1.1.1", 9999)); + + CNetAddr source1 = CNetAddr("250.1.1.1"); + + + CAddrInfo info1 = CAddrInfo(addr1, source1); + + uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); + uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); + + + BOOST_CHECK(info1.GetTriedBucket(nKey1) == 40); + + // Test 26: Make sure key actually randomizes bucket placement. A fail on + // this test could be a security issue. + BOOST_CHECK(info1.GetTriedBucket(nKey1) != info1.GetTriedBucket(nKey2)); + + // Test 27: Two addresses with same IP but different ports can map to + // different buckets because they have different keys. + CAddrInfo info2 = CAddrInfo(addr2, source1); + + BOOST_CHECK(info1.GetKey() != info2.GetKey()); + BOOST_CHECK(info1.GetTriedBucket(nKey1) != info2.GetTriedBucket(nKey1)); + + set buckets; + for (int i = 0; i < 255; i++) { + CAddrInfo infoi = CAddrInfo( + CAddress(CService("250.1.1." + boost::to_string(i))), + CNetAddr("250.1.1." + boost::to_string(i))); + int bucket = infoi.GetTriedBucket(nKey1); + buckets.insert(bucket); + } + // Test 28: IP addresses in the same group (\16 prefix for IPv4) should + // never get more than 8 buckets + BOOST_CHECK(buckets.size() == 8); + + buckets.clear(); + for (int j = 0; j < 255; j++) { + CAddrInfo infoj = CAddrInfo( + CAddress(CService("250." + boost::to_string(j) + ".1.1")), + CNetAddr("250." + boost::to_string(j) + ".1.1")); + int bucket = infoj.GetTriedBucket(nKey1); + buckets.insert(bucket); + } + // Test 29: IP addresses in the different groups should map to more than + // 8 buckets. + BOOST_CHECK(buckets.size() == 160); +} + +BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CAddress addr2 = CAddress(CService("250.1.2.1", 9999)); + + CNetAddr source1 = CNetAddr("250.1.2.1"); + + CAddrInfo info1 = CAddrInfo(addr1, source1); + + uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); + uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); + + BOOST_CHECK(info1.GetNewBucket(nKey1) == 786); + + // Test 30: Make sure key actually randomizes bucket placement. A fail on + // this test could be a security issue. + BOOST_CHECK(info1.GetNewBucket(nKey1) != info1.GetNewBucket(nKey2)); + + // Test 31: Ports should not effect bucket placement in the addr + CAddrInfo info2 = CAddrInfo(addr2, source1); + BOOST_CHECK(info1.GetKey() != info2.GetKey()); + BOOST_CHECK(info1.GetNewBucket(nKey1) == info2.GetNewBucket(nKey1)); + + set buckets; + for (int i = 0; i < 255; i++) { + CAddrInfo infoi = CAddrInfo( + CAddress(CService("250.1.1." + boost::to_string(i))), + CNetAddr("250.1.1." + boost::to_string(i))); + int bucket = infoi.GetNewBucket(nKey1); + buckets.insert(bucket); + } + // Test 32: IP addresses in the same group (\16 prefix for IPv4) should + // always map to the same bucket. + BOOST_CHECK(buckets.size() == 1); + + buckets.clear(); + for (int j = 0; j < 4 * 255; j++) { + CAddrInfo infoj = CAddrInfo(CAddress( + CService( + boost::to_string(250 + (j / 255)) + "." + boost::to_string(j % 256) + ".1.1")), + CNetAddr("251.4.1.1")); + int bucket = infoj.GetNewBucket(nKey1); + buckets.insert(bucket); + } + // Test 33: IP addresses in the same source groups should map to no more + // than 64 buckets. + BOOST_CHECK(buckets.size() <= 64); + + buckets.clear(); + for (int p = 0; p < 255; p++) { + CAddrInfo infoj = CAddrInfo( + CAddress(CService("250.1.1.1")), + CNetAddr("250." + boost::to_string(p) + ".1.1")); + int bucket = infoj.GetNewBucket(nKey1); + buckets.insert(bucket); + } + // Test 34: IP addresses in the different source groups should map to more + // than 64 buckets. + BOOST_CHECK(buckets.size() > 64); +} BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index cc82f7cab..ebabc2a85 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -1,273 +1,19 @@ -// Copyright (c) 2013 The Bitcoin Core developers +// Copyright (c) 2013-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // Unit tests for alert system -#include "alert.h" -#include "chain.h" #include "chainparams.h" -#include "clientversion.h" -#include "data/alertTests.raw.h" #include "main.h" // For PartitionCheck -#include "serialize.h" -#include "streams.h" -#include "util.h" -#include "utilstrencodings.h" -#include "key.h" +#include "test/testutil.h" #include "test/test_bitcoin.h" -#include - -#include -#include #include -bool SignAlert(CAlert &alert) -{ - CKey key; - std::vector vchkey = ParseHex("hex output of HexStr(CKey.GetPrivKey)"); - CPrivKey privKey(vchkey.begin(), vchkey.end()); - key.SetPrivKey(privKey, false); +BOOST_FIXTURE_TEST_SUITE(Alert_tests, TestingSetup) - CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION); - sMsg << *(CUnsignedAlert*)&alert; - alert.vchMsg = std::vector(sMsg.begin(), sMsg.end()); - - if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig)) - { - LogPrintf("Sign Alert() : key.Sign failed\n"); - return false; - } - return true; -} - -bool SignAndSave(CAlert &alert, CDataStream &buffer) -{ - if (!SignAlert(alert)) - { - LogPrintf("SignAndSave() : could not sign alert\n"); - return false; - } - buffer << alert; - return true; -} - -template -std::string HexStrArray(const T itbegin, const T itend) -{ - std::string rv; - static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - rv.reserve((itend-itbegin)*3); - int i = 0; - for(T it = itbegin; it < itend; ++it) - { - unsigned char val = (unsigned char)(*it); - if(it != itbegin) - { - if (i % 8 == 0) - rv.push_back('\n'); - else - rv.push_back(' '); - } - rv.push_back('0'); - rv.push_back('x'); - rv.push_back(hexmap[val>>4]); - rv.push_back(hexmap[val&15]); - rv.push_back(','); - i++; - } - - return rv; -} - -template -inline std::string HexStrArray(const T& vch) -{ - return HexStrArray(vch.begin(), vch.end()); -} - - -// alertTests contains 7 alerts, generated with this code: -// (SignAndSave code not shown, alert signing key is secret) -// -void GenerateAlertTests() -{ - CDataStream sBuffer(SER_DISK, CLIENT_VERSION); - - CAlert alert; - alert.nRelayUntil = 60; - alert.nExpiration = 24 * 60 * 60; - alert.nID = 1; - alert.nCancel = 0; // cancels previous messages up to this ID number - alert.nMinVer = 0; // These versions are protocol versions - alert.nMaxVer = 999001; - alert.nPriority = 1; - alert.strComment = "Alert comment"; - alert.strStatusBar = "Alert 1"; - - SignAndSave(alert, sBuffer); - - alert.setSubVer.insert(std::string("/Satoshi:0.1.0/")); - alert.strStatusBar = "Alert 1 for Satoshi 0.1.0"; - SignAndSave(alert, sBuffer); - - alert.setSubVer.insert(std::string("/Satoshi:0.2.0/")); - alert.strStatusBar = "Alert 1 for Satoshi 0.1.0, 0.2.0"; - SignAndSave(alert, sBuffer); - - alert.setSubVer.clear(); - ++alert.nID; - alert.nCancel = 1; - alert.nPriority = 100; - alert.strStatusBar = "Alert 2, cancels 1"; - SignAndSave(alert, sBuffer); - - alert.nExpiration += 60; - ++alert.nID; - SignAndSave(alert, sBuffer); - - ++alert.nID; - alert.nMinVer = 11; - alert.nMaxVer = 22; - SignAndSave(alert, sBuffer); - - ++alert.nID; - alert.strStatusBar = "Alert 2 for Satoshi 0.1.0"; - alert.setSubVer.insert(std::string("/Satoshi:0.1.0/")); - SignAndSave(alert, sBuffer); - - ++alert.nID; - alert.nMinVer = 0; - alert.nMaxVer = 999999; - alert.strStatusBar = "Evil Alert'; /bin/ls; echo '"; - alert.setSubVer.clear(); - SignAndSave(alert, sBuffer); - - std::vector vch = std::vector(sBuffer.begin(), sBuffer.end()); - - std::ofstream f; - f.open("alertTest.raw"); - for (std::vector::iterator itvch = vch.begin(); itvch != vch.end(); ++itvch) - { - f << *itvch; - } - f.close(); -} - -struct ReadAlerts : public TestingSetup -{ - ReadAlerts() - { - std::vector vch(alert_tests::alertTests, alert_tests::alertTests + sizeof(alert_tests::alertTests)); - CDataStream stream(vch, SER_DISK, CLIENT_VERSION); - try { - while (!stream.eof()) - { - CAlert alert; - stream >> alert; - alerts.push_back(alert); - } - } - catch (const std::exception&) { } - } - ~ReadAlerts() { } - - static std::vector read_lines(boost::filesystem::path filepath) - { - std::vector result; - - std::ifstream f(filepath.string().c_str()); - std::string line; - while (std::getline(f,line)) - result.push_back(line); - - return result; - } - - std::vector alerts; -}; - -BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts) - - -BOOST_AUTO_TEST_CASE(AlertApplies) -{ - SetMockTime(11); - const std::vector& alertKey = Params(CBaseChainParams::MAIN).AlertKey(); - - BOOST_FOREACH(const CAlert& alert, alerts) - { - BOOST_CHECK(alert.CheckSignature(alertKey)); - } - - BOOST_CHECK(alerts.size() >= 3); - - // Matches: - BOOST_CHECK(alerts[0].AppliesTo(1, "")); - BOOST_CHECK(alerts[0].AppliesTo(999001, "")); - BOOST_CHECK(alerts[0].AppliesTo(1, "/Satoshi:11.11.11/")); - - BOOST_CHECK(alerts[1].AppliesTo(1, "/Satoshi:0.1.0/")); - BOOST_CHECK(alerts[1].AppliesTo(999001, "/Satoshi:0.1.0/")); - - BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.1.0/")); - BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.2.0/")); - - // Don't match: - BOOST_CHECK(!alerts[0].AppliesTo(-1, "")); - BOOST_CHECK(!alerts[0].AppliesTo(999002, "")); - - BOOST_CHECK(!alerts[1].AppliesTo(1, "")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.1.0")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0/")); - BOOST_CHECK(!alerts[1].AppliesTo(-1, "/Satoshi:0.1.0/")); - BOOST_CHECK(!alerts[1].AppliesTo(999002, "/Satoshi:0.1.0/")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.2.0/")); - - BOOST_CHECK(!alerts[2].AppliesTo(1, "/Satoshi:0.3.0/")); - - SetMockTime(0); -} - - -BOOST_AUTO_TEST_CASE(AlertNotify) -{ - SetMockTime(11); - const std::vector& alertKey = Params(CBaseChainParams::MAIN).AlertKey(); - - boost::filesystem::path temp = GetTempPath() / - boost::filesystem::unique_path("alertnotify-%%%%.txt"); - - mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string(); - - BOOST_FOREACH(CAlert alert, alerts) - alert.ProcessAlert(alertKey, false); - - std::vector r = read_lines(temp); - BOOST_CHECK_EQUAL(r.size(), 4u); - -// Windows built-in echo semantics are different than posixy shells. Quotes and -// whitespace are printed literally. - -#ifndef WIN32 - BOOST_CHECK_EQUAL(r[0], "Alert 1"); - BOOST_CHECK_EQUAL(r[1], "Alert 2, cancels 1"); - BOOST_CHECK_EQUAL(r[2], "Alert 2, cancels 1"); - BOOST_CHECK_EQUAL(r[3], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed -#else - BOOST_CHECK_EQUAL(r[0], "'Alert 1' "); - BOOST_CHECK_EQUAL(r[1], "'Alert 2, cancels 1' "); - BOOST_CHECK_EQUAL(r[2], "'Alert 2, cancels 1' "); - BOOST_CHECK_EQUAL(r[3], "'Evil Alert; /bin/ls; echo ' "); -#endif - boost::filesystem::remove(temp); - - SetMockTime(0); -} static bool falseFunc() { return false; } @@ -294,10 +40,12 @@ BOOST_AUTO_TEST_CASE(PartitionAlert) // use them } + strMiscWarning = ""; + // Test 1: chain with blocks every nPowTargetSpacing seconds, // as normal, no worries: PartitionCheck(falseFunc, csDummy, &indexDummy[1999], nPowTargetSpacing); - BOOST_CHECK(strMiscWarning.empty()); + BOOST_CHECK_MESSAGE(strMiscWarning.empty(), strMiscWarning); // Test 2: go 3.5 hours without a block, expect a warning: now += 3*60*60+30*60; diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp index 2108efece..613f6c12d 100644 --- a/src/test/allocator_tests.cpp +++ b/src/test/allocator_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp new file mode 100644 index 000000000..fd6f88b36 --- /dev/null +++ b/src/test/amount_tests.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "amount.h" +#include "test/test_bitcoin.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(amount_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(GetFeeTest) +{ + CFeeRate feeRate; + + feeRate = CFeeRate(0); + // Must always return 0 + BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0); + BOOST_CHECK_EQUAL(feeRate.GetFee(1e5), 0); + + feeRate = CFeeRate(1000); + // Must always just return the arg + BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0); + BOOST_CHECK_EQUAL(feeRate.GetFee(1), 1); + BOOST_CHECK_EQUAL(feeRate.GetFee(121), 121); + BOOST_CHECK_EQUAL(feeRate.GetFee(999), 999); + BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 1e3); + BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 9e3); + + feeRate = CFeeRate(-1000); + // Must always just return -1 * arg + BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0); + BOOST_CHECK_EQUAL(feeRate.GetFee(1), -1); + BOOST_CHECK_EQUAL(feeRate.GetFee(121), -121); + BOOST_CHECK_EQUAL(feeRate.GetFee(999), -999); + BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), -1e3); + BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), -9e3); + + feeRate = CFeeRate(123); + // Truncates the result, if not integer + BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0); + BOOST_CHECK_EQUAL(feeRate.GetFee(8), 1); // Special case: returns 1 instead of 0 + BOOST_CHECK_EQUAL(feeRate.GetFee(9), 1); + BOOST_CHECK_EQUAL(feeRate.GetFee(121), 14); + BOOST_CHECK_EQUAL(feeRate.GetFee(122), 15); + BOOST_CHECK_EQUAL(feeRate.GetFee(999), 122); + BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 123); + BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 1107); + + feeRate = CFeeRate(-123); + // Truncates the result, if not integer + BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0); + BOOST_CHECK_EQUAL(feeRate.GetFee(8), -1); // Special case: returns -1 instead of 0 + BOOST_CHECK_EQUAL(feeRate.GetFee(9), -1); + + // Check full constructor + // default value + BOOST_CHECK(CFeeRate(CAmount(-1), 1000) == CFeeRate(-1)); + BOOST_CHECK(CFeeRate(CAmount(0), 1000) == CFeeRate(0)); + BOOST_CHECK(CFeeRate(CAmount(1), 1000) == CFeeRate(1)); + // lost precision (can only resolve satoshis per kB) + BOOST_CHECK(CFeeRate(CAmount(1), 1001) == CFeeRate(0)); + BOOST_CHECK(CFeeRate(CAmount(2), 1001) == CFeeRate(1)); + // some more integer checks + BOOST_CHECK(CFeeRate(CAmount(26), 789) == CFeeRate(32)); + BOOST_CHECK(CFeeRate(CAmount(27), 789) == CFeeRate(34)); + // Maximum size in bytes, should not crash + CFeeRate(MAX_MONEY, std::numeric_limits::max() >> 1).GetFeePerK(); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp index 17d6bed6d..53ab7e95e 100644 --- a/src/test/arith_uint256_tests.cpp +++ b/src/test/arith_uint256_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp index 8ec886142..6422b3a88 100644 --- a/src/test/base32_tests.cpp +++ b/src/test/base32_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 9845df697..e5a2e28b2 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp index 54c081b0e..ccad94d94 100644 --- a/src/test/base64_tests.cpp +++ b/src/test/base64_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/bctest.py b/src/test/bctest.py index 3a8d0ea51..8105b87ff 100644 --- a/src/test/bctest.py +++ b/src/test/bctest.py @@ -1,7 +1,7 @@ # Copyright 2014 BitPay, Inc. # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. - +from __future__ import division,print_function,unicode_literals import subprocess import os import json diff --git a/src/test/bignum.h b/src/test/bignum.h deleted file mode 100644 index e7aeee9db..000000000 --- a/src/test/bignum.h +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_TEST_BIGNUM_H -#define BITCOIN_TEST_BIGNUM_H - -#include -#include -#include -#include -#include -#include - -#include - -class bignum_error : public std::runtime_error -{ -public: - explicit bignum_error(const std::string& str) : std::runtime_error(str) {} -}; - - -/** C++ wrapper for BIGNUM (OpenSSL bignum) */ -class CBigNum : public BIGNUM -{ -public: - CBigNum() - { - BN_init(this); - } - - CBigNum(const CBigNum& b) - { - BN_init(this); - if (!BN_copy(this, &b)) - { - BN_clear_free(this); - throw bignum_error("CBigNum::CBigNum(const CBigNum&): BN_copy failed"); - } - } - - CBigNum& operator=(const CBigNum& b) - { - if (!BN_copy(this, &b)) - throw bignum_error("CBigNum::operator=: BN_copy failed"); - return (*this); - } - - ~CBigNum() - { - BN_clear_free(this); - } - - CBigNum(long long n) { BN_init(this); setint64(n); } - - explicit CBigNum(const std::vector& vch) - { - BN_init(this); - setvch(vch); - } - - int getint() const - { - BN_ULONG n = BN_get_word(this); - if (!BN_is_negative(this)) - return (n > (BN_ULONG)std::numeric_limits::max() ? std::numeric_limits::max() : n); - else - return (n > (BN_ULONG)std::numeric_limits::max() ? std::numeric_limits::min() : -(int)n); - } - - void setint64(int64_t sn) - { - unsigned char pch[sizeof(sn) + 6]; - unsigned char* p = pch + 4; - bool fNegative; - uint64_t n; - - if (sn < (int64_t)0) - { - // Since the minimum signed integer cannot be represented as positive so long as its type is signed, - // and it's not well-defined what happens if you make it unsigned before negating it, - // we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate - n = -(sn + 1); - ++n; - fNegative = true; - } else { - n = sn; - fNegative = false; - } - - bool fLeadingZeroes = true; - for (int i = 0; i < 8; i++) - { - unsigned char c = (n >> 56) & 0xff; - n <<= 8; - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = (fNegative ? 0x80 : 0); - else if (fNegative) - c |= 0x80; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize) & 0xff; - BN_mpi2bn(pch, p - pch, this); - } - - void setvch(const std::vector& vch) - { - std::vector vch2(vch.size() + 4); - unsigned int nSize = vch.size(); - // BIGNUM's byte stream format expects 4 bytes of - // big endian size data info at the front - vch2[0] = (nSize >> 24) & 0xff; - vch2[1] = (nSize >> 16) & 0xff; - vch2[2] = (nSize >> 8) & 0xff; - vch2[3] = (nSize >> 0) & 0xff; - // swap data to big endian - reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); - BN_mpi2bn(&vch2[0], vch2.size(), this); - } - - std::vector getvch() const - { - unsigned int nSize = BN_bn2mpi(this, NULL); - if (nSize <= 4) - return std::vector(); - std::vector vch(nSize); - BN_bn2mpi(this, &vch[0]); - vch.erase(vch.begin(), vch.begin() + 4); - reverse(vch.begin(), vch.end()); - return vch; - } - - friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); -}; - - - -inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) -{ - CBigNum r; - if (!BN_add(&r, &a, &b)) - throw bignum_error("CBigNum::operator+: BN_add failed"); - return r; -} - -inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) -{ - CBigNum r; - if (!BN_sub(&r, &a, &b)) - throw bignum_error("CBigNum::operator-: BN_sub failed"); - return r; -} - -inline const CBigNum operator-(const CBigNum& a) -{ - CBigNum r(a); - BN_set_negative(&r, !BN_is_negative(&r)); - return r; -} - -inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) == 0); } -inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) != 0); } -inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) <= 0); } -inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) >= 0); } -inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) < 0); } -inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); } - -#endif // BITCOIN_TEST_BIGNUM_H diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index d9c7c96c2..013e07be6 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Bitcoin Core developers +// Copyright (c) 2013-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -117,6 +117,22 @@ void RunTest(const TestVector &test) { } key = keyNew; pubkey = pubkeyNew; + + CDataStream ssPub(SER_DISK, CLIENT_VERSION); + ssPub << pubkeyNew; + BOOST_CHECK(ssPub.size() == 75); + + CDataStream ssPriv(SER_DISK, CLIENT_VERSION); + ssPriv << keyNew; + BOOST_CHECK(ssPriv.size() == 75); + + CExtPubKey pubCheck; + CExtKey privCheck; + ssPub >> pubCheck; + ssPriv >> privCheck; + + BOOST_CHECK(pubCheck == pubkeyNew); + BOOST_CHECK(privCheck == keyNew); } } diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py index 20afb16a9..95dd3e81b 100755 --- a/src/test/bitcoin-util-test.py +++ b/src/test/bitcoin-util-test.py @@ -2,7 +2,7 @@ # Copyright 2014 BitPay, Inc. # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. - +from __future__ import division,print_function,unicode_literals import os import bctest import buildenv diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 958ea36e5..d7bfb6519 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -205,7 +205,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_1) BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 8); vector vMatched; - BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + vector vIndex; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); @@ -222,7 +223,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_1) BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 7); - BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); @@ -250,7 +251,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_2) BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); vector vMatched; - BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + vector vIndex; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); @@ -276,7 +278,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2) BOOST_CHECK(merkleBlock.vMatchedTxn[3].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23")); BOOST_CHECK(merkleBlock.vMatchedTxn[3].first == 3); - BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); @@ -304,7 +306,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none) BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); vector vMatched; - BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + vector vIndex; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); @@ -327,7 +330,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none) BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23")); BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 3); - BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); @@ -354,7 +357,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize) BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); vector vMatched; - BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + vector vIndex; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); @@ -393,7 +397,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_4) BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 6); vector vMatched; - BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + vector vIndex; + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); @@ -410,7 +415,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_4) BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair); - BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot); + BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp deleted file mode 100644 index f7e247061..000000000 --- a/src/test/checkblock_tests.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2013-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "clientversion.h" -#include "consensus/validation.h" -#include "main.h" // For CheckBlock -#include "primitives/block.h" -#include "test/test_bitcoin.h" -#include "utiltime.h" - -#include - -#include -#include -#include - - -BOOST_FIXTURE_TEST_SUITE(CheckBlock_tests, BasicTestingSetup) - -bool read_block(const std::string& filename, CBlock& block) -{ - namespace fs = boost::filesystem; - fs::path testFile = fs::current_path() / "data" / filename; -#ifdef TEST_DATA_DIR - if (!fs::exists(testFile)) - { - testFile = fs::path(BOOST_PP_STRINGIZE(TEST_DATA_DIR)) / filename; - } -#endif - FILE* fp = fopen(testFile.string().c_str(), "rb"); - if (!fp) return false; - - fseek(fp, 8, SEEK_SET); // skip msgheader/size - - CAutoFile filein(fp, SER_DISK, CLIENT_VERSION); - if (filein.IsNull()) return false; - - filein >> block; - - return true; -} - -BOOST_AUTO_TEST_CASE(May15) -{ - // Putting a 1MB binary file in the git repository is not a great - // idea, so this test is only run if you manually download - // test/data/Mar12Fork.dat from - // http://sourceforge.net/projects/bitcoin/files/Bitcoin/blockchain/Mar12Fork.dat/download - unsigned int tMay15 = 1368576000; - SetMockTime(tMay15); // Test as if it was right at May 15 - - CBlock forkingBlock; - if (read_block("Mar12Fork.dat", forkingBlock)) - { - CValidationState state; - - // After May 15'th, big blocks are OK: - forkingBlock.nTime = tMay15; // Invalidates PoW - BOOST_CHECK(CheckBlock(forkingBlock, state, false, false)); - } - - SetMockTime(0); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/claimtrie_tests.cpp b/src/test/claimtrie_tests.cpp index 31274abe3..3764b1b9d 100644 --- a/src/test/claimtrie_tests.cpp +++ b/src/test/claimtrie_tests.cpp @@ -4,6 +4,7 @@ #include "main.h" #include "consensus/validation.h" +#include "consensus/merkle.h" #include "primitives/transaction.h" #include "miner.h" #include "txmempool.h" @@ -12,6 +13,7 @@ #include "coins.h" #include "streams.h" #include "chainparams.h" +#include "policy/policy.h" #include #include #include "test/test_bitcoin.h" @@ -72,7 +74,24 @@ CMutableTransaction BuildTransaction(const CTransaction& prev, uint32_t prevout= void AddToMempool(CMutableTransaction& tx) { - mempool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(tx, 0, GetTime(), 111.0, chainActive.Height())); + //CCoinsView dummy; + //CCoinsViewCache view(&dummy); + //CAmount inChainInputValue; + //double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue); + //unsigned int nSigOps = GetLegacySigOpCount(tx); + //nSigOps += GetP2SHSigOpCount(tx, view); + //LockPoints lp; + //BOOST_CHECK(CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)); + //mempool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(tx, 0, GetTime(), 111.1, chainActive.Height(), mempool.HasNoInputsOf(tx), 10000000000, false, nSigOps, lp)); + CValidationState state; + bool *fMissingInputs; + CFeeRate txFeeRate = CFeeRate(0); + BOOST_CHECK(AcceptToMemoryPool(mempool, state, tx, false, fMissingInputs, &txFeeRate)); + //TestMemPoolEntryHelper entry; + //entry.nFee = 11; + //entry.dPriority = 111.0; + //entry.nHeight = 11; + //mempool.addUnchecked(tx.GetHash(), entry.Fee(10000).Time(GetTime()).FromTx(tx)); } bool CreateBlock(CBlockTemplate* pblocktemplate) @@ -85,7 +104,7 @@ bool CreateBlock(CBlockTemplate* pblocktemplate) txCoinbase.vin[0].scriptSig = CScript() << CScriptNum(unique_block_counter++) << CScriptNum(chainActive.Height()); txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height() + 1, Params().GetConsensus()); pblock->vtx[0] = CTransaction(txCoinbase); - pblock->hashMerkleRoot = pblock->ComputeMerkleRoot(); + pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); for (int i = 0; ; ++i) { pblock->nNonce = i; @@ -95,7 +114,7 @@ bool CreateBlock(CBlockTemplate* pblocktemplate) } } CValidationState state; - bool success = (ProcessNewBlock(state, NULL, pblock, true, NULL) && state.IsValid() && pblock->GetHash() == chainActive.Tip()->GetBlockHash()); + bool success = (ProcessNewBlock(state, Params(), NULL, pblock, true, NULL) && state.IsValid() && pblock->GetHash() == chainActive.Tip()->GetBlockHash()); pblock->hashPrevBlock = pblock->GetHash(); return success; } @@ -106,11 +125,12 @@ bool RemoveBlock(uint256& blockhash) if (mapBlockIndex.count(blockhash) == 0) return false; CBlockIndex* pblockindex = mapBlockIndex[blockhash]; - InvalidateBlock(state, pblockindex); + InvalidateBlock(state, Params().GetConsensus(), pblockindex); if (state.IsValid()) { - ActivateBestChain(state); + ActivateBestChain(state, Params()); } + mempool.clear(); return state.IsValid(); } @@ -119,7 +139,7 @@ bool CreateCoinbases(unsigned int num_coinbases, std::vector& coin { CBlockTemplate *pblocktemplate; coinbases.clear(); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(Params(), scriptPubKey)); BOOST_CHECK(pblocktemplate->block.vtx.size() == 1); pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash(); for (unsigned int i = 0; i < 100 + num_coinbases; ++i) @@ -135,7 +155,7 @@ bool CreateCoinbases(unsigned int num_coinbases, std::vector& coin bool CreateBlocks(unsigned int num_blocks, unsigned int num_txs) { CBlockTemplate *pblocktemplate; - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(Params(), scriptPubKey)); BOOST_CHECK(pblocktemplate->block.vtx.size() == num_txs); pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash(); for (unsigned int i = 0; i < num_blocks; ++i) @@ -148,6 +168,7 @@ bool CreateBlocks(unsigned int num_blocks, unsigned int num_txs) BOOST_AUTO_TEST_CASE(claimtrie_merkle_hash) { + fRequireStandard = false; CClaimValue unused; uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); uint160 hash160; @@ -268,6 +289,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_merkle_hash) BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) { + fRequireStandard = false; BOOST_CHECK(pclaimTrie->nCurrentHeight == chainActive.Height() + 1); LOCK(cs_main); @@ -375,7 +397,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) // Verify claims for controlled names are delayed, and that the bigger claim wins when inserted BOOST_CHECK(CreateBlocks(5, 1)); - + AddToMempool(tx1); BOOST_CHECK(CreateBlocks(1, 2)); @@ -419,7 +441,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) for (pindex = chainActive.Tip(); pindex && pindex->pprev; pindex=pindex->pprev) { CBlock block; - BOOST_CHECK(ReadBlockFromDisk(block, pindex)); + BOOST_CHECK(ReadBlockFromDisk(block, pindex, Params().GetConsensus())); if (pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) { bool fClean = true; @@ -431,7 +453,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) { pindex = chainActive.Next(pindex); CBlock block; - BOOST_CHECK(ReadBlockFromDisk(block, pindex)); + BOOST_CHECK(ReadBlockFromDisk(block, pindex, Params().GetConsensus())); BOOST_CHECK(ConnectBlock(block, state, pindex, coins, trieCache)); } @@ -450,8 +472,8 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); blocks_to_invalidate.pop_back(); BOOST_CHECK(!pclaimTrie->getInfoForName(sName1, val)); - mempool.clear(); + BOOST_CHECK(pclaimTrie->empty()); BOOST_CHECK(pclaimTrie->getMerkleHash() == hash0); BOOST_CHECK(pclaimTrie->queueEmpty()); @@ -489,7 +511,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(pclaimTrie->queueEmpty()); - mempool.clear(); // Go back to the beginning @@ -515,7 +536,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) blocks_to_invalidate.pop_back(); BOOST_CHECK(pclaimTrie->empty()); BOOST_CHECK(pclaimTrie->queueEmpty()); - mempool.clear(); // Verify that if a claim in the queue is spent, it does not get into the trie @@ -565,8 +585,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); blocks_to_invalidate.pop_back(); - mempool.clear(); - BOOST_CHECK(CreateBlocks(1, 1)); BOOST_CHECK(!pclaimTrie->empty()); @@ -606,7 +624,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) BOOST_CHECK(pclaimTrie->getInfoForName(sName2, val)); BOOST_CHECK(val.outPoint == tx5OutPoint); BOOST_CHECK(pclaimTrie->haveClaim(sName2, tx2OutPoint)); - mempool.clear(); // roll back to the beginning @@ -614,7 +631,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) blocks_to_invalidate.pop_back(); BOOST_CHECK(pclaimTrie->empty()); BOOST_CHECK(pclaimTrie->queueEmpty()); - mempool.clear(); // Test undoing a spent update which updated a claim still in the queue @@ -672,7 +688,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) blocks_to_invalidate.pop_back(); BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(!pclaimTrie->queueEmpty()); - mempool.clear(); // make sure the update (tx3) still goes into effect when it's supposed to @@ -696,7 +711,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) blocks_to_invalidate.pop_back(); BOOST_CHECK(pclaimTrie->empty()); BOOST_CHECK(pclaimTrie->queueEmpty()); - mempool.clear(); // Test undoing an spent update which updated the best claim to a name @@ -826,8 +840,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); blocks_to_invalidate.pop_back(); - mempool.clear(); - // put it back in AddToMempool(tx10); @@ -898,8 +910,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); blocks_to_invalidate.pop_back(); - mempool.clear(); - // Put tx10 and tx11 in without tx1 in AddToMempool(tx10); @@ -924,7 +934,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); blocks_to_invalidate.pop_back(); - mempool.clear(); // spent tx10 with tx12 instead which is not a claim operation of any kind @@ -939,8 +948,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); blocks_to_invalidate.pop_back(); - mempool.clear(); - // make sure all claim for names which exist in the trie but have no // values get inserted immediately @@ -963,11 +970,11 @@ BOOST_AUTO_TEST_CASE(claimtrie_insert_update_claim) BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); blocks_to_invalidate.pop_back(); - mempool.clear(); } BOOST_AUTO_TEST_CASE(claimtrie_claim_expiration) { + fRequireStandard = false; BOOST_CHECK(pclaimTrie->nCurrentHeight == chainActive.Height() + 1); LOCK(cs_main); @@ -1089,8 +1096,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_claim_expiration) BOOST_CHECK(pclaimTrie->queueEmpty()); BOOST_CHECK(!pclaimTrie->expirationQueueEmpty()); - mempool.clear(); - // advance until the expiration event occurs. verify the event occurs on time. BOOST_CHECK(CreateBlocks(100, 1)); @@ -1125,8 +1130,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_claim_expiration) BOOST_CHECK(pclaimTrie->queueEmpty()); BOOST_CHECK(pclaimTrie->expirationQueueEmpty()); - mempool.clear(); - // roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again. BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); @@ -1266,6 +1269,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_claim_expiration) BOOST_AUTO_TEST_CASE(claimtrie_supporting_claims) { + fRequireStandard = false; BOOST_CHECK(pclaimTrie->nCurrentHeight == chainActive.Height() + 1); LOCK(cs_main); @@ -1390,6 +1394,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_supporting_claims) // spend tx3 + AddToMempool(tx6); BOOST_CHECK(CreateBlocks(1, 2)); @@ -1580,8 +1585,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_supporting_claims) BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); blocks_to_invalidate.pop_back(); - mempool.clear(); - BOOST_CHECK(!pclaimTrie->supportEmpty()); BOOST_CHECK(pclaimTrie->supportQueueEmpty()); BOOST_CHECK(pclaimTrie->getInfoForName(sName, val)); @@ -1617,6 +1620,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_supporting_claims) BOOST_AUTO_TEST_CASE(claimtrie_supporting_claims2) { + fRequireStandard = false; BOOST_CHECK(pclaimTrie->nCurrentHeight == chainActive.Height() + 1); LOCK(cs_main); @@ -2093,6 +2097,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_supporting_claims2) BOOST_AUTO_TEST_CASE(claimtrie_expiring_supports) { + fRequireStandard = false; BOOST_CHECK(pclaimTrie->nCurrentHeight = chainActive.Height() + 1); LOCK(cs_main); @@ -2333,6 +2338,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_expiring_supports) BOOST_AUTO_TEST_CASE(claimtrienode_serialize_unserialize) { + fRequireStandard = false; CDataStream ss(SER_DISK, 0); uint160 hash160; @@ -2480,6 +2486,7 @@ bool verify_proof(const CClaimTrieProof proof, uint256 rootHash, const std::stri BOOST_AUTO_TEST_CASE(claimtrievalue_proof) { + fRequireStandard = false; BOOST_CHECK(pclaimTrie->nCurrentHeight == chainActive.Height() + 1); LOCK(cs_main); diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 13d848311..48e3c8ed8 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014 The Bitcoin Core developers +// Copyright (c) 2014-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -6,6 +6,8 @@ #include "random.h" #include "uint256.h" #include "test/test_bitcoin.h" +#include "main.h" +#include "consensus/validation.h" #include #include @@ -45,19 +47,20 @@ public: bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock) { for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) { - map_[it->first] = it->second.coins; - if (it->second.coins.IsPruned() && insecure_rand() % 3 == 0) { - // Randomly delete empty entries on write. - map_.erase(it->first); + if (it->second.flags & CCoinsCacheEntry::DIRTY) { + // Same optimization used in CCoinsViewDB is to only write dirty entries. + map_[it->first] = it->second.coins; + if (it->second.coins.IsPruned() && insecure_rand() % 3 == 0) { + // Randomly delete empty entries on write. + map_.erase(it->first); + } } mapCoins.erase(it++); } - mapCoins.clear(); - hashBestBlock_ = hashBlock; + if (!hashBlock.IsNull()) + hashBestBlock_ = hashBlock; return true; } - - bool GetStats(CCoinsStats& stats) const { return false; } }; class CCoinsViewCacheTest : public CCoinsViewCache @@ -159,14 +162,23 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) } } + if (insecure_rand() % 100 == 0) { + // Every 100 iterations, flush an intermediate cache + if (stack.size() > 1 && insecure_rand() % 2 == 0) { + unsigned int flushIndex = insecure_rand() % (stack.size() - 1); + stack[flushIndex]->Flush(); + } + } if (insecure_rand() % 100 == 0) { // Every 100 iterations, change the cache stack. if (stack.size() > 0 && insecure_rand() % 2 == 0) { + //Remove the top cache stack.back()->Flush(); delete stack.back(); stack.pop_back(); } if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) { + //Add a new cache CCoinsView* tip = &base; if (stack.size() > 0) { tip = stack.back(); @@ -197,4 +209,140 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) BOOST_CHECK(missed_an_entry); } +// This test is similar to the previous test +// except the emphasis is on testing the functionality of UpdateCoins +// random txs are created and UpdateCoins is used to update the cache stack +// In particular it is tested that spending a duplicate coinbase tx +// has the expected effect (the other duplicate is overwitten at all cache levels) +BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) +{ + bool spent_a_duplicate_coinbase = false; + // A simple map to track what we expect the cache stack to represent. + std::map result; + + // The cache stack. + CCoinsViewTest base; // A CCoinsViewTest at the bottom. + std::vector stack; // A stack of CCoinsViewCaches on top. + stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache. + + // Track the txids we've used and whether they have been spent or not + std::map coinbaseids; + std::set alltxids; + std::set duplicateids; + + for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { + { + CMutableTransaction tx; + tx.vin.resize(1); + tx.vout.resize(1); + tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate + unsigned int height = insecure_rand(); + + // 1/10 times create a coinbase + if (insecure_rand() % 10 == 0 || coinbaseids.size() < 10) { + // 1/100 times create a duplicate coinbase + if (insecure_rand() % 10 == 0 && coinbaseids.size()) { + std::map::iterator coinbaseIt = coinbaseids.lower_bound(GetRandHash()); + if (coinbaseIt == coinbaseids.end()) { + coinbaseIt = coinbaseids.begin(); + } + //Use same random value to have same hash and be a true duplicate + tx.vout[0].nValue = coinbaseIt->second; + assert(tx.GetHash() == coinbaseIt->first); + duplicateids.insert(coinbaseIt->first); + } + else { + coinbaseids[tx.GetHash()] = tx.vout[0].nValue; + } + assert(CTransaction(tx).IsCoinBase()); + } + // 9/10 times create a regular tx + else { + uint256 prevouthash; + // equally likely to spend coinbase or non coinbase + std::set::iterator txIt = alltxids.lower_bound(GetRandHash()); + if (txIt == alltxids.end()) { + txIt = alltxids.begin(); + } + prevouthash = *txIt; + + // Construct the tx to spend the coins of prevouthash + tx.vin[0].prevout.hash = prevouthash; + tx.vin[0].prevout.n = 0; + + // Update the expected result of prevouthash to know these coins are spent + CCoins& oldcoins = result[prevouthash]; + oldcoins.Clear(); + + // It is of particular importance here that once we spend a coinbase tx hash + // it is no longer available to be duplicated (or spent again) + // BIP 34 in conjunction with enforcing BIP 30 (at least until BIP 34 was active) + // results in the fact that no coinbases were duplicated after they were already spent + alltxids.erase(prevouthash); + coinbaseids.erase(prevouthash); + + // The test is designed to ensure spending a duplicate coinbase will work properly + // if that ever happens and not resurrect the previously overwritten coinbase + if (duplicateids.count(prevouthash)) + spent_a_duplicate_coinbase = true; + + assert(!CTransaction(tx).IsCoinBase()); + } + // Track this tx to possibly spend later + alltxids.insert(tx.GetHash()); + + // Update the expected result to know about the new output coins + CCoins &coins = result[tx.GetHash()]; + coins.FromTx(tx, height); + + CValidationState dummy; + UpdateCoins(tx, dummy, *(stack.back()), height); + } + + // Once every 1000 iterations and at the end, verify the full cache. + if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { + for (std::map::iterator it = result.begin(); it != result.end(); it++) { + const CCoins* coins = stack.back()->AccessCoins(it->first); + if (coins) { + BOOST_CHECK(*coins == it->second); + } else { + BOOST_CHECK(it->second.IsPruned()); + } + } + } + + if (insecure_rand() % 100 == 0) { + // Every 100 iterations, flush an intermediate cache + if (stack.size() > 1 && insecure_rand() % 2 == 0) { + unsigned int flushIndex = insecure_rand() % (stack.size() - 1); + stack[flushIndex]->Flush(); + } + } + if (insecure_rand() % 100 == 0) { + // Every 100 iterations, change the cache stack. + if (stack.size() > 0 && insecure_rand() % 2 == 0) { + stack.back()->Flush(); + delete stack.back(); + stack.pop_back(); + } + if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) { + CCoinsView* tip = &base; + if (stack.size() > 0) { + tip = stack.back(); + } + stack.push_back(new CCoinsViewCacheTest(tip)); + } + } + } + + // Clean up the stack. + while (stack.size() > 0) { + delete stack.back(); + stack.pop_back(); + } + + // Verify coverage. + BOOST_CHECK(spent_a_duplicate_coinbase); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp index 376ae9368..35e4458bb 100644 --- a/src/test/compress_tests.cpp +++ b/src/test/compress_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index aeb2a5caa..0b46d718d 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014 The Bitcoin Core developers +// Copyright (c) 2014-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/data/alertTests.raw b/src/test/data/alertTests.raw deleted file mode 100644 index 1fa7acfbb..000000000 Binary files a/src/test/data/alertTests.raw and /dev/null differ diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json deleted file mode 100644 index df76cc6fa..000000000 --- a/src/test/data/script_invalid.json +++ /dev/null @@ -1,810 +0,0 @@ -[ -["Format is: [scriptSig, scriptPubKey, flags, ... comments]"], -["It is evaluated as if there was a crediting coinbase transaction with two 0"], -["pushes as scriptSig, and one output of 0 satoshi and given scriptPubKey,"], -["followed by a spending transaction which spends this output as only input (and"], -["correct prevout hash), using the given scriptSig. All nLockTimes are 0, all"], -["nSequences are max."], - -["", "DEPTH", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation"], -[" ", "DEPTH", "P2SH,STRICTENC", "and multiple spaces should not change that."], -[" ", "DEPTH", "P2SH,STRICTENC"], -[" ", "DEPTH", "P2SH,STRICTENC"], - -["", "", "P2SH,STRICTENC"], -["", "NOP", "P2SH,STRICTENC"], -["", "NOP DEPTH", "P2SH,STRICTENC"], -["NOP", "", "P2SH,STRICTENC"], -["NOP", "DEPTH", "P2SH,STRICTENC"], -["NOP","NOP", "P2SH,STRICTENC"], -["NOP","NOP DEPTH", "P2SH,STRICTENC"], - -["DEPTH", "", "P2SH,STRICTENC"], - -["0x4c01","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA1 with not enough bytes"], -["0x4d0200ff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA2 with not enough bytes"], -["0x4e03000000ffff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA4 with not enough bytes"], - -["1", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved"], -["0x52", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "0x51 through 0x60 push 1 through 16 onto stack"], -["0","NOP", "P2SH,STRICTENC"], -["1", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "VER non-functional"], -["0", "IF VERIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere"], -["0", "IF ELSE 1 ELSE VERIF ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere"], -["0", "IF VERNOTIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere"], -["0", "IF ELSE 1 ELSE VERNOTIF ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere"], - -["1 IF", "1 ENDIF", "P2SH,STRICTENC", "IF/ENDIF can't span scriptSig/scriptPubKey"], -["1 IF 0 ENDIF", "1 ENDIF", "P2SH,STRICTENC"], -["1 ELSE 0 ENDIF", "1", "P2SH,STRICTENC"], -["0 NOTIF", "123", "P2SH,STRICTENC"], - -["0", "DUP IF ENDIF", "P2SH,STRICTENC"], -["0", "IF 1 ENDIF", "P2SH,STRICTENC"], -["0", "DUP IF ELSE ENDIF", "P2SH,STRICTENC"], -["0", "IF 1 ELSE ENDIF", "P2SH,STRICTENC"], -["0", "NOTIF ELSE 1 ENDIF", "P2SH,STRICTENC"], - -["0 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], - -["0 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], - -["1", "IF RETURN ELSE ELSE 1 ENDIF", "P2SH,STRICTENC", "Multiple ELSEs"], -["1", "IF 1 ELSE ELSE RETURN ENDIF", "P2SH,STRICTENC"], - -["1", "ENDIF", "P2SH,STRICTENC", "Malformed IF/ELSE/ENDIF sequence"], -["1", "ELSE ENDIF", "P2SH,STRICTENC"], -["1", "ENDIF ELSE", "P2SH,STRICTENC"], -["1", "ENDIF ELSE IF", "P2SH,STRICTENC"], -["1", "IF ELSE ENDIF ELSE", "P2SH,STRICTENC"], -["1", "IF ELSE ENDIF ELSE ENDIF", "P2SH,STRICTENC"], -["1", "IF ENDIF ENDIF", "P2SH,STRICTENC"], -["1", "IF ELSE ELSE ENDIF ENDIF", "P2SH,STRICTENC"], - -["1", "RETURN", "P2SH,STRICTENC"], -["1", "DUP IF RETURN ENDIF", "P2SH,STRICTENC"], - -["1", "RETURN 'data'", "P2SH,STRICTENC", "canonical prunable txout format"], -["0 IF", "RETURN ENDIF 1", "P2SH,STRICTENC", "still prunable because IF/ENDIF can't span scriptSig/scriptPubKey"], - -["0", "VERIFY 1", "P2SH,STRICTENC"], -["1", "VERIFY", "P2SH,STRICTENC"], -["1", "VERIFY 0", "P2SH,STRICTENC"], - -["1 TOALTSTACK", "FROMALTSTACK 1", "P2SH,STRICTENC", "alt stack not shared between sig/pubkey"], - -["IFDUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["DUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["1", "DUP 1 ADD 2 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"], -["NOP", "NIP", "P2SH,STRICTENC"], -["NOP", "1 NIP", "P2SH,STRICTENC"], -["NOP", "1 0 NIP", "P2SH,STRICTENC"], -["NOP", "OVER 1", "P2SH,STRICTENC"], -["1", "OVER", "P2SH,STRICTENC"], -["0 1", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC"], -["19 20 21", "PICK 19 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["NOP", "0 PICK", "P2SH,STRICTENC"], -["1", "-1 PICK", "P2SH,STRICTENC"], -["19 20 21", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["19 20 21", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["19 20 21", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["NOP", "0 ROLL", "P2SH,STRICTENC"], -["1", "-1 ROLL", "P2SH,STRICTENC"], -["19 20 21", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["19 20 21", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["19 20 21", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["NOP", "ROT 1", "P2SH,STRICTENC"], -["NOP", "1 ROT 1", "P2SH,STRICTENC"], -["NOP", "1 2 ROT 1", "P2SH,STRICTENC"], -["NOP", "0 1 2 ROT", "P2SH,STRICTENC"], -["NOP", "SWAP 1", "P2SH,STRICTENC"], -["1", "SWAP 1", "P2SH,STRICTENC"], -["0 1", "SWAP 1 EQUALVERIFY", "P2SH,STRICTENC"], -["NOP", "TUCK 1", "P2SH,STRICTENC"], -["1", "TUCK 1", "P2SH,STRICTENC"], -["1 0", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC"], -["NOP", "2DUP 1", "P2SH,STRICTENC"], -["1", "2DUP 1", "P2SH,STRICTENC"], -["NOP", "3DUP 1", "P2SH,STRICTENC"], -["1", "3DUP 1", "P2SH,STRICTENC"], -["1 2", "3DUP 1", "P2SH,STRICTENC"], -["NOP", "2OVER 1", "P2SH,STRICTENC"], -["1", "2 3 2OVER 1", "P2SH,STRICTENC"], -["NOP", "2SWAP 1", "P2SH,STRICTENC"], -["1", "2 3 2SWAP 1", "P2SH,STRICTENC"], - -["'a' 'b'", "CAT", "P2SH,STRICTENC", "CAT disabled"], -["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "P2SH,STRICTENC", "CAT disabled"], -["'abc' 1 1", "SUBSTR", "P2SH,STRICTENC", "SUBSTR disabled"], -["'abc' 1 1 0", "IF SUBSTR ELSE 1 ENDIF", "P2SH,STRICTENC", "SUBSTR disabled"], -["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "P2SH,STRICTENC", "LEFT disabled"], -["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "P2SH,STRICTENC", "RIGHT disabled"], - -["NOP", "SIZE 1", "P2SH,STRICTENC"], - -["'abc'", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC", "INVERT disabled"], -["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "AND disabled"], -["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "OR disabled"], -["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "XOR disabled"], -["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2MUL disabled"], -["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2DIV disabled"], -["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MUL disabled"], -["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DIV disabled"], -["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MOD disabled"], -["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "LSHIFT disabled"], -["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "RSHIFT disabled"], - -["", "EQUAL NOT", "P2SH,STRICTENC", "EQUAL must error when there are no stack items"], -["0", "EQUAL NOT", "P2SH,STRICTENC", "EQUAL must error when there are not 2 stack items"], -["0 1","EQUAL", "P2SH,STRICTENC"], -["1 1 ADD", "0 EQUAL", "P2SH,STRICTENC"], -["11 1 ADD 12 SUB", "11 EQUAL", "P2SH,STRICTENC"], - -["2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] "], -["-2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] "], -["2147483647 DUP ADD", "4294967294 NUMEQUAL", "P2SH,STRICTENC", "NUMEQUAL must be in numeric range"], -["'abcdef' NOT", "0 EQUAL", "P2SH,STRICTENC", "NOT is an arithmetic operand"], - -["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 2MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 2DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled"], -["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "disabled"], - -["1","NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC"], -["'NOP_1_to_10' NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC"], - -["Ensure 100% coverage of discouraged NOPS"], -["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP6", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP7", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP8", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP9", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP10", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], - -["NOP10", "1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in scriptSig"], - -["1 0x01 0xb9", "HASH160 0x14 0x15727299b05b45fdaf9ac9ecf7565cfe27c3e567 EQUAL", - "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in redeemScript"], - -["0x50","1", "P2SH,STRICTENC", "opcode 0x50 is reserved"], -["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "opcodes above NOP10 invalid if executed"], -["1", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC"], - -["1 IF 1 ELSE", "0xff ENDIF", "P2SH,STRICTENC", "invalid because scriptSig and scriptPubKey are processed separately"], - -["NOP", "RIPEMD160", "P2SH,STRICTENC"], -["NOP", "SHA1", "P2SH,STRICTENC"], -["NOP", "SHA256", "P2SH,STRICTENC"], -["NOP", "HASH160", "P2SH,STRICTENC"], -["NOP", "HASH256", "P2SH,STRICTENC"], - -["NOP", -"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", -"P2SH,STRICTENC", -">20000 byte push"], -["0", -"IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1", -"P2SH,STRICTENC", -">20000 byte push in non-executed IF branch"], -["1", -"0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", -"P2SH,STRICTENC", -">201 opcodes executed. 0x61 is NOP"], -["0", -"IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1", -"P2SH,STRICTENC", -">201 opcodes including non-executed IF branch. 0x61 is NOP"], -["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"P2SH,STRICTENC", -">1,000 stack size (0x6f is 3DUP)"], -["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"1 TOALTSTACK 2 TOALTSTACK 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"P2SH,STRICTENC", -">1,000 stack+altstack size"], -["NOP", -"0 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", -"P2SH,STRICTENC", -"10,001-byte scriptPubKey"], - -["NOP5", "NOP10", "P2SH,STRICTENC"], - -["1","VER", "P2SH,STRICTENC", "OP_VER is reserved"], -["1","VERIF", "P2SH,STRICTENC", "OP_VERIF is reserved"], -["1","VERNOTIF", "P2SH,STRICTENC", "OP_VERNOTIF is reserved"], -["1","RESERVED", "P2SH,STRICTENC", "OP_RESERVED is reserved"], -["1","RESERVED1", "P2SH,STRICTENC", "OP_RESERVED1 is reserved"], -["1","RESERVED2", "P2SH,STRICTENC", "OP_RESERVED2 is reserved"], -["1","0xba", "P2SH,STRICTENC", "0xba == OP_NOP10 + 1"], - -["2147483648", "1ADD 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers"], -["2147483648", "NEGATE 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers"], -["-2147483648", "1ADD 1", "P2SH,STRICTENC", "Because we use a sign bit, -2147483648 is also 5 bytes"], -["2147483647", "1ADD 1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], -["2147483648", "1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], - -["2147483648 1", "BOOLOR 1", "P2SH,STRICTENC", "We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)"], -["2147483648 1", "BOOLAND 1", "P2SH,STRICTENC", "We cannot do BOOLAND on 5-byte integers"], - -["1", "1 ENDIF", "P2SH,STRICTENC", "ENDIF without IF"], -["1", "IF 1", "P2SH,STRICTENC", "IF without ENDIF"], -["1 IF 1", "ENDIF", "P2SH,STRICTENC", "IFs don't carry over"], - -["NOP", "IF 1 ENDIF", "P2SH,STRICTENC", "The following tests check the if(stack.size() < N) tests in each opcode"], -["NOP", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "They are here to catch copy-and-paste errors"], -["NOP", "VERIFY 1", "P2SH,STRICTENC", "Most of them are duplicated elsewhere,"], - -["NOP", "TOALTSTACK 1", "P2SH,STRICTENC", "but, hey, more is always better, right?"], -["1", "FROMALTSTACK", "P2SH,STRICTENC"], -["1", "2DROP 1", "P2SH,STRICTENC"], -["1", "2DUP", "P2SH,STRICTENC"], -["1 1", "3DUP", "P2SH,STRICTENC"], -["1 1 1", "2OVER", "P2SH,STRICTENC"], -["1 1 1 1 1", "2ROT", "P2SH,STRICTENC"], -["1 1 1", "2SWAP", "P2SH,STRICTENC"], -["NOP", "IFDUP 1", "P2SH,STRICTENC"], -["NOP", "DROP 1", "P2SH,STRICTENC"], -["NOP", "DUP 1", "P2SH,STRICTENC"], -["1", "NIP", "P2SH,STRICTENC"], -["1", "OVER", "P2SH,STRICTENC"], -["1 1 1 3", "PICK", "P2SH,STRICTENC"], -["0", "PICK 1", "P2SH,STRICTENC"], -["1 1 1 3", "ROLL", "P2SH,STRICTENC"], -["0", "ROLL 1", "P2SH,STRICTENC"], -["1 1", "ROT", "P2SH,STRICTENC"], -["1", "SWAP", "P2SH,STRICTENC"], -["1", "TUCK", "P2SH,STRICTENC"], - -["NOP", "SIZE 1", "P2SH,STRICTENC"], - -["1", "EQUAL 1", "P2SH,STRICTENC"], -["1", "EQUALVERIFY 1", "P2SH,STRICTENC"], - -["NOP", "1ADD 1", "P2SH,STRICTENC"], -["NOP", "1SUB 1", "P2SH,STRICTENC"], -["NOP", "NEGATE 1", "P2SH,STRICTENC"], -["NOP", "ABS 1", "P2SH,STRICTENC"], -["NOP", "NOT 1", "P2SH,STRICTENC"], -["NOP", "0NOTEQUAL 1", "P2SH,STRICTENC"], - -["1", "ADD", "P2SH,STRICTENC"], -["1", "SUB", "P2SH,STRICTENC"], -["1", "BOOLAND", "P2SH,STRICTENC"], -["1", "BOOLOR", "P2SH,STRICTENC"], -["1", "NUMEQUAL", "P2SH,STRICTENC"], -["1", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"], -["1", "NUMNOTEQUAL", "P2SH,STRICTENC"], -["1", "LESSTHAN", "P2SH,STRICTENC"], -["1", "GREATERTHAN", "P2SH,STRICTENC"], -["1", "LESSTHANOREQUAL", "P2SH,STRICTENC"], -["1", "GREATERTHANOREQUAL", "P2SH,STRICTENC"], -["1", "MIN", "P2SH,STRICTENC"], -["1", "MAX", "P2SH,STRICTENC"], -["1 1", "WITHIN", "P2SH,STRICTENC"], - -["NOP", "RIPEMD160 1", "P2SH,STRICTENC"], -["NOP", "SHA1 1", "P2SH,STRICTENC"], -["NOP", "SHA256 1", "P2SH,STRICTENC"], -["NOP", "HASH160 1", "P2SH,STRICTENC"], -["NOP", "HASH256 1", "P2SH,STRICTENC"], - -["Increase CHECKSIG and CHECKMULTISIG negative test coverage"], -["", "CHECKSIG NOT", "STRICTENC", "CHECKSIG must error when there are no stack items"], -["0", "CHECKSIG NOT", "STRICTENC", "CHECKSIG must error when there are not 2 stack items"], -["", "CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are no stack items"], -["", "-1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when the specified number of pubkeys is negative"], -["", "1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are not enough pubkeys on the stack"], -["", "-1 0 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when the specified number of signatures is negative"], -["", "1 'pk1' 1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are not enough signatures on the stack"], -["", "'dummy' 'sig1' 1 'pk1' 1 CHECKMULTISIG IF 1 ENDIF", "", "CHECKMULTISIG must push false to stack when signature is invalid when NOT in strict enc mode"], - -["", -"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", -"P2SH,STRICTENC", -"202 CHECKMULTISIGS, fails due to 201 op limit"], - -["1", -"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", -"P2SH,STRICTENC"], - -["", -"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", -"P2SH,STRICTENC", -"Fails due to 201 sig op limit"], - -["1", -"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", -"P2SH,STRICTENC"], - - -["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", "nPubKeys > 20"], -["0 'sig' 1 0", "CHECKMULTISIG 1", "P2SH,STRICTENC", "nSigs > nPubKeys"], - - -["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "Tests for Script.IsPushOnly()"], -["NOP5 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC"], - -["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "P2SH,STRICTENC", "OP_RESERVED in P2SH should fail"], -["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "P2SH,STRICTENC", "OP_VER in P2SH should fail"], - -["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"], - -["MINIMALDATA enforcement for PUSHDATAs"], - -["0x4c 0x00", "DROP 1", "MINIMALDATA", "Empty vector minimally represented by OP_0"], -["0x01 0x81", "DROP 1", "MINIMALDATA", "-1 minimally represented by OP_1NEGATE"], -["0x01 0x01", "DROP 1", "MINIMALDATA", "1 to 16 minimally represented by OP_1 to OP_16"], -["0x01 0x02", "DROP 1", "MINIMALDATA"], -["0x01 0x03", "DROP 1", "MINIMALDATA"], -["0x01 0x04", "DROP 1", "MINIMALDATA"], -["0x01 0x05", "DROP 1", "MINIMALDATA"], -["0x01 0x06", "DROP 1", "MINIMALDATA"], -["0x01 0x07", "DROP 1", "MINIMALDATA"], -["0x01 0x08", "DROP 1", "MINIMALDATA"], -["0x01 0x09", "DROP 1", "MINIMALDATA"], -["0x01 0x0a", "DROP 1", "MINIMALDATA"], -["0x01 0x0b", "DROP 1", "MINIMALDATA"], -["0x01 0x0c", "DROP 1", "MINIMALDATA"], -["0x01 0x0d", "DROP 1", "MINIMALDATA"], -["0x01 0x0e", "DROP 1", "MINIMALDATA"], -["0x01 0x0f", "DROP 1", "MINIMALDATA"], -["0x01 0x10", "DROP 1", "MINIMALDATA"], - -["0x4c 0x48 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", - "PUSHDATA1 of 72 bytes minimally represented by direct push"], - -["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", - "PUSHDATA2 of 255 bytes minimally represented by PUSHDATA1"], - -["0x4e 0x00010000 0x11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", - "PUSHDATA4 of 256 bytes minimally represented by PUSHDATA2"], - - -["MINIMALDATA enforcement for numeric arguments"], - -["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "numequals 0"], -["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "numequals 0"], -["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "0x80 (negative zero) numequals 0"], -["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "numequals 0"], -["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "numequals 5"], -["0x03 0x050000", "NOT DROP 1", "MINIMALDATA", "numequals 5"], -["0x02 0x0580", "NOT DROP 1", "MINIMALDATA", "numequals -5"], -["0x03 0x050080", "NOT DROP 1", "MINIMALDATA", "numequals -5"], -["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff"], -["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xff7f"], -["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffffff"], -["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff7f"], - -["Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule"], - -["1 0x02 0x0000", "PICK DROP", "MINIMALDATA"], -["1 0x02 0x0000", "ROLL DROP 1", "MINIMALDATA"], -["0x02 0x0000", "1ADD DROP 1", "MINIMALDATA"], -["0x02 0x0000", "1SUB DROP 1", "MINIMALDATA"], -["0x02 0x0000", "NEGATE DROP 1", "MINIMALDATA"], -["0x02 0x0000", "ABS DROP 1", "MINIMALDATA"], -["0x02 0x0000", "NOT DROP 1", "MINIMALDATA"], -["0x02 0x0000", "0NOTEQUAL DROP 1", "MINIMALDATA"], - -["0 0x02 0x0000", "ADD DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "ADD DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "SUB DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "SUB DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "BOOLAND DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "BOOLAND DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "BOOLOR DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "BOOLOR DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "NUMEQUAL DROP 1", "MINIMALDATA"], -["0x02 0x0000 1", "NUMEQUAL DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "NUMEQUALVERIFY 1", "MINIMALDATA"], -["0x02 0x0000 0", "NUMEQUALVERIFY 1", "MINIMALDATA"], -["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "LESSTHAN DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "LESSTHAN DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "GREATERTHAN DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "GREATERTHAN DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "MIN DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "MIN DROP 1", "MINIMALDATA"], -["0 0x02 0x0000", "MAX DROP 1", "MINIMALDATA"], -["0x02 0x0000 0", "MAX DROP 1", "MINIMALDATA"], - -["0x02 0x0000 0 0", "WITHIN DROP 1", "MINIMALDATA"], -["0 0x02 0x0000 0", "WITHIN DROP 1", "MINIMALDATA"], -["0 0 0x02 0x0000", "WITHIN DROP 1", "MINIMALDATA"], - -["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", "MINIMALDATA"], -["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", "MINIMALDATA"], -["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", "MINIMALDATA"], -["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", "MINIMALDATA"], -["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "MINIMALDATA"], - - -["Order of CHECKMULTISIG evaluation tests, inverted by swapping the order of"], -["pubkeys/signatures so they fail due to the STRICTENC rules on validly encoded"], -["signatures and pubkeys."], -[ - "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501", - "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0 2 CHECKMULTISIG NOT", - "STRICTENC", - "2-of-2 CHECKMULTISIG NOT with the first pubkey invalid, and both signatures validly encoded." -], -[ - "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 1", - "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT", - "STRICTENC", - "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid." -], - -["Increase DERSIG test coverage"], -["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Overly long signature is incorrectly encoded for DERSIG"], -["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Missing S is incorrectly encoded for DERSIG"], -["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "S with invalid S length is incorrectly encoded for DERSIG"], -["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer R is incorrectly encoded for DERSIG"], -["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer S is incorrectly encoded for DERSIG"], -["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Zero-length R is incorrectly encoded for DERSIG"], -["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "DERSIG", "Zero-length S is incorrectly encoded for DERSIG"], -["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Negative S is incorrectly encoded for DERSIG"], - -["Automatically generated test cases"], -[ - "0x47 0x304402200a5c6163f07b8c3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", - "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", - "", - "P2PK, bad sig" -], -[ - "0x47 0x3044022034bb0494b50b8ef130e2185bb220265b9284ef5b4b8a8da4d8415df489c83b5102206259a26d9cc0a125ac26af6153b17c02956855ebe1467412f066e402f5f05d1201 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", - "DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG", - "", - "P2PKH, bad pubkey" -], -[ - "0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790201", - "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", - "", - "P2PK anyonecanpay marked with normal hashtype" -], -[ - "0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", - "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", - "P2SH", - "P2SH(P2PK), bad redeemscript" -], -[ - "0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", - "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", - "P2SH", - "P2SH(P2PKH), bad sig" -], -[ - "0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0", - "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", - "", - "3-of-3, 2 sigs" -], -[ - "0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", - "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", - "P2SH", - "P2SH(2-of-3), 1 sig" -], -[ - "0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", - "DERSIG", - "P2PK with too much R padding" -], -[ - "0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", - "DERSIG", - "P2PK with too much S padding" -], -[ - "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", - "DERSIG", - "P2PK with too little R padding" -], -[ - "0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", - "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", - "DERSIG", - "P2PK NOT with bad sig with too much R padding" -], -[ - "0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", - "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", - "", - "P2PK NOT with too much R padding but no DERSIG" -], -[ - "0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", - "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", - "DERSIG", - "P2PK NOT with too much R padding" -], -[ - "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", - "DERSIG", - "BIP66 example 1, with DERSIG" -], -[ - "0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", - "", - "BIP66 example 2, without DERSIG" -], -[ - "0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", - "DERSIG", - "BIP66 example 2, with DERSIG" -], -[ - "0", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", - "", - "BIP66 example 3, without DERSIG" -], -[ - "0", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", - "DERSIG", - "BIP66 example 3, with DERSIG" -], -[ - "1", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", - "", - "BIP66 example 5, without DERSIG" -], -[ - "1", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", - "DERSIG", - "BIP66 example 5, with DERSIG" -], -[ - "1", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", - "DERSIG", - "BIP66 example 6, with DERSIG" -], -[ - "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", - "DERSIG", - "BIP66 example 7, with DERSIG" -], -[ - "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", - "", - "BIP66 example 8, without DERSIG" -], -[ - "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", - "DERSIG", - "BIP66 example 8, with DERSIG" -], -[ - "0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", - "", - "BIP66 example 9, without DERSIG" -], -[ - "0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", - "DERSIG", - "BIP66 example 9, with DERSIG" -], -[ - "0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", - "DERSIG", - "BIP66 example 10, with DERSIG" -], -[ - "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", - "", - "BIP66 example 11, without DERSIG" -], -[ - "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", - "DERSIG", - "BIP66 example 11, with DERSIG" -], -[ - "0x48 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb12510101", - "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", - "DERSIG", - "P2PK with multi-byte hashtype, with DERSIG" -], -[ - "0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001", - "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", - "LOW_S", - "P2PK with high S" -], -[ - "0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01", - "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", - "STRICTENC", - "P2PK with hybrid pubkey" -], -[ - "0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", - "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", - "", - "P2PK NOT with hybrid pubkey but no STRICTENC" -], -[ - "0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", - "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", - "STRICTENC", - "P2PK NOT with hybrid pubkey" -], -[ - "0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", - "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", - "STRICTENC", - "P2PK NOT with invalid hybrid pubkey" -], -[ - "0 0x47 0x3044022079c7824d6c868e0e1a273484e28c2654a27d043c8a27f49f52cb72efed0759090220452bbbf7089574fa082095a4fc1b3a16bafcf97a3a34d745fafc922cce66b27201", - "1 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 2 CHECKMULTISIG", - "STRICTENC", - "1-of-2 with the first 1 hybrid pubkey" -], -[ - "0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205", - "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", - "STRICTENC", - "P2PK with undefined hashtype" -], -[ - "0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05", - "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT", - "STRICTENC", - "P2PK NOT with invalid sig and undefined hashtype" -], -[ - "1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901", - "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", - "NULLDUMMY", - "3-of-3 with nonzero dummy" -], -[ - "1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01", - "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT", - "NULLDUMMY", - "3-of-3 NOT with invalid sig with nonzero dummy" -], -[ - "0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", - "SIGPUSHONLY", - "2-of-2 with two identical keys and sigs pushed using OP_DUP" -], -[ - "0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", - "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", - "", - "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY" -], -[ - "0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", - "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", - "SIGPUSHONLY", - "P2SH(P2PK) with non-push scriptSig" -], -[ - "0 0x47 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f01 0x46 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f", - "2 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 3 CHECKMULTISIG", - "P2SH,STRICTENC", - "2-of-3 with one valid and one invalid signature due to parse error, nSigs > validSigs" -], -[ - "11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", - "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", - "CLEANSTACK,P2SH", - "P2PK with unnecessary input" -], -[ - "11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac", - "HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL", - "CLEANSTACK,P2SH", - "P2SH with unnecessary input" -], - -["The End"] -] diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json new file mode 100644 index 000000000..f41c07979 --- /dev/null +++ b/src/test/data/script_tests.json @@ -0,0 +1,1818 @@ +[ +["Format is: [scriptSig, scriptPubKey, flags, expected_scripterror, ... comments]"], +["It is evaluated as if there was a crediting coinbase transaction with two 0"], +["pushes as scriptSig, and one output of 0 satoshi and given scriptPubKey,"], +["followed by a spending transaction which spends this output as only input (and"], +["correct prevout hash), using the given scriptSig. All nLockTimes are 0, all"], +["nSequences are max."], + +["", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "Test the test: we should have an empty stack after scriptSig evaluation"], +[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "and multiple spaces should not change that."], +[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "OK", "Similarly whitespace around and between symbols"], +["1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "OK"], +[" 1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "OK"], +["1 2 ", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "OK"], +[" 1 2 ", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "OK"], + +["1", "", "P2SH,STRICTENC", "OK"], +["0x02 0x01 0x00", "", "P2SH,STRICTENC", "OK", "all bytes are significant, not only the last one"], +["0x09 0x00000000 0x00000000 0x10", "", "P2SH,STRICTENC", "OK", "equals zero when cast to Int64"], + +["0x01 0x0b", "11 EQUAL", "P2SH,STRICTENC", "OK", "push 1 byte"], +["0x02 0x417a", "'Az' EQUAL", "P2SH,STRICTENC", "OK"], +["0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a", + "'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL", "P2SH,STRICTENC", "OK", "push 75 bytes"], + +["0x4c 0x01 0x07","7 EQUAL", "P2SH,STRICTENC", "OK", "0x4c is OP_PUSHDATA1"], +["0x4d 0x0100 0x08","8 EQUAL", "P2SH,STRICTENC", "OK", "0x4d is OP_PUSHDATA2"], +["0x4e 0x01000000 0x09","9 EQUAL", "P2SH,STRICTENC", "OK", "0x4e is OP_PUSHDATA4"], + +["0x4c 0x00","0 EQUAL", "P2SH,STRICTENC", "OK"], +["0x4d 0x0000","0 EQUAL", "P2SH,STRICTENC", "OK"], +["0x4e 0x00000000","0 EQUAL", "P2SH,STRICTENC", "OK"], +["0x4f 1000 ADD","999 EQUAL", "P2SH,STRICTENC", "OK"], +["0", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "OK", "0x50 is reserved (ok if not executed)"], +["0x51", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "OK", "0x51 through 0x60 push 1 through 16 onto stack"], +["1","NOP", "P2SH,STRICTENC", "OK"], +["0", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "VER non-functional (ok if not executed)"], +["0", "IF RESERVED RESERVED1 RESERVED2 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "RESERVED ok in un-executed IF"], + +["1", "DUP IF ENDIF", "P2SH,STRICTENC", "OK"], +["1", "IF 1 ENDIF", "P2SH,STRICTENC", "OK"], +["1", "DUP IF ELSE ENDIF", "P2SH,STRICTENC", "OK"], +["1", "IF 1 ELSE ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], + +["1 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], +["1 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], +["1 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], +["0 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], + +["1 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], +["1 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], +["1 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], +["0 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "OK"], + +["0", "IF 0 ELSE 1 ELSE 0 ENDIF", "P2SH,STRICTENC", "OK", "Multiple ELSE's are valid and executed inverts on each ELSE encountered"], +["1", "IF 1 ELSE 0 ELSE ENDIF", "P2SH,STRICTENC", "OK"], +["1", "IF ELSE 0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["1", "IF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL", "P2SH,STRICTENC", "OK"], +["'' 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"], + +["1", "NOTIF 0 ELSE 1 ELSE 0 ENDIF", "P2SH,STRICTENC", "OK", "Multiple ELSE's are valid and execution inverts on each ELSE encountered"], +["0", "NOTIF 1 ELSE 0 ELSE ENDIF", "P2SH,STRICTENC", "OK"], +["0", "NOTIF ELSE 0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "NOTIF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL", "P2SH,STRICTENC", "OK"], +["'' 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"], + +["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"], +["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"], + +["0", "IF RETURN ENDIF 1", "P2SH,STRICTENC", "OK", "RETURN only works if executed"], + +["1 1", "VERIFY", "P2SH,STRICTENC", "OK"], +["1 0x05 0x01 0x00 0x00 0x00 0x00", "VERIFY", "P2SH,STRICTENC", "OK", "values >4 bytes can be cast to boolean"], +["1 0x01 0x80", "IF 0 ENDIF", "P2SH,STRICTENC", "OK", "negative 0 is false"], + +["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 21 EQUAL", "P2SH,STRICTENC", "OK"], +["'gavin_was_here' TOALTSTACK 11 FROMALTSTACK", "'gavin_was_here' EQUALVERIFY 11 EQUAL", "P2SH,STRICTENC", "OK"], + +["0 IFDUP", "DEPTH 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC", "OK"], +["1 IFDUP", "DEPTH 2 EQUALVERIFY 1 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "OK"], +["0x05 0x0100000000 IFDUP", "DEPTH 2 EQUALVERIFY 0x05 0x0100000000 EQUAL", "P2SH,STRICTENC", "OK", "IFDUP dups non ints"], +["0 DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["0", "DUP 1 ADD 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC", "OK"], +["0 1", "NIP", "P2SH,STRICTENC", "OK"], +["1 0", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC", "OK"], +["22 21 20", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "ROT 22 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "ROT DROP 20 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "ROT DROP DROP 21 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "ROT ROT 21 EQUAL", "P2SH,STRICTENC", "OK"], +["22 21 20", "ROT ROT ROT 20 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 24 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT DROP 25 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 2DROP 20 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 2DROP DROP 21 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 2DROP 2DROP 22 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 2DROP 2DROP DROP 23 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 2ROT 22 EQUAL", "P2SH,STRICTENC", "OK"], +["25 24 23 22 21 20", "2ROT 2ROT 2ROT 20 EQUAL", "P2SH,STRICTENC", "OK"], +["1 0", "SWAP 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC", "OK"], +["0 1", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC", "OK"], +["13 14", "2DUP ROT EQUALVERIFY EQUAL", "P2SH,STRICTENC", "OK"], +["-1 0 1 2", "3DUP DEPTH 7 EQUALVERIFY ADD ADD 3 EQUALVERIFY 2DROP 0 EQUALVERIFY", "P2SH,STRICTENC", "OK"], +["1 2 3 5", "2OVER ADD ADD 8 EQUALVERIFY ADD ADD 6 EQUAL", "P2SH,STRICTENC", "OK"], +["1 3 5 7", "2SWAP ADD 4 EQUALVERIFY ADD 12 EQUAL", "P2SH,STRICTENC", "OK"], +["0", "SIZE 0 EQUAL", "P2SH,STRICTENC", "OK"], +["1", "SIZE 1 EQUAL", "P2SH,STRICTENC", "OK"], +["127", "SIZE 1 EQUAL", "P2SH,STRICTENC", "OK"], +["128", "SIZE 2 EQUAL", "P2SH,STRICTENC", "OK"], +["32767", "SIZE 2 EQUAL", "P2SH,STRICTENC", "OK"], +["32768", "SIZE 3 EQUAL", "P2SH,STRICTENC", "OK"], +["8388607", "SIZE 3 EQUAL", "P2SH,STRICTENC", "OK"], +["8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC", "OK"], +["2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC", "OK"], +["2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], +["549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], +["549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC", "OK"], +["9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC", "OK"], +["-1", "SIZE 1 EQUAL", "P2SH,STRICTENC", "OK"], +["-127", "SIZE 1 EQUAL", "P2SH,STRICTENC", "OK"], +["-128", "SIZE 2 EQUAL", "P2SH,STRICTENC", "OK"], +["-32767", "SIZE 2 EQUAL", "P2SH,STRICTENC", "OK"], +["-32768", "SIZE 3 EQUAL", "P2SH,STRICTENC", "OK"], +["-8388607", "SIZE 3 EQUAL", "P2SH,STRICTENC", "OK"], +["-8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC", "OK"], +["-2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC", "OK"], +["-2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], +["-549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC", "OK"], +["-549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC", "OK"], +["-9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC", "OK"], +["'abcdefghijklmnopqrstuvwxyz'", "SIZE 26 EQUAL", "P2SH,STRICTENC", "OK"], + +["42", "SIZE 1 EQUALVERIFY 42 EQUAL", "P2SH,STRICTENC", "OK", "SIZE does not consume argument"], + +["2 -2 ADD", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["2147483647 -2147483647 ADD", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["-1 -1 ADD", "-2 EQUAL", "P2SH,STRICTENC", "OK"], + +["0 0","EQUAL", "P2SH,STRICTENC", "OK"], +["1 1 ADD", "2 EQUAL", "P2SH,STRICTENC", "OK"], +["1 1ADD", "2 EQUAL", "P2SH,STRICTENC", "OK"], +["111 1SUB", "110 EQUAL", "P2SH,STRICTENC", "OK"], +["111 1 ADD 12 SUB", "100 EQUAL", "P2SH,STRICTENC", "OK"], +["0 ABS", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["16 ABS", "16 EQUAL", "P2SH,STRICTENC", "OK"], +["-16 ABS", "-16 NEGATE EQUAL", "P2SH,STRICTENC", "OK"], +["0 NOT", "NOP", "P2SH,STRICTENC", "OK"], +["1 NOT", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["11 NOT", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["0 0NOTEQUAL", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["1 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC", "OK"], +["111 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC", "OK"], +["-111 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC", "OK"], +["1 1 BOOLAND", "NOP", "P2SH,STRICTENC", "OK"], +["1 0 BOOLAND", "NOT", "P2SH,STRICTENC", "OK"], +["0 1 BOOLAND", "NOT", "P2SH,STRICTENC", "OK"], +["0 0 BOOLAND", "NOT", "P2SH,STRICTENC", "OK"], +["16 17 BOOLAND", "NOP", "P2SH,STRICTENC", "OK"], +["1 1 BOOLOR", "NOP", "P2SH,STRICTENC", "OK"], +["1 0 BOOLOR", "NOP", "P2SH,STRICTENC", "OK"], +["0 1 BOOLOR", "NOP", "P2SH,STRICTENC", "OK"], +["0 0 BOOLOR", "NOT", "P2SH,STRICTENC", "OK"], +["16 17 BOOLOR", "NOP", "P2SH,STRICTENC", "OK"], +["11 10 1 ADD", "NUMEQUAL", "P2SH,STRICTENC", "OK"], +["11 10 1 ADD", "NUMEQUALVERIFY 1", "P2SH,STRICTENC", "OK"], +["11 10 1 ADD", "NUMNOTEQUAL NOT", "P2SH,STRICTENC", "OK"], +["111 10 1 ADD", "NUMNOTEQUAL", "P2SH,STRICTENC", "OK"], +["11 10", "LESSTHAN NOT", "P2SH,STRICTENC", "OK"], +["4 4", "LESSTHAN NOT", "P2SH,STRICTENC", "OK"], +["10 11", "LESSTHAN", "P2SH,STRICTENC", "OK"], +["-11 11", "LESSTHAN", "P2SH,STRICTENC", "OK"], +["-11 -10", "LESSTHAN", "P2SH,STRICTENC", "OK"], +["11 10", "GREATERTHAN", "P2SH,STRICTENC", "OK"], +["4 4", "GREATERTHAN NOT", "P2SH,STRICTENC", "OK"], +["10 11", "GREATERTHAN NOT", "P2SH,STRICTENC", "OK"], +["-11 11", "GREATERTHAN NOT", "P2SH,STRICTENC", "OK"], +["-11 -10", "GREATERTHAN NOT", "P2SH,STRICTENC", "OK"], +["11 10", "LESSTHANOREQUAL NOT", "P2SH,STRICTENC", "OK"], +["4 4", "LESSTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["10 11", "LESSTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["-11 11", "LESSTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["-11 -10", "LESSTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["11 10", "GREATERTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["4 4", "GREATERTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["10 11", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC", "OK"], +["-11 11", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC", "OK"], +["-11 -10", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC", "OK"], +["1 0 MIN", "0 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0 1 MIN", "0 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["-1 0 MIN", "-1 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0 -2147483647 MIN", "-2147483647 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["2147483647 0 MAX", "2147483647 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0 100 MAX", "100 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["-100 0 MAX", "0 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0 -2147483647 MAX", "0 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0 0 1", "WITHIN", "P2SH,STRICTENC", "OK"], +["1 0 1", "WITHIN NOT", "P2SH,STRICTENC", "OK"], +["0 -2147483647 2147483647", "WITHIN", "P2SH,STRICTENC", "OK"], +["-1 -100 100", "WITHIN", "P2SH,STRICTENC", "OK"], +["11 -100 100", "WITHIN", "P2SH,STRICTENC", "OK"], +["-2147483647 -100 100", "WITHIN NOT", "P2SH,STRICTENC", "OK"], +["2147483647 -100 100", "WITHIN NOT", "P2SH,STRICTENC", "OK"], + +["2147483647 2147483647 SUB", "0 EQUAL", "P2SH,STRICTENC", "OK"], +["2147483647 DUP ADD", "4294967294 EQUAL", "P2SH,STRICTENC", "OK", ">32 bit EQUAL is valid"], +["2147483647 NEGATE DUP ADD", "-4294967294 EQUAL", "P2SH,STRICTENC", "OK"], + +["''", "RIPEMD160 0x14 0x9c1185a5c5e9fc54612808977ee8f548b2258d31 EQUAL", "P2SH,STRICTENC", "OK"], +["'a'", "RIPEMD160 0x14 0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffe EQUAL", "P2SH,STRICTENC", "OK"], +["'abcdefghijklmnopqrstuvwxyz'", "RIPEMD160 0x14 0xf71c27109c692c1b56bbdceb5b9d2865b3708dbc EQUAL", "P2SH,STRICTENC", "OK"], +["''", "SHA1 0x14 0xda39a3ee5e6b4b0d3255bfef95601890afd80709 EQUAL", "P2SH,STRICTENC", "OK"], +["'a'", "SHA1 0x14 0x86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 EQUAL", "P2SH,STRICTENC", "OK"], +["'abcdefghijklmnopqrstuvwxyz'", "SHA1 0x14 0x32d10c7b8cf96570ca04ce37f2a19d84240d3a89 EQUAL", "P2SH,STRICTENC", "OK"], +["''", "SHA256 0x20 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 EQUAL", "P2SH,STRICTENC", "OK"], +["'a'", "SHA256 0x20 0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb EQUAL", "P2SH,STRICTENC", "OK"], +["'abcdefghijklmnopqrstuvwxyz'", "SHA256 0x20 0x71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 EQUAL", "P2SH,STRICTENC", "OK"], +["''", "DUP HASH160 SWAP SHA256 RIPEMD160 EQUAL", "P2SH,STRICTENC", "OK"], +["''", "DUP HASH256 SWAP SHA256 SHA256 EQUAL", "P2SH,STRICTENC", "OK"], +["''", "NOP HASH160 0x14 0xb472a266d0bd89c13706a4132ccfb16f7c3b9fcb EQUAL", "P2SH,STRICTENC", "OK"], +["'a'", "HASH160 NOP 0x14 0x994355199e516ff76c4fa4aab39337b9d84cf12b EQUAL", "P2SH,STRICTENC", "OK"], +["'abcdefghijklmnopqrstuvwxyz'", "HASH160 0x4c 0x14 0xc286a1af0947f58d1ad787385b1c2c4a976f9e71 EQUAL", "P2SH,STRICTENC", "OK"], +["''", "HASH256 0x20 0x5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456 EQUAL", "P2SH,STRICTENC", "OK"], +["'a'", "HASH256 0x20 0xbf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8 EQUAL", "P2SH,STRICTENC", "OK"], +["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL", "P2SH,STRICTENC", "OK"], + + +["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC", "OK"], +["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC", "OK"], + +["1", "NOP", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "OK", "Discourage NOPx flag allows OP_NOP"], + +["0", "IF NOP10 ENDIF 1", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "OK", + "Discouraged NOPs are allowed if not executed"], + +["0", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "opcodes above NOP10 invalid if executed"], +["0", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], + +["NOP", +"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", +"P2SH,STRICTENC", "OK", +"520 byte push"], +["1", +"0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"P2SH,STRICTENC", "OK", +"201 opcodes executed. 0x61 is NOP"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"P2SH,STRICTENC", "OK", +"1,000 stack size (0x6f is 3DUP)"], +["1 TOALTSTACK 2 TOALTSTACK 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 2 3 4 5 6 7 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"P2SH,STRICTENC", "OK", +"1,000 stack size (altstack cleared between scriptSig/scriptPubKey)"], +["'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"P2SH,STRICTENC", "OK", +"Max-size (10,000-byte), max-push(520 bytes), max-opcodes(201), max stack size(1,000 items). 0x6f is 3DUP, 0x61 is NOP"], + +["0", +"IF 0x5050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050 ENDIF 1", +"P2SH,STRICTENC", "OK", +">201 opcodes, but RESERVED (0x50) doesn't count towards opcode limit."], + +["NOP","1", "P2SH,STRICTENC", "OK"], + +["1", "0x01 0x01 EQUAL", "P2SH,STRICTENC", "OK", "The following is useful for checking implementations of BN_bn2mpi"], +["127", "0x01 0x7F EQUAL", "P2SH,STRICTENC", "OK"], +["128", "0x02 0x8000 EQUAL", "P2SH,STRICTENC", "OK", "Leave room for the sign bit"], +["32767", "0x02 0xFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["32768", "0x03 0x008000 EQUAL", "P2SH,STRICTENC", "OK"], +["8388607", "0x03 0xFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["8388608", "0x04 0x00008000 EQUAL", "P2SH,STRICTENC", "OK"], +["2147483647", "0x04 0xFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["2147483648", "0x05 0x0000008000 EQUAL", "P2SH,STRICTENC", "OK"], +["549755813887", "0x05 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["549755813888", "0x06 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["9223372036854775807", "0x08 0xFFFFFFFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"], +["-1", "0x01 0x81 EQUAL", "P2SH,STRICTENC", "OK", "Numbers are little-endian with the MSB being a sign bit"], +["-127", "0x01 0xFF EQUAL", "P2SH,STRICTENC", "OK"], +["-128", "0x02 0x8080 EQUAL", "P2SH,STRICTENC", "OK"], +["-32767", "0x02 0xFFFF EQUAL", "P2SH,STRICTENC", "OK"], +["-32768", "0x03 0x008080 EQUAL", "P2SH,STRICTENC", "OK"], +["-8388607", "0x03 0xFFFFFF EQUAL", "P2SH,STRICTENC", "OK"], +["-8388608", "0x04 0x00008080 EQUAL", "P2SH,STRICTENC", "OK"], +["-2147483647", "0x04 0xFFFFFFFF EQUAL", "P2SH,STRICTENC", "OK"], +["-2147483648", "0x05 0x0000008080 EQUAL", "P2SH,STRICTENC", "OK"], +["-4294967295", "0x05 0xFFFFFFFF80 EQUAL", "P2SH,STRICTENC", "OK"], +["-549755813887", "0x05 0xFFFFFFFFFF EQUAL", "P2SH,STRICTENC", "OK"], +["-549755813888", "0x06 0x000000008080 EQUAL", "P2SH,STRICTENC", "OK"], +["-9223372036854775807", "0x08 0xFFFFFFFFFFFFFFFF EQUAL", "P2SH,STRICTENC", "OK"], + +["2147483647", "1ADD 2147483648 EQUAL", "P2SH,STRICTENC", "OK", "We can do math on 4-byte integers, and compare 5-byte ones"], +["2147483647", "1ADD 1", "P2SH,STRICTENC", "OK"], +["-2147483647", "1ADD 1", "P2SH,STRICTENC", "OK"], + +["1", "0x02 0x0100 EQUAL NOT", "P2SH,STRICTENC", "OK", "Not the same byte array..."], +["1", "0x02 0x0100 NUMEQUAL", "P2SH,STRICTENC", "OK", "... but they are numerically equal"], +["11", "0x4c 0x03 0x0b0000 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0", "0x01 0x80 EQUAL NOT", "P2SH,STRICTENC", "OK"], +["0", "0x01 0x80 NUMEQUAL", "P2SH,STRICTENC", "OK", "Zero numerically equals negative zero"], +["0", "0x02 0x0080 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0x03 0x000080", "0x04 0x00000080 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0x03 0x100080", "0x04 0x10000080 NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0x03 0x100000", "0x04 0x10000000 NUMEQUAL", "P2SH,STRICTENC", "OK"], + +["NOP", "NOP 1", "P2SH,STRICTENC", "OK", "The following tests check the if(stack.size() < N) tests in each opcode"], +["1", "IF 1 ENDIF", "P2SH,STRICTENC", "OK", "They are here to catch copy-and-paste errors"], +["0", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "OK", "Most of them are duplicated elsewhere,"], +["1", "VERIFY 1", "P2SH,STRICTENC", "OK", "but, hey, more is always better, right?"], + +["0", "TOALTSTACK 1", "P2SH,STRICTENC", "OK"], +["1", "TOALTSTACK FROMALTSTACK", "P2SH,STRICTENC", "OK"], +["0 0", "2DROP 1", "P2SH,STRICTENC", "OK"], +["0 1", "2DUP", "P2SH,STRICTENC", "OK"], +["0 0 1", "3DUP", "P2SH,STRICTENC", "OK"], +["0 1 0 0", "2OVER", "P2SH,STRICTENC", "OK"], +["0 1 0 0 0 0", "2ROT", "P2SH,STRICTENC", "OK"], +["0 1 0 0", "2SWAP", "P2SH,STRICTENC", "OK"], +["1", "IFDUP", "P2SH,STRICTENC", "OK"], +["NOP", "DEPTH 1", "P2SH,STRICTENC", "OK"], +["0", "DROP 1", "P2SH,STRICTENC", "OK"], +["1", "DUP", "P2SH,STRICTENC", "OK"], +["0 1", "NIP", "P2SH,STRICTENC", "OK"], +["1 0", "OVER", "P2SH,STRICTENC", "OK"], +["1 0 0 0 3", "PICK", "P2SH,STRICTENC", "OK"], +["1 0", "PICK", "P2SH,STRICTENC", "OK"], +["1 0 0 0 3", "ROLL", "P2SH,STRICTENC", "OK"], +["1 0", "ROLL", "P2SH,STRICTENC", "OK"], +["1 0 0", "ROT", "P2SH,STRICTENC", "OK"], +["1 0", "SWAP", "P2SH,STRICTENC", "OK"], +["0 1", "TUCK", "P2SH,STRICTENC", "OK"], + +["1", "SIZE", "P2SH,STRICTENC", "OK"], + +["0 0", "EQUAL", "P2SH,STRICTENC", "OK"], +["0 0", "EQUALVERIFY 1", "P2SH,STRICTENC", "OK"], +["0 0 1", "EQUAL EQUAL", "P2SH,STRICTENC", "OK", "OP_0 and bools must have identical byte representations"], + +["0", "1ADD", "P2SH,STRICTENC", "OK"], +["2", "1SUB", "P2SH,STRICTENC", "OK"], +["-1", "NEGATE", "P2SH,STRICTENC", "OK"], +["-1", "ABS", "P2SH,STRICTENC", "OK"], +["0", "NOT", "P2SH,STRICTENC", "OK"], +["-1", "0NOTEQUAL", "P2SH,STRICTENC", "OK"], + +["1 0", "ADD", "P2SH,STRICTENC", "OK"], +["1 0", "SUB", "P2SH,STRICTENC", "OK"], +["-1 -1", "BOOLAND", "P2SH,STRICTENC", "OK"], +["-1 0", "BOOLOR", "P2SH,STRICTENC", "OK"], +["0 0", "NUMEQUAL", "P2SH,STRICTENC", "OK"], +["0 0", "NUMEQUALVERIFY 1", "P2SH,STRICTENC", "OK"], +["-1 0", "NUMNOTEQUAL", "P2SH,STRICTENC", "OK"], +["-1 0", "LESSTHAN", "P2SH,STRICTENC", "OK"], +["1 0", "GREATERTHAN", "P2SH,STRICTENC", "OK"], +["0 0", "LESSTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["0 0", "GREATERTHANOREQUAL", "P2SH,STRICTENC", "OK"], +["-1 0", "MIN", "P2SH,STRICTENC", "OK"], +["1 0", "MAX", "P2SH,STRICTENC", "OK"], +["-1 -1 0", "WITHIN", "P2SH,STRICTENC", "OK"], + +["0", "RIPEMD160", "P2SH,STRICTENC", "OK"], +["0", "SHA1", "P2SH,STRICTENC", "OK"], +["0", "SHA256", "P2SH,STRICTENC", "OK"], +["0", "HASH160", "P2SH,STRICTENC", "OK"], +["0", "HASH256", "P2SH,STRICTENC", "OK"], +["NOP", "CODESEPARATOR 1", "P2SH,STRICTENC", "OK"], + +["NOP", "NOP1 1", "P2SH,STRICTENC", "OK"], +["NOP", "CHECKLOCKTIMEVERIFY 1", "P2SH,STRICTENC", "OK"], +["NOP", "NOP3 1", "P2SH,STRICTENC", "OK"], +["NOP", "NOP4 1", "P2SH,STRICTENC", "OK"], +["NOP", "NOP5 1", "P2SH,STRICTENC", "OK"], +["NOP", "NOP9 1", "P2SH,STRICTENC", "OK"], +["NOP", "NOP10 1", "P2SH,STRICTENC", "OK"], + +["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "CHECKMULTISIG is allowed to have zero keys and/or sigs"], +["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "Zero sigs means no sigs are checked"], +["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], + +["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "CHECKMULTISIG is allowed to have zero keys and/or sigs"], +["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "Zero sigs means no sigs are checked"], +["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], + +["", "0 0 'a' 'b' 2 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK", "Test from up to 20 pubkeys, all not checked"], +["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "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"], +["", "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"], +["", "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"], +["", "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"], +["", "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"], +["", "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"], +["", "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"], +["", "0 0 'a' 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 2 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "OK"], +["", "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"], +["", "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"], +["", "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"], +["", "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"], +["", "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"], +["", "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"], + +["", +"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", +"P2SH,STRICTENC", "OK", +"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"], + +["1", +"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", +"P2SH,STRICTENC", "OK"], + +["", +"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", +"P2SH,STRICTENC", "OK", +"Even though there are no signatures being checked nOpCount is incremented by the number of keys."], + +["1", +"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", +"P2SH,STRICTENC", "OK"], + +["0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "OK", "Very basic P2SH"], +["0x4c 0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "OK"], + +["0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242", +"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL", +"P2SH,STRICTENC", "OK", +"Basic PUSH signedness check"], + +["0x4c 0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242", +"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL", +"P2SH,STRICTENC", "OK", +"Basic PUSHDATA1 signedness check"], + +["all PUSHDATA forms are equivalent"], + +["0x4c 0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "OK", "PUSHDATA1 of 75 bytes equals direct push of it"], +["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4c 0xFF 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "OK", "PUSHDATA2 of 255 bytes equals PUSHDATA1 of it"], + +["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "OK", "Basic OP_0 execution"], + +["Numeric pushes"], + +["0x01 0x81", "0x4f EQUAL", "", "OK", "OP1_NEGATE pushes 0x81"], +["0x01 0x01", "0x51 EQUAL", "", "OK", "OP_1 pushes 0x01"], +["0x01 0x02", "0x52 EQUAL", "", "OK", "OP_2 pushes 0x02"], +["0x01 0x03", "0x53 EQUAL", "", "OK", "OP_3 pushes 0x03"], +["0x01 0x04", "0x54 EQUAL", "", "OK", "OP_4 pushes 0x04"], +["0x01 0x05", "0x55 EQUAL", "", "OK", "OP_5 pushes 0x05"], +["0x01 0x06", "0x56 EQUAL", "", "OK", "OP_6 pushes 0x06"], +["0x01 0x07", "0x57 EQUAL", "", "OK", "OP_7 pushes 0x07"], +["0x01 0x08", "0x58 EQUAL", "", "OK", "OP_8 pushes 0x08"], +["0x01 0x09", "0x59 EQUAL", "", "OK", "OP_9 pushes 0x09"], +["0x01 0x0a", "0x5a EQUAL", "", "OK", "OP_10 pushes 0x0a"], +["0x01 0x0b", "0x5b EQUAL", "", "OK", "OP_11 pushes 0x0b"], +["0x01 0x0c", "0x5c EQUAL", "", "OK", "OP_12 pushes 0x0c"], +["0x01 0x0d", "0x5d EQUAL", "", "OK", "OP_13 pushes 0x0d"], +["0x01 0x0e", "0x5e EQUAL", "", "OK", "OP_14 pushes 0x0e"], +["0x01 0x0f", "0x5f EQUAL", "", "OK", "OP_15 pushes 0x0f"], +["0x01 0x10", "0x60 EQUAL", "", "OK", "OP_16 pushes 0x10"], + +["Equivalency of different numeric encodings"], + +["0x02 0x8000", "128 NUMEQUAL", "", "OK", "0x8000 equals 128"], +["0x01 0x00", "0 NUMEQUAL", "", "OK", "0x00 numequals 0"], +["0x01 0x80", "0 NUMEQUAL", "", "OK", "0x80 (negative zero) numequals 0"], +["0x02 0x0080", "0 NUMEQUAL", "", "OK", "0x0080 numequals 0"], +["0x02 0x0500", "5 NUMEQUAL", "", "OK", "0x0500 numequals 5"], +["0x03 0xff7f80", "0x02 0xffff NUMEQUAL", "", "OK", ""], +["0x03 0xff7f00", "0x02 0xff7f NUMEQUAL", "", "OK", ""], +["0x04 0xffff7f80", "0x03 0xffffff NUMEQUAL", "", "OK", ""], +["0x04 0xffff7f00", "0x03 0xffff7f NUMEQUAL", "", "OK", ""], + +["Unevaluated non-minimal pushes are ignored"], + +["0 IF 0x4c 0x00 ENDIF 1", "", "MINIMALDATA", "OK", "non-minimal PUSHDATA1 ignored"], +["0 IF 0x4d 0x0000 ENDIF 1", "", "MINIMALDATA", "OK", "non-minimal PUSHDATA2 ignored"], +["0 IF 0x4c 0x00000000 ENDIF 1", "", "MINIMALDATA", "OK", "non-minimal PUSHDATA4 ignored"], +["0 IF 0x01 0x81 ENDIF 1", "", "MINIMALDATA", "OK", "1NEGATE equiv"], +["0 IF 0x01 0x01 ENDIF 1", "", "MINIMALDATA", "OK", "OP_1 equiv"], +["0 IF 0x01 0x02 ENDIF 1", "", "MINIMALDATA", "OK", "OP_2 equiv"], +["0 IF 0x01 0x03 ENDIF 1", "", "MINIMALDATA", "OK", "OP_3 equiv"], +["0 IF 0x01 0x04 ENDIF 1", "", "MINIMALDATA", "OK", "OP_4 equiv"], +["0 IF 0x01 0x05 ENDIF 1", "", "MINIMALDATA", "OK", "OP_5 equiv"], +["0 IF 0x01 0x06 ENDIF 1", "", "MINIMALDATA", "OK", "OP_6 equiv"], +["0 IF 0x01 0x07 ENDIF 1", "", "MINIMALDATA", "OK", "OP_7 equiv"], +["0 IF 0x01 0x08 ENDIF 1", "", "MINIMALDATA", "OK", "OP_8 equiv"], +["0 IF 0x01 0x09 ENDIF 1", "", "MINIMALDATA", "OK", "OP_9 equiv"], +["0 IF 0x01 0x0a ENDIF 1", "", "MINIMALDATA", "OK", "OP_10 equiv"], +["0 IF 0x01 0x0b ENDIF 1", "", "MINIMALDATA", "OK", "OP_11 equiv"], +["0 IF 0x01 0x0c ENDIF 1", "", "MINIMALDATA", "OK", "OP_12 equiv"], +["0 IF 0x01 0x0d ENDIF 1", "", "MINIMALDATA", "OK", "OP_13 equiv"], +["0 IF 0x01 0x0e ENDIF 1", "", "MINIMALDATA", "OK", "OP_14 equiv"], +["0 IF 0x01 0x0f ENDIF 1", "", "MINIMALDATA", "OK", "OP_15 equiv"], +["0 IF 0x01 0x10 ENDIF 1", "", "MINIMALDATA", "OK", "OP_16 equiv"], + +["Numeric minimaldata rules are only applied when a stack item is numerically evaluated; the push itself is allowed"], + +["0x01 0x00", "1", "MINIMALDATA", "OK"], +["0x01 0x80", "1", "MINIMALDATA", "OK"], +["0x02 0x0180", "1", "MINIMALDATA", "OK"], +["0x02 0x0100", "1", "MINIMALDATA", "OK"], +["0x02 0x0200", "1", "MINIMALDATA", "OK"], +["0x02 0x0300", "1", "MINIMALDATA", "OK"], +["0x02 0x0400", "1", "MINIMALDATA", "OK"], +["0x02 0x0500", "1", "MINIMALDATA", "OK"], +["0x02 0x0600", "1", "MINIMALDATA", "OK"], +["0x02 0x0700", "1", "MINIMALDATA", "OK"], +["0x02 0x0800", "1", "MINIMALDATA", "OK"], +["0x02 0x0900", "1", "MINIMALDATA", "OK"], +["0x02 0x0a00", "1", "MINIMALDATA", "OK"], +["0x02 0x0b00", "1", "MINIMALDATA", "OK"], +["0x02 0x0c00", "1", "MINIMALDATA", "OK"], +["0x02 0x0d00", "1", "MINIMALDATA", "OK"], +["0x02 0x0e00", "1", "MINIMALDATA", "OK"], +["0x02 0x0f00", "1", "MINIMALDATA", "OK"], +["0x02 0x1000", "1", "MINIMALDATA", "OK"], + +["Valid version of the 'Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule' script_invalid test"], + +["1 0x02 0x0000", "PICK DROP", "", "OK"], +["1 0x02 0x0000", "ROLL DROP 1", "", "OK"], +["0x02 0x0000", "1ADD DROP 1", "", "OK"], +["0x02 0x0000", "1SUB DROP 1", "", "OK"], +["0x02 0x0000", "NEGATE DROP 1", "", "OK"], +["0x02 0x0000", "ABS DROP 1", "", "OK"], +["0x02 0x0000", "NOT DROP 1", "", "OK"], +["0x02 0x0000", "0NOTEQUAL DROP 1", "", "OK"], + +["0 0x02 0x0000", "ADD DROP 1", "", "OK"], +["0x02 0x0000 0", "ADD DROP 1", "", "OK"], +["0 0x02 0x0000", "SUB DROP 1", "", "OK"], +["0x02 0x0000 0", "SUB DROP 1", "", "OK"], +["0 0x02 0x0000", "BOOLAND DROP 1", "", "OK"], +["0x02 0x0000 0", "BOOLAND DROP 1", "", "OK"], +["0 0x02 0x0000", "BOOLOR DROP 1", "", "OK"], +["0x02 0x0000 0", "BOOLOR DROP 1", "", "OK"], +["0 0x02 0x0000", "NUMEQUAL DROP 1", "", "OK"], +["0x02 0x0000 1", "NUMEQUAL DROP 1", "", "OK"], +["0 0x02 0x0000", "NUMEQUALVERIFY 1", "", "OK"], +["0x02 0x0000 0", "NUMEQUALVERIFY 1", "", "OK"], +["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", "", "OK"], +["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", "", "OK"], +["0 0x02 0x0000", "LESSTHAN DROP 1", "", "OK"], +["0x02 0x0000 0", "LESSTHAN DROP 1", "", "OK"], +["0 0x02 0x0000", "GREATERTHAN DROP 1", "", "OK"], +["0x02 0x0000 0", "GREATERTHAN DROP 1", "", "OK"], +["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", "", "OK"], +["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", "", "OK"], +["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", "", "OK"], +["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", "", "OK"], +["0 0x02 0x0000", "MIN DROP 1", "", "OK"], +["0x02 0x0000 0", "MIN DROP 1", "", "OK"], +["0 0x02 0x0000", "MAX DROP 1", "", "OK"], +["0x02 0x0000 0", "MAX DROP 1", "", "OK"], + +["0x02 0x0000 0 0", "WITHIN DROP 1", "", "OK"], +["0 0x02 0x0000 0", "WITHIN DROP 1", "", "OK"], +["0 0 0x02 0x0000", "WITHIN DROP 1", "", "OK"], + +["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", "", "OK"], +["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", "", "OK"], +["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", "", "OK"], +["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", "", "OK"], +["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "", "OK"], + +["While not really correctly DER encoded, the empty signature is allowed by"], +["STRICTENC to provide a compact way to provide a delibrately invalid signature."], +["0", "0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 CHECKSIG NOT", "STRICTENC", "OK"], +["0 0", "1 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 1 CHECKMULTISIG NOT", "STRICTENC", "OK"], + +["CHECKMULTISIG evaluation order tests. CHECKMULTISIG evaluates signatures and"], +["pubkeys in a specific order, and will exit early if the number of signatures"], +["left to check is greater than the number of keys left. As STRICTENC fails the"], +["script when it reaches an invalidly encoded signature or pubkey, we can use it"], +["to test the exact order in which signatures and pubkeys are evaluated by"], +["distinguishing CHECKMULTISIG returning false on the stack and the script as a"], +["whole failing."], +["See also the corresponding inverted versions of these tests in script_invalid.json"], +[ + "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501", + "2 0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT", + "STRICTENC", "OK", + "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." +], +[ + "0 0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501", + "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT", + "STRICTENC", "OK", + "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." +], + +["Increase test coverage for DERSIG"], +["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "", "OK", "Overly long signature is correctly encoded"], +["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "", "OK", "Missing S is correctly encoded"], +["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "S with invalid S length is correctly encoded"], +["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Non-integer R is correctly encoded"], +["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Non-integer S is correctly encoded"], +["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Zero-length R is correctly encoded"], +["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "", "OK", "Zero-length S is correctly encoded for DERSIG"], +["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Negative S is correctly encoded"], + +["", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE", "Test the test: we should have an empty stack after scriptSig evaluation"], +[" ", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE", "and multiple spaces should not change that."], +[" ", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE"], +[" ", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE"], + +["", "", "P2SH,STRICTENC","EVAL_FALSE"], +["", "NOP", "P2SH,STRICTENC","EVAL_FALSE"], +["", "NOP DEPTH", "P2SH,STRICTENC", "EVAL_FALSE"], +["NOP", "", "P2SH,STRICTENC", "EVAL_FALSE"], +["NOP", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE"], +["NOP","NOP", "P2SH,STRICTENC", "EVAL_FALSE"], +["NOP","NOP DEPTH", "P2SH,STRICTENC", "EVAL_FALSE"], + +["DEPTH", "", "P2SH,STRICTENC", "EVAL_FALSE"], + +["0x4c01","0x01 NOP", "P2SH,STRICTENC","BAD_OPCODE", "PUSHDATA1 with not enough bytes"], +["0x4d0200ff","0x01 NOP", "P2SH,STRICTENC","BAD_OPCODE", "PUSHDATA2 with not enough bytes"], +["0x4e03000000ffff","0x01 NOP", "P2SH,STRICTENC","BAD_OPCODE", "PUSHDATA4 with not enough bytes"], + +["1", "IF 0x50 ENDIF 1", "P2SH,STRICTENC","BAD_OPCODE", "0x50 is reserved"], +["0x52", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC","EVAL_FALSE", "0x51 through 0x60 push 1 through 16 onto stack"], +["0","NOP", "P2SH,STRICTENC","EVAL_FALSE",""], +["1", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "VER non-functional"], +["0", "IF VERIF ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "VERIF illegal everywhere"], +["0", "IF ELSE 1 ELSE VERIF ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "VERIF illegal everywhere"], +["0", "IF VERNOTIF ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "VERNOTIF illegal everywhere"], +["0", "IF ELSE 1 ELSE VERNOTIF ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "VERNOTIF illegal everywhere"], + +["1 IF", "1 ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "IF/ENDIF can't span scriptSig/scriptPubKey"], +["1 IF 0 ENDIF", "1 ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL"], +["1 ELSE 0 ENDIF", "1", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL"], +["0 NOTIF", "123", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL"], + +["0", "DUP IF ENDIF", "P2SH,STRICTENC", "EVAL_FALSE"], +["0", "IF 1 ENDIF", "P2SH,STRICTENC", "EVAL_FALSE"], +["0", "DUP IF ELSE ENDIF", "P2SH,STRICTENC", "EVAL_FALSE"], +["0", "IF 1 ELSE ENDIF", "P2SH,STRICTENC", "EVAL_FALSE"], +["0", "NOTIF ELSE 1 ENDIF", "P2SH,STRICTENC", "EVAL_FALSE"], + +["0 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "EVAL_FALSE"], +["0 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "EVAL_FALSE"], +["1 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "EVAL_FALSE"], +["0 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "EVAL_FALSE"], + +["0 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "EVAL_FALSE"], +["0 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "EVAL_FALSE"], +["1 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "EVAL_FALSE"], +["0 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "EVAL_FALSE"], + +["1", "IF RETURN ELSE ELSE 1 ENDIF", "P2SH,STRICTENC", "OP_RETURN", "Multiple ELSEs"], +["1", "IF 1 ELSE ELSE RETURN ENDIF", "P2SH,STRICTENC", "OP_RETURN"], + +["1", "ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "Malformed IF/ELSE/ENDIF sequence"], +["1", "ELSE ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL"], +["1", "ENDIF ELSE", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL"], +["1", "ENDIF ELSE IF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL"], +["1", "IF ELSE ENDIF ELSE", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL"], +["1", "IF ELSE ENDIF ELSE ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL"], +["1", "IF ENDIF ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL"], +["1", "IF ELSE ELSE ENDIF ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL"], + +["1", "RETURN", "P2SH,STRICTENC", "OP_RETURN"], +["1", "DUP IF RETURN ENDIF", "P2SH,STRICTENC", "OP_RETURN"], + +["1", "RETURN 'data'", "P2SH,STRICTENC", "OP_RETURN", "canonical prunable txout format"], +["0 IF", "RETURN ENDIF 1", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "still prunable because IF/ENDIF can't span scriptSig/scriptPubKey"], + +["0", "VERIFY 1", "P2SH,STRICTENC", "VERIFY"], +["1", "VERIFY", "P2SH,STRICTENC", "EVAL_FALSE"], +["1", "VERIFY 0", "P2SH,STRICTENC", "EVAL_FALSE"], + +["1 TOALTSTACK", "FROMALTSTACK 1", "P2SH,STRICTENC", "INVALID_ALTSTACK_OPERATION", "alt stack not shared between sig/pubkey"], + +["IFDUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["DUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "DUP 1 ADD 2 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], +["NOP", "NIP", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "1 NIP", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "1 0 NIP", "P2SH,STRICTENC", "EVAL_FALSE"], +["NOP", "OVER 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "OVER", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["0 1", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC", "EVAL_FALSE"], +["19 20 21", "PICK 19 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "0 PICK", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "-1 PICK", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["19 20 21", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "EQUALVERIFY"], +["19 20 21", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "EQUALVERIFY"], +["19 20 21", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "EQUALVERIFY"], +["NOP", "0 ROLL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "-1 ROLL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["19 20 21", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "EQUALVERIFY"], +["19 20 21", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "EQUALVERIFY"], +["19 20 21", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "EQUALVERIFY"], +["NOP", "ROT 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "1 ROT 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "1 2 ROT 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "0 1 2 ROT", "P2SH,STRICTENC", "EVAL_FALSE"], +["NOP", "SWAP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "SWAP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["0 1", "SWAP 1 EQUALVERIFY", "P2SH,STRICTENC", "EQUALVERIFY"], +["NOP", "TUCK 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "TUCK 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1 0", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC", "EVAL_FALSE"], +["NOP", "2DUP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "2DUP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "3DUP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "3DUP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1 2", "3DUP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "2OVER 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "2 3 2OVER 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "2SWAP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "2 3 2SWAP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], + +["'a' 'b'", "CAT", "P2SH,STRICTENC", "DISABLED_OPCODE", "CAT disabled"], +["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "CAT disabled"], +["'abc' 1 1", "SUBSTR", "P2SH,STRICTENC", "DISABLED_OPCODE", "SUBSTR disabled"], +["'abc' 1 1 0", "IF SUBSTR ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "SUBSTR disabled"], +["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "LEFT disabled"], +["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "RIGHT disabled"], + +["NOP", "SIZE 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], + +["'abc'", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "INVERT disabled"], +["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "AND disabled"], +["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "OR disabled"], +["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "XOR disabled"], +["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "2MUL disabled"], +["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "2DIV disabled"], +["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "MUL disabled"], +["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "DIV disabled"], +["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "MOD disabled"], +["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "LSHIFT disabled"], +["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "RSHIFT disabled"], + +["", "EQUAL NOT", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "EQUAL must error when there are no stack items"], +["0", "EQUAL NOT", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "EQUAL must error when there are not 2 stack items"], +["0 1","EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], +["1 1 ADD", "0 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], +["11 1 ADD 12 SUB", "11 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], + +["2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "UNKNOWN_ERROR", "arithmetic operands must be in range [-2^31...2^31] "], +["-2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "UNKNOWN_ERROR", "arithmetic operands must be in range [-2^31...2^31] "], +["2147483647 DUP ADD", "4294967294 NUMEQUAL", "P2SH,STRICTENC", "UNKNOWN_ERROR", "NUMEQUAL must be in numeric range"], +["'abcdef' NOT", "0 EQUAL", "P2SH,STRICTENC", "UNKNOWN_ERROR", "NOT is an arithmetic operand"], + +["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], +["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], +["2 2MUL", "4 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], +["2 2DIV", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], +["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], +["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], +["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], + +["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], +["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], + +["Ensure 100% coverage of discouraged NOPS"], +["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "CHECKLOCKTIMEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP3", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP4", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP9", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP10", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], + +["NOP10", "1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in scriptSig"], + +["1 0x01 0xb9", "HASH160 0x14 0x15727299b05b45fdaf9ac9ecf7565cfe27c3e567 EQUAL", + "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in redeemScript"], + +["0x50","1", "P2SH,STRICTENC", "BAD_OPCODE", "opcode 0x50 is reserved"], +["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "opcodes above NOP10 invalid if executed"], +["1", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], + +["1 IF 1 ELSE", "0xff ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "invalid because scriptSig and scriptPubKey are processed separately"], + +["NOP", "RIPEMD160", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "SHA1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "SHA256", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "HASH160", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "HASH256", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], + +["NOP", +"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", +"P2SH,STRICTENC", +"PUSH_SIZE", +">20000 byte push"], +["0", +"IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1", +"P2SH,STRICTENC", +"SCRIPT_SIZE", +">20000 byte push in non-executed IF branch"], +["1", +"0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"P2SH,STRICTENC", +"OP_COUNT", +">201 opcodes executed. 0x61 is NOP"], +["0", +"IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1", +"P2SH,STRICTENC", +"OP_COUNT", +">201 opcodes including non-executed IF branch. 0x61 is NOP"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"P2SH,STRICTENC", +"STACK_SIZE", +">1,000 stack size (0x6f is 3DUP)"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 TOALTSTACK 2 TOALTSTACK 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"P2SH,STRICTENC", +"STACK_SIZE", +">1,000 stack+altstack size"], +["NOP", +"0 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"P2SH,STRICTENC", +"SCRIPT_SIZE", +"10,001-byte scriptPubKey"], + +["NOP1","NOP10", "P2SH,STRICTENC", "EVAL_FALSE"], + +["1","VER", "P2SH,STRICTENC", "BAD_OPCODE", "OP_VER is reserved"], +["1","VERIF", "P2SH,STRICTENC", "BAD_OPCODE", "OP_VERIF is reserved"], +["1","VERNOTIF", "P2SH,STRICTENC", "BAD_OPCODE", "OP_VERNOTIF is reserved"], +["1","RESERVED", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED is reserved"], +["1","RESERVED1", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED1 is reserved"], +["1","RESERVED2", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED2 is reserved"], +["1","0xba", "P2SH,STRICTENC", "BAD_OPCODE", "0xba == OP_NOP10 + 1"], + +["2147483648", "1ADD 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"], +["2147483648", "NEGATE 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"], +["-2147483648", "1ADD 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "Because we use a sign bit, -2147483648 is also 5 bytes"], +["2147483647", "1ADD 1SUB 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], +["2147483648", "1SUB 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], + +["2147483648 1", "BOOLOR 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)"], +["2147483648 1", "BOOLAND 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do BOOLAND on 5-byte integers"], + +["1", "1 ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "ENDIF without IF"], +["1", "IF 1", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "IF without ENDIF"], +["1 IF 1", "ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "IFs don't carry over"], + +["NOP", "IF 1 ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "The following tests check the if(stack.size() < N) tests in each opcode"], +["NOP", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "They are here to catch copy-and-paste errors"], +["NOP", "VERIFY 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "Most of them are duplicated elsewhere,"], + +["NOP", "TOALTSTACK 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "but, hey, more is always better, right?"], +["1", "FROMALTSTACK", "P2SH,STRICTENC", "INVALID_ALTSTACK_OPERATION"], +["1", "2DROP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "2DUP", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1 1", "3DUP", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1 1 1", "2OVER", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1 1 1 1 1", "2ROT", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1 1 1", "2SWAP", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "IFDUP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "DROP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "DUP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "NIP", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "OVER", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1 1 1 3", "PICK", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["0", "PICK 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1 1 1 3", "ROLL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["0", "ROLL 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1 1", "ROT", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "SWAP", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "TUCK", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], + +["NOP", "SIZE 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], + +["1", "EQUAL 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "EQUALVERIFY 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], + +["NOP", "1ADD 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "1SUB 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "NEGATE 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "ABS 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "NOT 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "0NOTEQUAL 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], + +["1", "ADD", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "SUB", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "BOOLAND", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "BOOLOR", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "NUMEQUAL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "NUMEQUALVERIFY 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "NUMNOTEQUAL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "LESSTHAN", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "GREATERTHAN", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "LESSTHANOREQUAL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "GREATERTHANOREQUAL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "MIN", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1", "MAX", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["1 1", "WITHIN", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], + +["NOP", "RIPEMD160 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "SHA1 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "SHA256 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "HASH160 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], +["NOP", "HASH256 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], + +["Increase CHECKSIG and CHECKMULTISIG negative test coverage"], +["", "CHECKSIG NOT", "STRICTENC", "INVALID_STACK_OPERATION", "CHECKSIG must error when there are no stack items"], +["0", "CHECKSIG NOT", "STRICTENC", "INVALID_STACK_OPERATION", "CHECKSIG must error when there are not 2 stack items"], +["", "CHECKMULTISIG NOT", "STRICTENC", "INVALID_STACK_OPERATION", "CHECKMULTISIG must error when there are no stack items"], +["", "-1 CHECKMULTISIG NOT", "STRICTENC", "PUBKEY_COUNT", "CHECKMULTISIG must error when the specified number of pubkeys is negative"], +["", "1 CHECKMULTISIG NOT", "STRICTENC", "INVALID_STACK_OPERATION", "CHECKMULTISIG must error when there are not enough pubkeys on the stack"], +["", "-1 0 CHECKMULTISIG NOT", "STRICTENC", "SIG_COUNT", "CHECKMULTISIG must error when the specified number of signatures is negative"], +["", "1 'pk1' 1 CHECKMULTISIG NOT", "STRICTENC", "INVALID_STACK_OPERATION", "CHECKMULTISIG must error when there are not enough signatures on the stack"], +["", "'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"], + +["", +"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", +"P2SH,STRICTENC", +"OP_COUNT", +"202 CHECKMULTISIGS, fails due to 201 op limit"], + +["1", +"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", +"P2SH,STRICTENC", +"INVALID_STACK_OPERATION", +""], + +["", +"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", +"P2SH,STRICTENC", +"OP_COUNT", +"Fails due to 201 sig op limit"], + +["1", +"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", +"P2SH,STRICTENC", +"OP_COUNT", +""], + + +["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"], +["0 'sig' 1 0", "CHECKMULTISIG 1", "P2SH,STRICTENC", "SIG_COUNT", "nSigs > nPubKeys"], + + +["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "SIG_PUSHONLY", "Tests for Script.IsPushOnly()"], +["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "SIG_PUSHONLY"], + +["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED in P2SH should fail"], +["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "P2SH,STRICTENC", "BAD_OPCODE", "OP_VER in P2SH should fail"], + +["0x00", "'00' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE", "Basic OP_0 execution"], + +["MINIMALDATA enforcement for PUSHDATAs"], + +["0x4c 0x00", "DROP 1", "MINIMALDATA", "MINIMALDATA", "Empty vector minimally represented by OP_0"], +["0x01 0x81", "DROP 1", "MINIMALDATA", "MINIMALDATA", "-1 minimally represented by OP_1NEGATE"], +["0x01 0x01", "DROP 1", "MINIMALDATA", "MINIMALDATA", "1 to 16 minimally represented by OP_1 to OP_16"], +["0x01 0x02", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x03", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x04", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x05", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x06", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x07", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x08", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x09", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x0a", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x0b", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x0c", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x0d", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x0e", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x0f", "DROP 1", "MINIMALDATA", "MINIMALDATA"], +["0x01 0x10", "DROP 1", "MINIMALDATA", "MINIMALDATA"], + +["0x4c 0x48 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", + "MINIMALDATA", + "PUSHDATA1 of 72 bytes minimally represented by direct push"], + +["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", + "MINIMALDATA", + "PUSHDATA2 of 255 bytes minimally represented by PUSHDATA1"], + +["0x4e 0x00010000 0x11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", + "MINIMALDATA", + "PUSHDATA4 of 256 bytes minimally represented by PUSHDATA2"], + +["MINIMALDATA enforcement for numeric arguments"], + +["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 0"], +["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 0"], +["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "0x80 (negative zero) numequals 0"], +["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 0"], +["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 5"], +["0x03 0x050000", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 5"], +["0x02 0x0580", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals -5"], +["0x03 0x050080", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals -5"], +["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "Minimal encoding is 0xffff"], +["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "Minimal encoding is 0xff7f"], +["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "Minimal encoding is 0xffffff"], +["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "Minimal encoding is 0xffff7f"], + +["Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule"], + +["1 0x02 0x0000", "PICK DROP", "MINIMALDATA", "UNKNOWN_ERROR"], +["1 0x02 0x0000", "ROLL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000", "1ADD DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000", "1SUB DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000", "NEGATE DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000", "ABS DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000", "0NOTEQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], + +["0 0x02 0x0000", "ADD DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "ADD DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "SUB DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "SUB DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "BOOLAND DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "BOOLAND DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "BOOLOR DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "BOOLOR DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "NUMEQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 1", "NUMEQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "NUMEQUALVERIFY 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "NUMEQUALVERIFY 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "LESSTHAN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "LESSTHAN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "GREATERTHAN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "GREATERTHAN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "MIN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "MIN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "MAX DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 0", "MAX DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], + +["0x02 0x0000 0 0", "WITHIN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000 0", "WITHIN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0 0x02 0x0000", "WITHIN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], + +["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "MINIMALDATA", "UNKNOWN_ERROR"], + + +["Order of CHECKMULTISIG evaluation tests, inverted by swapping the order of"], +["pubkeys/signatures so they fail due to the STRICTENC rules on validly encoded"], +["signatures and pubkeys."], +[ + "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501", + "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0 2 CHECKMULTISIG NOT", + "STRICTENC", + "PUBKEYTYPE", + "2-of-2 CHECKMULTISIG NOT with the first pubkey invalid, and both signatures validly encoded." +], +[ + "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 1", + "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT", + "STRICTENC", + "SIG_DER", + "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid." +], +[ + "0 0x47 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f01 0x46 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f", + "2 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 3 CHECKMULTISIG", + "P2SH,STRICTENC", + "SIG_DER", + "2-of-3 with one valid and one invalid signature due to parse error, nSigs > validSigs" +], + +["Increase DERSIG test coverage"], +["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Overly long signature is incorrectly encoded for DERSIG"], +["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Missing S is incorrectly encoded for DERSIG"], +["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "S with invalid S length is incorrectly encoded for DERSIG"], +["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Non-integer R is incorrectly encoded for DERSIG"], +["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Non-integer S is incorrectly encoded for DERSIG"], +["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Zero-length R is incorrectly encoded for DERSIG"], +["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Zero-length S is incorrectly encoded for DERSIG"], +["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "SIG_DER", "Negative S is incorrectly encoded for DERSIG"], + +["Automatically generated test cases"], +[ + "0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "", + "OK", + "P2PK" +], +[ + "0x47 0x304402200a5c6163f07b8c3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "", + "EVAL_FALSE", + "P2PK, bad sig" +], +[ + "0x47 0x304402206e05a6fe23c59196ffe176c9ddc31e73a9885638f9d1328d47c0c703863b8876022076feb53811aa5b04e0e79f938eb19906cc5e67548bc555a8e8b8b0fc603d840c01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", + "DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG", + "", + "OK", + "P2PKH" +], +[ + "0x47 0x3044022034bb0494b50b8ef130e2185bb220265b9284ef5b4b8a8da4d8415df489c83b5102206259a26d9cc0a125ac26af6153b17c02956855ebe1467412f066e402f5f05d1201 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", + "DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG", + "", + "EQUALVERIFY", + "P2PKH, bad pubkey" +], +[ + "0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790281", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", + "", + "OK", + "P2PK anyonecanpay" +], +[ + "0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790201", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", + "", + "EVAL_FALSE", + "P2PK anyonecanpay marked with normal hashtype" +], +[ + "0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", + "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", + "P2SH", + "OK", + "P2SH(P2PK)" +], +[ + "0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", + "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", + "P2SH", + "EVAL_FALSE", + "P2SH(P2PK), bad redeemscript" +], +[ + "0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", + "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", + "", + "OK", + "P2SH(P2PKH), bad sig but no VERIFY_P2SH" +], +[ + "0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", + "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", + "P2SH", + "EQUALVERIFY", + "P2SH(P2PKH), bad sig" +], +[ + "0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", + "", + "OK", + "3-of-3" +], +[ + "0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", + "", + "EVAL_FALSE", + "3-of-3, 2 sigs" +], +[ + "0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0x47 0x30440220563e5b3b1fc11662a84bc5ea2a32cc3819703254060ba30d639a1aaf2d5068ad0220601c1f47ddc76d93284dd9ed68f7c9974c4a0ea7cbe8a247d6bc3878567a5fca01 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", + "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", + "P2SH", + "OK", + "P2SH(2-of-3)" +], +[ + "0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", + "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", + "P2SH", + "EVAL_FALSE", + "P2SH(2-of-3), 1 sig" +], +[ + "0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "OK", + "P2PK with too much R padding but no DERSIG" +], +[ + "0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "DERSIG", + "SIG_DER", + "P2PK with too much R padding" +], +[ + "0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "OK", + "P2PK with too much S padding but no DERSIG" +], +[ + "0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "DERSIG", + "SIG_DER", + "P2PK with too much S padding" +], +[ + "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "OK", + "P2PK with too little R padding but no DERSIG" +], +[ + "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "DERSIG", + "SIG_DER", + "P2PK with too little R padding" +], +[ + "0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", + "", + "OK", + "P2PK NOT with bad sig with too much R padding but no DERSIG" +], +[ + "0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", + "DERSIG", + "SIG_DER", + "P2PK NOT with bad sig with too much R padding" +], +[ + "0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", + "", + "EVAL_FALSE", + "P2PK NOT with too much R padding but no DERSIG" +], +[ + "0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", + "DERSIG", + "SIG_DER", + "P2PK NOT with too much R padding" +], +[ + "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "OK", + "BIP66 example 1, without DERSIG" +], +[ + "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "DERSIG", + "SIG_DER", + "BIP66 example 1, with DERSIG" +], +[ + "0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "", + "EVAL_FALSE", + "BIP66 example 2, without DERSIG" +], +[ + "0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "DERSIG", + "SIG_DER", + "BIP66 example 2, with DERSIG" +], +[ + "0", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "EVAL_FALSE", + "BIP66 example 3, without DERSIG" +], +[ + "0", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "DERSIG", + "EVAL_FALSE", + "BIP66 example 3, with DERSIG" +], +[ + "0", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "", + "OK", + "BIP66 example 4, without DERSIG" +], +[ + "0", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "DERSIG", + "OK", + "BIP66 example 4, with DERSIG" +], +[ + "1", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "EVAL_FALSE", + "BIP66 example 5, without DERSIG" +], +[ + "1", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "DERSIG", + "SIG_DER", + "BIP66 example 5, with DERSIG" +], +[ + "1", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "", + "OK", + "BIP66 example 6, without DERSIG" +], +[ + "1", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", + "DERSIG", + "SIG_DER", + "BIP66 example 6, with DERSIG" +], +[ + "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", + "", + "OK", + "BIP66 example 7, without DERSIG" +], +[ + "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", + "DERSIG", + "SIG_DER", + "BIP66 example 7, with DERSIG" +], +[ + "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", + "", + "EVAL_FALSE", + "BIP66 example 8, without DERSIG" +], +[ + "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", + "DERSIG", + "SIG_DER", + "BIP66 example 8, with DERSIG" +], +[ + "0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", + "", + "EVAL_FALSE", + "BIP66 example 9, without DERSIG" +], +[ + "0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", + "DERSIG", + "SIG_DER", + "BIP66 example 9, with DERSIG" +], +[ + "0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", + "", + "OK", + "BIP66 example 10, without DERSIG" +], +[ + "0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", + "DERSIG", + "SIG_DER", + "BIP66 example 10, with DERSIG" +], +[ + "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", + "", + "EVAL_FALSE", + "BIP66 example 11, without DERSIG" +], +[ + "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", + "DERSIG", + "EVAL_FALSE", + "BIP66 example 11, with DERSIG" +], +[ + "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", + "", + "OK", + "BIP66 example 12, without DERSIG" +], +[ + "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", + "DERSIG", + "OK", + "BIP66 example 12, with DERSIG" +], +[ + "0x48 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb12510101", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "", + "OK", + "P2PK with multi-byte hashtype, without DERSIG" +], +[ + "0x48 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb12510101", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "DERSIG", + "SIG_DER", + "P2PK with multi-byte hashtype, with DERSIG" +], +[ + "0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "", + "OK", + "P2PK with high S but no LOW_S" +], +[ + "0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "LOW_S", + "SIG_HIGH_S", + "P2PK with high S" +], +[ + "0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "", + "OK", + "P2PK with hybrid pubkey but no STRICTENC" +], +[ + "0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "STRICTENC", + "PUBKEYTYPE", + "P2PK with hybrid pubkey" +], +[ + "0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", + "", + "EVAL_FALSE", + "P2PK NOT with hybrid pubkey but no STRICTENC" +], +[ + "0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", + "STRICTENC", + "PUBKEYTYPE", + "P2PK NOT with hybrid pubkey" +], +[ + "0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", + "", + "OK", + "P2PK NOT with invalid hybrid pubkey but no STRICTENC" +], +[ + "0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", + "STRICTENC", + "PUBKEYTYPE", + "P2PK NOT with invalid hybrid pubkey" +], +[ + "0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401", + "1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", + "", + "OK", + "1-of-2 with the second 1 hybrid pubkey and no STRICTENC" +], +[ + "0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401", + "1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", + "STRICTENC", + "OK", + "1-of-2 with the second 1 hybrid pubkey" +], +[ + "0 0x47 0x3044022079c7824d6c868e0e1a273484e28c2654a27d043c8a27f49f52cb72efed0759090220452bbbf7089574fa082095a4fc1b3a16bafcf97a3a34d745fafc922cce66b27201", + "1 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 2 CHECKMULTISIG", + "STRICTENC", + "PUBKEYTYPE", + "1-of-2 with the first 1 hybrid pubkey" +], +[ + "0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", + "", + "OK", + "P2PK with undefined hashtype but no STRICTENC" +], +[ + "0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", + "STRICTENC", + "SIG_HASHTYPE", + "P2PK with undefined hashtype" +], +[ + "0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT", + "", + "OK", + "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC" +], +[ + "0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT", + "STRICTENC", + "SIG_HASHTYPE", + "P2PK NOT with invalid sig and undefined hashtype" +], +[ + "1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", + "", + "OK", + "3-of-3 with nonzero dummy but no NULLDUMMY" +], +[ + "1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", + "NULLDUMMY", + "SIG_NULLDUMMY", + "3-of-3 with nonzero dummy" +], +[ + "1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT", + "", + "OK", + "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY" +], +[ + "1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT", + "NULLDUMMY", + "SIG_NULLDUMMY", + "3-of-3 NOT with invalid sig with nonzero dummy" +], +[ + "0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", + "", + "OK", + "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY" +], +[ + "0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", + "SIGPUSHONLY", + "SIG_PUSHONLY", + "2-of-2 with two identical keys and sigs pushed using OP_DUP" +], +[ + "0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP9 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", + "HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL", + "", + "OK", + "P2SH(P2PK) with non-push scriptSig but no P2SH or SIGPUSHONLY" +], +[ + "0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 NOP9", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "", + "OK", + "P2PK with non-push scriptSig but with P2SH validation" +], +[ + "0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP9 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", + "HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL", + "P2SH", + "SIG_PUSHONLY", + "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY" +], +[ + "0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP9 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", + "HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL", + "SIGPUSHONLY", + "SIG_PUSHONLY", + "P2SH(P2PK) with non-push scriptSig but not P2SH" +], +[ + "0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", + "SIGPUSHONLY", + "OK", + "2-of-2 with two identical keys and sigs pushed" +], +[ + "11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "P2SH", + "OK", + "P2PK with unnecessary input but no CLEANSTACK" +], +[ + "11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "CLEANSTACK,P2SH", + "CLEANSTACK", + "P2PK with unnecessary input" +], +[ + "11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac", + "HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL", + "P2SH", + "OK", + "P2SH with unnecessary input but no CLEANSTACK" +], +[ + "11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac", + "HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL", + "CLEANSTACK,P2SH", + "CLEANSTACK", + "P2SH with unnecessary input" +], +[ + "0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac", + "HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL", + "CLEANSTACK,P2SH", + "OK", + "P2SH with CLEANSTACK" +], + +["The End"] +] diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json deleted file mode 100644 index 47d49db81..000000000 --- a/src/test/data/script_valid.json +++ /dev/null @@ -1,907 +0,0 @@ -[ -["Format is: [scriptSig, scriptPubKey, flags, ... comments]"], -["It is evaluated as if there was a crediting coinbase transaction with two 0"], -["pushes as scriptSig, and one output of 0 satoshi and given scriptPubKey,"], -["followed by a spending transaction which spends this output as only input (and"], -["correct prevout hash), using the given scriptSig. All nLockTimes are 0, all"], -["nSequences are max."], - -["", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation"], -[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "and multiple spaces should not change that."], -[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "Similarly whitespace around and between symbols"], -["1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], -[" 1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], -["1 2 ", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], -[" 1 2 ", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], - -["1", "", "P2SH,STRICTENC"], -["0x02 0x01 0x00", "", "P2SH,STRICTENC", "all bytes are significant, not only the last one"], -["0x09 0x00000000 0x00000000 0x10", "", "P2SH,STRICTENC", "equals zero when cast to Int64"], - -["0x01 0x0b", "11 EQUAL", "P2SH,STRICTENC", "push 1 byte"], -["0x02 0x417a", "'Az' EQUAL", "P2SH,STRICTENC"], -["0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a", - "'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL", "P2SH,STRICTENC", "push 75 bytes"], - -["0x4c 0x01 0x07","7 EQUAL", "P2SH,STRICTENC", "0x4c is OP_PUSHDATA1"], -["0x4d 0x0100 0x08","8 EQUAL", "P2SH,STRICTENC", "0x4d is OP_PUSHDATA2"], -["0x4e 0x01000000 0x09","9 EQUAL", "P2SH,STRICTENC", "0x4e is OP_PUSHDATA4"], - -["0x4c 0x00","0 EQUAL", "P2SH,STRICTENC"], -["0x4d 0x0000","0 EQUAL", "P2SH,STRICTENC"], -["0x4e 0x00000000","0 EQUAL", "P2SH,STRICTENC"], -["0x4f 1000 ADD","999 EQUAL", "P2SH,STRICTENC"], -["0", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved (ok if not executed)"], -["0x51", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "0x51 through 0x60 push 1 through 16 onto stack"], -["1","NOP", "P2SH,STRICTENC"], -["0", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "VER non-functional (ok if not executed)"], -["0", "IF RESERVED RESERVED1 RESERVED2 ELSE 1 ENDIF", "P2SH,STRICTENC", "RESERVED ok in un-executed IF"], - -["1", "DUP IF ENDIF", "P2SH,STRICTENC"], -["1", "IF 1 ENDIF", "P2SH,STRICTENC"], -["1", "DUP IF ELSE ENDIF", "P2SH,STRICTENC"], -["1", "IF 1 ELSE ENDIF", "P2SH,STRICTENC"], -["0", "IF ELSE 1 ENDIF", "P2SH,STRICTENC"], - -["1 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], - -["1 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], - -["0", "IF 0 ELSE 1 ELSE 0 ENDIF", "P2SH,STRICTENC", "Multiple ELSE's are valid and executed inverts on each ELSE encountered"], -["1", "IF 1 ELSE 0 ELSE ENDIF", "P2SH,STRICTENC"], -["1", "IF ELSE 0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL", "P2SH,STRICTENC"], -["'' 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"], - -["1", "NOTIF 0 ELSE 1 ELSE 0 ENDIF", "P2SH,STRICTENC", "Multiple ELSE's are valid and execution inverts on each ELSE encountered"], -["0", "NOTIF 1 ELSE 0 ELSE ENDIF", "P2SH,STRICTENC"], -["0", "NOTIF ELSE 0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "NOTIF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL", "P2SH,STRICTENC"], -["'' 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"], - -["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", "Nested ELSE ELSE"], -["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"], - -["0", "IF RETURN ENDIF 1", "P2SH,STRICTENC", "RETURN only works if executed"], - -["1 1", "VERIFY", "P2SH,STRICTENC"], -["1 0x05 0x01 0x00 0x00 0x00 0x00", "VERIFY", "P2SH,STRICTENC", "values >4 bytes can be cast to boolean"], -["1 0x01 0x80", "IF 0 ENDIF", "P2SH,STRICTENC", "negative 0 is false"], - -["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 21 EQUAL", "P2SH,STRICTENC"], -["'gavin_was_here' TOALTSTACK 11 FROMALTSTACK", "'gavin_was_here' EQUALVERIFY 11 EQUAL", "P2SH,STRICTENC"], - -["0 IFDUP", "DEPTH 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"], -["1 IFDUP", "DEPTH 2 EQUALVERIFY 1 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], -["0x05 0x0100000000 IFDUP", "DEPTH 2 EQUALVERIFY 0x05 0x0100000000 EQUAL", "P2SH,STRICTENC", "IFDUP dups non ints"], -["0 DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["0", "DUP 1 ADD 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"], -["0 1", "NIP", "P2SH,STRICTENC"], -["1 0", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC"], -["22 21 20", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "ROT 22 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "ROT DROP 20 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "ROT DROP DROP 21 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "ROT ROT 21 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "ROT ROT ROT 20 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 24 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT DROP 25 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 2DROP 20 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 2DROP DROP 21 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 2DROP 2DROP 22 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 2DROP 2DROP DROP 23 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 2ROT 22 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 2ROT 2ROT 20 EQUAL", "P2SH,STRICTENC"], -["1 0", "SWAP 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"], -["0 1", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC"], -["13 14", "2DUP ROT EQUALVERIFY EQUAL", "P2SH,STRICTENC"], -["-1 0 1 2", "3DUP DEPTH 7 EQUALVERIFY ADD ADD 3 EQUALVERIFY 2DROP 0 EQUALVERIFY", "P2SH,STRICTENC"], -["1 2 3 5", "2OVER ADD ADD 8 EQUALVERIFY ADD ADD 6 EQUAL", "P2SH,STRICTENC"], -["1 3 5 7", "2SWAP ADD 4 EQUALVERIFY ADD 12 EQUAL", "P2SH,STRICTENC"], -["0", "SIZE 0 EQUAL", "P2SH,STRICTENC"], -["1", "SIZE 1 EQUAL", "P2SH,STRICTENC"], -["127", "SIZE 1 EQUAL", "P2SH,STRICTENC"], -["128", "SIZE 2 EQUAL", "P2SH,STRICTENC"], -["32767", "SIZE 2 EQUAL", "P2SH,STRICTENC"], -["32768", "SIZE 3 EQUAL", "P2SH,STRICTENC"], -["8388607", "SIZE 3 EQUAL", "P2SH,STRICTENC"], -["8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC"], -["2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC"], -["2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC"], -["549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC"], -["549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC"], -["9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC"], -["-1", "SIZE 1 EQUAL", "P2SH,STRICTENC"], -["-127", "SIZE 1 EQUAL", "P2SH,STRICTENC"], -["-128", "SIZE 2 EQUAL", "P2SH,STRICTENC"], -["-32767", "SIZE 2 EQUAL", "P2SH,STRICTENC"], -["-32768", "SIZE 3 EQUAL", "P2SH,STRICTENC"], -["-8388607", "SIZE 3 EQUAL", "P2SH,STRICTENC"], -["-8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC"], -["-2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC"], -["-2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC"], -["-549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC"], -["-549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC"], -["-9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC"], -["'abcdefghijklmnopqrstuvwxyz'", "SIZE 26 EQUAL", "P2SH,STRICTENC"], - -["42", "SIZE 1 EQUALVERIFY 42 EQUAL", "P2SH,STRICTENC", "SIZE does not consume argument"], - -["2 -2 ADD", "0 EQUAL", "P2SH,STRICTENC"], -["2147483647 -2147483647 ADD", "0 EQUAL", "P2SH,STRICTENC"], -["-1 -1 ADD", "-2 EQUAL", "P2SH,STRICTENC"], - -["0 0","EQUAL", "P2SH,STRICTENC"], -["1 1 ADD", "2 EQUAL", "P2SH,STRICTENC"], -["1 1ADD", "2 EQUAL", "P2SH,STRICTENC"], -["111 1SUB", "110 EQUAL", "P2SH,STRICTENC"], -["111 1 ADD 12 SUB", "100 EQUAL", "P2SH,STRICTENC"], -["0 ABS", "0 EQUAL", "P2SH,STRICTENC"], -["16 ABS", "16 EQUAL", "P2SH,STRICTENC"], -["-16 ABS", "-16 NEGATE EQUAL", "P2SH,STRICTENC"], -["0 NOT", "NOP", "P2SH,STRICTENC"], -["1 NOT", "0 EQUAL", "P2SH,STRICTENC"], -["11 NOT", "0 EQUAL", "P2SH,STRICTENC"], -["0 0NOTEQUAL", "0 EQUAL", "P2SH,STRICTENC"], -["1 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC"], -["111 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC"], -["-111 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC"], -["1 1 BOOLAND", "NOP", "P2SH,STRICTENC"], -["1 0 BOOLAND", "NOT", "P2SH,STRICTENC"], -["0 1 BOOLAND", "NOT", "P2SH,STRICTENC"], -["0 0 BOOLAND", "NOT", "P2SH,STRICTENC"], -["16 17 BOOLAND", "NOP", "P2SH,STRICTENC"], -["1 1 BOOLOR", "NOP", "P2SH,STRICTENC"], -["1 0 BOOLOR", "NOP", "P2SH,STRICTENC"], -["0 1 BOOLOR", "NOP", "P2SH,STRICTENC"], -["0 0 BOOLOR", "NOT", "P2SH,STRICTENC"], -["16 17 BOOLOR", "NOP", "P2SH,STRICTENC"], -["11 10 1 ADD", "NUMEQUAL", "P2SH,STRICTENC"], -["11 10 1 ADD", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"], -["11 10 1 ADD", "NUMNOTEQUAL NOT", "P2SH,STRICTENC"], -["111 10 1 ADD", "NUMNOTEQUAL", "P2SH,STRICTENC"], -["11 10", "LESSTHAN NOT", "P2SH,STRICTENC"], -["4 4", "LESSTHAN NOT", "P2SH,STRICTENC"], -["10 11", "LESSTHAN", "P2SH,STRICTENC"], -["-11 11", "LESSTHAN", "P2SH,STRICTENC"], -["-11 -10", "LESSTHAN", "P2SH,STRICTENC"], -["11 10", "GREATERTHAN", "P2SH,STRICTENC"], -["4 4", "GREATERTHAN NOT", "P2SH,STRICTENC"], -["10 11", "GREATERTHAN NOT", "P2SH,STRICTENC"], -["-11 11", "GREATERTHAN NOT", "P2SH,STRICTENC"], -["-11 -10", "GREATERTHAN NOT", "P2SH,STRICTENC"], -["11 10", "LESSTHANOREQUAL NOT", "P2SH,STRICTENC"], -["4 4", "LESSTHANOREQUAL", "P2SH,STRICTENC"], -["10 11", "LESSTHANOREQUAL", "P2SH,STRICTENC"], -["-11 11", "LESSTHANOREQUAL", "P2SH,STRICTENC"], -["-11 -10", "LESSTHANOREQUAL", "P2SH,STRICTENC"], -["11 10", "GREATERTHANOREQUAL", "P2SH,STRICTENC"], -["4 4", "GREATERTHANOREQUAL", "P2SH,STRICTENC"], -["10 11", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC"], -["-11 11", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC"], -["-11 -10", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC"], -["1 0 MIN", "0 NUMEQUAL", "P2SH,STRICTENC"], -["0 1 MIN", "0 NUMEQUAL", "P2SH,STRICTENC"], -["-1 0 MIN", "-1 NUMEQUAL", "P2SH,STRICTENC"], -["0 -2147483647 MIN", "-2147483647 NUMEQUAL", "P2SH,STRICTENC"], -["2147483647 0 MAX", "2147483647 NUMEQUAL", "P2SH,STRICTENC"], -["0 100 MAX", "100 NUMEQUAL", "P2SH,STRICTENC"], -["-100 0 MAX", "0 NUMEQUAL", "P2SH,STRICTENC"], -["0 -2147483647 MAX", "0 NUMEQUAL", "P2SH,STRICTENC"], -["0 0 1", "WITHIN", "P2SH,STRICTENC"], -["1 0 1", "WITHIN NOT", "P2SH,STRICTENC"], -["0 -2147483647 2147483647", "WITHIN", "P2SH,STRICTENC"], -["-1 -100 100", "WITHIN", "P2SH,STRICTENC"], -["11 -100 100", "WITHIN", "P2SH,STRICTENC"], -["-2147483647 -100 100", "WITHIN NOT", "P2SH,STRICTENC"], -["2147483647 -100 100", "WITHIN NOT", "P2SH,STRICTENC"], - -["2147483647 2147483647 SUB", "0 EQUAL", "P2SH,STRICTENC"], -["2147483647 DUP ADD", "4294967294 EQUAL", "P2SH,STRICTENC", ">32 bit EQUAL is valid"], -["2147483647 NEGATE DUP ADD", "-4294967294 EQUAL", "P2SH,STRICTENC"], - -["''", "RIPEMD160 0x14 0x9c1185a5c5e9fc54612808977ee8f548b2258d31 EQUAL", "P2SH,STRICTENC"], -["'a'", "RIPEMD160 0x14 0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffe EQUAL", "P2SH,STRICTENC"], -["'abcdefghijklmnopqrstuvwxyz'", "RIPEMD160 0x14 0xf71c27109c692c1b56bbdceb5b9d2865b3708dbc EQUAL", "P2SH,STRICTENC"], -["''", "SHA1 0x14 0xda39a3ee5e6b4b0d3255bfef95601890afd80709 EQUAL", "P2SH,STRICTENC"], -["'a'", "SHA1 0x14 0x86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 EQUAL", "P2SH,STRICTENC"], -["'abcdefghijklmnopqrstuvwxyz'", "SHA1 0x14 0x32d10c7b8cf96570ca04ce37f2a19d84240d3a89 EQUAL", "P2SH,STRICTENC"], -["''", "SHA256 0x20 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 EQUAL", "P2SH,STRICTENC"], -["'a'", "SHA256 0x20 0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb EQUAL", "P2SH,STRICTENC"], -["'abcdefghijklmnopqrstuvwxyz'", "SHA256 0x20 0x71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 EQUAL", "P2SH,STRICTENC"], -["''", "DUP HASH160 SWAP SHA256 RIPEMD160 EQUAL", "P2SH,STRICTENC"], -["''", "DUP HASH256 SWAP SHA256 SHA256 EQUAL", "P2SH,STRICTENC"], -["''", "NOP HASH160 0x14 0xb472a266d0bd89c13706a4132ccfb16f7c3b9fcb EQUAL", "P2SH,STRICTENC"], -["'a'", "HASH160 NOP 0x14 0x994355199e516ff76c4fa4aab39337b9d84cf12b EQUAL", "P2SH,STRICTENC"], -["'abcdefghijklmnopqrstuvwxyz'", "HASH160 0x4c 0x14 0xc286a1af0947f58d1ad787385b1c2c4a976f9e71 EQUAL", "P2SH,STRICTENC"], -["''", "HASH256 0x20 0x5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456 EQUAL", "P2SH,STRICTENC"], -["'a'", "HASH256 0x20 0xbf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8 EQUAL", "P2SH,STRICTENC"], -["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL", "P2SH,STRICTENC"], - - -["1","NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC"], -["'NOP_1_to_10' NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC"], - -["1", "NOP", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "Discourage NOPx flag allows OP_NOP"], - -["0", "IF NOP10 ENDIF 1", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", - "Discouraged NOPs are allowed if not executed"], - -["0", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "opcodes above NOP10 invalid if executed"], -["0", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC"], - -["NOP", -"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", -"P2SH,STRICTENC", -"520 byte push"], -["1", -"0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", -"P2SH,STRICTENC", -"201 opcodes executed. 0x61 is NOP"], -["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"P2SH,STRICTENC", -"1,000 stack size (0x6f is 3DUP)"], -["1 TOALTSTACK 2 TOALTSTACK 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"1 2 3 4 5 6 7 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"P2SH,STRICTENC", -"1,000 stack size (altstack cleared between scriptSig/scriptPubKey)"], -["'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", -"P2SH,STRICTENC", -"Max-size (10,000-byte), max-push(520 bytes), max-opcodes(201), max stack size(1,000 items). 0x6f is 3DUP, 0x61 is NOP"], - -["0", -"IF 0x5050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050 ENDIF 1", -"P2SH,STRICTENC", -">201 opcodes, but RESERVED (0x50) doesn't count towards opcode limit."], - -["NOP","1", "P2SH,STRICTENC"], - -["1", "0x01 0x01 EQUAL", "P2SH,STRICTENC", "The following is useful for checking implementations of BN_bn2mpi"], -["127", "0x01 0x7F EQUAL", "P2SH,STRICTENC"], -["128", "0x02 0x8000 EQUAL", "P2SH,STRICTENC", "Leave room for the sign bit"], -["32767", "0x02 0xFF7F EQUAL", "P2SH,STRICTENC"], -["32768", "0x03 0x008000 EQUAL", "P2SH,STRICTENC"], -["8388607", "0x03 0xFFFF7F EQUAL", "P2SH,STRICTENC"], -["8388608", "0x04 0x00008000 EQUAL", "P2SH,STRICTENC"], -["2147483647", "0x04 0xFFFFFF7F EQUAL", "P2SH,STRICTENC"], -["2147483648", "0x05 0x0000008000 EQUAL", "P2SH,STRICTENC"], -["549755813887", "0x05 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC"], -["549755813888", "0x06 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC"], -["9223372036854775807", "0x08 0xFFFFFFFFFFFFFF7F EQUAL", "P2SH,STRICTENC"], -["-1", "0x01 0x81 EQUAL", "P2SH,STRICTENC", "Numbers are little-endian with the MSB being a sign bit"], -["-127", "0x01 0xFF EQUAL", "P2SH,STRICTENC"], -["-128", "0x02 0x8080 EQUAL", "P2SH,STRICTENC"], -["-32767", "0x02 0xFFFF EQUAL", "P2SH,STRICTENC"], -["-32768", "0x03 0x008080 EQUAL", "P2SH,STRICTENC"], -["-8388607", "0x03 0xFFFFFF EQUAL", "P2SH,STRICTENC"], -["-8388608", "0x04 0x00008080 EQUAL", "P2SH,STRICTENC"], -["-2147483647", "0x04 0xFFFFFFFF EQUAL", "P2SH,STRICTENC"], -["-2147483648", "0x05 0x0000008080 EQUAL", "P2SH,STRICTENC"], -["-4294967295", "0x05 0xFFFFFFFF80 EQUAL", "P2SH,STRICTENC"], -["-549755813887", "0x05 0xFFFFFFFFFF EQUAL", "P2SH,STRICTENC"], -["-549755813888", "0x06 0x000000008080 EQUAL", "P2SH,STRICTENC"], -["-9223372036854775807", "0x08 0xFFFFFFFFFFFFFFFF EQUAL", "P2SH,STRICTENC"], - -["2147483647", "1ADD 2147483648 EQUAL", "P2SH,STRICTENC", "We can do math on 4-byte integers, and compare 5-byte ones"], -["2147483647", "1ADD 1", "P2SH,STRICTENC"], -["-2147483647", "1ADD 1", "P2SH,STRICTENC"], - -["1", "0x02 0x0100 EQUAL NOT", "P2SH,STRICTENC", "Not the same byte array..."], -["1", "0x02 0x0100 NUMEQUAL", "P2SH,STRICTENC", "... but they are numerically equal"], -["11", "0x4c 0x03 0x0b0000 NUMEQUAL", "P2SH,STRICTENC"], -["0", "0x01 0x80 EQUAL NOT", "P2SH,STRICTENC"], -["0", "0x01 0x80 NUMEQUAL", "P2SH,STRICTENC", "Zero numerically equals negative zero"], -["0", "0x02 0x0080 NUMEQUAL", "P2SH,STRICTENC"], -["0x03 0x000080", "0x04 0x00000080 NUMEQUAL", "P2SH,STRICTENC"], -["0x03 0x100080", "0x04 0x10000080 NUMEQUAL", "P2SH,STRICTENC"], -["0x03 0x100000", "0x04 0x10000000 NUMEQUAL", "P2SH,STRICTENC"], - -["NOP", "NOP 1", "P2SH,STRICTENC", "The following tests check the if(stack.size() < N) tests in each opcode"], -["1", "IF 1 ENDIF", "P2SH,STRICTENC", "They are here to catch copy-and-paste errors"], -["0", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "Most of them are duplicated elsewhere,"], -["1", "VERIFY 1", "P2SH,STRICTENC", "but, hey, more is always better, right?"], - -["0", "TOALTSTACK 1", "P2SH,STRICTENC"], -["1", "TOALTSTACK FROMALTSTACK", "P2SH,STRICTENC"], -["0 0", "2DROP 1", "P2SH,STRICTENC"], -["0 1", "2DUP", "P2SH,STRICTENC"], -["0 0 1", "3DUP", "P2SH,STRICTENC"], -["0 1 0 0", "2OVER", "P2SH,STRICTENC"], -["0 1 0 0 0 0", "2ROT", "P2SH,STRICTENC"], -["0 1 0 0", "2SWAP", "P2SH,STRICTENC"], -["1", "IFDUP", "P2SH,STRICTENC"], -["NOP", "DEPTH 1", "P2SH,STRICTENC"], -["0", "DROP 1", "P2SH,STRICTENC"], -["1", "DUP", "P2SH,STRICTENC"], -["0 1", "NIP", "P2SH,STRICTENC"], -["1 0", "OVER", "P2SH,STRICTENC"], -["1 0 0 0 3", "PICK", "P2SH,STRICTENC"], -["1 0", "PICK", "P2SH,STRICTENC"], -["1 0 0 0 3", "ROLL", "P2SH,STRICTENC"], -["1 0", "ROLL", "P2SH,STRICTENC"], -["1 0 0", "ROT", "P2SH,STRICTENC"], -["1 0", "SWAP", "P2SH,STRICTENC"], -["0 1", "TUCK", "P2SH,STRICTENC"], - -["1", "SIZE", "P2SH,STRICTENC"], - -["0 0", "EQUAL", "P2SH,STRICTENC"], -["0 0", "EQUALVERIFY 1", "P2SH,STRICTENC"], -["0 0 1", "EQUAL EQUAL", "P2SH,STRICTENC", "OP_0 and bools must have identical byte representations"], - -["0", "1ADD", "P2SH,STRICTENC"], -["2", "1SUB", "P2SH,STRICTENC"], -["-1", "NEGATE", "P2SH,STRICTENC"], -["-1", "ABS", "P2SH,STRICTENC"], -["0", "NOT", "P2SH,STRICTENC"], -["-1", "0NOTEQUAL", "P2SH,STRICTENC"], - -["1 0", "ADD", "P2SH,STRICTENC"], -["1 0", "SUB", "P2SH,STRICTENC"], -["-1 -1", "BOOLAND", "P2SH,STRICTENC"], -["-1 0", "BOOLOR", "P2SH,STRICTENC"], -["0 0", "NUMEQUAL", "P2SH,STRICTENC"], -["0 0", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"], -["-1 0", "NUMNOTEQUAL", "P2SH,STRICTENC"], -["-1 0", "LESSTHAN", "P2SH,STRICTENC"], -["1 0", "GREATERTHAN", "P2SH,STRICTENC"], -["0 0", "LESSTHANOREQUAL", "P2SH,STRICTENC"], -["0 0", "GREATERTHANOREQUAL", "P2SH,STRICTENC"], -["-1 0", "MIN", "P2SH,STRICTENC"], -["1 0", "MAX", "P2SH,STRICTENC"], -["-1 -1 0", "WITHIN", "P2SH,STRICTENC"], - -["0", "RIPEMD160", "P2SH,STRICTENC"], -["0", "SHA1", "P2SH,STRICTENC"], -["0", "SHA256", "P2SH,STRICTENC"], -["0", "HASH160", "P2SH,STRICTENC"], -["0", "HASH256", "P2SH,STRICTENC"], -["NOP", "CODESEPARATOR 1", "P2SH,STRICTENC"], - -["NOP", "NOP5 1", "P2SH,STRICTENC"], -["NOP", "NOP6 1", "P2SH,STRICTENC"], -["NOP", "NOP7 1", "P2SH,STRICTENC"], -["NOP", "NOP8 1", "P2SH,STRICTENC"], -["NOP", "NOP9 1", "P2SH,STRICTENC"], -["NOP", "NOP10 1", "P2SH,STRICTENC"], - -["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "CHECKMULTISIG is allowed to have zero keys and/or sigs"], -["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "Zero sigs means no sigs are checked"], -["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], - -["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "CHECKMULTISIG is allowed to have zero keys and/or sigs"], -["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "Zero sigs means no sigs are checked"], -["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], - -["", "0 0 'a' 'b' 2 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "Test from up to 20 pubkeys, all not checked"], -["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "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"], -["", "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"], -["", "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"], -["", "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"], -["", "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"], -["", "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"], -["", "0 0 'a' 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 2 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "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"], -["", "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"], -["", "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"], -["", "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"], -["", "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"], - -["", -"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", -"P2SH,STRICTENC", -"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"], - -["1", -"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", -"P2SH,STRICTENC"], - -["", -"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", -"P2SH,STRICTENC", -"Even though there are no signatures being checked nOpCount is incremented by the number of keys."], - -["1", -"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", -"P2SH,STRICTENC"], - -["0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "Very basic P2SH"], -["0x4c 0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC"], - -["0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242", -"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL", -"P2SH,STRICTENC", -"Basic PUSH signedness check"], - -["0x4c 0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242", -"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL", -"P2SH,STRICTENC", -"Basic PUSHDATA1 signedness check"], - -["all PUSHDATA forms are equivalent"], - -["0x4c 0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "PUSHDATA1 of 75 bytes equals direct push of it"], -["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4c 0xFF 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "PUSHDATA2 of 255 bytes equals PUSHDATA1 of it"], - -["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"], - -["Numeric pushes"], - -["0x01 0x81", "0x4f EQUAL", "", "OP1_NEGATE pushes 0x81"], -["0x01 0x01", "0x51 EQUAL", "", "OP_1 pushes 0x01"], -["0x01 0x02", "0x52 EQUAL", "", "OP_2 pushes 0x02"], -["0x01 0x03", "0x53 EQUAL", "", "OP_3 pushes 0x03"], -["0x01 0x04", "0x54 EQUAL", "", "OP_4 pushes 0x04"], -["0x01 0x05", "0x55 EQUAL", "", "OP_5 pushes 0x05"], -["0x01 0x06", "0x56 EQUAL", "", "OP_6 pushes 0x06"], -["0x01 0x07", "0x57 EQUAL", "", "OP_7 pushes 0x07"], -["0x01 0x08", "0x58 EQUAL", "", "OP_8 pushes 0x08"], -["0x01 0x09", "0x59 EQUAL", "", "OP_9 pushes 0x09"], -["0x01 0x0a", "0x5a EQUAL", "", "OP_10 pushes 0x0a"], -["0x01 0x0b", "0x5b EQUAL", "", "OP_11 pushes 0x0b"], -["0x01 0x0c", "0x5c EQUAL", "", "OP_12 pushes 0x0c"], -["0x01 0x0d", "0x5d EQUAL", "", "OP_13 pushes 0x0d"], -["0x01 0x0e", "0x5e EQUAL", "", "OP_14 pushes 0x0e"], -["0x01 0x0f", "0x5f EQUAL", "", "OP_15 pushes 0x0f"], -["0x01 0x10", "0x60 EQUAL", "", "OP_16 pushes 0x10"], - -["Equivalency of different numeric encodings"], - -["0x02 0x8000", "128 NUMEQUAL", "", "0x8000 equals 128"], -["0x01 0x00", "0 NUMEQUAL", "", "0x00 numequals 0"], -["0x01 0x80", "0 NUMEQUAL", "", "0x80 (negative zero) numequals 0"], -["0x02 0x0080", "0 NUMEQUAL", "", "0x0080 numequals 0"], -["0x02 0x0500", "5 NUMEQUAL", "", "0x0500 numequals 5"], -["0x03 0xff7f80", "0x02 0xffff NUMEQUAL", "", ""], -["0x03 0xff7f00", "0x02 0xff7f NUMEQUAL", "", ""], -["0x04 0xffff7f80", "0x03 0xffffff NUMEQUAL", "", ""], -["0x04 0xffff7f00", "0x03 0xffff7f NUMEQUAL", "", ""], - -["Unevaluated non-minimal pushes are ignored"], - -["0 IF 0x4c 0x00 ENDIF 1", "", "MINIMALDATA", "non-minimal PUSHDATA1 ignored"], -["0 IF 0x4d 0x0000 ENDIF 1", "", "MINIMALDATA", "non-minimal PUSHDATA2 ignored"], -["0 IF 0x4c 0x00000000 ENDIF 1", "", "MINIMALDATA", "non-minimal PUSHDATA4 ignored"], -["0 IF 0x01 0x81 ENDIF 1", "", "MINIMALDATA", "1NEGATE equiv"], -["0 IF 0x01 0x01 ENDIF 1", "", "MINIMALDATA", "OP_1 equiv"], -["0 IF 0x01 0x02 ENDIF 1", "", "MINIMALDATA", "OP_2 equiv"], -["0 IF 0x01 0x03 ENDIF 1", "", "MINIMALDATA", "OP_3 equiv"], -["0 IF 0x01 0x04 ENDIF 1", "", "MINIMALDATA", "OP_4 equiv"], -["0 IF 0x01 0x05 ENDIF 1", "", "MINIMALDATA", "OP_5 equiv"], -["0 IF 0x01 0x06 ENDIF 1", "", "MINIMALDATA", "OP_6 equiv"], -["0 IF 0x01 0x07 ENDIF 1", "", "MINIMALDATA", "OP_7 equiv"], -["0 IF 0x01 0x08 ENDIF 1", "", "MINIMALDATA", "OP_8 equiv"], -["0 IF 0x01 0x09 ENDIF 1", "", "MINIMALDATA", "OP_9 equiv"], -["0 IF 0x01 0x0a ENDIF 1", "", "MINIMALDATA", "OP_10 equiv"], -["0 IF 0x01 0x0b ENDIF 1", "", "MINIMALDATA", "OP_11 equiv"], -["0 IF 0x01 0x0c ENDIF 1", "", "MINIMALDATA", "OP_12 equiv"], -["0 IF 0x01 0x0d ENDIF 1", "", "MINIMALDATA", "OP_13 equiv"], -["0 IF 0x01 0x0e ENDIF 1", "", "MINIMALDATA", "OP_14 equiv"], -["0 IF 0x01 0x0f ENDIF 1", "", "MINIMALDATA", "OP_15 equiv"], -["0 IF 0x01 0x10 ENDIF 1", "", "MINIMALDATA", "OP_16 equiv"], - -["Numeric minimaldata rules are only applied when a stack item is numerically evaluated; the push itself is allowed"], - -["0x01 0x00", "1", "MINIMALDATA"], -["0x01 0x80", "1", "MINIMALDATA"], -["0x02 0x0180", "1", "MINIMALDATA"], -["0x02 0x0100", "1", "MINIMALDATA"], -["0x02 0x0200", "1", "MINIMALDATA"], -["0x02 0x0300", "1", "MINIMALDATA"], -["0x02 0x0400", "1", "MINIMALDATA"], -["0x02 0x0500", "1", "MINIMALDATA"], -["0x02 0x0600", "1", "MINIMALDATA"], -["0x02 0x0700", "1", "MINIMALDATA"], -["0x02 0x0800", "1", "MINIMALDATA"], -["0x02 0x0900", "1", "MINIMALDATA"], -["0x02 0x0a00", "1", "MINIMALDATA"], -["0x02 0x0b00", "1", "MINIMALDATA"], -["0x02 0x0c00", "1", "MINIMALDATA"], -["0x02 0x0d00", "1", "MINIMALDATA"], -["0x02 0x0e00", "1", "MINIMALDATA"], -["0x02 0x0f00", "1", "MINIMALDATA"], -["0x02 0x1000", "1", "MINIMALDATA"], - -["Valid version of the 'Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule' script_invalid test"], - -["1 0x02 0x0000", "PICK DROP", ""], -["1 0x02 0x0000", "ROLL DROP 1", ""], -["0x02 0x0000", "1ADD DROP 1", ""], -["0x02 0x0000", "1SUB DROP 1", ""], -["0x02 0x0000", "NEGATE DROP 1", ""], -["0x02 0x0000", "ABS DROP 1", ""], -["0x02 0x0000", "NOT DROP 1", ""], -["0x02 0x0000", "0NOTEQUAL DROP 1", ""], - -["0 0x02 0x0000", "ADD DROP 1", ""], -["0x02 0x0000 0", "ADD DROP 1", ""], -["0 0x02 0x0000", "SUB DROP 1", ""], -["0x02 0x0000 0", "SUB DROP 1", ""], -["0 0x02 0x0000", "BOOLAND DROP 1", ""], -["0x02 0x0000 0", "BOOLAND DROP 1", ""], -["0 0x02 0x0000", "BOOLOR DROP 1", ""], -["0x02 0x0000 0", "BOOLOR DROP 1", ""], -["0 0x02 0x0000", "NUMEQUAL DROP 1", ""], -["0x02 0x0000 1", "NUMEQUAL DROP 1", ""], -["0 0x02 0x0000", "NUMEQUALVERIFY 1", ""], -["0x02 0x0000 0", "NUMEQUALVERIFY 1", ""], -["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", ""], -["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", ""], -["0 0x02 0x0000", "LESSTHAN DROP 1", ""], -["0x02 0x0000 0", "LESSTHAN DROP 1", ""], -["0 0x02 0x0000", "GREATERTHAN DROP 1", ""], -["0x02 0x0000 0", "GREATERTHAN DROP 1", ""], -["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", ""], -["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", ""], -["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", ""], -["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", ""], -["0 0x02 0x0000", "MIN DROP 1", ""], -["0x02 0x0000 0", "MIN DROP 1", ""], -["0 0x02 0x0000", "MAX DROP 1", ""], -["0x02 0x0000 0", "MAX DROP 1", ""], - -["0x02 0x0000 0 0", "WITHIN DROP 1", ""], -["0 0x02 0x0000 0", "WITHIN DROP 1", ""], -["0 0 0x02 0x0000", "WITHIN DROP 1", ""], - -["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", ""], -["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", ""], -["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", ""], -["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", ""], -["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", ""], - -["While not really correctly DER encoded, the empty signature is allowed by"], -["STRICTENC to provide a compact way to provide a delibrately invalid signature."], -["0", "0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 CHECKSIG NOT", "STRICTENC"], -["0 0", "1 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 1 CHECKMULTISIG NOT", "STRICTENC"], - -["CHECKMULTISIG evaluation order tests. CHECKMULTISIG evaluates signatures and"], -["pubkeys in a specific order, and will exit early if the number of signatures"], -["left to check is greater than the number of keys left. As STRICTENC fails the"], -["script when it reaches an invalidly encoded signature or pubkey, we can use it"], -["to test the exact order in which signatures and pubkeys are evaluated by"], -["distinguishing CHECKMULTISIG returning false on the stack and the script as a"], -["whole failing."], -["See also the corresponding inverted versions of these tests in script_invalid.json"], -[ - "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501", - "2 0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT", - "STRICTENC", - "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." -], -[ - "0 0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501", - "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT", - "STRICTENC", - "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." -], - -["Increase test coverage for DERSIG"], -["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "", "Overly long signature is correctly encoded"], -["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "", "Missing S is correctly encoded"], -["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "", "S with invalid S length is correctly encoded"], -["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "Non-integer R is correctly encoded"], -["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "Non-integer S is correctly encoded"], -["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "Zero-length R is correctly encoded"], -["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "", "Zero-length S is correctly encoded for DERSIG"], -["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "", "Negative S is correctly encoded"], - -["Automatically generated test cases"], -[ - "0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", - "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", - "", - "P2PK" -], -[ - "0x47 0x304402206e05a6fe23c59196ffe176c9ddc31e73a9885638f9d1328d47c0c703863b8876022076feb53811aa5b04e0e79f938eb19906cc5e67548bc555a8e8b8b0fc603d840c01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", - "DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG", - "", - "P2PKH" -], -[ - "0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790281", - "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", - "", - "P2PK anyonecanpay" -], -[ - "0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", - "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", - "P2SH", - "P2SH(P2PK)" -], -[ - "0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", - "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", - "", - "P2SH(P2PKH), bad sig but no VERIFY_P2SH" -], -[ - "0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901", - "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", - "", - "3-of-3" -], -[ - "0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0x47 0x30440220563e5b3b1fc11662a84bc5ea2a32cc3819703254060ba30d639a1aaf2d5068ad0220601c1f47ddc76d93284dd9ed68f7c9974c4a0ea7cbe8a247d6bc3878567a5fca01 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", - "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", - "P2SH", - "P2SH(2-of-3)" -], -[ - "0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", - "", - "P2PK with too much R padding but no DERSIG" -], -[ - "0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", - "", - "P2PK with too much S padding but no DERSIG" -], -[ - "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", - "", - "P2PK with too little R padding but no DERSIG" -], -[ - "0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601", - "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", - "", - "P2PK NOT with bad sig with too much R padding but no DERSIG" -], -[ - "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", - "", - "BIP66 example 1, without DERSIG" -], -[ - "0", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", - "", - "BIP66 example 4, without DERSIG" -], -[ - "0", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", - "DERSIG", - "BIP66 example 4, with DERSIG" -], -[ - "1", - "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT", - "", - "BIP66 example 6, without DERSIG" -], -[ - "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG", - "", - "BIP66 example 7, without DERSIG" -], -[ - "0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", - "", - "BIP66 example 10, without DERSIG" -], -[ - "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", - "", - "BIP66 example 12, without DERSIG" -], -[ - "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT", - "DERSIG", - "BIP66 example 12, with DERSIG" -], -[ - "0x48 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb12510101", - "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", - "", - "P2PK with multi-byte hashtype, without DERSIG" -], -[ - "0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001", - "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", - "", - "P2PK with high S but no LOW_S" -], -[ - "0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01", - "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", - "", - "P2PK with hybrid pubkey but no STRICTENC" -], -[ - "0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101", - "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", - "", - "P2PK NOT with invalid hybrid pubkey but no STRICTENC" -], -[ - "0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401", - "1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", - "", - "1-of-2 with the second 1 hybrid pubkey and no STRICTENC" -], -[ - "0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401", - "1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", - "STRICTENC", - "1-of-2 with the second 1 hybrid pubkey" -], -[ - "0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205", - "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", - "", - "P2PK with undefined hashtype but no STRICTENC" -], -[ - "0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05", - "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT", - "", - "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC" -], -[ - "1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901", - "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", - "", - "3-of-3 with nonzero dummy but no NULLDUMMY" -], -[ - "1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01", - "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT", - "", - "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY" -], -[ - "0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", - "", - "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY" -], -[ - "0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901", - "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", - "SIGPUSHONLY", - "2-of-2 with two identical keys and sigs pushed" -], -[ - "11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", - "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", - "P2SH", - "P2PK with unnecessary input but no CLEANSTACK" -], -[ - "11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac", - "HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL", - "P2SH", - "P2SH with unnecessary input but no CLEANSTACK" -], -[ - "0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac", - "HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL", - "CLEANSTACK,P2SH", - "P2SH with CLEANSTACK" -], - -["The End"] -] diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index 0e034770f..2d7d9b958 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -64,9 +64,13 @@ [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff655151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "P2SH"], -["Null txin"], -[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "HASH160 0x14 0x02dae7dbbda56097959cba59b1989dd3e47937bf EQUAL"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6e49304602210086f39e028e46dafa8e1e3be63906465f4cf038fbe5ed6403dc3e74ae876e6431022100c4625c675cfc5c7e3a0e0d7eaec92ac24da20c73a88eb40d09253e51ac6def5201232103a183ddc41e84753aca47723c965d1b5c8b0e2b537963518355e6dd6cf8415e50acffffffff010000000000000000015100000000", "P2SH"], +["Null txin, but without being a coinbase (because there are two inputs)"], +[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"], + ["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"01000000020000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff010000000000000000015100000000", "P2SH"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"], + ["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], +"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff010000000000000000015100000000", "P2SH"], ["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"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], @@ -123,75 +127,133 @@ ["CHECKLOCKTIMEVERIFY tests"], ["By-height locks, with argument just beyond tx nLockTime"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKLOCKTIMEVERIFY 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000fe64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], ["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 CHECKLOCKTIMEVERIFY 1"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKLOCKTIMEVERIFY 1"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"], ["Argument missing"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "CHECKLOCKTIMEVERIFY 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], -"010000000100010000000000000000000000000000000000000000000000000000000000000000000001b2010000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000001b1010000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["Argument negative with by-blockheight nLockTime=0"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["Argument negative with by-blocktime nLockTime=500,000,000"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY 1"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], -"010000000100010000000000000000000000000000000000000000000000000000000000000000000004005194b2010000000100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000004005194b1010000000100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["Input locked"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2ffffffff0100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1ffffffff0100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["Another input being unlocked isn't sufficient; the CHECKLOCKTIMEVERIFY-using input must be unlocked"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"] , +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"] , ["0000000000000000000000000000000000000000000000000000000000000200", 1, "1"]], "010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["Argument/tx height/time mismatch, both versions"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b200000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP3 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b100000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], ["Argument 2^32 with nLockTime=2^32-1"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 CHECKLOCKTIMEVERIFY 1"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"], ["Same, but with nLockTime=2^31-1"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKLOCKTIMEVERIFY 1"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffff7f", "P2SH,CHECKLOCKTIMEVERIFY"], ["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 CHECKLOCKTIMEVERIFY 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["Failure due to failing CHECKLOCKTIMEVERIFY in scriptSig"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["Failure due to failing CHECKLOCKTIMEVERIFY in redeemScript"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["A transaction with a non-standard DER signature."], +[[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]], +"010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH,DERSIG"], + +["CHECKSEQUENCEVERIFY tests"], + +["By-height locks, with argument just beyond txin.nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["By-time locks, with argument just beyond txin.nSequence (but within numerical boundries)"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194305 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument missing"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument negative with by-blockheight txin.nSequence=0"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument negative with by-blocktime txin.nSequence=CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument/tx height/time mismatch, both versions"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Failure due to failing CHECKSEQUENCEVERIFY in scriptSig"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Failure due to failing CHECKSEQUENCEVERIFY in redeemScript"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]], -"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Failure due to insufficient tx.nVersion (<2)"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Make diffs cleaner by leaving a comment here without comma at the end"] ] diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json index 3c9a88880..717ad1954 100644 --- a/src/test/data/tx_valid.json +++ b/src/test/data/tx_valid.json @@ -190,44 +190,132 @@ ["CHECKLOCKTIMEVERIFY tests"], ["By-height locks, with argument == 0 and == tx nLockTime"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], ["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKLOCKTIMEVERIFY 1"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"], ["Any non-maxint nSequence is fine"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["The argument can be calculated rather than created directly by a PUSHDATA"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD CHECKLOCKTIMEVERIFY 1"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], ["Perhaps even by an ADD producing a 5-byte result that is out of bounds for other opcodes"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 2147483647 ADD NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 2147483647 ADD CHECKLOCKTIMEVERIFY 1"]], "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"], ["5 byte non-minimally-encoded arguments are valid"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 CHECKLOCKTIMEVERIFY 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["Valid CHECKLOCKTIMEVERIFY in scriptSig"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["Valid CHECKLOCKTIMEVERIFY in redeemScript"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["A transaction with a non-standard DER signature."], +[[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]], +"010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH"], + +["CHECKSEQUENCEVERIFY tests"], + +["By-height locks, with argument == 0 and == txin.nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["By-time locks, with argument == 0 and == txin.nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Upper sequence with upper sequence is fine"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument 2^31 with various nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument 2^32-1 with various nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument 3<<31 with various nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["5 byte non-minimally-encoded operandss are valid"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["The argument can be calculated rather than created directly by a PUSHDATA"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194303 1ADD NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 1SUB NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["An ADD producing a 5-byte result that sets CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 65536 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 4259840 ADD NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Valid CHECKSEQUENCEVERIFY in scriptSig"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Valid CHECKSEQUENCEVERIFY in redeemScript"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]], -"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"], +"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Make diffs cleaner by leaving a comment here without comma at the end"] ] diff --git a/src/test/leveldbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp similarity index 86% rename from src/test/leveldbwrapper_tests.cpp rename to src/test/dbwrapper_tests.cpp index 606313b00..e39931587 100644 --- a/src/test/leveldbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -1,8 +1,8 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "leveldbwrapper.h" +#include "dbwrapper.h" #include "uint256.h" #include "random.h" #include "test/test_bitcoin.h" @@ -25,15 +25,15 @@ bool is_null_key(const vector& key) { return isnull; } -BOOST_FIXTURE_TEST_SUITE(leveldbwrapper_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup) -BOOST_AUTO_TEST_CASE(leveldbwrapper) +BOOST_AUTO_TEST_CASE(dbwrapper) { // Perform tests both obfuscated and non-obfuscated. for (int i = 0; i < 2; i++) { bool obfuscate = (bool)i; path ph = temp_directory_path() / unique_path(); - CLevelDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); + CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); char key = 'k'; uint256 in = GetRandHash(); uint256 res; @@ -48,13 +48,13 @@ BOOST_AUTO_TEST_CASE(leveldbwrapper) } // Test batch operations -BOOST_AUTO_TEST_CASE(leveldbwrapper_batch) +BOOST_AUTO_TEST_CASE(dbwrapper_batch) { // Perform tests both obfuscated and non-obfuscated. for (int i = 0; i < 2; i++) { bool obfuscate = (bool)i; path ph = temp_directory_path() / unique_path(); - CLevelDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); + CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); char key = 'i'; uint256 in = GetRandHash(); @@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(leveldbwrapper_batch) uint256 in3 = GetRandHash(); uint256 res; - CLevelDBBatch batch(&dbw.GetObfuscateKey()); + CDBBatch batch(&dbw.GetObfuscateKey()); batch.Write(key, in); batch.Write(key2, in2); @@ -85,13 +85,13 @@ BOOST_AUTO_TEST_CASE(leveldbwrapper_batch) } } -BOOST_AUTO_TEST_CASE(leveldbwrapper_iterator) +BOOST_AUTO_TEST_CASE(dbwrapper_iterator) { // Perform tests both obfuscated and non-obfuscated. for (int i = 0; i < 2; i++) { bool obfuscate = (bool)i; path ph = temp_directory_path() / unique_path(); - CLevelDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); + CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); // The two keys are intentionally chosen for ordering char key = 'j'; @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(leveldbwrapper_iterator) uint256 in2 = GetRandHash(); BOOST_CHECK(dbw.Write(key2, in2)); - boost::scoped_ptr it(const_cast(&dbw)->NewIterator()); + boost::scoped_ptr it(const_cast(&dbw)->NewIterator()); // Be sure to seek past the obfuscation key (if it exists) it->Seek(key); @@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. - CLevelDBWrapper* dbw = new CLevelDBWrapper(ph, (1 << 10), false, false, false); + CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false); char key = 'k'; uint256 in = GetRandHash(); uint256 res; @@ -147,7 +147,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) delete dbw; // Now, set up another wrapper that wants to obfuscate the same directory - CLevelDBWrapper odbw(ph, (1 << 10), false, false, true); + CDBWrapper odbw(ph, (1 << 10), false, false, true); // Check that the key/val we wrote with unobfuscated wrapper exists and // is readable. @@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex) create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. - CLevelDBWrapper* dbw = new CLevelDBWrapper(ph, (1 << 10), false, false, false); + CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false); char key = 'k'; uint256 in = GetRandHash(); uint256 res; @@ -188,7 +188,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex) delete dbw; // Simulate a -reindex by wiping the existing data store - CLevelDBWrapper odbw(ph, (1 << 10), false, true, true); + CDBWrapper odbw(ph, (1 << 10), false, true, true); // Check that the key/val we wrote with unobfuscated wrapper doesn't exist uint256 res2; diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index eb61a2884..9f59de3ef 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index e5d2e5a43..35079d161 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Bitcoin Core developers +// Copyright (c) 2013-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 6facf860b..d9648242f 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp index 19c4ebdf8..a8e23a826 100644 --- a/src/test/main_tests.cpp +++ b/src/test/main_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014 The Bitcoin Core developers +// Copyright (c) 2014-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -89,5 +89,4 @@ BOOST_AUTO_TEST_CASE(test_combiner_all) Test.disconnect(&ReturnTrue); BOOST_CHECK(Test()); } - BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index 5bf1e98e8..c8b43df26 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -17,6 +17,7 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) { // Test CTxMemPool::remove functionality + TestMemPoolEntryHelper entry; // Parent transaction with three children, // and three grand-children: CMutableTransaction txParent; @@ -56,33 +57,33 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) std::list removed; // Nothing in pool, remove should do nothing: - testPool.remove(txParent, removed, true); + testPool.removeRecursive(txParent, removed); BOOST_CHECK_EQUAL(removed.size(), 0); // Just the parent: - testPool.addUnchecked(txParent.GetHash(), CTxMemPoolEntry(txParent, 0, 0, 0.0, 1)); - testPool.remove(txParent, removed, true); + testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); + testPool.removeRecursive(txParent, removed); BOOST_CHECK_EQUAL(removed.size(), 1); removed.clear(); // Parent, children, grandchildren: - testPool.addUnchecked(txParent.GetHash(), CTxMemPoolEntry(txParent, 0, 0, 0.0, 1)); + testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); for (int i = 0; i < 3; i++) { - testPool.addUnchecked(txChild[i].GetHash(), CTxMemPoolEntry(txChild[i], 0, 0, 0.0, 1)); - testPool.addUnchecked(txGrandChild[i].GetHash(), CTxMemPoolEntry(txGrandChild[i], 0, 0, 0.0, 1)); + testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i])); + testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); } // Remove Child[0], GrandChild[0] should be removed: - testPool.remove(txChild[0], removed, true); + testPool.removeRecursive(txChild[0], removed); BOOST_CHECK_EQUAL(removed.size(), 2); removed.clear(); // ... make sure grandchild and child are gone: - testPool.remove(txGrandChild[0], removed, true); + testPool.removeRecursive(txGrandChild[0], removed); BOOST_CHECK_EQUAL(removed.size(), 0); - testPool.remove(txChild[0], removed, true); + testPool.removeRecursive(txChild[0], removed); BOOST_CHECK_EQUAL(removed.size(), 0); // Remove parent, all children/grandchildren should go: - testPool.remove(txParent, removed, true); + testPool.removeRecursive(txParent, removed); BOOST_CHECK_EQUAL(removed.size(), 5); BOOST_CHECK_EQUAL(testPool.size(), 0); removed.clear(); @@ -90,23 +91,24 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) // Add children and grandchildren, but NOT the parent (simulate the parent being in a block) for (int i = 0; i < 3; i++) { - testPool.addUnchecked(txChild[i].GetHash(), CTxMemPoolEntry(txChild[i], 0, 0, 0.0, 1)); - testPool.addUnchecked(txGrandChild[i].GetHash(), CTxMemPoolEntry(txGrandChild[i], 0, 0, 0.0, 1)); + testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i])); + testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); } // Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be // put into the mempool (maybe because it is non-standard): - testPool.remove(txParent, removed, true); + testPool.removeRecursive(txParent, removed); BOOST_CHECK_EQUAL(removed.size(), 6); BOOST_CHECK_EQUAL(testPool.size(), 0); removed.clear(); } +template void CheckSort(CTxMemPool &pool, std::vector &sortedOrder) { BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size()); - CTxMemPool::indexed_transaction_set::nth_index<1>::type::iterator it = pool.mapTx.get<1>().begin(); + typename CTxMemPool::indexed_transaction_set::index::type::iterator it = pool.mapTx.get().begin(); int count=0; - for (; it != pool.mapTx.get<1>().end(); ++it, ++count) { + for (; it != pool.mapTx.get().end(); ++it, ++count) { BOOST_CHECK_EQUAL(it->GetTx().GetHash().ToString(), sortedOrder[count]); } } @@ -114,51 +116,55 @@ void CheckSort(CTxMemPool &pool, std::vector &sortedOrder) BOOST_AUTO_TEST_CASE(MempoolIndexingTest) { CTxMemPool pool(CFeeRate(0)); + TestMemPoolEntryHelper entry; + entry.hadNoDependencies = true; /* 3rd highest fee */ CMutableTransaction tx1 = CMutableTransaction(); tx1.vout.resize(1); tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx1.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx1.GetHash(), CTxMemPoolEntry(tx1, 10000LL, 0, 10.0, 1, true)); + pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1)); /* highest fee */ CMutableTransaction tx2 = CMutableTransaction(); tx2.vout.resize(1); tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx2.vout[0].nValue = 2 * COIN; - pool.addUnchecked(tx2.GetHash(), CTxMemPoolEntry(tx2, 20000LL, 0, 9.0, 1, true)); + pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2)); /* lowest fee */ CMutableTransaction tx3 = CMutableTransaction(); tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx3.vout[0].nValue = 5 * COIN; - pool.addUnchecked(tx3.GetHash(), CTxMemPoolEntry(tx3, 0LL, 0, 100.0, 1, true)); + pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).Priority(100.0).FromTx(tx3)); /* 2nd highest fee */ CMutableTransaction tx4 = CMutableTransaction(); tx4.vout.resize(1); tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx4.vout[0].nValue = 6 * COIN; - pool.addUnchecked(tx4.GetHash(), CTxMemPoolEntry(tx4, 15000LL, 0, 1.0, 1, true)); + pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4)); /* equal fee rate to tx1, but newer */ CMutableTransaction tx5 = CMutableTransaction(); tx5.vout.resize(1); tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx5.vout[0].nValue = 11 * COIN; - pool.addUnchecked(tx5.GetHash(), CTxMemPoolEntry(tx5, 10000LL, 1, 10.0, 1, true)); + entry.nTime = 1; + entry.dPriority = 10.0; + pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5)); BOOST_CHECK_EQUAL(pool.size(), 5); std::vector sortedOrder; sortedOrder.resize(5); - sortedOrder[0] = tx2.GetHash().ToString(); // 20000 - sortedOrder[1] = tx4.GetHash().ToString(); // 15000 + sortedOrder[0] = tx3.GetHash().ToString(); // 0 + sortedOrder[1] = tx5.GetHash().ToString(); // 10000 sortedOrder[2] = tx1.GetHash().ToString(); // 10000 - sortedOrder[3] = tx5.GetHash().ToString(); // 10000 - sortedOrder[4] = tx3.GetHash().ToString(); // 0 - CheckSort(pool, sortedOrder); + sortedOrder[3] = tx4.GetHash().ToString(); // 15000 + sortedOrder[4] = tx2.GetHash().ToString(); // 20000 + CheckSort(pool, sortedOrder); /* low fee but with high fee child */ /* tx6 -> tx7 -> tx8, tx9 -> tx10 */ @@ -166,11 +172,11 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx6.vout.resize(1); tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx6.vout[0].nValue = 20 * COIN; - pool.addUnchecked(tx6.GetHash(), CTxMemPoolEntry(tx6, 0LL, 1, 10.0, 1, true)); + pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6)); BOOST_CHECK_EQUAL(pool.size(), 6); // Check that at this point, tx6 is sorted low - sortedOrder.push_back(tx6.GetHash().ToString()); - CheckSort(pool, sortedOrder); + sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString()); + CheckSort(pool, sortedOrder); CTxMemPool::setEntries setAncestors; setAncestors.insert(pool.mapTx.find(tx6.GetHash())); @@ -186,18 +192,17 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) CTxMemPool::setEntries setAncestorsCalculated; std::string dummy; - CTxMemPoolEntry entry7(tx7, 2000000LL, 1, 10.0, 1, true); - BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry7, setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); + BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(2000000LL).FromTx(tx7), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); BOOST_CHECK(setAncestorsCalculated == setAncestors); - pool.addUnchecked(tx7.GetHash(), CTxMemPoolEntry(tx7, 2000000LL, 1, 10.0, 1, true), setAncestors); + pool.addUnchecked(tx7.GetHash(), entry.FromTx(tx7), setAncestors); BOOST_CHECK_EQUAL(pool.size(), 7); // Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ... - sortedOrder.erase(sortedOrder.end()-1); - sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString()); - sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString()); - CheckSort(pool, sortedOrder); + sortedOrder.erase(sortedOrder.begin()); + sortedOrder.push_back(tx6.GetHash().ToString()); + sortedOrder.push_back(tx7.GetHash().ToString()); + CheckSort(pool, sortedOrder); /* low fee child of tx7 */ CMutableTransaction tx8 = CMutableTransaction(); @@ -208,11 +213,11 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx8.vout[0].nValue = 10 * COIN; setAncestors.insert(pool.mapTx.find(tx7.GetHash())); - pool.addUnchecked(tx8.GetHash(), CTxMemPoolEntry(tx8, 0LL, 2, 10.0, 1, true), setAncestors); + pool.addUnchecked(tx8.GetHash(), entry.Fee(0LL).Time(2).FromTx(tx8), setAncestors); // Now tx8 should be sorted low, but tx6/tx both high - sortedOrder.push_back(tx8.GetHash().ToString()); - CheckSort(pool, sortedOrder); + sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString()); + CheckSort(pool, sortedOrder); /* low fee child of tx7 */ CMutableTransaction tx9 = CMutableTransaction(); @@ -222,12 +227,12 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx9.vout.resize(1); tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx9.vout[0].nValue = 1 * COIN; - pool.addUnchecked(tx9.GetHash(), CTxMemPoolEntry(tx9, 0LL, 3, 10.0, 1, true), setAncestors); + pool.addUnchecked(tx9.GetHash(), entry.Fee(0LL).Time(3).FromTx(tx9), setAncestors); // tx9 should be sorted low BOOST_CHECK_EQUAL(pool.size(), 9); - sortedOrder.push_back(tx9.GetHash().ToString()); - CheckSort(pool, sortedOrder); + sortedOrder.insert(sortedOrder.begin(), tx9.GetHash().ToString()); + CheckSort(pool, sortedOrder); std::vector snapshotOrder = sortedOrder; @@ -245,40 +250,331 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx10.vout[0].nValue = 10 * COIN; setAncestorsCalculated.clear(); - CTxMemPoolEntry entry10(tx10, 200000LL, 4, 10.0, 1, true); - BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry10, setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); + BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(4).FromTx(tx10), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); BOOST_CHECK(setAncestorsCalculated == setAncestors); - pool.addUnchecked(tx10.GetHash(), CTxMemPoolEntry(tx10, 200000LL, 4, 10.0, 1, true), setAncestors); + pool.addUnchecked(tx10.GetHash(), entry.FromTx(tx10), setAncestors); /** * tx8 and tx9 should both now be sorted higher * Final order after tx10 is added: * - * tx7 = 2.2M (4 txs) - * tx6 = 2.2M (5 txs) - * tx10 = 200k (1 tx) - * tx8 = 200k (2 txs) - * tx9 = 200k (2 txs) - * tx2 = 20000 (1) - * tx4 = 15000 (1) - * tx1 = 10000 (1) - * tx5 = 10000 (1) * tx3 = 0 (1) + * tx5 = 10000 (1) + * tx1 = 10000 (1) + * tx4 = 15000 (1) + * tx2 = 20000 (1) + * tx9 = 200k (2 txs) + * tx8 = 200k (2 txs) + * tx10 = 200k (1 tx) + * tx6 = 2.2M (5 txs) + * tx7 = 2.2M (4 txs) */ - sortedOrder.erase(sortedOrder.end()-2, sortedOrder.end()); // take out tx8, tx9 from the end - sortedOrder.insert(sortedOrder.begin()+2, tx10.GetHash().ToString()); // tx10 is after tx6 - sortedOrder.insert(sortedOrder.begin()+3, tx9.GetHash().ToString()); - sortedOrder.insert(sortedOrder.begin()+3, tx8.GetHash().ToString()); - CheckSort(pool, sortedOrder); + sortedOrder.erase(sortedOrder.begin(), sortedOrder.begin()+2); // take out tx9, tx8 from the beginning + sortedOrder.insert(sortedOrder.begin()+5, tx9.GetHash().ToString()); + sortedOrder.insert(sortedOrder.begin()+6, tx8.GetHash().ToString()); + sortedOrder.insert(sortedOrder.begin()+7, tx10.GetHash().ToString()); // tx10 is just before tx6 + CheckSort(pool, sortedOrder); // there should be 10 transactions in the mempool BOOST_CHECK_EQUAL(pool.size(), 10); // Now try removing tx10 and verify the sort order returns to normal std::list removed; - pool.remove(pool.mapTx.find(tx10.GetHash())->GetTx(), removed, true); - CheckSort(pool, snapshotOrder); + pool.removeRecursive(pool.mapTx.find(tx10.GetHash())->GetTx(), removed); + CheckSort(pool, snapshotOrder); + + pool.removeRecursive(pool.mapTx.find(tx9.GetHash())->GetTx(), removed); + pool.removeRecursive(pool.mapTx.find(tx8.GetHash())->GetTx(), removed); + /* Now check the sort on the mining score index. + * Final order should be: + * + * tx7 (2M) + * tx2 (20k) + * tx4 (15000) + * tx1/tx5 (10000) + * tx3/6 (0) + * (Ties resolved by hash) + */ + sortedOrder.clear(); + sortedOrder.push_back(tx7.GetHash().ToString()); + sortedOrder.push_back(tx2.GetHash().ToString()); + sortedOrder.push_back(tx4.GetHash().ToString()); + if (tx1.GetHash() < tx5.GetHash()) { + sortedOrder.push_back(tx5.GetHash().ToString()); + sortedOrder.push_back(tx1.GetHash().ToString()); + } else { + sortedOrder.push_back(tx1.GetHash().ToString()); + sortedOrder.push_back(tx5.GetHash().ToString()); + } + if (tx3.GetHash() < tx6.GetHash()) { + sortedOrder.push_back(tx6.GetHash().ToString()); + sortedOrder.push_back(tx3.GetHash().ToString()); + } else { + sortedOrder.push_back(tx3.GetHash().ToString()); + sortedOrder.push_back(tx6.GetHash().ToString()); + } + CheckSort(pool, sortedOrder); +} + +BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) +{ + CTxMemPool pool(CFeeRate(0)); + TestMemPoolEntryHelper entry; + entry.hadNoDependencies = true; + + /* 3rd highest fee */ + CMutableTransaction tx1 = CMutableTransaction(); + tx1.vout.resize(1); + tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx1.vout[0].nValue = 10 * COIN; + pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1)); + + /* highest fee */ + CMutableTransaction tx2 = CMutableTransaction(); + tx2.vout.resize(1); + tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx2.vout[0].nValue = 2 * COIN; + pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2)); + uint64_t tx2Size = ::GetSerializeSize(tx2, SER_NETWORK, PROTOCOL_VERSION); + + /* lowest fee */ + CMutableTransaction tx3 = CMutableTransaction(); + tx3.vout.resize(1); + tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx3.vout[0].nValue = 5 * COIN; + pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).Priority(100.0).FromTx(tx3)); + + /* 2nd highest fee */ + CMutableTransaction tx4 = CMutableTransaction(); + tx4.vout.resize(1); + tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx4.vout[0].nValue = 6 * COIN; + pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4)); + + /* equal fee rate to tx1, but newer */ + CMutableTransaction tx5 = CMutableTransaction(); + tx5.vout.resize(1); + tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx5.vout[0].nValue = 11 * COIN; + pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5)); + BOOST_CHECK_EQUAL(pool.size(), 5); + + std::vector sortedOrder; + sortedOrder.resize(5); + sortedOrder[0] = tx2.GetHash().ToString(); // 20000 + sortedOrder[1] = tx4.GetHash().ToString(); // 15000 + // tx1 and tx5 are both 10000 + // Ties are broken by hash, not timestamp, so determine which + // hash comes first. + if (tx1.GetHash() < tx5.GetHash()) { + sortedOrder[2] = tx1.GetHash().ToString(); + sortedOrder[3] = tx5.GetHash().ToString(); + } else { + sortedOrder[2] = tx5.GetHash().ToString(); + sortedOrder[3] = tx1.GetHash().ToString(); + } + sortedOrder[4] = tx3.GetHash().ToString(); // 0 + + CheckSort(pool, sortedOrder); + + /* low fee parent with high fee child */ + /* tx6 (0) -> tx7 (high) */ + CMutableTransaction tx6 = CMutableTransaction(); + tx6.vout.resize(1); + tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx6.vout[0].nValue = 20 * COIN; + uint64_t tx6Size = ::GetSerializeSize(tx6, SER_NETWORK, PROTOCOL_VERSION); + + pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6)); + BOOST_CHECK_EQUAL(pool.size(), 6); + sortedOrder.push_back(tx6.GetHash().ToString()); + CheckSort(pool, sortedOrder); + + CMutableTransaction tx7 = CMutableTransaction(); + tx7.vin.resize(1); + tx7.vin[0].prevout = COutPoint(tx6.GetHash(), 0); + tx7.vin[0].scriptSig = CScript() << OP_11; + tx7.vout.resize(1); + tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx7.vout[0].nValue = 10 * COIN; + uint64_t tx7Size = ::GetSerializeSize(tx7, SER_NETWORK, PROTOCOL_VERSION); + + /* set the fee to just below tx2's feerate when including ancestor */ + CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1; + + //CTxMemPoolEntry entry7(tx7, fee, 2, 10.0, 1, true); + pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7)); + BOOST_CHECK_EQUAL(pool.size(), 7); + sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString()); + CheckSort(pool, sortedOrder); + + /* after tx6 is mined, tx7 should move up in the sort */ + std::vector vtx; + vtx.push_back(tx6); + std::list dummy; + pool.removeForBlock(vtx, 1, dummy, false); + + sortedOrder.erase(sortedOrder.begin()+1); + sortedOrder.pop_back(); + sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString()); + CheckSort(pool, sortedOrder); +} + + +BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) +{ + CTxMemPool pool(CFeeRate(1000)); + TestMemPoolEntryHelper entry; + entry.dPriority = 10.0; + + CMutableTransaction tx1 = CMutableTransaction(); + tx1.vin.resize(1); + tx1.vin[0].scriptSig = CScript() << OP_1; + tx1.vout.resize(1); + tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL; + tx1.vout[0].nValue = 10 * COIN; + pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1, &pool)); + + CMutableTransaction tx2 = CMutableTransaction(); + tx2.vin.resize(1); + tx2.vin[0].scriptSig = CScript() << OP_2; + tx2.vout.resize(1); + tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL; + tx2.vout[0].nValue = 10 * COIN; + pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2, &pool)); + + pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing + BOOST_CHECK(pool.exists(tx1.GetHash())); + BOOST_CHECK(pool.exists(tx2.GetHash())); + + pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // should remove the lower-feerate transaction + BOOST_CHECK(pool.exists(tx1.GetHash())); + BOOST_CHECK(!pool.exists(tx2.GetHash())); + + pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2, &pool)); + CMutableTransaction tx3 = CMutableTransaction(); + tx3.vin.resize(1); + tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0); + tx3.vin[0].scriptSig = CScript() << OP_2; + tx3.vout.resize(1); + tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL; + tx3.vout[0].nValue = 10 * COIN; + pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3, &pool)); + + pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP) + BOOST_CHECK(!pool.exists(tx1.GetHash())); + BOOST_CHECK(pool.exists(tx2.GetHash())); + BOOST_CHECK(pool.exists(tx3.GetHash())); + + pool.TrimToSize(::GetSerializeSize(CTransaction(tx1), SER_NETWORK, PROTOCOL_VERSION)); // mempool is limited to tx1's size in memory usage, so nothing fits + BOOST_CHECK(!pool.exists(tx1.GetHash())); + BOOST_CHECK(!pool.exists(tx2.GetHash())); + BOOST_CHECK(!pool.exists(tx3.GetHash())); + + CFeeRate maxFeeRateRemoved(25000, ::GetSerializeSize(CTransaction(tx3), SER_NETWORK, PROTOCOL_VERSION) + ::GetSerializeSize(CTransaction(tx2), SER_NETWORK, PROTOCOL_VERSION)); + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000); + + CMutableTransaction tx4 = CMutableTransaction(); + tx4.vin.resize(2); + tx4.vin[0].prevout.SetNull(); + tx4.vin[0].scriptSig = CScript() << OP_4; + tx4.vin[1].prevout.SetNull(); + tx4.vin[1].scriptSig = CScript() << OP_4; + tx4.vout.resize(2); + tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL; + tx4.vout[0].nValue = 10 * COIN; + tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL; + tx4.vout[1].nValue = 10 * COIN; + + CMutableTransaction tx5 = CMutableTransaction(); + tx5.vin.resize(2); + tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0); + tx5.vin[0].scriptSig = CScript() << OP_4; + tx5.vin[1].prevout.SetNull(); + tx5.vin[1].scriptSig = CScript() << OP_5; + tx5.vout.resize(2); + tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL; + tx5.vout[0].nValue = 10 * COIN; + tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL; + tx5.vout[1].nValue = 10 * COIN; + + CMutableTransaction tx6 = CMutableTransaction(); + tx6.vin.resize(2); + tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1); + tx6.vin[0].scriptSig = CScript() << OP_4; + tx6.vin[1].prevout.SetNull(); + tx6.vin[1].scriptSig = CScript() << OP_6; + tx6.vout.resize(2); + tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL; + tx6.vout[0].nValue = 10 * COIN; + tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL; + tx6.vout[1].nValue = 10 * COIN; + + CMutableTransaction tx7 = CMutableTransaction(); + tx7.vin.resize(2); + tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0); + tx7.vin[0].scriptSig = CScript() << OP_5; + tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0); + tx7.vin[1].scriptSig = CScript() << OP_6; + tx7.vout.resize(2); + tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL; + tx7.vout[0].nValue = 10 * COIN; + tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL; + tx7.vout[1].nValue = 10 * COIN; + + pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4, &pool)); + pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); + pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6, &pool)); + pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); + + // we only require this remove, at max, 2 txn, because its not clear what we're really optimizing for aside from that + pool.TrimToSize(pool.DynamicMemoryUsage() - 1); + BOOST_CHECK(pool.exists(tx4.GetHash())); + BOOST_CHECK(pool.exists(tx6.GetHash())); + BOOST_CHECK(!pool.exists(tx7.GetHash())); + + if (!pool.exists(tx5.GetHash())) + pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); + pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); + + pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7 + BOOST_CHECK(pool.exists(tx4.GetHash())); + BOOST_CHECK(!pool.exists(tx5.GetHash())); + BOOST_CHECK(pool.exists(tx6.GetHash())); + BOOST_CHECK(!pool.exists(tx7.GetHash())); + + pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); + pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); + + std::vector vtx; + std::list conflicts; + SetMockTime(42); + SetMockTime(42 + CTxMemPool::ROLLING_FEE_HALFLIFE); + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000); + // ... we should keep the same min fee until we get a block + pool.removeForBlock(vtx, 1, conflicts); + SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE); + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/2); + // ... then feerate should drop 1/2 each halflife + + SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2); + BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/4); + // ... with a 1/2 halflife when mempool is < 1/2 its target size + + SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4); + BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/8); + // ... with a 1/4 halflife when mempool is < 1/4 its target size + + SetMockTime(42 + 7*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4); + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 1000); + // ... but feerate should never drop below 1000 + + SetMockTime(42 + 8*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4); + BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0); + // ... unless it has gone all the way to 0 (after getting past 1000/2) + + SetMockTime(0); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp new file mode 100644 index 000000000..b40ab848d --- /dev/null +++ b/src/test/merkle_tests.cpp @@ -0,0 +1,136 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "consensus/merkle.h" +#include "test/test_bitcoin.h" +#include "random.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(merkle_tests, TestingSetup) + +// Older version of the merkle root computation code, for comparison. +static uint256 BlockBuildMerkleTree(const CBlock& block, bool* fMutated, std::vector& vMerkleTree) +{ + vMerkleTree.clear(); + vMerkleTree.reserve(block.vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes. + for (std::vector::const_iterator it(block.vtx.begin()); it != block.vtx.end(); ++it) + vMerkleTree.push_back(it->GetHash()); + int j = 0; + bool mutated = false; + for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + for (int i = 0; i < nSize; i += 2) + { + int i2 = std::min(i+1, nSize-1); + if (i2 == i + 1 && i2 + 1 == nSize && vMerkleTree[j+i] == vMerkleTree[j+i2]) { + // Two identical hashes at the end of the list at a particular level. + mutated = true; + } + vMerkleTree.push_back(Hash(vMerkleTree[j+i].begin(), vMerkleTree[j+i].end(), + vMerkleTree[j+i2].begin(), vMerkleTree[j+i2].end())); + } + j += nSize; + } + if (fMutated) { + *fMutated = mutated; + } + return (vMerkleTree.empty() ? uint256() : vMerkleTree.back()); +} + +// Older version of the merkle branch computation code, for comparison. +static std::vector BlockGetMerkleBranch(const CBlock& block, const std::vector& vMerkleTree, int nIndex) +{ + std::vector vMerkleBranch; + int j = 0; + for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + int i = std::min(nIndex^1, nSize-1); + vMerkleBranch.push_back(vMerkleTree[j+i]); + nIndex >>= 1; + j += nSize; + } + return vMerkleBranch; +} + +static inline int ctz(uint32_t i) { + if (i == 0) return 0; + int j = 0; + while (!(i & 1)) { + j++; + i >>= 1; + } + return j; +} + +BOOST_AUTO_TEST_CASE(merkle_test) +{ + for (int i = 0; i < 32; i++) { + // Try 32 block sizes: all sizes from 0 to 16 inclusive, and then 15 random sizes. + int ntx = (i <= 16) ? i : 17 + (insecure_rand() % 4000); + // Try up to 3 mutations. + for (int mutate = 0; mutate <= 3; mutate++) { + int duplicate1 = mutate >= 1 ? 1 << ctz(ntx) : 0; // The last how many transactions to duplicate first. + if (duplicate1 >= ntx) break; // Duplication of the entire tree results in a different root (it adds a level). + int ntx1 = ntx + duplicate1; // The resulting number of transactions after the first duplication. + int duplicate2 = mutate >= 2 ? 1 << ctz(ntx1) : 0; // Likewise for the second mutation. + if (duplicate2 >= ntx1) break; + int ntx2 = ntx1 + duplicate2; + int duplicate3 = mutate >= 3 ? 1 << ctz(ntx2) : 0; // And for the third mutation. + if (duplicate3 >= ntx2) break; + int ntx3 = ntx2 + duplicate3; + // Build a block with ntx different transactions. + CBlock block; + block.vtx.resize(ntx); + for (int j = 0; j < ntx; j++) { + CMutableTransaction mtx; + mtx.nLockTime = j; + block.vtx[j] = mtx; + } + // Compute the root of the block before mutating it. + bool unmutatedMutated = false; + uint256 unmutatedRoot = BlockMerkleRoot(block, &unmutatedMutated); + BOOST_CHECK(unmutatedMutated == false); + // Optionally mutate by duplicating the last transactions, resulting in the same merkle root. + block.vtx.resize(ntx3); + for (int j = 0; j < duplicate1; j++) { + block.vtx[ntx + j] = block.vtx[ntx + j - duplicate1]; + } + for (int j = 0; j < duplicate2; j++) { + block.vtx[ntx1 + j] = block.vtx[ntx1 + j - duplicate2]; + } + for (int j = 0; j < duplicate3; j++) { + block.vtx[ntx2 + j] = block.vtx[ntx2 + j - duplicate3]; + } + // Compute the merkle root and merkle tree using the old mechanism. + bool oldMutated = false; + std::vector merkleTree; + uint256 oldRoot = BlockBuildMerkleTree(block, &oldMutated, merkleTree); + // Compute the merkle root using the new mechanism. + bool newMutated = false; + uint256 newRoot = BlockMerkleRoot(block, &newMutated); + BOOST_CHECK(oldRoot == newRoot); + BOOST_CHECK(newRoot == unmutatedRoot); + BOOST_CHECK((newRoot == uint256()) == (ntx == 0)); + BOOST_CHECK(oldMutated == newMutated); + BOOST_CHECK(newMutated == !!mutate); + // If no mutation was done (once for every ntx value), try up to 16 branches. + if (mutate == 0) { + for (int loop = 0; loop < std::min(ntx, 16); loop++) { + // If ntx <= 16, try all branches. Otherise, try 16 random ones. + int mtx = loop; + if (ntx > 16) { + mtx = insecure_rand() % ntx; + } + std::vector newBranch = BlockMerkleBranch(block, mtx); + std::vector oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx); + BOOST_CHECK(oldBranch == newBranch); + BOOST_CHECK(ComputeMerkleRootFromBranch(block.vtx[mtx].GetHash(), newBranch, mtx) == oldRoot); + } + } + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index b78231e38..d4ea5668c 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -1,9 +1,11 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "chainparams.h" #include "coins.h" +#include "consensus/consensus.h" +#include "consensus/merkle.h" #include "consensus/validation.h" #include "main.h" #include "miner.h" @@ -104,27 +106,48 @@ const unsigned int nonces[] = { 1143704, 89400, 277776, 1555386, 2463291, 1965076, 2377228, 170135, 112842, 118000, }; +CBlockIndex CreateBlockIndex(int nHeight) +{ + CBlockIndex index; + index.nHeight = nHeight; + index.pprev = chainActive.Tip(); + return index; +} + +bool TestSequenceLocks(const CTransaction &tx, int flags) +{ + LOCK(mempool.cs); + return CheckSequenceLocks(tx, flags); +} + // NOTE: These tests rely on CreateNewBlock doing its own self-validation! BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { + const CChainParams& chainparams = Params(CBaseChainParams::MAIN); CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; CBlockTemplate *pblocktemplate; CMutableTransaction tx,tx2; CScript script; uint256 hash; + TestMemPoolEntryHelper entry; + entry.nFee = 11; + entry.dPriority = 111.0; + entry.nHeight = 11; + LOCK(cs_main); fCheckpointsEnabled = false; // Simple block creation, nothing special yet: - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) + int baseheight = 0; std::vectortxFirst; for (unsigned int i = 0; i < 110; ++i) { - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); CBlock *pblock = &pblocktemplate->block; // pointer for convenience pblock->hashPrevBlock = chainActive.Tip()->GetBlockHash(); pblock->nVersion = 1; @@ -137,9 +160,11 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) txCoinbase.vout[0].scriptPubKey = CScript(); txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height() + 1, Params().GetConsensus()); pblock->vtx[0] = CTransaction(txCoinbase); - if (txFirst.size() < 2) + if (txFirst.size() == 0) + baseheight = chainActive.Height(); + if (txFirst.size() < 4) txFirst.push_back(new CTransaction(pblock->vtx[0])); - pblock->hashMerkleRoot = pblock->ComputeMerkleRoot(); + pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->nNonce = nonces[i]; /*bool fFound = false; for (int j = 0; !fFound; j++) @@ -156,13 +181,13 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) } }*/ CValidationState state; - BOOST_CHECK(ProcessNewBlock(state, NULL, pblock, true, NULL)); + BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)); BOOST_CHECK(state.IsValid()); delete pblocktemplate; } // Just to make sure we can still make simple blocks - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; // block sigops > limit: 1000 CHECKMULTISIG + 1 @@ -175,12 +200,28 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 50000000LL; for (unsigned int i = 0; i < 1001; ++i) { - tx.vout[0].nValue -= 10000; + tx.vout[0].nValue -= 100; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); + bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase + // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails + mempool.addUnchecked(hash, entry.Fee(100000).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error); + mempool.clear(); + + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vout[0].nValue = 50000000LL; + for (unsigned int i = 0; i < 1001; ++i) + { + tx.vout[0].nValue -= 100; + hash = tx.GetHash(); + bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase + // If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes + mempool.addUnchecked(hash, entry.Fee(50000).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOps(20).FromTx(tx)); + tx.vin[0].prevout.hash = hash; + } + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -192,23 +233,23 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].scriptSig << vchData << OP_DROP; tx.vin[0].scriptSig << OP_1; tx.vin[0].prevout.hash = txFirst[0]->GetHash(); - tx.vout[0].nValue = 50000000LL; + tx.vout[0].nValue = 500000LL; for (unsigned int i = 0; i < 128; ++i) { - tx.vout[0].nValue -= 10000; + tx.vout[0].nValue -= 100; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); + bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase + mempool.addUnchecked(hash, entry.Fee(100000).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); - // orphan in mempool + // orphan in mempool, template creation fails hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); - delete pblocktemplate; + mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).FromTx(tx)); + BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error); mempool.clear(); // child with higher priority than parent @@ -216,7 +257,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = 49000000LL; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); + mempool.addUnchecked(hash, entry.Fee(1000000LL).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin.resize(2); tx.vin[1].scriptSig = CScript() << OP_1; @@ -224,23 +265,23 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[1].prevout.n = 0; tx.vout[0].nValue = 59000000LL; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + mempool.addUnchecked(hash, entry.Fee(4000000LL).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); - // coinbase in mempool + // coinbase in mempool, template creation fails tx.vin.resize(1); tx.vin[0].prevout.SetNull(); tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; tx.vout[0].nValue = 0; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); - delete pblocktemplate; + // give it a fee so it'll get mined + mempool.addUnchecked(hash, entry.Fee(100000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error); mempool.clear(); - // invalid (pre-p2sh) txn in mempool + // invalid (pre-p2sh) txn in mempool, template creation fails tx.vin[0].prevout.hash = txFirst[0]->GetHash(); tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript() << OP_1; @@ -248,76 +289,121 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) script = CScript() << OP_0; tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script)); hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); + mempool.addUnchecked(hash, entry.Fee(10000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; - tx.vin[0].scriptSig = CScript() << (std::vector)script; + tx.vin[0].scriptSig = CScript() << std::vector(script.begin(), script.end()); tx.vout[0].nValue -= 10000; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); - delete pblocktemplate; + mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error); mempool.clear(); - // double spend txn pair in mempool + // double spend txn pair in mempool, template creation fails tx.vin[0].prevout.hash = txFirst[0]->GetHash(); tx.vin[0].scriptSig = CScript() << OP_1; tx.vout[0].nValue = 49000000LL; tx.vout[0].scriptPubKey = CScript() << OP_1; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); + mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); - delete pblocktemplate; + mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error); mempool.clear(); // non-final txs in mempool SetMockTime(chainActive.Tip()->GetMedianTimePast()+1); + int flags = LOCKTIME_VERIFY_SEQUENCE|LOCKTIME_MEDIAN_TIME_PAST; + // height map + std::vector prevheights; - // height locked - tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + // relative height locked + tx.nVersion = 2; + tx.vin.resize(1); + prevheights.resize(1); + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); // only 1 transaction + tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript() << OP_1; - tx.vin[0].nSequence = 0; + tx.vin[0].nSequence = chainActive.Tip()->nHeight + 1; // txFirst[0] is the 2nd block + prevheights[0] = baseheight + 1; + tx.vout.resize(1); tx.vout[0].nValue = 49000000LL; tx.vout[0].scriptPubKey = CScript() << OP_1; - tx.nLockTime = chainActive.Tip()->nHeight+1; + tx.nLockTime = 0; hash = tx.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(!CheckFinalTx(tx)); + mempool.addUnchecked(hash, entry.Fee(1000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes + BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail + BOOST_CHECK(SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 2))); // Sequence locks pass on 2nd block - // time locked - tx2.vin.resize(1); - tx2.vin[0].prevout.hash = txFirst[1]->GetHash(); - tx2.vin[0].prevout.n = 0; - tx2.vin[0].scriptSig = CScript() << OP_1; - tx2.vin[0].nSequence = 0; - tx2.vout.resize(1); - tx2.vout[0].nValue = 49000000LL; - tx2.vout[0].scriptPubKey = CScript() << OP_1; - tx2.nLockTime = chainActive.Tip()->GetMedianTimePast()+1; - hash = tx2.GetHash(); - mempool.addUnchecked(hash, CTxMemPoolEntry(tx2, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(!CheckFinalTx(tx2)); + // relative time locked + tx.vin[0].prevout.hash = txFirst[1]->GetHash(); + tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((chainActive.Tip()->GetMedianTimePast()+1-chainActive[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block + prevheights[0] = baseheight + 2; + hash = tx.GetHash(); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes + BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) + chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast + BOOST_CHECK(SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 1))); // Sequence locks pass 512 seconds later + for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) + chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime -= 512; //undo tricked MTP - // Neither tx should have make it into the template. - BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1); - delete pblocktemplate; + // absolute height locked + tx.vin[0].prevout.hash = txFirst[2]->GetHash(); + tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1; + prevheights[0] = baseheight + 3; + tx.nLockTime = chainActive.Tip()->nHeight + 1; + hash = tx.GetHash(); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(!CheckFinalTx(tx, flags)); // Locktime fails + BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass + BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast())); // Locktime passes on 2nd block - // However if we advance height and time by one, both will. - chainActive.Tip()->nHeight++; - SetMockTime(chainActive.Tip()->GetMedianTimePast()+2); + // absolute time locked + tx.vin[0].prevout.hash = txFirst[3]->GetHash(); + tx.nLockTime = chainActive.Tip()->GetMedianTimePast(); + prevheights.resize(1); + prevheights[0] = baseheight + 4; + hash = tx.GetHash(); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(!CheckFinalTx(tx, flags)); // Locktime fails + BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass + BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later - // FIXME: we should *actually* create a new block so the following test - // works; CheckFinalTx() isn't fooled by monkey-patching nHeight. - //BOOST_CHECK(CheckFinalTx(tx)); - //BOOST_CHECK(CheckFinalTx(tx2)); + // mempool-dependent transactions (not added) + tx.vin[0].prevout.hash = hash; + prevheights[0] = chainActive.Tip()->nHeight + 1; + tx.nLockTime = 0; + tx.vin[0].nSequence = 0; + BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes + BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass + tx.vin[0].nSequence = 1; + BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail + tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG; + BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass + tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1; + BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); + + // None of the of the absolute height/time locked tx should have made + // it into the template because we still check IsFinalTx in CreateNewBlock, + // but relative locked txs will if inconsistently added to mempool. + // For now these will still generate a valid template until BIP68 soft fork BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3); delete pblocktemplate; + // However if we advance height by 1 and time by 512, all of them should be mined + for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) + chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast + chainActive.Tip()->nHeight++; + SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1); + + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); + BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5); + delete pblocktemplate; chainActive.Tip()->nHeight--; SetMockTime(0); diff --git a/src/test/mruset_tests.cpp b/src/test/mruset_tests.cpp deleted file mode 100644 index 2b68f8899..000000000 --- a/src/test/mruset_tests.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "mruset.h" - -#include "random.h" -#include "util.h" -#include "test/test_bitcoin.h" - -#include - -#include - -#define NUM_TESTS 16 -#define MAX_SIZE 100 - -using namespace std; - -BOOST_FIXTURE_TEST_SUITE(mruset_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(mruset_test) -{ - // The mruset being tested. - mruset mru(5000); - - // Run the test 10 times. - for (int test = 0; test < 10; test++) { - // Reset mru. - mru.clear(); - - // A deque + set to simulate the mruset. - std::deque rep; - std::set all; - - // Insert 10000 random integers below 15000. - for (int j=0; j<10000; j++) { - int add = GetRandInt(15000); - mru.insert(add); - - // Add the number to rep/all as well. - if (all.count(add) == 0) { - all.insert(add); - rep.push_back(add); - if (all.size() == 5001) { - all.erase(rep.front()); - rep.pop_front(); - } - } - - // Do a full comparison between mru and the simulated mru every 1000 and every 5001 elements. - if (j % 1000 == 0 || j % 5001 == 0) { - mruset mru2 = mru; // Also try making a copy - - // Check that all elements that should be in there, are in there. - BOOST_FOREACH(int x, rep) { - BOOST_CHECK(mru.count(x)); - BOOST_CHECK(mru2.count(x)); - } - - // Check that all elements that are in there, should be in there. - BOOST_FOREACH(int x, mru) { - BOOST_CHECK(all.count(x)); - } - - // Check that all elements that are in there, should be in there. - BOOST_FOREACH(int x, mru2) { - BOOST_CHECK(all.count(x)); - } - - for (int t = 0; t < 10; t++) { - int r = GetRandInt(15000); - BOOST_CHECK(all.count(r) == mru.count(r)); - BOOST_CHECK(all.count(r) == mru2.count(r)); - } - } - } - } -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index b65c299ad..edf1650ca 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index b1ef0ed24..4168f75e9 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index d9f3c3e46..2f3f60788 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -1,7 +1,8 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "consensus/merkle.h" #include "merkleblock.h" #include "serialize.h" #include "streams.h" @@ -48,7 +49,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1) } // calculate actual merkle root and height - uint256 merkleRoot1 = block.ComputeMerkleRoot(); + uint256 merkleRoot1 = BlockMerkleRoot(block); std::vector vTxid(nTx, uint256()); for (unsigned int j=0; j vMatchTxid2; - uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2); + std::vector vIndex; + uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2, vIndex); // check that it has the same merkle root as the original, and a valid one BOOST_CHECK(merkleRoot1 == merkleRoot2); @@ -101,7 +103,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1) CPartialMerkleTreeTester pmt3(pmt2); pmt3.Damage(); std::vector vMatchTxid3; - uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3); + uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3, vIndex); BOOST_CHECK(merkleRoot3 != merkleRoot1); } } @@ -121,7 +123,8 @@ BOOST_AUTO_TEST_CASE(pmt_malleability) CPartialMerkleTree tree(vTxid, vMatch); std::vector vTxid2; - BOOST_CHECK(tree.ExtractMatches(vTxid).IsNull()); + std::vector vIndex; + BOOST_CHECK(tree.ExtractMatches(vTxid, vIndex).IsNull()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp index cb64ee7c6..644c3da21 100644 --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -16,6 +16,7 @@ BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) { CTxMemPool mpool(CFeeRate(1000)); + TestMemPoolEntryHelper entry; CAmount basefee(2000); double basepri = 1e6; CAmount deltaFee(100); @@ -63,7 +64,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique uint256 hash = tx.GetHash(); - mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx))); + mpool.addUnchecked(hash, entry.Fee(feeV[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).Height(blocknum).FromTx(tx, &mpool)); txHashes[j].push_back(hash); } } @@ -83,11 +84,18 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) block.clear(); if (blocknum == 30) { // At this point we should need to combine 5 buckets to get enough data points - // So estimateFee(1) should fail and estimateFee(2) should return somewhere around - // 8*baserate + // So estimateFee(1,2,3) should fail and estimateFee(4) should return somewhere around + // 8*baserate. estimateFee(4) %'s are 100,100,100,100,90 = average 98% BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0)); - BOOST_CHECK(mpool.estimateFee(2).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee); - BOOST_CHECK(mpool.estimateFee(2).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee); + BOOST_CHECK(mpool.estimateFee(2) == CFeeRate(0)); + BOOST_CHECK(mpool.estimateFee(3) == CFeeRate(0)); + BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee); + BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee); + int answerFound; + BOOST_CHECK(mpool.estimateSmartFee(1, &answerFound) == mpool.estimateFee(4) && answerFound == 4); + BOOST_CHECK(mpool.estimateSmartFee(3, &answerFound) == mpool.estimateFee(4) && answerFound == 4); + BOOST_CHECK(mpool.estimateSmartFee(4, &answerFound) == mpool.estimateFee(4) && answerFound == 4); + BOOST_CHECK(mpool.estimateSmartFee(8, &answerFound) == mpool.estimateFee(8) && answerFound == 8); } } @@ -96,9 +104,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) // Highest feerate is 10*baseRate and gets in all blocks, // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%, // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%, - // so estimateFee(1) should return 9*baseRate. - // Third highest feerate has 90% chance of being included by 2 blocks, - // so estimateFee(2) should return 8*baseRate etc... + // so estimateFee(1) should return 10*baseRate. + // Second highest feerate has 100% chance of being included by 2 blocks, + // so estimateFee(2) should return 9*baseRate etc... for (int i = 1; i < 10;i++) { origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK()); origPriEst.push_back(mpool.estimatePriority(i)); @@ -106,10 +114,11 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]); BOOST_CHECK(origPriEst[i-1] <= origPriEst[i-2]); } - BOOST_CHECK(origFeeEst[i-1] < (10-i)*baseRate.GetFeePerK() + deltaFee); - BOOST_CHECK(origFeeEst[i-1] > (10-i)*baseRate.GetFeePerK() - deltaFee); - BOOST_CHECK(origPriEst[i-1] < pow(10,10-i) * basepri + deltaPri); - BOOST_CHECK(origPriEst[i-1] > pow(10,10-i) * basepri - deltaPri); + int mult = 11-i; + BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee); + BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee); + BOOST_CHECK(origPriEst[i-1] < pow(10,mult) * basepri + deltaPri); + BOOST_CHECK(origPriEst[i-1] > pow(10,mult) * basepri - deltaPri); } // Mine 50 more blocks with no transactions happening, estimates shouldn't change @@ -132,16 +141,19 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx tx.vin[0].prevout.n = 10000*blocknum+100*j+k; uint256 hash = tx.GetHash(); - mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx))); + mpool.addUnchecked(hash, entry.Fee(feeV[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).Height(blocknum).FromTx(tx, &mpool)); txHashes[j].push_back(hash); } } mpool.removeForBlock(block, ++blocknum, dummyConflicted); } + int answerFound; for (int i = 1; i < 10;i++) { - BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); - BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri); + BOOST_CHECK(mpool.estimateFee(i) == CFeeRate(0) || mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); + BOOST_CHECK(mpool.estimateSmartFee(i, &answerFound).GetFeePerK() > origFeeEst[answerFound-1] - deltaFee); + BOOST_CHECK(mpool.estimatePriority(i) == -1 || mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri); + BOOST_CHECK(mpool.estimateSmartPriority(i, &answerFound) > origPriEst[answerFound-1] - deltaPri); } // Mine all those transactions @@ -161,14 +173,14 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri); } - // Mine 100 more blocks where everything is mined every block - // Estimates should be below original estimates (not possible for last estimate) - while (blocknum < 365) { + // Mine 200 more blocks where everything is mined every block + // Estimates should be below original estimates + while (blocknum < 465) { for (int j = 0; j < 10; j++) { // For each fee/pri multiple for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx tx.vin[0].prevout.n = 10000*blocknum+100*j+k; uint256 hash = tx.GetHash(); - mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx))); + mpool.addUnchecked(hash, entry.Fee(feeV[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).Height(blocknum).FromTx(tx, &mpool)); CTransaction btx; if (mpool.lookup(hash, btx)) block.push_back(btx); @@ -177,10 +189,22 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) mpool.removeForBlock(block, ++blocknum, dummyConflicted); block.clear(); } - for (int i = 1; i < 9; i++) { + for (int i = 1; i < 10; i++) { BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee); BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] - deltaPri); } + + // Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee + // and that estimateSmartPriority returns essentially an infinite value + mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[0][5]).Time(GetTime()).Priority(priV[1][5]).Height(blocknum).FromTx(tx, &mpool)); + // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[0][5] + mpool.TrimToSize(1); + BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[0][5]); + for (int i = 1; i < 10; i++) { + BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.estimateFee(i).GetFeePerK()); + BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK()); + BOOST_CHECK(mpool.estimateSmartPriority(i) == INF_PRIORITY); + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp new file mode 100644 index 000000000..b39b90353 --- /dev/null +++ b/src/test/prevector_tests.cpp @@ -0,0 +1,228 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include "prevector.h" +#include "random.h" + +#include "serialize.h" +#include "streams.h" + +#include "test/test_bitcoin.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(PrevectorTests, TestingSetup) + +template +class prevector_tester { + typedef std::vector realtype; + realtype real_vector; + realtype real_vector_alt; + + typedef prevector pretype; + pretype pre_vector; + pretype pre_vector_alt; + + typedef typename pretype::size_type Size; + + void test() { + const pretype& const_pre_vector = pre_vector; + BOOST_CHECK_EQUAL(real_vector.size(), pre_vector.size()); + BOOST_CHECK_EQUAL(real_vector.empty(), pre_vector.empty()); + for (Size s = 0; s < real_vector.size(); s++) { + BOOST_CHECK(real_vector[s] == pre_vector[s]); + BOOST_CHECK(&(pre_vector[s]) == &(pre_vector.begin()[s])); + BOOST_CHECK(&(pre_vector[s]) == &*(pre_vector.begin() + s)); + BOOST_CHECK(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size())); + } + // BOOST_CHECK(realtype(pre_vector) == real_vector); + BOOST_CHECK(pretype(real_vector.begin(), real_vector.end()) == pre_vector); + BOOST_CHECK(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector); + size_t pos = 0; + BOOST_FOREACH(const T& v, pre_vector) { + BOOST_CHECK(v == real_vector[pos++]); + } + BOOST_REVERSE_FOREACH(const T& v, pre_vector) { + BOOST_CHECK(v == real_vector[--pos]); + } + BOOST_FOREACH(const T& v, const_pre_vector) { + BOOST_CHECK(v == real_vector[pos++]); + } + BOOST_REVERSE_FOREACH(const T& v, const_pre_vector) { + BOOST_CHECK(v == real_vector[--pos]); + } + CDataStream ss1(SER_DISK, 0); + CDataStream ss2(SER_DISK, 0); + ss1 << real_vector; + ss2 << pre_vector; + BOOST_CHECK_EQUAL(ss1.size(), ss2.size()); + for (Size s = 0; s < ss1.size(); s++) { + BOOST_CHECK_EQUAL(ss1[s], ss2[s]); + } + } + +public: + void resize(Size s) { + real_vector.resize(s); + BOOST_CHECK_EQUAL(real_vector.size(), s); + pre_vector.resize(s); + BOOST_CHECK_EQUAL(pre_vector.size(), s); + test(); + } + + void reserve(Size s) { + real_vector.reserve(s); + BOOST_CHECK(real_vector.capacity() >= s); + pre_vector.reserve(s); + BOOST_CHECK(pre_vector.capacity() >= s); + test(); + } + + void insert(Size position, const T& value) { + real_vector.insert(real_vector.begin() + position, value); + pre_vector.insert(pre_vector.begin() + position, value); + test(); + } + + void insert(Size position, Size count, const T& value) { + real_vector.insert(real_vector.begin() + position, count, value); + pre_vector.insert(pre_vector.begin() + position, count, value); + test(); + } + + template + void insert_range(Size position, I first, I last) { + real_vector.insert(real_vector.begin() + position, first, last); + pre_vector.insert(pre_vector.begin() + position, first, last); + test(); + } + + void erase(Size position) { + real_vector.erase(real_vector.begin() + position); + pre_vector.erase(pre_vector.begin() + position); + test(); + } + + void erase(Size first, Size last) { + real_vector.erase(real_vector.begin() + first, real_vector.begin() + last); + pre_vector.erase(pre_vector.begin() + first, pre_vector.begin() + last); + test(); + } + + void update(Size pos, const T& value) { + real_vector[pos] = value; + pre_vector[pos] = value; + test(); + } + + void push_back(const T& value) { + real_vector.push_back(value); + pre_vector.push_back(value); + test(); + } + + void pop_back() { + real_vector.pop_back(); + pre_vector.pop_back(); + test(); + } + + void clear() { + real_vector.clear(); + pre_vector.clear(); + } + + void assign(Size n, const T& value) { + real_vector.assign(n, value); + pre_vector.assign(n, value); + } + + Size size() { + return real_vector.size(); + } + + Size capacity() { + return pre_vector.capacity(); + } + + void shrink_to_fit() { + pre_vector.shrink_to_fit(); + test(); + } + + void swap() { + real_vector.swap(real_vector_alt); + pre_vector.swap(pre_vector_alt); + test(); + } +}; + +BOOST_AUTO_TEST_CASE(PrevectorTestInt) +{ + for (int j = 0; j < 64; j++) { + prevector_tester<8, int> test; + for (int i = 0; i < 2048; i++) { + int r = insecure_rand(); + if ((r % 4) == 0) { + test.insert(insecure_rand() % (test.size() + 1), insecure_rand()); + } + if (test.size() > 0 && ((r >> 2) % 4) == 1) { + test.erase(insecure_rand() % test.size()); + } + if (((r >> 4) % 8) == 2) { + int new_size = std::max(0, std::min(30, test.size() + (insecure_rand() % 5) - 2)); + test.resize(new_size); + } + if (((r >> 7) % 8) == 3) { + test.insert(insecure_rand() % (test.size() + 1), 1 + (insecure_rand() % 2), insecure_rand()); + } + if (((r >> 10) % 8) == 4) { + int del = std::min(test.size(), 1 + (insecure_rand() % 2)); + int beg = insecure_rand() % (test.size() + 1 - del); + test.erase(beg, beg + del); + } + if (((r >> 13) % 16) == 5) { + test.push_back(insecure_rand()); + } + if (test.size() > 0 && ((r >> 17) % 16) == 6) { + test.pop_back(); + } + if (((r >> 21) % 32) == 7) { + int values[4]; + int num = 1 + (insecure_rand() % 4); + for (int i = 0; i < num; i++) { + values[i] = insecure_rand(); + } + test.insert_range(insecure_rand() % (test.size() + 1), values, values + num); + } + if (((r >> 26) % 32) == 8) { + int del = std::min(test.size(), 1 + (insecure_rand() % 4)); + int beg = insecure_rand() % (test.size() + 1 - del); + test.erase(beg, beg + del); + } + r = insecure_rand(); + if (r % 32 == 9) { + test.reserve(insecure_rand() % 32); + } + if ((r >> 5) % 64 == 10) { + test.shrink_to_fit(); + } + if (test.size() > 0) { + test.update(insecure_rand() % test.size(), insecure_rand()); + } + if (((r >> 11) % 1024) == 11) { + test.clear(); + } + if (((r >> 21) % 512) == 12) { + test.assign(insecure_rand() % 32, insecure_rand()); + } + if (((r >> 15) % 64) == 3) { + test.swap(); + } + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp index e7e627ae0..8bdff9700 100644 --- a/src/test/reverselock_tests.cpp +++ b/src/test/reverselock_tests.cpp @@ -42,22 +42,18 @@ BOOST_AUTO_TEST_CASE(reverselock_errors) BOOST_CHECK(failed); BOOST_CHECK(!lock.owns_lock()); - // Make sure trying to lock a lock after it has been reverse locked fails - failed = false; - bool locked = false; + // Locking the original lock after it has been taken by a reverse lock + // makes no sense. Ensure that the original lock no longer owns the lock + // after giving it to a reverse one. lock.lock(); BOOST_CHECK(lock.owns_lock()); - - try { + { reverse_lock > rlock(lock); - lock.lock(); - locked = true; - } catch(...) { - failed = true; + BOOST_CHECK(!lock.owns_lock()); } - BOOST_CHECK(locked && failed); + BOOST_CHECK(failed); BOOST_CHECK(lock.owns_lock()); } diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 5ea18d31f..5077b0ff5 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -1,9 +1,9 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcserver.h" -#include "rpcclient.h" +#include "rpc/server.h" +#include "rpc/client.h" #include "base58.h" #include "netbase.h" @@ -11,6 +11,7 @@ #include "test/test_bitcoin.h" #include +#include #include #include @@ -36,7 +37,7 @@ UniValue CallRPC(string args) string strMethod = vArgs[0]; vArgs.erase(vArgs.begin()); UniValue params = RPCConvertValues(strMethod, vArgs); - + BOOST_CHECK(tableRPC[strMethod]); rpcfn_type method = tableRPC[strMethod]->actor; try { UniValue result = (*method)(params, false); @@ -72,6 +73,7 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams) BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), runtime_error); string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"; BOOST_CHECK_NO_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx)); + BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").get_int(), 193); BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1); BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0); BOOST_CHECK_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx+" extra"), runtime_error); @@ -236,7 +238,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) UniValue o1 = ar[0].get_obj(); UniValue adr = find_value(o1, "address"); BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/32"); - BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0 remove")));; + BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0 remove"))); BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); ar = r.get_array(); BOOST_CHECK_EQUAL(ar.size(), 0); @@ -259,14 +261,14 @@ BOOST_AUTO_TEST_CASE(rpc_ban) adr = find_value(o1, "address"); banned_until = find_value(o1, "banned_until"); BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24"); - int64_t now = GetTime(); + int64_t now = GetTime(); BOOST_CHECK(banned_until.get_int64() > now); BOOST_CHECK(banned_until.get_int64()-now <= 200); // must throw an exception because 127.0.0.1 is in already banned suubnet range BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.1 add")), runtime_error); - BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0/24 remove")));; + BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0/24 remove"))); BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); ar = r.get_array(); BOOST_CHECK_EQUAL(ar.size(), 0); @@ -307,4 +309,27 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_EQUAL(adr.get_str(), "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128"); } +BOOST_AUTO_TEST_CASE(rpc_convert_values_generatetoaddress) +{ + UniValue result; + + BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", boost::assign::list_of("101")("mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a"))); + BOOST_CHECK_EQUAL(result[0].get_int(), 101); + BOOST_CHECK_EQUAL(result[1].get_str(), "mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a"); + + BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", boost::assign::list_of("101")("mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU"))); + BOOST_CHECK_EQUAL(result[0].get_int(), 101); + BOOST_CHECK_EQUAL(result[1].get_str(), "mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU"); + + BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", boost::assign::list_of("1")("mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a")("9"))); + BOOST_CHECK_EQUAL(result[0].get_int(), 1); + BOOST_CHECK_EQUAL(result[1].get_str(), "mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a"); + BOOST_CHECK_EQUAL(result[2].get_int(), 9); + + BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", boost::assign::list_of("1")("mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU")("9"))); + BOOST_CHECK_EQUAL(result[0].get_int(), 1); + BOOST_CHECK_EQUAL(result[1].get_str(), "mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU"); + BOOST_CHECK_EQUAL(result[2].get_int(), 9); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index f69e797fd..aa1e1d4a5 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -1,9 +1,9 @@ -// Copyright (c) 2013-2014 The Bitcoin Core developers +// Copyright (c) 2013-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcserver.h" -#include "rpcclient.h" +#include "rpc/server.h" +#include "rpc/client.h" #include "base58.h" #include "main.h" diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp index f5f7f381d..51f9e9f39 100644 --- a/src/test/sanity_tests.cpp +++ b/src/test/sanity_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index cb1a427db..9acd0e243 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -40,6 +40,7 @@ static void MicroSleep(uint64_t n) #endif } +#if 0 /* Disabled for now because there is a race condition issue in this test - see #6540 */ BOOST_AUTO_TEST_CASE(manythreads) { seed_insecure_rand(false); @@ -115,5 +116,6 @@ BOOST_AUTO_TEST_CASE(manythreads) } BOOST_CHECK_EQUAL(counterSum, 200); } +#endif BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 16c9a4a86..28b85e8d2 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -25,7 +25,7 @@ using namespace std; static std::vector Serialize(const CScript& s) { - std::vector sSerialized(s); + std::vector sSerialized(s.begin(), s.end()); return sSerialized; } @@ -339,22 +339,13 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) // SignSignature doesn't know how to sign these. We're // not testing validating signatures, so just create // dummy signatures that DO include the correct P2SH scripts: - txTo.vin[3].scriptSig << OP_11 << OP_11 << static_cast >(oneAndTwo); - txTo.vin[4].scriptSig << static_cast >(fifteenSigops); + txTo.vin[3].scriptSig << OP_11 << OP_11 << vector(oneAndTwo.begin(), oneAndTwo.end()); + txTo.vin[4].scriptSig << vector(fifteenSigops.begin(), fifteenSigops.end()); BOOST_CHECK(::AreInputsStandard(txTo, coins)); // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4] BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U); - // Make sure adding crap to the scriptSigs makes them non-standard: - for (int i = 0; i < 3; i++) - { - CScript t = txTo.vin[i].scriptSig; - txTo.vin[i].scriptSig = (CScript() << 11) + t; - BOOST_CHECK(!::AreInputsStandard(txTo, coins)); - txTo.vin[i].scriptSig = t; - } - CMutableTransaction txToNonStd1; txToNonStd1.vout.resize(1); txToNonStd1.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); @@ -362,7 +353,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txToNonStd1.vin.resize(1); txToNonStd1.vin[0].prevout.n = 5; txToNonStd1.vin[0].prevout.hash = txFrom.GetHash(); - txToNonStd1.vin[0].scriptSig << static_cast >(sixteenSigops); + txToNonStd1.vin[0].scriptSig << vector(sixteenSigops.begin(), sixteenSigops.end()); BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U); @@ -374,7 +365,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txToNonStd2.vin.resize(1); txToNonStd2.vin[0].prevout.n = 6; txToNonStd2.vin[0].prevout.hash = txFrom.GetHash(); - txToNonStd2.vin[0].scriptSig << static_cast >(twentySigops); + txToNonStd2.vin[0].scriptSig << vector(twentySigops.begin(), twentySigops.end()); BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U); diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 8dc31152f..8deefca5b 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1,9 +1,8 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "data/script_invalid.json.h" -#include "data/script_valid.json.h" +#include "data/script_tests.json.h" #include "core_io.h" #include "key.h" @@ -52,6 +51,64 @@ read_json(const std::string& jsondata) return v.get_array(); } +struct ScriptErrorDesc +{ + ScriptError_t err; + const char *name; +}; + +static ScriptErrorDesc script_errors[]={ + {SCRIPT_ERR_OK, "OK"}, + {SCRIPT_ERR_UNKNOWN_ERROR, "UNKNOWN_ERROR"}, + {SCRIPT_ERR_EVAL_FALSE, "EVAL_FALSE"}, + {SCRIPT_ERR_OP_RETURN, "OP_RETURN"}, + {SCRIPT_ERR_SCRIPT_SIZE, "SCRIPT_SIZE"}, + {SCRIPT_ERR_PUSH_SIZE, "PUSH_SIZE"}, + {SCRIPT_ERR_OP_COUNT, "OP_COUNT"}, + {SCRIPT_ERR_STACK_SIZE, "STACK_SIZE"}, + {SCRIPT_ERR_SIG_COUNT, "SIG_COUNT"}, + {SCRIPT_ERR_PUBKEY_COUNT, "PUBKEY_COUNT"}, + {SCRIPT_ERR_VERIFY, "VERIFY"}, + {SCRIPT_ERR_EQUALVERIFY, "EQUALVERIFY"}, + {SCRIPT_ERR_CHECKMULTISIGVERIFY, "CHECKMULTISIGVERIFY"}, + {SCRIPT_ERR_CHECKSIGVERIFY, "CHECKSIGVERIFY"}, + {SCRIPT_ERR_NUMEQUALVERIFY, "NUMEQUALVERIFY"}, + {SCRIPT_ERR_BAD_OPCODE, "BAD_OPCODE"}, + {SCRIPT_ERR_DISABLED_OPCODE, "DISABLED_OPCODE"}, + {SCRIPT_ERR_INVALID_STACK_OPERATION, "INVALID_STACK_OPERATION"}, + {SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, "INVALID_ALTSTACK_OPERATION"}, + {SCRIPT_ERR_UNBALANCED_CONDITIONAL, "UNBALANCED_CONDITIONAL"}, + {SCRIPT_ERR_NEGATIVE_LOCKTIME, "NEGATIVE_LOCKTIME"}, + {SCRIPT_ERR_UNSATISFIED_LOCKTIME, "UNSATISFIED_LOCKTIME"}, + {SCRIPT_ERR_SIG_HASHTYPE, "SIG_HASHTYPE"}, + {SCRIPT_ERR_SIG_DER, "SIG_DER"}, + {SCRIPT_ERR_MINIMALDATA, "MINIMALDATA"}, + {SCRIPT_ERR_SIG_PUSHONLY, "SIG_PUSHONLY"}, + {SCRIPT_ERR_SIG_HIGH_S, "SIG_HIGH_S"}, + {SCRIPT_ERR_SIG_NULLDUMMY, "SIG_NULLDUMMY"}, + {SCRIPT_ERR_PUBKEYTYPE, "PUBKEYTYPE"}, + {SCRIPT_ERR_CLEANSTACK, "CLEANSTACK"}, + {SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, "DISCOURAGE_UPGRADABLE_NOPS"} +}; + +const char *FormatScriptError(ScriptError_t err) +{ + for (unsigned int i=0; i::max(); + txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; txCredit.vout[0].scriptPubKey = scriptPubKey; txCredit.vout[0].nValue = 0; @@ -80,20 +137,21 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMu txSpend.vin[0].prevout.hash = txCredit.GetHash(); txSpend.vin[0].prevout.n = 0; txSpend.vin[0].scriptSig = scriptSig; - txSpend.vin[0].nSequence = std::numeric_limits::max(); + txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; txSpend.vout[0].scriptPubKey = CScript(); txSpend.vout[0].nValue = 0; return txSpend; } -void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message) +void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, const std::string& message, int scriptError) { + bool expect = (scriptError == SCRIPT_ERR_OK); ScriptError err; CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)); CMutableTransaction tx2 = tx; BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0), &err) == expect, message); - BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message); + BOOST_CHECK_MESSAGE(err == scriptError, std::string(FormatScriptError(err)) + " where " + std::string(FormatScriptError((ScriptError_t)scriptError)) + " expected: " + message); #if defined(HAVE_CONSENSUS_LIB) CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << tx2; @@ -187,6 +245,7 @@ private: std::vector push; std::string comment; int flags; + int scriptError; void DoPush() { @@ -204,7 +263,7 @@ private: } public: - TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_) + TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_), scriptError(SCRIPT_ERR_OK) { if (P2SH) { creditTx = BuildCreditingTransaction(CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL); @@ -214,6 +273,12 @@ public: spendTx = BuildSpendingTransaction(CScript(), creditTx); } + TestBuilder& ScriptError(ScriptError_t err) + { + scriptError = err; + return *this; + } + TestBuilder& Add(const CScript& script) { DoPush(); @@ -260,7 +325,7 @@ public: TestBuilder& PushRedeem() { - DoPush(static_cast >(scriptPubKey)); + DoPush(std::vector(scriptPubKey.begin(), scriptPubKey.end())); return *this; } @@ -284,11 +349,11 @@ public: return *this; } - TestBuilder& Test(bool expect) + TestBuilder& Test() { TestBuilder copy = *this; // Make a copy so we can rollback the push. DoPush(); - DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, expect, comment); + DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, comment, scriptError); *this = copy; return *this; } @@ -300,6 +365,7 @@ public: array.push_back(FormatScript(spendTx.vin[0].scriptSig)); array.push_back(FormatScript(creditTx.vout[0].scriptPubKey)); array.push_back(FormatScriptFlags(flags)); + array.push_back(FormatScriptError((ScriptError_t)scriptError)); array.push_back(comment); return array; } @@ -314,332 +380,328 @@ public: return creditTx.vout[0].scriptPubKey; } }; + +std::string JSONPrettyPrint(const UniValue& univalue) +{ + std::string ret = univalue.write(4); + // Workaround for libunivalue pretty printer, which puts a space between comma's and newlines + size_t pos = 0; + while ((pos = ret.find(" \n", pos)) != std::string::npos) { + ret.replace(pos, 2, "\n"); + pos++; + } + return ret; +} } BOOST_AUTO_TEST_CASE(script_build) { const KeyData keys; - std::vector good; - std::vector bad; + std::vector tests; - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "P2PK", 0 - ).PushSig(keys.key0)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "P2PK, bad sig", 0 - ).PushSig(keys.key0).DamagePush(10)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, + "P2PK", 0 + ).PushSig(keys.key0)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, + "P2PK, bad sig", 0 + ).PushSig(keys.key0).DamagePush(10).ScriptError(SCRIPT_ERR_EVAL_FALSE)); - good.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, - "P2PKH", 0 - ).PushSig(keys.key1).Push(keys.pubkey1C)); - bad.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey2C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, - "P2PKH, bad pubkey", 0 - ).PushSig(keys.key2).Push(keys.pubkey2C).DamagePush(5)); + tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, + "P2PKH", 0 + ).PushSig(keys.key1).Push(keys.pubkey1C)); + tests.push_back(TestBuilder(CScript() << 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)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, - "P2PK anyonecanpay", 0 - ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, - "P2PK anyonecanpay marked with normal hashtype", 0 - ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY).EditPush(70, "81", "01")); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, + "P2PK anyonecanpay", 0 + ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, - "P2SH(P2PK)", SCRIPT_VERIFY_P2SH, true - ).PushSig(keys.key0).PushRedeem()); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, - "P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true - ).PushSig(keys.key0).PushRedeem().DamagePush(10)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, + "P2SH(P2PK)", SCRIPT_VERIFY_P2SH, true + ).PushSig(keys.key0).PushRedeem()); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, + "P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true + ).PushSig(keys.key0).PushRedeem().DamagePush(10).ScriptError(SCRIPT_ERR_EVAL_FALSE)); - good.push_back(TestBuilder(CScript() << 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()); - bad.push_back(TestBuilder(CScript() << 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()); + tests.push_back(TestBuilder(CScript() << 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()); + tests.push_back(TestBuilder(CScript() << 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)); - good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, - "3-of-3", 0 - ).Num(0).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2)); - bad.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, - "3-of-3, 2 sigs", 0 - ).Num(0).PushSig(keys.key0).PushSig(keys.key1).Num(0)); + tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, + "3-of-3", 0 + ).Num(0).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2)); + tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); - good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, - "P2SH(2-of-3)", SCRIPT_VERIFY_P2SH, true - ).Num(0).PushSig(keys.key1).PushSig(keys.key2).PushRedeem()); - bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, - "P2SH(2-of-3), 1 sig", SCRIPT_VERIFY_P2SH, true - ).Num(0).PushSig(keys.key1).Num(0).PushRedeem()); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, + "P2SH(2-of-3)", SCRIPT_VERIFY_P2SH, true + ).Num(0).PushSig(keys.key1).PushSig(keys.key2).PushRedeem()); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, - "P2PK with too much R padding but no DERSIG", 0 - ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, - "P2PK with too much R padding", SCRIPT_VERIFY_DERSIG - ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.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")); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.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")); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, - "P2PK with too little R padding but no DERSIG", 0 - ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, - "P2PK with too little R padding", SCRIPT_VERIFY_DERSIG - ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.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")); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.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")); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, + "P2PK with too much R padding but no DERSIG", 0 + ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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")); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, + "P2PK with too little R padding but no DERSIG", 0 + ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, - "BIP66 example 1, without DERSIG", 0 - ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, - "BIP66 example 1, with DERSIG", SCRIPT_VERIFY_DERSIG - ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, - "BIP66 example 2, without DERSIG", 0 - ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, - "BIP66 example 2, with DERSIG", SCRIPT_VERIFY_DERSIG - ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, - "BIP66 example 3, without DERSIG", 0 - ).Num(0)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, - "BIP66 example 3, with DERSIG", SCRIPT_VERIFY_DERSIG - ).Num(0)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, - "BIP66 example 4, without DERSIG", 0 - ).Num(0)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, - "BIP66 example 4, with DERSIG", SCRIPT_VERIFY_DERSIG - ).Num(0)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, - "BIP66 example 5, without DERSIG", 0 - ).Num(1)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, - "BIP66 example 5, with DERSIG", SCRIPT_VERIFY_DERSIG - ).Num(1)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, - "BIP66 example 6, without DERSIG", 0 - ).Num(1)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, - "BIP66 example 6, with DERSIG", SCRIPT_VERIFY_DERSIG - ).Num(1)); - good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); - bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); - bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); - bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); - bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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")); - bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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")); - good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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")); - bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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")); - bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); - bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); - good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); - good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, - "P2PK with multi-byte hashtype, without DERSIG", 0 - ).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101")); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, - "P2PK with multi-byte hashtype, with DERSIG", SCRIPT_VERIFY_DERSIG - ).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101")); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, + "BIP66 example 1, without DERSIG", 0 + ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, + "BIP66 example 3, without DERSIG", 0 + ).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, + "BIP66 example 3, with DERSIG", SCRIPT_VERIFY_DERSIG + ).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, + "BIP66 example 4, without DERSIG", 0 + ).Num(0)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, + "BIP66 example 4, with DERSIG", SCRIPT_VERIFY_DERSIG + ).Num(0)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, + "BIP66 example 5, without DERSIG", 0 + ).Num(1).ScriptError(SCRIPT_ERR_EVAL_FALSE)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, + "BIP66 example 5, with DERSIG", SCRIPT_VERIFY_DERSIG + ).Num(1).ScriptError(SCRIPT_ERR_SIG_DER)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, + "BIP66 example 6, without DERSIG", 0 + ).Num(1)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, + "BIP66 example 6, with DERSIG", SCRIPT_VERIFY_DERSIG + ).Num(1).ScriptError(SCRIPT_ERR_SIG_DER)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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")); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, + "P2PK with multi-byte hashtype, without DERSIG", 0 + ).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101")); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, - "P2PK with high S but no LOW_S", 0 - ).PushSig(keys.key2, SIGHASH_ALL, 32, 33)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, - "P2PK with high S", SCRIPT_VERIFY_LOW_S - ).PushSig(keys.key2, SIGHASH_ALL, 32, 33)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, + "P2PK with high S but no LOW_S", 0 + ).PushSig(keys.key2, SIGHASH_ALL, 32, 33)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, + "P2PK with high S", SCRIPT_VERIFY_LOW_S + ).PushSig(keys.key2, SIGHASH_ALL, 32, 33).ScriptError(SCRIPT_ERR_SIG_HIGH_S)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, - "P2PK with hybrid pubkey but no STRICTENC", 0 - ).PushSig(keys.key0, SIGHASH_ALL)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, - "P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC - ).PushSig(keys.key0, SIGHASH_ALL)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, - "P2PK NOT with hybrid pubkey but no STRICTENC", 0 - ).PushSig(keys.key0, SIGHASH_ALL)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, - "P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC - ).PushSig(keys.key0, SIGHASH_ALL)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, - "P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0 - ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, - "P2PK NOT with invalid hybrid pubkey", SCRIPT_VERIFY_STRICTENC - ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10)); - good.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.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)); - good.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, - "1-of-2 with the second 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC - ).Num(0).PushSig(keys.key1, SIGHASH_ALL)); - bad.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, + "P2PK with hybrid pubkey but no STRICTENC", 0 + ).PushSig(keys.key0, SIGHASH_ALL)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, + "P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC + ).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE)); + tests.push_back(TestBuilder(CScript() << 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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, + "P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC + ).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, + "P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0 + ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10)); + tests.push_back(TestBuilder(CScript() << 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)); + tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, + "1-of-2 with the second 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC + ).Num(0).PushSig(keys.key1, SIGHASH_ALL)); + tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.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)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, - "P2PK with undefined hashtype but no STRICTENC", 0 - ).PushSig(keys.key1, 5)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, - "P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC - ).PushSig(keys.key1, 5)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, - "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC", 0 - ).PushSig(keys.key1, 5).DamagePush(10)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, - "P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC - ).PushSig(keys.key1, 5).DamagePush(10)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, + "P2PK with undefined hashtype but no STRICTENC", 0 + ).PushSig(keys.key1, 5)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, + "P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC + ).PushSig(keys.key1, 5).ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, + "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC", 0 + ).PushSig(keys.key1, 5).DamagePush(10)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.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)); - good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, - "3-of-3 with nonzero dummy but no NULLDUMMY", 0 - ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2)); - bad.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, - "3-of-3 with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY - ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2)); - good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, - "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY", 0 - ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10)); - bad.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, - "3-of-3 NOT with invalid sig with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY - ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10)); + tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, + "3-of-3 with nonzero dummy but no NULLDUMMY", 0 + ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2)); + tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, + "3-of-3 with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY + ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); + tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, + "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY", 0 + ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10)); + tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, + "3-of-3 NOT with invalid sig with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY + ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10).ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); - good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); - bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, - "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", 0 - ).PushSig(keys.key2).PushRedeem()); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, - "P2SH(P2PK) with non-push scriptSig", SCRIPT_VERIFY_SIGPUSHONLY - ).PushSig(keys.key2).PushRedeem()); - good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); - - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "P2PK with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH - ).Num(11).PushSig(keys.key0)); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "P2PK with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH - ).Num(11).PushSig(keys.key0)); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "P2SH with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH, true - ).Num(11).PushSig(keys.key0).PushRedeem()); - bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "P2SH with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true - ).Num(11).PushSig(keys.key0).PushRedeem()); - good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "P2SH with CLEANSTACK", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true - ).PushSig(keys.key0).PushRedeem()); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, + "P2SH(P2PK) with non-push scriptSig but no P2SH or SIGPUSHONLY", 0, true + ).PushSig(keys.key2).Add(CScript() << OP_NOP9).PushRedeem()); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, + "P2PK with non-push scriptSig but with P2SH validation", 0 + ).PushSig(keys.key2).Add(CScript() << OP_NOP9)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, + "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", SCRIPT_VERIFY_P2SH, true + ).PushSig(keys.key2).Add(CScript() << OP_NOP9).PushRedeem().ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, + "P2SH(P2PK) with non-push scriptSig but not P2SH", SCRIPT_VERIFY_SIGPUSHONLY, true + ).PushSig(keys.key2).Add(CScript() << OP_NOP9).PushRedeem().ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); + tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.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)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, + "P2PK with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH + ).Num(11).PushSig(keys.key0)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, + "P2PK with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH + ).Num(11).PushSig(keys.key0).ScriptError(SCRIPT_ERR_CLEANSTACK)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, + "P2SH with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH, true + ).Num(11).PushSig(keys.key0).PushRedeem()); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, + "P2SH with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true + ).Num(11).PushSig(keys.key0).PushRedeem().ScriptError(SCRIPT_ERR_CLEANSTACK)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, + "P2SH with CLEANSTACK", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true + ).PushSig(keys.key0).PushRedeem()); - std::set tests_good; - std::set tests_bad; + std::set tests_set; { - UniValue json_good = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid))); - UniValue json_bad = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid))); + UniValue json_tests = read_json(std::string(json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests))); - for (unsigned int idx = 0; idx < json_good.size(); idx++) { - const UniValue& tv = json_good[idx]; - tests_good.insert(tv.get_array().write()); - } - for (unsigned int idx = 0; idx < json_bad.size(); idx++) { - const UniValue& tv = json_bad[idx]; - tests_bad.insert(tv.get_array().write()); + for (unsigned int idx = 0; idx < json_tests.size(); idx++) { + const UniValue& tv = json_tests[idx]; + tests_set.insert(JSONPrettyPrint(tv.get_array())); } } - std::string strGood; - std::string strBad; + std::string strGen; - BOOST_FOREACH(TestBuilder& test, good) { - test.Test(true); - std::string str = test.GetJSON().write(); + BOOST_FOREACH(TestBuilder& test, tests) { + test.Test(); + std::string str = JSONPrettyPrint(test.GetJSON()); #ifndef UPDATE_JSON_TESTS - if (tests_good.count(str) == 0) { + if (tests_set.count(str) == 0) { BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment()); } #endif - strGood += str + ",\n"; - } - BOOST_FOREACH(TestBuilder& test, bad) { - test.Test(false); - std::string str = test.GetJSON().write(); -#ifndef UPDATE_JSON_TESTS - if (tests_bad.count(str) == 0) { - BOOST_CHECK_MESSAGE(false, "Missing auto script_invalid test: " + test.GetComment()); - } -#endif - strBad += str + ",\n"; + strGen += str + ",\n"; } #ifdef UPDATE_JSON_TESTS - FILE* valid = fopen("script_valid.json.gen", "w"); - fputs(strGood.c_str(), valid); - fclose(valid); - FILE* invalid = fopen("script_invalid.json.gen", "w"); - fputs(strBad.c_str(), invalid); - fclose(invalid); + FILE* file = fopen("script_tests.json.gen", "w"); + fputs(strGen.c_str(), file); + fclose(file); #endif } -BOOST_AUTO_TEST_CASE(script_valid) +BOOST_AUTO_TEST_CASE(script_json_test) { - // Read tests from test/data/script_valid.json + // Read tests from test/data/script_tests.json // Format is an array of arrays - // Inner arrays are [ "scriptSig", "scriptPubKey", "flags" ] + // Inner arrays are [ "scriptSig", "scriptPubKey", "flags", "expected_scripterror" ] // ... where scriptSig and scriptPubKey are stringified // scripts. - UniValue tests = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid))); + UniValue tests = read_json(std::string(json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests))); for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; string strTest = test.write(); - if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments) + if (test.size() < 4) // Allow size > 3; extra stuff ignored (useful for comments) { if (test.size() != 1) { BOOST_ERROR("Bad test: " << strTest); @@ -651,33 +713,9 @@ BOOST_AUTO_TEST_CASE(script_valid) string scriptPubKeyString = test[1].get_str(); CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[2].get_str()); + int scriptError = ParseScriptError(test[3].get_str()); - DoTest(scriptPubKey, scriptSig, scriptflags, true, strTest); - } -} - -BOOST_AUTO_TEST_CASE(script_invalid) -{ - // Scripts that should evaluate as invalid - UniValue tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid))); - - for (unsigned int idx = 0; idx < tests.size(); idx++) { - UniValue test = tests[idx]; - string strTest = test.write(); - if (test.size() < 3) // Allow size > 2; extra stuff ignored (useful for comments) - { - if (test.size() != 1) { - BOOST_ERROR("Bad test: " << strTest); - } - continue; - } - string scriptSigString = test[0].get_str(); - CScript scriptSig = ParseScript(scriptSigString); - string scriptPubKeyString = test[1].get_str(); - CScript scriptPubKey = ParseScript(scriptPubKeyString); - unsigned int scriptflags = ParseScriptFlags(test[2].get_str()); - - DoTest(scriptPubKey, scriptSig, scriptflags, false, strTest); + DoTest(scriptPubKey, scriptSig, scriptflags, strTest, scriptError); } } @@ -892,7 +930,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig); BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig); // dummy scriptSigCopy with placeholder, should always choose non-placeholder: - scriptSigCopy = CScript() << OP_0 << static_cast >(pkSingle); + scriptSigCopy = CScript() << OP_0 << vector(pkSingle.begin(), pkSingle.end()); combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig); BOOST_CHECK(combined == scriptSig); combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, scriptSigCopy); @@ -1028,10 +1066,10 @@ BOOST_AUTO_TEST_CASE(script_IsPushOnly_on_invalid_scripts) BOOST_AUTO_TEST_CASE(script_GetScriptAsm) { - BOOST_CHECK_EQUAL("OP_NOP3", ScriptToAsmStr(CScript() << OP_NOP3, true)); - BOOST_CHECK_EQUAL("OP_NOP3", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true)); - BOOST_CHECK_EQUAL("OP_NOP3", ScriptToAsmStr(CScript() << OP_NOP3)); - BOOST_CHECK_EQUAL("OP_NOP3", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY)); + BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2, true)); + BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true)); + BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2)); + BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY)); string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090"); string pubKey("03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2"); diff --git a/src/test/scriptnum10.h b/src/test/scriptnum10.h new file mode 100644 index 000000000..94dd58526 --- /dev/null +++ b/src/test/scriptnum10.h @@ -0,0 +1,183 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_TEST_SCRIPTNUM10_H +#define BITCOIN_TEST_SCRIPTNUM10_H + +#include +#include +#include +#include +#include +#include +#include "assert.h" + +class scriptnum10_error : public std::runtime_error +{ +public: + explicit scriptnum10_error(const std::string& str) : std::runtime_error(str) {} +}; + +class CScriptNum10 +{ +/** + * The ScriptNum implementation from Bitcoin Core 0.10.0, for cross-comparison. + */ +public: + + explicit CScriptNum10(const int64_t& n) + { + m_value = n; + } + + static const size_t nDefaultMaxNumSize = 4; + + explicit CScriptNum10(const std::vector& vch, bool fRequireMinimal, + const size_t nMaxNumSize = nDefaultMaxNumSize) + { + if (vch.size() > nMaxNumSize) { + throw scriptnum10_error("script number overflow"); + } + if (fRequireMinimal && vch.size() > 0) { + // Check that the number is encoded with the minimum possible + // number of bytes. + // + // If the most-significant-byte - excluding the sign bit - is zero + // then we're not minimal. Note how this test also rejects the + // negative-zero encoding, 0x80. + if ((vch.back() & 0x7f) == 0) { + // One exception: if there's more than one byte and the most + // significant bit of the second-most-significant-byte is set + // it would conflict with the sign bit. An example of this case + // is +-255, which encode to 0xff00 and 0xff80 respectively. + // (big-endian). + if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) { + throw scriptnum10_error("non-minimally encoded script number"); + } + } + } + m_value = set_vch(vch); + } + + inline bool operator==(const int64_t& rhs) const { return m_value == rhs; } + inline bool operator!=(const int64_t& rhs) const { return m_value != rhs; } + inline bool operator<=(const int64_t& rhs) const { return m_value <= rhs; } + inline bool operator< (const int64_t& rhs) const { return m_value < rhs; } + inline bool operator>=(const int64_t& rhs) const { return m_value >= rhs; } + inline bool operator> (const int64_t& rhs) const { return m_value > rhs; } + + inline bool operator==(const CScriptNum10& rhs) const { return operator==(rhs.m_value); } + inline bool operator!=(const CScriptNum10& rhs) const { return operator!=(rhs.m_value); } + inline bool operator<=(const CScriptNum10& rhs) const { return operator<=(rhs.m_value); } + inline bool operator< (const CScriptNum10& rhs) const { return operator< (rhs.m_value); } + inline bool operator>=(const CScriptNum10& rhs) const { return operator>=(rhs.m_value); } + inline bool operator> (const CScriptNum10& rhs) const { return operator> (rhs.m_value); } + + inline CScriptNum10 operator+( const int64_t& rhs) const { return CScriptNum10(m_value + rhs);} + inline CScriptNum10 operator-( const int64_t& rhs) const { return CScriptNum10(m_value - rhs);} + inline CScriptNum10 operator+( const CScriptNum10& rhs) const { return operator+(rhs.m_value); } + inline CScriptNum10 operator-( const CScriptNum10& rhs) const { return operator-(rhs.m_value); } + + inline CScriptNum10& operator+=( const CScriptNum10& rhs) { return operator+=(rhs.m_value); } + inline CScriptNum10& operator-=( const CScriptNum10& rhs) { return operator-=(rhs.m_value); } + + inline CScriptNum10 operator-() const + { + assert(m_value != std::numeric_limits::min()); + return CScriptNum10(-m_value); + } + + inline CScriptNum10& operator=( const int64_t& rhs) + { + m_value = rhs; + return *this; + } + + inline CScriptNum10& operator+=( const int64_t& rhs) + { + assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits::max() - rhs) || + (rhs < 0 && m_value >= std::numeric_limits::min() - rhs)); + m_value += rhs; + return *this; + } + + inline CScriptNum10& operator-=( const int64_t& rhs) + { + assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits::min() + rhs) || + (rhs < 0 && m_value <= std::numeric_limits::max() + rhs)); + m_value -= rhs; + return *this; + } + + int getint() const + { + if (m_value > std::numeric_limits::max()) + return std::numeric_limits::max(); + else if (m_value < std::numeric_limits::min()) + return std::numeric_limits::min(); + return m_value; + } + + std::vector getvch() const + { + return serialize(m_value); + } + + static std::vector serialize(const int64_t& value) + { + if(value == 0) + return std::vector(); + + std::vector result; + const bool neg = value < 0; + uint64_t absvalue = neg ? -value : value; + + while(absvalue) + { + result.push_back(absvalue & 0xff); + absvalue >>= 8; + } + +// - If the most significant byte is >= 0x80 and the value is positive, push a +// new zero-byte to make the significant byte < 0x80 again. + +// - If the most significant byte is >= 0x80 and the value is negative, push a +// new 0x80 byte that will be popped off when converting to an integral. + +// - If the most significant byte is < 0x80 and the value is negative, add +// 0x80 to it, since it will be subtracted and interpreted as a negative when +// converting to an integral. + + if (result.back() & 0x80) + result.push_back(neg ? 0x80 : 0); + else if (neg) + result.back() |= 0x80; + + return result; + } + +private: + static int64_t set_vch(const std::vector& vch) + { + if (vch.empty()) + return 0; + + int64_t result = 0; + for (size_t i = 0; i != vch.size(); ++i) + result |= static_cast(vch[i]) << 8*i; + + // If the input vector's most significant byte is 0x80, remove it from + // the result's msb and return a negative. + if (vch.back() & 0x80) + return -((int64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1))))); + + return result; + } + + int64_t m_value; +}; + + +#endif // BITCOIN_TEST_BIGNUM_H diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp index d95724dbe..6b6689c7d 100644 --- a/src/test/scriptnum_tests.cpp +++ b/src/test/scriptnum_tests.cpp @@ -1,8 +1,8 @@ -// Copyright (c) 2012-2014 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "bignum.h" +#include "scriptnum10.h" #include "script/script.h" #include "test/test_bitcoin.h" @@ -16,45 +16,48 @@ static const int64_t values[] = \ { 0, 1, CHAR_MIN, CHAR_MAX, UCHAR_MAX, SHRT_MIN, USHRT_MAX, INT_MIN, INT_MAX, UINT_MAX, LONG_MIN, LONG_MAX }; static const int64_t offsets[] = { 1, 0x79, 0x80, 0x81, 0xFF, 0x7FFF, 0x8000, 0xFFFF, 0x10000}; -static bool verify(const CBigNum& bignum, const CScriptNum& scriptnum) +static bool verify(const CScriptNum10& bignum, const CScriptNum& scriptnum) { return bignum.getvch() == scriptnum.getvch() && bignum.getint() == scriptnum.getint(); } static void CheckCreateVch(const int64_t& num) { - CBigNum bignum(num); + CScriptNum10 bignum(num); CScriptNum scriptnum(num); BOOST_CHECK(verify(bignum, scriptnum)); - CBigNum bignum2(bignum.getvch()); + std::vector vch = bignum.getvch(); + + CScriptNum10 bignum2(bignum.getvch(), false); + vch = scriptnum.getvch(); CScriptNum scriptnum2(scriptnum.getvch(), false); BOOST_CHECK(verify(bignum2, scriptnum2)); - CBigNum bignum3(scriptnum2.getvch()); + CScriptNum10 bignum3(scriptnum2.getvch(), false); CScriptNum scriptnum3(bignum2.getvch(), false); BOOST_CHECK(verify(bignum3, scriptnum3)); } static void CheckCreateInt(const int64_t& num) { - CBigNum bignum(num); + CScriptNum10 bignum(num); CScriptNum scriptnum(num); BOOST_CHECK(verify(bignum, scriptnum)); - BOOST_CHECK(verify(bignum.getint(), CScriptNum(scriptnum.getint()))); - BOOST_CHECK(verify(scriptnum.getint(), CScriptNum(bignum.getint()))); - BOOST_CHECK(verify(CBigNum(scriptnum.getint()).getint(), CScriptNum(CScriptNum(bignum.getint()).getint()))); + BOOST_CHECK(verify(CScriptNum10(bignum.getint()), CScriptNum(scriptnum.getint()))); + BOOST_CHECK(verify(CScriptNum10(scriptnum.getint()), CScriptNum(bignum.getint()))); + BOOST_CHECK(verify(CScriptNum10(CScriptNum10(scriptnum.getint()).getint()), CScriptNum(CScriptNum(bignum.getint()).getint()))); } static void CheckAdd(const int64_t& num1, const int64_t& num2) { - const CBigNum bignum1(num1); - const CBigNum bignum2(num2); + const CScriptNum10 bignum1(num1); + const CScriptNum10 bignum2(num2); const CScriptNum scriptnum1(num1); const CScriptNum scriptnum2(num2); - CBigNum bignum3(num1); - CBigNum bignum4(num1); + CScriptNum10 bignum3(num1); + CScriptNum10 bignum4(num1); CScriptNum scriptnum3(num1); CScriptNum scriptnum4(num1); @@ -71,7 +74,7 @@ static void CheckAdd(const int64_t& num1, const int64_t& num2) static void CheckNegate(const int64_t& num) { - const CBigNum bignum(num); + const CScriptNum10 bignum(num); const CScriptNum scriptnum(num); // -INT64_MIN is undefined @@ -81,8 +84,8 @@ static void CheckNegate(const int64_t& num) static void CheckSubtract(const int64_t& num1, const int64_t& num2) { - const CBigNum bignum1(num1); - const CBigNum bignum2(num2); + const CScriptNum10 bignum1(num1); + const CScriptNum10 bignum2(num2); const CScriptNum scriptnum1(num1); const CScriptNum scriptnum2(num2); bool invalid = false; @@ -107,8 +110,8 @@ static void CheckSubtract(const int64_t& num1, const int64_t& num2) static void CheckCompare(const int64_t& num1, const int64_t& num2) { - const CBigNum bignum1(num1); - const CBigNum bignum2(num2); + const CScriptNum10 bignum1(num1); + const CScriptNum10 bignum2(num2); const CScriptNum scriptnum1(num1); const CScriptNum scriptnum2(num2); @@ -149,7 +152,7 @@ static void RunCreate(const int64_t& num) CheckCreateVch(num); else { - BOOST_CHECK_THROW (CheckCreateVch(num), scriptnum_error); + BOOST_CHECK_THROW (CheckCreateVch(num), scriptnum10_error); } } diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index cc8f2b788..bec2c7459 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -160,6 +160,27 @@ BOOST_AUTO_TEST_CASE(varints) } } +BOOST_AUTO_TEST_CASE(varints_bitpatterns) +{ + CDataStream ss(SER_DISK, 0); + ss << VARINT(0); BOOST_CHECK_EQUAL(HexStr(ss), "00"); ss.clear(); + ss << VARINT(0x7f); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear(); + ss << VARINT((int8_t)0x7f); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear(); + ss << VARINT(0x80); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear(); + ss << VARINT((uint8_t)0x80); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear(); + ss << VARINT(0x1234); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear(); + ss << VARINT((int16_t)0x1234); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear(); + ss << VARINT(0xffff); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear(); + ss << VARINT((uint16_t)0xffff); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear(); + ss << VARINT(0x123456); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear(); + ss << VARINT((int32_t)0x123456); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear(); + ss << VARINT(0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear(); + ss << VARINT((uint32_t)0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear(); + ss << VARINT(0xffffffff); BOOST_CHECK_EQUAL(HexStr(ss), "8efefefe7f"); ss.clear(); + ss << VARINT(0x7fffffffffffffffLL); BOOST_CHECK_EQUAL(HexStr(ss), "fefefefefefefefe7f"); ss.clear(); + ss << VARINT(0xffffffffffffffffULL); BOOST_CHECK_EQUAL(HexStr(ss), "80fefefefefefefefe7f"); ss.clear(); +} + BOOST_AUTO_TEST_CASE(compactsize) { CDataStream ss(SER_DISK, 0); diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 6fca64d5d..04c6fa962 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Bitcoin Core developers +// Copyright (c) 2013-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index b26fed99f..a207fd921 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -20,7 +20,7 @@ using namespace std; static std::vector Serialize(const CScript& s) { - std::vector sSerialized(s); + std::vector sSerialized(s.begin(), s.end()); return sSerialized; } diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp index a904e3862..f14b902fe 100644 --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014 The Bitcoin Core developers +// Copyright (c) 2014-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index 0ed8f363d..34f501e86 100644 --- a/src/test/streams_tests.cpp +++ b/src/test/streams_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index efc537e0e..5f272a72f 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,19 +15,22 @@ #include "pubkey.h" #include "random.h" #include "txdb.h" +#include "txmempool.h" #include "ui_interface.h" -#include "util.h" +#include "rpc/server.h" +#include "rpc/register.h" #ifdef ENABLE_WALLET #include "wallet/db.h" #include "wallet/wallet.h" #endif +#include "test/testutil.h" + #include #include #include CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h -CWallet* pwalletMain; extern bool fPrintToConsole; extern void noui_connect(); @@ -36,6 +39,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName) { ECC_Start(); SetupEnvironment(); + SetupNetworking(); fPrintToDebugLog = false; // don't want to write to debug.log file fCheckBlockIndex = true; SelectParams(chainName); @@ -49,8 +53,13 @@ BasicTestingSetup::~BasicTestingSetup() TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName) { + const CChainParams& chainparams = Params(); + // Ideally we'd move all the RPC tests to the functional testing framework + // instead of unit tests, but for now we need these here. + RegisterAllCoreRPCCommands(tableRPC); #ifdef ENABLE_WALLET bitdb.MakeMock(); + RegisterWalletRPCCommands(tableRPC); #endif ClearDatadirCache(); pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); @@ -60,7 +69,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha pcoinsdbview = new CCoinsViewDB(1 << 23, true); pcoinsTip = new CCoinsViewCache(pcoinsdbview); pclaimTrie = new CClaimTrie(true, false, 1); - InitBlockIndex(); + InitBlockIndex(chainparams); #ifdef ENABLE_WALLET bool fFirstRun; pwalletMain = new CWallet("wallet.dat"); @@ -115,7 +124,8 @@ TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST) CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector& txns, const CScript& scriptPubKey) { - CBlockTemplate *pblocktemplate = CreateNewBlock(scriptPubKey); + const CChainParams& chainparams = Params(CBaseChainParams::REGTEST); + CBlockTemplate *pblocktemplate = CreateNewBlock(chainparams, scriptPubKey); CBlock& block = pblocktemplate->block; // Replace mempool-selected txns with just coinbase plus passed-in txns: @@ -126,10 +136,10 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector& unsigned int extraNonce = 0; IncrementExtraNonce(&block, chainActive.Tip(), extraNonce); - while (!CheckProofOfWork(block.GetPoWHash(), block.nBits, Params(CBaseChainParams::REGTEST).GetConsensus())) ++block.nNonce; + while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; CValidationState state; - ProcessNewBlock(state, NULL, &block, true, NULL); + ProcessNewBlock(state, chainparams, NULL, &block, true, NULL); CBlock result = block; delete pblocktemplate; @@ -142,10 +152,23 @@ TestChain100Setup::~TestChain100Setup() RegTestingSetup::RegTestingSetup() : TestingSetup(CBaseChainParams::REGTEST) { + minRelayTxFee = CFeeRate(0); } RegTestingSetup::~RegTestingSetup() { + minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); +} + + +CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPool *pool) { + CTransaction txn(tx); + bool hasNoDependencies = pool ? pool->HasNoInputsOf(tx) : hadNoDependencies; + // Hack to assume either its completely dependent on other mempool txs or not at all + CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0; + + return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight, + hasNoDependencies, inChainValue, spendsCoinbase, sigOpCount, lp); } void Shutdown(void* parg) diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 58a35ff3d..d5ca079b2 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -1,9 +1,15 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef BITCOIN_TEST_TEST_BITCOIN_H #define BITCOIN_TEST_TEST_BITCOIN_H #include "chainparamsbase.h" #include "key.h" +#include "pubkey.h" #include "txdb.h" +#include "txmempool.h" #include #include @@ -12,6 +18,8 @@ * This just configures logging and chain parameters. */ struct BasicTestingSetup { + ECCVerifyHandle globalVerifyHandle; + BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN); ~BasicTestingSetup(); }; @@ -56,4 +64,34 @@ struct RegTestingSetup: public TestingSetup { ~RegTestingSetup(); }; +class CTxMemPoolEntry; +class CTxMemPool; + +struct TestMemPoolEntryHelper +{ + // Default values + CAmount nFee; + int64_t nTime; + double dPriority; + unsigned int nHeight; + bool hadNoDependencies; + bool spendsCoinbase; + unsigned int sigOpCount; + LockPoints lp; + + TestMemPoolEntryHelper() : + nFee(0), nTime(0), dPriority(0.0), nHeight(1), + hadNoDependencies(false), spendsCoinbase(false), sigOpCount(1) { } + + CTxMemPoolEntry FromTx(CMutableTransaction &tx, CTxMemPool *pool = NULL); + + // Change the default value + TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; } + TestMemPoolEntryHelper &Time(int64_t _time) { nTime = _time; return *this; } + TestMemPoolEntryHelper &Priority(double _priority) { dPriority = _priority; return *this; } + TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; } + TestMemPoolEntryHelper &HadNoDependencies(bool _hnd) { hadNoDependencies = _hnd; return *this; } + TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; } + TestMemPoolEntryHelper &SigOps(unsigned int _sigops) { sigOpCount = _sigops; return *this; } +}; #endif diff --git a/src/test/testutil.cpp b/src/test/testutil.cpp new file mode 100644 index 000000000..304cffb79 --- /dev/null +++ b/src/test/testutil.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2009-2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "testutil.h" + +#ifdef WIN32 +#include +#endif + +#include + +boost::filesystem::path GetTempPath() { +#if BOOST_FILESYSTEM_VERSION == 3 + return boost::filesystem::temp_directory_path(); +#else + // TODO: remove when we don't support filesystem v2 anymore + boost::filesystem::path path; +#ifdef WIN32 + char pszPath[MAX_PATH] = ""; + + if (GetTempPathA(MAX_PATH, pszPath)) + path = boost::filesystem::path(pszPath); +#else + path = boost::filesystem::path("/tmp"); +#endif + if (path.empty() || !boost::filesystem::is_directory(path)) { + LogPrintf("GetTempPath(): failed to find temp path\n"); + return boost::filesystem::path(""); + } + return path; +#endif +} diff --git a/src/test/testutil.h b/src/test/testutil.h new file mode 100644 index 000000000..5875dc50e --- /dev/null +++ b/src/test/testutil.h @@ -0,0 +1,15 @@ +// Copyright (c) 2009-2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +/** + * Utility functions shared by unit tests + */ +#ifndef BITCOIN_TEST_TESTUTIL_H +#define BITCOIN_TEST_TESTUTIL_H + +#include + +boost::filesystem::path GetTempPath(); + +#endif // BITCOIN_TEST_TESTUTIL_H diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp index 887cfb476..1224ff845 100644 --- a/src/test/timedata_tests.cpp +++ b/src/test/timedata_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 31ac3fe23..17f9f9e5b 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -44,7 +44,8 @@ static std::map mapFlagNames = boost::assign::map_list_of (string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY) (string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) (string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK) - (string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY); + (string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) + (string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY); unsigned int ParseScriptFlags(string strFlags) { @@ -310,14 +311,6 @@ BOOST_AUTO_TEST_CASE(test_Get) BOOST_CHECK(AreInputsStandard(t1, coins)); BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT); - - // Adding extra junk to the scriptSig should make it non-standard: - t1.vin[0].scriptSig << OP_11; - BOOST_CHECK(!AreInputsStandard(t1, coins)); - - // ... as should not having enough: - t1.vin[0].scriptSig = CScript(); - BOOST_CHECK(!AreInputsStandard(t1, coins)); } BOOST_AUTO_TEST_CASE(test_IsStandard) @@ -342,12 +335,27 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) string reason; BOOST_CHECK(IsStandardTx(t, reason)); - //t.vout[0].nValue = 501; // dust + // Check dust with default relay fee: + CAmount nDustThreshold = 182 * minRelayTxFee.GetFeePerK()/1000 * 3; + BOOST_CHECK_EQUAL(nDustThreshold, 546); + // dust: + //t.vout[0].nValue = nDustThreshold - 1; //BOOST_CHECK(!IsStandardTx(t, reason)); - - t.vout[0].nValue = 2730; // not dust + // not dust: + t.vout[0].nValue = nDustThreshold; BOOST_CHECK(IsStandardTx(t, reason)); + // Check dust with odd relay fee to verify rounding: + // nDustThreshold = 182 * 1234 / 1000 * 3 + minRelayTxFee = CFeeRate(1234); + // dust: + //t.vout[0].nValue = 672 - 1; + //BOOST_CHECK(!IsStandardTx(t, reason)); + // not dust: + t.vout[0].nValue = 672; + BOOST_CHECK(IsStandardTx(t, reason)); + minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); + t.vout[0].scriptPubKey = CScript() << OP_1; BOOST_CHECK(!IsStandardTx(t, reason)); diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index edad18644..237b26329 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -23,7 +23,7 @@ ToMemPool(CMutableTransaction& tx) LOCK(cs_main); CValidationState state; - return AcceptToMemoryPool(mempool, state, tx, false, NULL, false); + return AcceptToMemoryPool(mempool, state, tx, false, NULL, NULL, true, 0); } BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index 426d296a9..da0a3d73e 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "arith_uint256.h" diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp index 945c1acbe..45d480c81 100644 --- a/src/test/univalue_tests.cpp +++ b/src/test/univalue_tests.cpp @@ -1,4 +1,5 @@ // Copyright 2014 BitPay, Inc. +// Copyright (c) 2014-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 997dc3193..b99f952a0 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -60,6 +60,10 @@ BOOST_AUTO_TEST_CASE(util_ParseHex) result = ParseHex("12 34 56 78"); BOOST_CHECK(result.size() == 4 && result[0] == 0x12 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78); + // Leading space must be supported (used in CDBEnv::Salvage) + result = ParseHex(" 89 34 56 78"); + BOOST_CHECK(result.size() == 4 && result[0] == 0x89 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78); + // Stop parsing at invalid value result = ParseHex("1234 invalid 1234"); BOOST_CHECK(result.size() == 2 && result[0] == 0x12 && result[1] == 0x34); @@ -196,6 +200,8 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney) BOOST_CHECK_EQUAL(ret, COIN*10); BOOST_CHECK(ParseMoney("1.00", ret)); BOOST_CHECK_EQUAL(ret, COIN); + BOOST_CHECK(ParseMoney("1", ret)); + BOOST_CHECK_EQUAL(ret, COIN); BOOST_CHECK(ParseMoney("0.1", ret)); BOOST_CHECK_EQUAL(ret, COIN/10); BOOST_CHECK(ParseMoney("0.01", ret)); @@ -215,6 +221,9 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney) // Attempted 63 bit overflow should fail BOOST_CHECK(!ParseMoney("92233720368.54775808", ret)); + + // Parsing negative amounts must fail + BOOST_CHECK(!ParseMoney("-1", ret)); } BOOST_AUTO_TEST_CASE(util_IsHex) @@ -399,12 +408,27 @@ BOOST_AUTO_TEST_CASE(test_FormatParagraph) { BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), ""); BOOST_CHECK_EQUAL(FormatParagraph("test", 79, 0), "test"); - BOOST_CHECK_EQUAL(FormatParagraph(" test", 79, 0), "test"); + BOOST_CHECK_EQUAL(FormatParagraph(" test", 79, 0), " test"); BOOST_CHECK_EQUAL(FormatParagraph("test test", 79, 0), "test test"); BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 0), "test\ntest"); - BOOST_CHECK_EQUAL(FormatParagraph("testerde test ", 4, 0), "testerde\ntest"); + BOOST_CHECK_EQUAL(FormatParagraph("testerde test", 4, 0), "testerde\ntest"); BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 4), "test\n test"); - BOOST_CHECK_EQUAL(FormatParagraph("This is a very long test string. This is a second sentence in the very long test string."), "This is a very long test string. This is a second sentence in the very long\ntest string."); + + // Make sure we don't indent a fully-new line following a too-long line ending + BOOST_CHECK_EQUAL(FormatParagraph("test test\nabc", 4, 4), "test\n test\nabc"); + + 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"); + + // Test wrap length is exact + 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"); + 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"); + // Indent should be included in length of lines + 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"); + + 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."); + 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."); + 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."); + 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."); } BOOST_AUTO_TEST_CASE(test_FormatSubVersion) diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp new file mode 100644 index 000000000..1f86a06a3 --- /dev/null +++ b/src/test/versionbits_tests.cpp @@ -0,0 +1,316 @@ +// Copyright (c) 2014-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chain.h" +#include "random.h" +#include "versionbits.h" +#include "test/test_bitcoin.h" +#include "chainparams.h" +#include "main.h" +#include "consensus/params.h" + +#include + +/* Define a virtual block time, one block per 10 minutes after Nov 14 2014, 0:55:36am */ +int32_t TestTime(int nHeight) { return 1415926536 + 600 * nHeight; } + +static const Consensus::Params paramsDummy = Consensus::Params(); + +class TestConditionChecker : public AbstractThresholdConditionChecker +{ +private: + mutable ThresholdConditionCache cache; + +public: + int64_t BeginTime(const Consensus::Params& params) const { return TestTime(10000); } + int64_t EndTime(const Consensus::Params& params) const { return TestTime(20000); } + int Period(const Consensus::Params& params) const { return 1000; } + int Threshold(const Consensus::Params& params) const { return 900; } + bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const { return (pindex->nVersion & 0x100); } + + ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, paramsDummy, cache); } +}; + +#define CHECKERS 6 + +class VersionBitsTester +{ + // A fake blockchain + std::vector vpblock; + + // 6 independent checkers for the same bit. + // The first one performs all checks, the second only 50%, the third only 25%, etc... + // This is to test whether lack of cached information leads to the same results. + TestConditionChecker checker[CHECKERS]; + + // Test counter (to identify failures) + int num; + +public: + VersionBitsTester() : num(0) {} + + VersionBitsTester& Reset() { + for (unsigned int i = 0; i < vpblock.size(); i++) { + delete vpblock[i]; + } + for (unsigned int i = 0; i < CHECKERS; i++) { + checker[i] = TestConditionChecker(); + } + vpblock.clear(); + return *this; + } + + ~VersionBitsTester() { + Reset(); + } + + VersionBitsTester& Mine(unsigned int height, int32_t nTime, int32_t nVersion) { + while (vpblock.size() < height) { + CBlockIndex* pindex = new CBlockIndex(); + pindex->nHeight = vpblock.size(); + pindex->pprev = vpblock.size() > 0 ? vpblock.back() : NULL; + pindex->nTime = nTime; + pindex->nVersion = nVersion; + pindex->BuildSkip(); + vpblock.push_back(pindex); + } + return *this; + } + + VersionBitsTester& TestDefined() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_DEFINED, strprintf("Test %i for DEFINED", num)); + } + } + num++; + return *this; + } + + VersionBitsTester& TestStarted() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_STARTED, strprintf("Test %i for STARTED", num)); + } + } + num++; + return *this; + } + + VersionBitsTester& TestLockedIn() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_LOCKED_IN, strprintf("Test %i for LOCKED_IN", num)); + } + } + num++; + return *this; + } + + VersionBitsTester& TestActive() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE", num)); + } + } + num++; + return *this; + } + + VersionBitsTester& TestFailed() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_FAILED, strprintf("Test %i for FAILED", num)); + } + } + num++; + return *this; + } + + CBlockIndex * Tip() { return vpblock.size() ? vpblock.back() : NULL; } +}; + +BOOST_FIXTURE_TEST_SUITE(versionbits_tests, TestingSetup) + +BOOST_AUTO_TEST_CASE(versionbits_test) +{ + for (int i = 0; i < 64; i++) { + // DEFINED -> FAILED + VersionBitsTester().TestDefined() + .Mine(1, TestTime(1), 0x100).TestDefined() + .Mine(11, TestTime(11), 0x100).TestDefined() + .Mine(989, TestTime(989), 0x100).TestDefined() + .Mine(999, TestTime(20000), 0x100).TestDefined() + .Mine(1000, TestTime(20000), 0x100).TestFailed() + .Mine(1999, TestTime(30001), 0x100).TestFailed() + .Mine(2000, TestTime(30002), 0x100).TestFailed() + .Mine(2001, TestTime(30003), 0x100).TestFailed() + .Mine(2999, TestTime(30004), 0x100).TestFailed() + .Mine(3000, TestTime(30005), 0x100).TestFailed() + + // DEFINED -> STARTED -> FAILED + .Reset().TestDefined() + .Mine(1, TestTime(1), 0).TestDefined() + .Mine(1000, TestTime(10000) - 1, 0x100).TestDefined() // One second more and it would be defined + .Mine(2000, TestTime(10000), 0x100).TestStarted() // So that's what happens the next period + .Mine(2051, TestTime(10010), 0).TestStarted() // 51 old blocks + .Mine(2950, TestTime(10020), 0x100).TestStarted() // 899 new blocks + .Mine(3000, TestTime(20000), 0).TestFailed() // 50 old blocks (so 899 out of the past 1000) + .Mine(4000, TestTime(20010), 0x100).TestFailed() + + // DEFINED -> STARTED -> FAILED while threshold reached + .Reset().TestDefined() + .Mine(1, TestTime(1), 0).TestDefined() + .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined + .Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period + .Mine(2999, TestTime(30000), 0x100).TestStarted() // 999 new blocks + .Mine(3000, TestTime(30000), 0x100).TestFailed() // 1 new block (so 1000 out of the past 1000 are new) + .Mine(3999, TestTime(30001), 0).TestFailed() + .Mine(4000, TestTime(30002), 0).TestFailed() + .Mine(14333, TestTime(30003), 0).TestFailed() + .Mine(24000, TestTime(40000), 0).TestFailed() + + // DEFINED -> STARTED -> LOCKEDIN at the last minute -> ACTIVE + .Reset().TestDefined() + .Mine(1, TestTime(1), 0).TestDefined() + .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined + .Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period + .Mine(2050, TestTime(10010), 0x200).TestStarted() // 50 old blocks + .Mine(2950, TestTime(10020), 0x100).TestStarted() // 900 new blocks + .Mine(2999, TestTime(19999), 0x200).TestStarted() // 49 old blocks + .Mine(3000, TestTime(29999), 0x200).TestLockedIn() // 1 old block (so 900 out of the past 1000) + .Mine(3999, TestTime(30001), 0).TestLockedIn() + .Mine(4000, TestTime(30002), 0).TestActive() + .Mine(14333, TestTime(30003), 0).TestActive() + .Mine(24000, TestTime(40000), 0).TestActive(); + } + + // Sanity checks of version bit deployments + const Consensus::Params &mainnetParams = Params(CBaseChainParams::MAIN).GetConsensus(); + for (int i=0; i<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { + uint32_t bitmask = VersionBitsMask(mainnetParams, (Consensus::DeploymentPos)i); + // Make sure that no deployment tries to set an invalid bit. + BOOST_CHECK_EQUAL(bitmask & ~(uint32_t)VERSIONBITS_TOP_MASK, bitmask); + + // Verify that the deployment windows of different deployment using the + // same bit are disjoint. + // This test may need modification at such time as a new deployment + // is proposed that reuses the bit of an activated soft fork, before the + // end time of that soft fork. (Alternatively, the end time of that + // activated soft fork could be later changed to be earlier to avoid + // overlap.) + for (int j=i+1; j<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; j++) { + if (VersionBitsMask(mainnetParams, (Consensus::DeploymentPos)j) == bitmask) { + BOOST_CHECK(mainnetParams.vDeployments[j].nStartTime > mainnetParams.vDeployments[i].nTimeout || + mainnetParams.vDeployments[i].nStartTime > mainnetParams.vDeployments[j].nTimeout); + } + } + } +} + +BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) +{ + // Check that ComputeBlockVersion will set the appropriate bit correctly + // on mainnet. + const Consensus::Params &mainnetParams = Params(CBaseChainParams::MAIN).GetConsensus(); + + // Use the TESTDUMMY deployment for testing purposes. + int64_t bit = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit; + int64_t nStartTime = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime; + int64_t nTimeout = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout; + + assert(nStartTime < nTimeout); + + // In the first chain, test that the bit is set by CBV until it has failed. + // In the second chain, test the bit is set by CBV while STARTED and + // LOCKED-IN, and then no longer set while ACTIVE. + VersionBitsTester firstChain, secondChain; + + // Start generating blocks before nStartTime + int64_t nTime = nStartTime - 1; + + // Before MedianTimePast of the chain has crossed nStartTime, the bit + // should not be set. + CBlockIndex *lastBlock = NULL; + lastBlock = firstChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1< 0) { + lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1< vTimeOffsets(BITCOIN_TIMEDATA_MAX_SAMPLES, 0); vTimeOffsets.input(nOffsetSample); - LogPrintf("Added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60); + LogPrint("net","added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60); // There is a known issue here (see issue #4521): // @@ -79,7 +83,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) int64_t nMedian = vTimeOffsets.median(); std::vector vSorted = vTimeOffsets.sorted(); // Only let other nodes change our time by so much - if (abs64(nMedian) < 70 * 60) + if (abs64(nMedian) <= std::max(0, GetArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT))) { nTimeOffset = nMedian; } @@ -99,17 +103,17 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) if (!fMatch) { fDone = true; - string strMessage = _("Please check that your computer's date and time are correct! If your clock is wrong LBRYcrd Core will not work properly."); + 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)); strMiscWarning = strMessage; uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING); } } } - if (fDebug) { - BOOST_FOREACH(int64_t n, vSorted) - LogPrintf("%+d ", n); - LogPrintf("| "); - } - LogPrintf("nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset/60); + + BOOST_FOREACH(int64_t n, vSorted) + LogPrint("net", "%+d ", n); + LogPrint("net", "| "); + + LogPrint("net", "nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset/60); } } diff --git a/src/timedata.h b/src/timedata.h index 2296baf11..9f2499c85 100644 --- a/src/timedata.h +++ b/src/timedata.h @@ -10,6 +10,8 @@ #include #include +static const int64_t DEFAULT_MAX_TIME_ADJUSTMENT = 70 * 60; + class CNetAddr; /** diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp new file mode 100644 index 000000000..1c7bc2dbe --- /dev/null +++ b/src/torcontrol.cpp @@ -0,0 +1,705 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "torcontrol.h" +#include "utilstrencodings.h" +#include "net.h" +#include "util.h" +#include "crypto/hmac_sha256.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/** Default control port */ +const std::string DEFAULT_TOR_CONTROL = "127.0.0.1:9051"; +/** Tor cookie size (from control-spec.txt) */ +static const int TOR_COOKIE_SIZE = 32; +/** Size of client/server nonce for SAFECOOKIE */ +static const int TOR_NONCE_SIZE = 32; +/** For computing serverHash in SAFECOOKIE */ +static const std::string TOR_SAFE_SERVERKEY = "Tor safe cookie authentication server-to-controller hash"; +/** For computing clientHash in SAFECOOKIE */ +static const std::string TOR_SAFE_CLIENTKEY = "Tor safe cookie authentication controller-to-server hash"; +/** Exponential backoff configuration - initial timeout in seconds */ +static const float RECONNECT_TIMEOUT_START = 1.0; +/** Exponential backoff configuration - growth factor */ +static const float RECONNECT_TIMEOUT_EXP = 1.5; +/** Maximum length for lines received on TorControlConnection. + * tor-control-spec.txt mentions that there is explicitly no limit defined to line length, + * this is belt-and-suspenders sanity limit to prevent memory exhaustion. + */ +static const int MAX_LINE_LENGTH = 100000; + +/****** Low-level TorControlConnection ********/ + +/** Reply from Tor, can be single or multi-line */ +class TorControlReply +{ +public: + TorControlReply() { Clear(); } + + int code; + std::vector lines; + + void Clear() + { + code = 0; + lines.clear(); + } +}; + +/** Low-level handling for Tor control connection. + * Speaks the SMTP-like protocol as defined in torspec/control-spec.txt + */ +class TorControlConnection +{ +public: + typedef boost::function ConnectionCB; + typedef boost::function ReplyHandlerCB; + + /** Create a new TorControlConnection. + */ + TorControlConnection(struct event_base *base); + ~TorControlConnection(); + + /** + * Connect to a Tor control port. + * target is address of the form host:port. + * connected is the handler that is called when connection is successfully established. + * disconnected is a handler that is called when the connection is broken. + * Return true on success. + */ + bool Connect(const std::string &target, const ConnectionCB& connected, const ConnectionCB& disconnected); + + /** + * Disconnect from Tor control port. + */ + bool Disconnect(); + + /** Send a command, register a handler for the reply. + * A trailing CRLF is automatically added. + * Return true on success. + */ + bool Command(const std::string &cmd, const ReplyHandlerCB& reply_handler); + + /** Response handlers for async replies */ + boost::signals2::signal async_handler; +private: + /** Callback when ready for use */ + boost::function connected; + /** Callback when connection lost */ + boost::function disconnected; + /** Libevent event base */ + struct event_base *base; + /** Connection to control socket */ + struct bufferevent *b_conn; + /** Message being received */ + TorControlReply message; + /** Response handlers */ + std::deque reply_handlers; + + /** Libevent handlers: internal */ + static void readcb(struct bufferevent *bev, void *ctx); + static void eventcb(struct bufferevent *bev, short what, void *ctx); +}; + +TorControlConnection::TorControlConnection(struct event_base *base): + base(base), b_conn(0) +{ +} + +TorControlConnection::~TorControlConnection() +{ + if (b_conn) + bufferevent_free(b_conn); +} + +void TorControlConnection::readcb(struct bufferevent *bev, void *ctx) +{ + TorControlConnection *self = (TorControlConnection*)ctx; + struct evbuffer *input = bufferevent_get_input(bev); + size_t n_read_out = 0; + char *line; + assert(input); + // If there is not a whole line to read, evbuffer_readln returns NULL + while((line = evbuffer_readln(input, &n_read_out, EVBUFFER_EOL_CRLF)) != NULL) + { + std::string s(line, n_read_out); + free(line); + if (s.size() < 4) // Short line + continue; + // (-|+| ) + self->message.code = atoi(s.substr(0,3)); + self->message.lines.push_back(s.substr(4)); + char ch = s[3]; // '-','+' or ' ' + if (ch == ' ') { + // Final line, dispatch reply and clean up + if (self->message.code >= 600) { + // Dispatch async notifications to async handler + // Synchronous and asynchronous messages are never interleaved + self->async_handler(*self, self->message); + } else { + if (!self->reply_handlers.empty()) { + // Invoke reply handler with message + self->reply_handlers.front()(*self, self->message); + self->reply_handlers.pop_front(); + } else { + LogPrint("tor", "tor: Received unexpected sync reply %i\n", self->message.code); + } + } + self->message.Clear(); + } + } + // Check for size of buffer - protect against memory exhaustion with very long lines + // Do this after evbuffer_readln to make sure all full lines have been + // removed from the buffer. Everything left is an incomplete line. + if (evbuffer_get_length(input) > MAX_LINE_LENGTH) { + LogPrintf("tor: Disconnecting because MAX_LINE_LENGTH exceeded\n"); + self->Disconnect(); + } +} + +void TorControlConnection::eventcb(struct bufferevent *bev, short what, void *ctx) +{ + TorControlConnection *self = (TorControlConnection*)ctx; + if (what & BEV_EVENT_CONNECTED) { + LogPrint("tor", "tor: Successfully connected!\n"); + self->connected(*self); + } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { + if (what & BEV_EVENT_ERROR) + LogPrint("tor", "tor: Error connecting to Tor control socket\n"); + else + LogPrint("tor", "tor: End of stream\n"); + self->Disconnect(); + self->disconnected(*self); + } +} + +bool TorControlConnection::Connect(const std::string &target, const ConnectionCB& connected, const ConnectionCB& disconnected) +{ + if (b_conn) + Disconnect(); + // Parse target address:port + struct sockaddr_storage connect_to_addr; + int connect_to_addrlen = sizeof(connect_to_addr); + if (evutil_parse_sockaddr_port(target.c_str(), + (struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0) { + LogPrintf("tor: Error parsing socket address %s\n", target); + return false; + } + + // Create a new socket, set up callbacks and enable notification bits + b_conn = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); + if (!b_conn) + return false; + bufferevent_setcb(b_conn, TorControlConnection::readcb, NULL, TorControlConnection::eventcb, this); + bufferevent_enable(b_conn, EV_READ|EV_WRITE); + this->connected = connected; + this->disconnected = disconnected; + + // Finally, connect to target + if (bufferevent_socket_connect(b_conn, (struct sockaddr*)&connect_to_addr, connect_to_addrlen) < 0) { + LogPrintf("tor: Error connecting to address %s\n", target); + return false; + } + return true; +} + +bool TorControlConnection::Disconnect() +{ + if (b_conn) + bufferevent_free(b_conn); + b_conn = 0; + return true; +} + +bool TorControlConnection::Command(const std::string &cmd, const ReplyHandlerCB& reply_handler) +{ + if (!b_conn) + return false; + struct evbuffer *buf = bufferevent_get_output(b_conn); + if (!buf) + return false; + evbuffer_add(buf, cmd.data(), cmd.size()); + evbuffer_add(buf, "\r\n", 2); + reply_handlers.push_back(reply_handler); + return true; +} + +/****** General parsing utilities ********/ + +/* Split reply line in the form 'AUTH METHODS=...' into a type + * 'AUTH' and arguments 'METHODS=...'. + */ +static std::pair SplitTorReplyLine(const std::string &s) +{ + size_t ptr=0; + std::string type; + while (ptr < s.size() && s[ptr] != ' ') { + type.push_back(s[ptr]); + ++ptr; + } + if (ptr < s.size()) + ++ptr; // skip ' ' + return make_pair(type, s.substr(ptr)); +} + +/** Parse reply arguments in the form 'METHODS=COOKIE,SAFECOOKIE COOKIEFILE=".../control_auth_cookie"'. + */ +static std::map ParseTorReplyMapping(const std::string &s) +{ + std::map mapping; + size_t ptr=0; + while (ptr < s.size()) { + std::string key, value; + while (ptr < s.size() && s[ptr] != '=') { + key.push_back(s[ptr]); + ++ptr; + } + if (ptr == s.size()) // unexpected end of line + return std::map(); + ++ptr; // skip '=' + if (ptr < s.size() && s[ptr] == '"') { // Quoted string + ++ptr; // skip '=' + bool escape_next = false; + while (ptr < s.size() && (!escape_next && s[ptr] != '"')) { + escape_next = (s[ptr] == '\\'); + value.push_back(s[ptr]); + ++ptr; + } + if (ptr == s.size()) // unexpected end of line + return std::map(); + ++ptr; // skip closing '"' + /* TODO: unescape value - according to the spec this depends on the + * context, some strings use C-LogPrintf style escape codes, some + * don't. So may be better handled at the call site. + */ + } else { // Unquoted value. Note that values can contain '=' at will, just no spaces + while (ptr < s.size() && s[ptr] != ' ') { + value.push_back(s[ptr]); + ++ptr; + } + } + if (ptr < s.size() && s[ptr] == ' ') + ++ptr; // skip ' ' after key=value + mapping[key] = value; + } + return mapping; +} + +/** Read full contents of a file and return them in a std::string. + * Returns a pair . + * If an error occurred, status will be false, otherwise status will be true and the data will be returned in string. + * + * @param maxsize Puts a maximum size limit on the file that is read. If the file is larger than this, truncated data + * (with len > maxsize) will be returned. + */ +static std::pair ReadBinaryFile(const std::string &filename, size_t maxsize=std::numeric_limits::max()) +{ + FILE *f = fopen(filename.c_str(), "rb"); + if (f == NULL) + return std::make_pair(false,""); + std::string retval; + char buffer[128]; + size_t n; + while ((n=fread(buffer, 1, sizeof(buffer), f)) > 0) { + retval.append(buffer, buffer+n); + if (retval.size() > maxsize) + break; + } + fclose(f); + return std::make_pair(true,retval); +} + +/** Write contents of std::string to a file. + * @return true on success. + */ +static bool WriteBinaryFile(const std::string &filename, const std::string &data) +{ + FILE *f = fopen(filename.c_str(), "wb"); + if (f == NULL) + return false; + if (fwrite(data.data(), 1, data.size(), f) != data.size()) { + fclose(f); + return false; + } + fclose(f); + return true; +} + +/****** Bitcoin specific TorController implementation ********/ + +/** Controller that connects to Tor control socket, authenticate, then create + * and maintain a ephemeral hidden service. + */ +class TorController +{ +public: + TorController(struct event_base* base, const std::string& target); + ~TorController(); + + /** Get name fo file to store private key in */ + std::string GetPrivateKeyFile(); + + /** Reconnect, after getting disconnected */ + void Reconnect(); +private: + struct event_base* base; + std::string target; + TorControlConnection conn; + std::string private_key; + std::string service_id; + bool reconnect; + struct event *reconnect_ev; + float reconnect_timeout; + CService service; + /** Cooie for SAFECOOKIE auth */ + std::vector cookie; + /** ClientNonce for SAFECOOKIE auth */ + std::vector clientNonce; + + /** Callback for ADD_ONION result */ + void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply); + /** Callback for AUTHENTICATE result */ + void auth_cb(TorControlConnection& conn, const TorControlReply& reply); + /** Callback for AUTHCHALLENGE result */ + void authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply); + /** Callback for PROTOCOLINFO result */ + void protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply); + /** Callback after successful connection */ + void connected_cb(TorControlConnection& conn); + /** Callback after connection lost or failed connection attempt */ + void disconnected_cb(TorControlConnection& conn); + + /** Callback for reconnect timer */ + static void reconnect_cb(evutil_socket_t fd, short what, void *arg); +}; + +TorController::TorController(struct event_base* baseIn, const std::string& target): + base(baseIn), + target(target), conn(base), reconnect(true), reconnect_ev(0), + reconnect_timeout(RECONNECT_TIMEOUT_START) +{ + reconnect_ev = event_new(base, -1, 0, reconnect_cb, this); + if (!reconnect_ev) + LogPrintf("tor: Failed to create event for reconnection: out of memory?\n"); + // Start connection attempts immediately + if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1), + boost::bind(&TorController::disconnected_cb, this, _1) )) { + LogPrintf("tor: Initiating connection to Tor control port %s failed\n", target); + } + // Read service private key if cached + std::pair pkf = ReadBinaryFile(GetPrivateKeyFile()); + if (pkf.first) { + LogPrint("tor", "tor: Reading cached private key from %s\n", GetPrivateKeyFile()); + private_key = pkf.second; + } +} + +TorController::~TorController() +{ + if (reconnect_ev) { + event_free(reconnect_ev); + reconnect_ev = 0; + } + if (service.IsValid()) { + RemoveLocal(service); + } +} + +void TorController::add_onion_cb(TorControlConnection& conn, const TorControlReply& reply) +{ + if (reply.code == 250) { + LogPrint("tor", "tor: ADD_ONION successful\n"); + BOOST_FOREACH(const std::string &s, reply.lines) { + std::map m = ParseTorReplyMapping(s); + std::map::iterator i; + if ((i = m.find("ServiceID")) != m.end()) + service_id = i->second; + if ((i = m.find("PrivateKey")) != m.end()) + private_key = i->second; + } + + service = CService(service_id+".onion", GetListenPort(), false); + LogPrintf("tor: Got service ID %s, advertising service %s\n", service_id, service.ToString()); + if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) { + LogPrint("tor", "tor: Cached service private key to %s\n", GetPrivateKeyFile()); + } else { + LogPrintf("tor: Error writing service private key to %s\n", GetPrivateKeyFile()); + } + AddLocal(service, LOCAL_MANUAL); + // ... onion requested - keep connection open + } else if (reply.code == 510) { // 510 Unrecognized command + LogPrintf("tor: Add onion failed with unrecognized command (You probably need to upgrade Tor)\n"); + } else { + LogPrintf("tor: Add onion failed; error code %d\n", reply.code); + } +} + +void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& reply) +{ + if (reply.code == 250) { + LogPrint("tor", "tor: Authentication successful\n"); + + // Now that we know Tor is running setup the proxy for onion addresses + // if -onion isn't set to something else. + if (GetArg("-onion", "") == "") { + proxyType addrOnion = proxyType(CService("127.0.0.1", 9050), true); + SetProxy(NET_TOR, addrOnion); + SetLimited(NET_TOR, false); + } + + // Finally - now create the service + if (private_key.empty()) // No private key, generate one + private_key = "NEW:BEST"; + // Request hidden service, redirect port. + // Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient + // choice. TODO; refactor the shutdown sequence some day. + conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, GetListenPort(), GetListenPort()), + boost::bind(&TorController::add_onion_cb, this, _1, _2)); + } else { + LogPrintf("tor: Authentication failed\n"); + } +} + +/** Compute Tor SAFECOOKIE response. + * + * ServerHash is computed as: + * HMAC-SHA256("Tor safe cookie authentication server-to-controller hash", + * CookieString | ClientNonce | ServerNonce) + * (with the HMAC key as its first argument) + * + * After a controller sends a successful AUTHCHALLENGE command, the + * next command sent on the connection must be an AUTHENTICATE command, + * and the only authentication string which that AUTHENTICATE command + * will accept is: + * + * HMAC-SHA256("Tor safe cookie authentication controller-to-server hash", + * CookieString | ClientNonce | ServerNonce) + * + */ +static std::vector ComputeResponse(const std::string &key, const std::vector &cookie, const std::vector &clientNonce, const std::vector &serverNonce) +{ + CHMAC_SHA256 computeHash((const uint8_t*)key.data(), key.size()); + std::vector computedHash(CHMAC_SHA256::OUTPUT_SIZE, 0); + computeHash.Write(begin_ptr(cookie), cookie.size()); + computeHash.Write(begin_ptr(clientNonce), clientNonce.size()); + computeHash.Write(begin_ptr(serverNonce), serverNonce.size()); + computeHash.Finalize(begin_ptr(computedHash)); + return computedHash; +} + +void TorController::authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply) +{ + if (reply.code == 250) { + LogPrint("tor", "tor: SAFECOOKIE authentication challenge successful\n"); + std::pair l = SplitTorReplyLine(reply.lines[0]); + if (l.first == "AUTHCHALLENGE") { + std::map m = ParseTorReplyMapping(l.second); + std::vector serverHash = ParseHex(m["SERVERHASH"]); + std::vector serverNonce = ParseHex(m["SERVERNONCE"]); + LogPrint("tor", "tor: AUTHCHALLENGE ServerHash %s ServerNonce %s\n", HexStr(serverHash), HexStr(serverNonce)); + if (serverNonce.size() != 32) { + LogPrintf("tor: ServerNonce is not 32 bytes, as required by spec\n"); + return; + } + + std::vector computedServerHash = ComputeResponse(TOR_SAFE_SERVERKEY, cookie, clientNonce, serverNonce); + if (computedServerHash != serverHash) { + LogPrintf("tor: ServerHash %s does not match expected ServerHash %s\n", HexStr(serverHash), HexStr(computedServerHash)); + return; + } + + std::vector computedClientHash = ComputeResponse(TOR_SAFE_CLIENTKEY, cookie, clientNonce, serverNonce); + conn.Command("AUTHENTICATE " + HexStr(computedClientHash), boost::bind(&TorController::auth_cb, this, _1, _2)); + } else { + LogPrintf("tor: Invalid reply to AUTHCHALLENGE\n"); + } + } else { + LogPrintf("tor: SAFECOOKIE authentication challenge failed\n"); + } +} + +void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply) +{ + if (reply.code == 250) { + std::set methods; + std::string cookiefile; + /* + * 250-AUTH METHODS=COOKIE,SAFECOOKIE COOKIEFILE="/home/x/.tor/control_auth_cookie" + * 250-AUTH METHODS=NULL + * 250-AUTH METHODS=HASHEDPASSWORD + */ + BOOST_FOREACH(const std::string &s, reply.lines) { + std::pair l = SplitTorReplyLine(s); + if (l.first == "AUTH") { + std::map m = ParseTorReplyMapping(l.second); + std::map::iterator i; + if ((i = m.find("METHODS")) != m.end()) + boost::split(methods, i->second, boost::is_any_of(",")); + if ((i = m.find("COOKIEFILE")) != m.end()) + cookiefile = i->second; + } else if (l.first == "VERSION") { + std::map m = ParseTorReplyMapping(l.second); + std::map::iterator i; + if ((i = m.find("Tor")) != m.end()) { + LogPrint("tor", "tor: Connected to Tor version %s\n", i->second); + } + } + } + BOOST_FOREACH(const std::string &s, methods) { + LogPrint("tor", "tor: Supported authentication method: %s\n", s); + } + // Prefer NULL, otherwise SAFECOOKIE. If a password is provided, use HASHEDPASSWORD + /* Authentication: + * cookie: hex-encoded ~/.tor/control_auth_cookie + * password: "password" + */ + std::string torpassword = GetArg("-torpassword", ""); + if (methods.count("NULL")) { + LogPrint("tor", "tor: Using NULL authentication\n"); + conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2)); + } else if (methods.count("SAFECOOKIE")) { + // Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie + LogPrint("tor", "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile); + std::pair status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE); + if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) { + // conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, _1, _2)); + cookie = std::vector(status_cookie.second.begin(), status_cookie.second.end()); + clientNonce = std::vector(TOR_NONCE_SIZE, 0); + GetRandBytes(&clientNonce[0], TOR_NONCE_SIZE); + conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2)); + } else { + if (status_cookie.first) { + LogPrintf("tor: Authentication cookie %s is not exactly %i bytes, as is required by the spec\n", cookiefile, TOR_COOKIE_SIZE); + } else { + LogPrintf("tor: Authentication cookie %s could not be opened (check permissions)\n", cookiefile); + } + } + } else if (methods.count("HASHEDPASSWORD")) { + if (!torpassword.empty()) { + LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n"); + boost::replace_all(torpassword, "\"", "\\\""); + conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2)); + } else { + LogPrintf("tor: Password authentication required, but no password provided with -torpassword\n"); + } + } else { + LogPrintf("tor: No supported authentication method\n"); + } + } else { + LogPrintf("tor: Requesting protocol info failed\n"); + } +} + +void TorController::connected_cb(TorControlConnection& conn) +{ + reconnect_timeout = RECONNECT_TIMEOUT_START; + // First send a PROTOCOLINFO command to figure out what authentication is expected + if (!conn.Command("PROTOCOLINFO 1", boost::bind(&TorController::protocolinfo_cb, this, _1, _2))) + LogPrintf("tor: Error sending initial protocolinfo command\n"); +} + +void TorController::disconnected_cb(TorControlConnection& conn) +{ + // Stop advertising service when disconnected + if (service.IsValid()) + RemoveLocal(service); + service = CService(); + if (!reconnect) + return; + + LogPrint("tor", "tor: Not connected to Tor control port %s, trying to reconnect\n", target); + + // Single-shot timer for reconnect. Use exponential backoff. + struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0)); + if (reconnect_ev) + event_add(reconnect_ev, &time); + reconnect_timeout *= RECONNECT_TIMEOUT_EXP; +} + +void TorController::Reconnect() +{ + /* Try to reconnect and reestablish if we get booted - for example, Tor + * may be restarting. + */ + if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1), + boost::bind(&TorController::disconnected_cb, this, _1) )) { + LogPrintf("tor: Re-initiating connection to Tor control port %s failed\n", target); + } +} + +std::string TorController::GetPrivateKeyFile() +{ + return (GetDataDir() / "onion_private_key").string(); +} + +void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg) +{ + TorController *self = (TorController*)arg; + self->Reconnect(); +} + +/****** Thread ********/ +struct event_base *base; +boost::thread torControlThread; + +static void TorControlThread() +{ + TorController ctrl(base, GetArg("-torcontrol", DEFAULT_TOR_CONTROL)); + + event_base_dispatch(base); +} + +void StartTorControl(boost::thread_group& threadGroup, CScheduler& scheduler) +{ + assert(!base); +#ifdef WIN32 + evthread_use_windows_threads(); +#else + evthread_use_pthreads(); +#endif + base = event_base_new(); + if (!base) { + LogPrintf("tor: Unable to create event_base\n"); + return; + } + + torControlThread = boost::thread(boost::bind(&TraceThread, "torcontrol", &TorControlThread)); +} + +void InterruptTorControl() +{ + if (base) { + LogPrintf("tor: Thread interrupt\n"); + event_base_loopbreak(base); + } +} + +void StopTorControl() +{ + if (base) { + torControlThread.join(); + event_base_free(base); + base = 0; + } +} + diff --git a/src/torcontrol.h b/src/torcontrol.h new file mode 100644 index 000000000..72dc82c5b --- /dev/null +++ b/src/torcontrol.h @@ -0,0 +1,20 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +/** + * Functionality for communicating with Tor. + */ +#ifndef BITCOIN_TORCONTROL_H +#define BITCOIN_TORCONTROL_H + +#include "scheduler.h" + +extern const std::string DEFAULT_TOR_CONTROL; +static const bool DEFAULT_LISTEN_ONION = true; + +void StartTorControl(boost::thread_group& threadGroup, CScheduler& scheduler); +void InterruptTorControl(); +void StopTorControl(); + +#endif /* BITCOIN_TORCONTROL_H */ diff --git a/src/txdb.cpp b/src/txdb.cpp index 1d000e87e..cdf799711 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -49,7 +49,7 @@ uint256 CCoinsViewDB::GetBestBlock() const { } bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { - CLevelDBBatch batch(&db.GetObfuscateKey()); + CDBBatch batch(&db.GetObfuscateKey()); size_t count = 0; size_t changed = 0; for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { @@ -71,7 +71,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return db.WriteBatch(batch); } -CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) { +CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) { } bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) { @@ -94,54 +94,56 @@ bool CBlockTreeDB::ReadLastBlockFile(int &nFile) { return Read(DB_LAST_BLOCK, nFile); } -bool CCoinsViewDB::GetStats(CCoinsStats &stats) const { +CCoinsViewCursor *CCoinsViewDB::Cursor() const +{ + CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast(&db)->NewIterator(), GetBestBlock()); /* It seems that there are no "const iterators" for LevelDB. Since we only need read operations on it, use a const-cast to get around that restriction. */ - boost::scoped_ptr pcursor(const_cast(&db)->NewIterator()); - pcursor->Seek(DB_COINS); + i->pcursor->Seek(DB_COINS); + // Cache key of first record + i->pcursor->GetKey(i->keyTmp); + return i; +} - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - stats.hashBlock = GetBestBlock(); - ss << stats.hashBlock; - CAmount nTotalAmount = 0; - while (pcursor->Valid()) { - boost::this_thread::interruption_point(); - std::pair key; - CCoins coins; - if (pcursor->GetKey(key) && key.first == DB_COINS) { - if (pcursor->GetValue(coins)) { - stats.nTransactions++; - for (unsigned int i=0; iGetKeySize(); - ss << VARINT(0); - } else { - return error("CCoinsViewDB::GetStats() : unable to read value"); - } - } else { - break; - } - pcursor->Next(); +bool CCoinsViewDBCursor::GetKey(uint256 &key) const +{ + // Return cached key + if (keyTmp.first == DB_COINS) { + key = keyTmp.second; + return true; } - { - LOCK(cs_main); - stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight; + return false; +} + +bool CCoinsViewDBCursor::GetValue(CCoins &coins) const +{ + return pcursor->GetValue(coins); +} + +unsigned int CCoinsViewDBCursor::GetValueSize() const +{ + return pcursor->GetValueSize(); +} + +bool CCoinsViewDBCursor::Valid() const +{ + return keyTmp.first == DB_COINS; +} + +void CCoinsViewDBCursor::Next() +{ + pcursor->Next(); + if (pcursor->Valid()) { + bool ok = pcursor->GetKey(keyTmp); + assert(ok); // If GetKey fails here something must be wrong with underlying database, we cannot handle that here + } else { + keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false } - stats.hashSerialized = ss.GetHash(); - stats.nTotalAmount = nTotalAmount; - return true; } bool CBlockTreeDB::WriteBatchSync(const std::vector >& fileInfo, int nLastFile, const std::vector& blockinfo) { - CLevelDBBatch batch(&GetObfuscateKey()); + CDBBatch batch(&GetObfuscateKey()); for (std::vector >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) { batch.Write(make_pair(DB_BLOCK_FILES, it->first), *it->second); } @@ -157,7 +159,7 @@ bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) { } bool CBlockTreeDB::WriteTxIndex(const std::vector >&vect) { - CLevelDBBatch batch(&GetObfuscateKey()); + CDBBatch batch(&GetObfuscateKey()); for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) batch.Write(make_pair(DB_TXINDEX, it->first), it->second); return WriteBatch(batch); @@ -177,7 +179,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) { bool CBlockTreeDB::LoadBlockIndexGuts() { - boost::scoped_ptr pcursor(NewIterator()); + boost::scoped_ptr pcursor(NewIterator()); pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256())); diff --git a/src/txdb.h b/src/txdb.h index bef5dc9fd..749802f0e 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,7 +7,7 @@ #define BITCOIN_TXDB_H #include "coins.h" -#include "leveldbwrapper.h" +#include "dbwrapper.h" #include #include @@ -26,11 +26,13 @@ static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024; //! min. -dbcache in (MiB) static const int64_t nMinDbCache = 4; -/** CCoinsView backed by the LevelDB coin database (chainstate/) */ +class CCoinsViewDBCursor; + +/** CCoinsView backed by the coin database (chainstate/) */ class CCoinsViewDB : public CCoinsView { protected: - CLevelDBWrapper db; + CDBWrapper db; public: CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); @@ -38,11 +40,33 @@ public: bool HaveCoins(const uint256 &txid) const; uint256 GetBestBlock() const; bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); - bool GetStats(CCoinsStats &stats) const; + CCoinsViewCursor *Cursor() const; +}; + +/** Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB */ +class CCoinsViewDBCursor: public CCoinsViewCursor +{ +public: + ~CCoinsViewDBCursor() {} + + bool GetKey(uint256 &key) const; + bool GetValue(CCoins &coins) const; + unsigned int GetValueSize() const; + + bool Valid() const; + void Next(); + +private: + CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256 &hashBlockIn): + CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {} + boost::scoped_ptr pcursor; + std::pair keyTmp; + + friend class CCoinsViewDB; }; /** Access to the block database (blocks/index/) */ -class CBlockTreeDB : public CLevelDBWrapper +class CBlockTreeDB : public CDBWrapper { public: CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 1370cab0c..52c779311 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,17 +11,21 @@ #include "main.h" #include "policy/fees.h" #include "streams.h" +#include "timedata.h" #include "util.h" #include "utilmoneystr.h" +#include "utiltime.h" #include "version.h" using namespace std; CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, - int64_t _nTime, double _dPriority, - unsigned int _nHeight, bool poolHasNoInputsOf): - tx(_tx), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight), - hadNoDependencies(poolHasNoInputsOf) + int64_t _nTime, double _entryPriority, unsigned int _entryHeight, + bool poolHasNoInputsOf, CAmount _inChainInputValue, + bool _spendsCoinbase, unsigned int _sigOps, LockPoints lp): + tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), + hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), + spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), lockPoints(lp) { nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); nModSize = tx.CalculateModifiedSize(nTxSize); @@ -29,7 +33,16 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, nCountWithDescendants = 1; nSizeWithDescendants = nTxSize; - nFeesWithDescendants = nFee; + nModFeesWithDescendants = nFee; + CAmount nValueIn = tx.GetValueOut()+nFee; + assert(inChainInputValue <= nValueIn); + + feeDelta = 0; + + nCountWithAncestors = 1; + nSizeWithAncestors = nTxSize; + nModFeesWithAncestors = nFee; + nSigOpCountWithAncestors = sigOpCount; } CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) @@ -40,30 +53,35 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) double CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const { - CAmount nValueIn = tx.GetValueOut()+nFee; - double deltaPriority = ((double)(currentHeight-nHeight)*nValueIn)/nModSize; - double dResult = dPriority + deltaPriority; + double deltaPriority = ((double)(currentHeight-entryHeight)*inChainInputValue)/nModSize; + double dResult = entryPriority + deltaPriority; + if (dResult < 0) // This should only happen if it was called with a height below entry height + dResult = 0; return dResult; } +void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta) +{ + nModFeesWithDescendants += newFeeDelta - feeDelta; + nModFeesWithAncestors += newFeeDelta - feeDelta; + feeDelta = newFeeDelta; +} + +void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp) +{ + lockPoints = lp; +} + // Update the given tx for any in-mempool descendants. // Assumes that setMemPoolChildren is correct for the given tx and all // descendants. -bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit, cacheMap &cachedDescendants, const std::set &setExclude) +void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set &setExclude) { - // Track the number of entries (outside setExclude) that we'd need to visit - // (will bail out if it exceeds maxDescendantsToVisit) - int nChildrenToVisit = 0; - setEntries stageEntries, setAllDescendants; stageEntries = GetMemPoolChildren(updateIt); while (!stageEntries.empty()) { const txiter cit = *stageEntries.begin(); - if (cit->IsDirty()) { - // Don't consider any more children if any descendant is dirty - return false; - } setAllDescendants.insert(cit); stageEntries.erase(cit); const setEntries &setChildren = GetMemPoolChildren(cit); @@ -73,22 +91,11 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit // We've already calculated this one, just add the entries for this set // but don't traverse again. BOOST_FOREACH(const txiter cacheEntry, cacheIt->second) { - // update visit count only for new child transactions - // (outside of setExclude and stageEntries) - if (setAllDescendants.insert(cacheEntry).second && - !setExclude.count(cacheEntry->GetTx().GetHash()) && - !stageEntries.count(cacheEntry)) { - nChildrenToVisit++; - } + setAllDescendants.insert(cacheEntry); } } else if (!setAllDescendants.count(childEntry)) { - // Schedule for later processing and update our visit count - if (stageEntries.insert(childEntry).second && !setExclude.count(childEntry->GetTx().GetHash())) { - nChildrenToVisit++; - } - } - if (nChildrenToVisit > maxDescendantsToVisit) { - return false; + // Schedule for later processing + stageEntries.insert(childEntry); } } } @@ -100,19 +107,21 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit BOOST_FOREACH(txiter cit, setAllDescendants) { if (!setExclude.count(cit->GetTx().GetHash())) { modifySize += cit->GetTxSize(); - modifyFee += cit->GetFee(); + modifyFee += cit->GetModifiedFee(); modifyCount++; cachedDescendants[updateIt].insert(cit); + // Update ancestor state for each descendant + mapTx.modify(cit, update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCount())); } } mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount)); - return true; } // vHashesToUpdate is the set of transaction hashes from a disconnected block // which has been re-added to the mempool. // for each entry, look for descendants that are outside hashesToUpdate, and // add fee/size information for such descendants to the parent. +// for each such descendant, also update the ancestor state to include the parent. void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashesToUpdate) { LOCK(cs); @@ -152,14 +161,11 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashes UpdateParent(childIter, it, true); } } - if (!UpdateForDescendants(it, 100, mapMemPoolDescendantsToUpdate, setAlreadyIncluded)) { - // Mark as dirty if we can't do the calculation. - mapTx.modify(it, set_dirty()); - } + UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, setAlreadyIncluded); } } -bool 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 */) +bool 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 { setEntries parentHashes; const CTransaction &tx = entry.GetTx(); @@ -230,12 +236,26 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors } const int64_t updateCount = (add ? 1 : -1); const int64_t updateSize = updateCount * it->GetTxSize(); - const CAmount updateFee = updateCount * it->GetFee(); + const CAmount updateFee = updateCount * it->GetModifiedFee(); BOOST_FOREACH(txiter ancestorIt, setAncestors) { mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, updateCount)); } } +void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncestors) +{ + int64_t updateCount = setAncestors.size(); + int64_t updateSize = 0; + CAmount updateFee = 0; + int updateSigOps = 0; + BOOST_FOREACH(txiter ancestorIt, setAncestors) { + updateSize += ancestorIt->GetTxSize(); + updateFee += ancestorIt->GetModifiedFee(); + updateSigOps += ancestorIt->GetSigOpCount(); + } + mapTx.modify(it, update_ancestor_state(updateSize, updateFee, updateCount, updateSigOps)); +} + void CTxMemPool::UpdateChildrenForRemoval(txiter it) { const setEntries &setMemPoolChildren = GetMemPoolChildren(it); @@ -244,11 +264,30 @@ void CTxMemPool::UpdateChildrenForRemoval(txiter it) } } -void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) +void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants) { // For each entry, walk back all ancestors and decrement size associated with this // transaction const uint64_t nNoLimit = std::numeric_limits::max(); + if (updateDescendants) { + // updateDescendants should be true whenever we're not recursively + // removing a tx and all its descendants, eg when a transaction is + // confirmed in a block. + // Here we only update statistics and not data in mapLinks (which + // we need to preserve until we're finished with all operations that + // need to traverse the mempool). + BOOST_FOREACH(txiter removeIt, entriesToRemove) { + setEntries setDescendants; + CalculateDescendants(removeIt, setDescendants); + setDescendants.erase(removeIt); // don't update state for self + int64_t modifySize = -((int64_t)removeIt->GetTxSize()); + CAmount modifyFee = -removeIt->GetModifiedFee(); + int modifySigOps = -removeIt->GetSigOpCount(); + BOOST_FOREACH(txiter dit, setDescendants) { + mapTx.modify(dit, update_ancestor_state(modifySize, modifyFee, -1, modifySigOps)); + } + } + } BOOST_FOREACH(txiter removeIt, entriesToRemove) { setEntries setAncestors; const CTxMemPoolEntry &entry = *removeIt; @@ -272,10 +311,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) // transactions as the set of things to update for removal. CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false); // Note that UpdateAncestorsOf severs the child links that point to - // removeIt in the entries for the parents of removeIt. This is - // fine since we don't need to use the mempool children of any entries - // to walk back over our ancestors (but we do need the mempool - // parents!) + // removeIt in the entries for the parents of removeIt. UpdateAncestorsOf(false, removeIt, setAncestors); } // After updating all the ancestor sizes, we can now sever the link between each @@ -286,34 +322,38 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) } } -void CTxMemPoolEntry::SetDirty() +void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount) { - nCountWithDescendants = 0; - nSizeWithDescendants = nTxSize; - nFeesWithDescendants = nFee; + nSizeWithDescendants += modifySize; + assert(int64_t(nSizeWithDescendants) > 0); + nModFeesWithDescendants += modifyFee; + nCountWithDescendants += modifyCount; + assert(int64_t(nCountWithDescendants) > 0); } -void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount) +void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps) { - if (!IsDirty()) { - nSizeWithDescendants += modifySize; - assert(int64_t(nSizeWithDescendants) > 0); - nFeesWithDescendants += modifyFee; - assert(nFeesWithDescendants >= 0); - nCountWithDescendants += modifyCount; - assert(int64_t(nCountWithDescendants) > 0); - } + nSizeWithAncestors += modifySize; + assert(int64_t(nSizeWithAncestors) > 0); + nModFeesWithAncestors += modifyFee; + nCountWithAncestors += modifyCount; + assert(int64_t(nCountWithAncestors) > 0); + nSigOpCountWithAncestors += modifySigOps; + assert(int(nSigOpCountWithAncestors) >= 0); } -CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) : +CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) : nTransactionsUpdated(0) { + _clear(); //lock free clear + // Sanity checks off by default for performance, because otherwise // accepting transactions becomes O(N^2) where N is the number // of transactions in the pool - fSanityCheck = false; + nCheckFrequency = 0; - minerPolicyEstimator = new CBlockPolicyEstimator(_minRelayFee); + minerPolicyEstimator = new CBlockPolicyEstimator(_minReasonableRelayFee); + minReasonableRelayFee = _minReasonableRelayFee; } CTxMemPool::~CTxMemPool() @@ -355,6 +395,17 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, indexed_transaction_set::iterator newit = mapTx.insert(entry).first; mapLinks.insert(make_pair(newit, TxLinks())); + // Update transaction for any feeDelta created by PrioritiseTransaction + // TODO: refactor so that the fee delta is calculated before inserting + // into mapTx. + std::map >::const_iterator pos = mapDeltas.find(hash); + if (pos != mapDeltas.end()) { + const std::pair &deltas = pos->second; + if (deltas.second) { + mapTx.modify(newit, update_fee_delta(deltas.second)); + } + } + // Update cachedInnerUsage to include contained transaction's usage. // (When we update the entry for in-mempool parents, memory usage will be // further updated.) @@ -381,6 +432,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, } } UpdateAncestorsOf(true, newit, setAncestors); + UpdateEntryForAncestors(newit, setAncestors); nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); @@ -433,7 +485,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants } } -void CTxMemPool::remove(const CTransaction &origTx, std::list& removed, bool fRecursive) +void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list& removed) { // Remove transaction from memory pool { @@ -442,8 +494,8 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem txiter origit = mapTx.find(origTx.GetHash()); if (origit != mapTx.end()) { txToRemove.insert(origit); - } else if (fRecursive) { - // If recursively removing but origTx isn't in the mempool + } else { + // When recursively removing but origTx isn't in the mempool // be sure to remove any children that are in the pool. This can // happen during chain re-orgs if origTx isn't re-accepted into // the mempool for any reason. @@ -457,42 +509,49 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem } } setEntries setAllRemoves; - if (fRecursive) { - BOOST_FOREACH(txiter it, txToRemove) { - CalculateDescendants(it, setAllRemoves); - } - } else { - setAllRemoves.swap(txToRemove); + BOOST_FOREACH(txiter it, txToRemove) { + CalculateDescendants(it, setAllRemoves); } BOOST_FOREACH(txiter it, setAllRemoves) { removed.push_back(it->GetTx()); } - RemoveStaged(setAllRemoves); + RemoveStaged(setAllRemoves, false); } } -void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight) +void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags) { - // Remove transactions spending a coinbase which are now immature + // Remove transactions spending a coinbase which are now immature and no-longer-final transactions LOCK(cs); list transactionsToRemove; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction& tx = it->GetTx(); - BOOST_FOREACH(const CTxIn& txin, tx.vin) { - indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); - if (it2 != mapTx.end()) - continue; - const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); - if (fSanityCheck) assert(coins); - if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) { - transactionsToRemove.push_back(tx); - break; + LockPoints lp = it->GetLockPoints(); + bool validLP = TestLockPointValidity(&lp); + if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(tx, flags, &lp, validLP)) { + // Note if CheckSequenceLocks fails the LockPoints may still be invalid + // So it's critical that we remove the tx and not depend on the LockPoints. + transactionsToRemove.push_back(tx); + } else if (it->GetSpendsCoinbase()) { + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); + if (it2 != mapTx.end()) + continue; + const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); + if (nCheckFrequency != 0) assert(coins); + if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) { + transactionsToRemove.push_back(tx); + break; + } } } + if (!validLP) { + mapTx.modify(it, update_lock_points(lp)); + } } BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) { list removed; - remove(tx, removed, true); + removeRecursive(tx, removed); } } @@ -507,7 +566,8 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list const CTransaction &txConflict = *it->second.ptx; if (txConflict != tx) { - remove(txConflict, removed, true); + removeRecursive(txConflict, removed); + ClearPrioritisation(txConflict.GetHash()); } } } @@ -531,29 +591,46 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned i } BOOST_FOREACH(const CTransaction& tx, vtx) { - std::list dummy; - remove(tx, dummy, false); + txiter it = mapTx.find(tx.GetHash()); + if (it != mapTx.end()) { + setEntries stage; + stage.insert(it); + RemoveStaged(stage, true); + } removeConflicts(tx, conflicts); ClearPrioritisation(tx.GetHash()); } // After the txs in the new block have been removed from the mempool, update policy estimates minerPolicyEstimator->processBlock(nBlockHeight, entries, fCurrentEstimate); + lastRollingFeeUpdate = GetTime(); + blockSinceLastRollingFeeBump = true; } -void CTxMemPool::clear() +void CTxMemPool::_clear() { - LOCK(cs); mapLinks.clear(); mapTx.clear(); mapNextTx.clear(); totalTxSize = 0; cachedInnerUsage = 0; + lastRollingFeeUpdate = GetTime(); + blockSinceLastRollingFeeBump = false; + rollingMinimumFeeRate = 0; ++nTransactionsUpdated; } +void CTxMemPool::clear() +{ + LOCK(cs); + _clear(); +} + void CTxMemPool::check(const CCoinsViewCache *pcoins) const { - if (!fSanityCheck) + if (nCheckFrequency == 0) + return; + + if (insecure_rand() >= nCheckFrequency) return; LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); @@ -576,6 +653,8 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children); bool fDependsWait = false; setEntries setParentCheck; + int64_t parentSizes = 0; + unsigned int parentSigOpCount = 0; BOOST_FOREACH(const CTxIn &txin, tx.vin) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); @@ -583,7 +662,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const const CTransaction& tx2 = it2->GetTx(); assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); fDependsWait = true; - setParentCheck.insert(it2); + if (setParentCheck.insert(it2).second) { + parentSizes += it2->GetTxSize(); + parentSigOpCount += it2->GetSigOpCount(); + } } else { const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash); assert(coins && coins->IsAvailable(txin.prevout.n)); @@ -596,31 +678,42 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const i++; } assert(setParentCheck == GetMemPoolParents(it)); + // Verify ancestor state is correct. + setEntries setAncestors; + uint64_t nNoLimit = std::numeric_limits::max(); + std::string dummy; + CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); + uint64_t nCountCheck = setAncestors.size() + 1; + uint64_t nSizeCheck = it->GetTxSize(); + CAmount nFeesCheck = it->GetModifiedFee(); + unsigned int nSigOpCheck = it->GetSigOpCount(); + + BOOST_FOREACH(txiter ancestorIt, setAncestors) { + nSizeCheck += ancestorIt->GetTxSize(); + nFeesCheck += ancestorIt->GetModifiedFee(); + nSigOpCheck += ancestorIt->GetSigOpCount(); + } + + assert(it->GetCountWithAncestors() == nCountCheck); + assert(it->GetSizeWithAncestors() == nSizeCheck); + assert(it->GetSigOpCountWithAncestors() == nSigOpCheck); + assert(it->GetModFeesWithAncestors() == nFeesCheck); + // Check children against mapNextTx CTxMemPool::setEntries setChildrenCheck; std::map::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); int64_t childSizes = 0; - CAmount childFees = 0; for (; iter != mapNextTx.end() && iter->first.hash == it->GetTx().GetHash(); ++iter) { txiter childit = mapTx.find(iter->second.ptx->GetHash()); assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions if (setChildrenCheck.insert(childit).second) { childSizes += childit->GetTxSize(); - childFees += childit->GetFee(); } } assert(setChildrenCheck == GetMemPoolChildren(it)); - // Also check to make sure size/fees is greater than sum with immediate children. + // Also check to make sure size is greater than sum with immediate children. // just a sanity check, not definitive that this calc is correct... - // also check that the size is less than the size of the entire mempool. - if (!it->IsDirty()) { - assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize()); - assert(it->GetFeesWithDescendants() >= childFees + it->GetFee()); - } else { - assert(it->GetSizeWithDescendants() == it->GetTxSize()); - assert(it->GetFeesWithDescendants() == it->GetFee()); - } - assert(it->GetFeesWithDescendants() >= 0); + assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize()); if (fDependsWait) waitingOnDependants.push_back(&(*it)); @@ -678,16 +771,36 @@ bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const return true; } +bool CTxMemPool::lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const +{ + LOCK(cs); + indexed_transaction_set::const_iterator i = mapTx.find(hash); + if (i == mapTx.end()) + return false; + feeRate = CFeeRate(i->GetFee(), i->GetTxSize()); + return true; +} + CFeeRate CTxMemPool::estimateFee(int nBlocks) const { LOCK(cs); return minerPolicyEstimator->estimateFee(nBlocks); } +CFeeRate CTxMemPool::estimateSmartFee(int nBlocks, int *answerFoundAtBlocks) const +{ + LOCK(cs); + return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks, *this); +} double CTxMemPool::estimatePriority(int nBlocks) const { LOCK(cs); return minerPolicyEstimator->estimatePriority(nBlocks); } +double CTxMemPool::estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks) const +{ + LOCK(cs); + return minerPolicyEstimator->estimateSmartPriority(nBlocks, answerFoundAtBlocks, *this); +} bool CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const @@ -731,14 +844,26 @@ void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, std::pair &deltas = mapDeltas[hash]; deltas.first += dPriorityDelta; deltas.second += nFeeDelta; + txiter it = mapTx.find(hash); + if (it != mapTx.end()) { + mapTx.modify(it, update_fee_delta(deltas.second)); + // Now update all ancestors' modified fees with descendants + setEntries setAncestors; + uint64_t nNoLimit = std::numeric_limits::max(); + std::string dummy; + CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false); + BOOST_FOREACH(txiter ancestorIt, setAncestors) { + mapTx.modify(ancestorIt, update_descendant_state(0, nFeeDelta, 0)); + } + } } LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta)); } -void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) +void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const { LOCK(cs); - std::map >::iterator pos = mapDeltas.find(hash); + std::map >::const_iterator pos = mapDeltas.find(hash); if (pos == mapDeltas.end()) return; const std::pair &deltas = pos->second; @@ -780,18 +905,34 @@ bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { size_t CTxMemPool::DynamicMemoryUsage() const { LOCK(cs); - // Estimate the overhead of mapTx to be 9 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. - return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 9 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage; + // Estimate the overhead of mapTx to be 15 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. + return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage; } -void CTxMemPool::RemoveStaged(setEntries &stage) { +void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants) { AssertLockHeld(cs); - UpdateForRemoveFromMempool(stage); + UpdateForRemoveFromMempool(stage, updateDescendants); BOOST_FOREACH(const txiter& it, stage) { removeUnchecked(it); } } +int CTxMemPool::Expire(int64_t time) { + LOCK(cs); + indexed_transaction_set::index::type::iterator it = mapTx.get().begin(); + setEntries toremove; + while (it != mapTx.get().end() && it->GetTime() < time) { + toremove.insert(mapTx.project<0>(it)); + it++; + } + setEntries stage; + BOOST_FOREACH(txiter removeit, toremove) { + CalculateDescendants(removeit, stage); + } + RemoveStaged(stage, false); + return stage.size(); +} + bool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate) { LOCK(cs); @@ -837,3 +978,80 @@ const CTxMemPool::setEntries & CTxMemPool::GetMemPoolChildren(txiter entry) cons assert(it != mapLinks.end()); return it->second.children; } + +CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const { + LOCK(cs); + if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0) + return CFeeRate(rollingMinimumFeeRate); + + int64_t time = GetTime(); + if (time > lastRollingFeeUpdate + 10) { + double halflife = ROLLING_FEE_HALFLIFE; + if (DynamicMemoryUsage() < sizelimit / 4) + halflife /= 4; + else if (DynamicMemoryUsage() < sizelimit / 2) + halflife /= 2; + + rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife); + lastRollingFeeUpdate = time; + + if (rollingMinimumFeeRate < minReasonableRelayFee.GetFeePerK() / 2) { + rollingMinimumFeeRate = 0; + return CFeeRate(0); + } + } + return std::max(CFeeRate(rollingMinimumFeeRate), minReasonableRelayFee); +} + +void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) { + AssertLockHeld(cs); + if (rate.GetFeePerK() > rollingMinimumFeeRate) { + rollingMinimumFeeRate = rate.GetFeePerK(); + blockSinceLastRollingFeeBump = false; + } +} + +void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRemaining) { + LOCK(cs); + + unsigned nTxnRemoved = 0; + CFeeRate maxFeeRateRemoved(0); + while (DynamicMemoryUsage() > sizelimit) { + indexed_transaction_set::index::type::iterator it = mapTx.get().begin(); + + // We set the new mempool min fee to the feerate of the removed set, plus the + // "minimum reasonable fee rate" (ie some value under which we consider txn + // to have 0 fee). This way, we don't allow txn to enter mempool with feerate + // equal to txn which were removed with no block in between. + CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants()); + removed += minReasonableRelayFee; + trackPackageRemoved(removed); + maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed); + + setEntries stage; + CalculateDescendants(mapTx.project<0>(it), stage); + nTxnRemoved += stage.size(); + + std::vector txn; + if (pvNoSpendsRemaining) { + txn.reserve(stage.size()); + BOOST_FOREACH(txiter it, stage) + txn.push_back(it->GetTx()); + } + RemoveStaged(stage, false); + if (pvNoSpendsRemaining) { + BOOST_FOREACH(const CTransaction& tx, txn) { + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + if (exists(txin.prevout.hash)) + continue; + std::map::iterator it = mapNextTx.lower_bound(COutPoint(txin.prevout.hash, 0)); + if (it == mapNextTx.end() || it->first.hash != txin.prevout.hash) + pvNoSpendsRemaining->push_back(txin.prevout.hash); + } + } + } + } + + if (maxFeeRateRemoved > CFeeRate(0)) + LogPrint("mempool", "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString()); +} diff --git a/src/txmempool.h b/src/txmempool.h index c0eef0dd2..de4ba0b37 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -19,6 +19,7 @@ #include "boost/multi_index/ordered_index.hpp" class CAutoFile; +class CBlockIndex; inline double AllowFreeThreshold() { @@ -35,6 +36,21 @@ inline bool AllowFree(double dPriority) /** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */ static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF; +struct LockPoints +{ + // Will be set to the blockchain height and median time past + // values that would be necessary to satisfy all relative locktime + // constraints (BIP68) of this tx given our view of block chain history + int height; + int64_t time; + // As long as the current chain descends from the highest height block + // containing one of the inputs used in the calculation, then the cached + // values are still valid even after a reorg. + CBlockIndex* maxInputBlock; + + LockPoints() : height(0), time(0), maxInputBlock(NULL) { } +}; + class CTxMemPool; /** \class CTxMemPoolEntry @@ -44,12 +60,12 @@ class CTxMemPool; * ("descendant" transactions). * * When a new entry is added to the mempool, we update the descendant state - * (nCountWithDescendants, nSizeWithDescendants, and nFeesWithDescendants) for + * (nCountWithDescendants, nSizeWithDescendants, and nModFeesWithDescendants) for * all ancestors of the newly added transaction. * * If updating the descendant state is skipped, we can mark the entry as - * "dirty", and set nSizeWithDescendants/nFeesWithDescendants to equal nTxSize/ - * nTxFee. (This can potentially happen during a reorg, where we limit the + * "dirty", and set nSizeWithDescendants/nModFeesWithDescendants to equal nTxSize/ + * nFee+feeDelta. (This can potentially happen during a reorg, where we limit the * amount of work we're willing to do to avoid consuming too much CPU.) * */ @@ -58,51 +74,78 @@ class CTxMemPoolEntry { private: CTransaction tx; - CAmount nFee; //! Cached to avoid expensive parent-transaction lookups - size_t nTxSize; //! ... and avoid recomputing tx size - size_t nModSize; //! ... and modified size for priority - size_t nUsageSize; //! ... and total memory usage - int64_t nTime; //! Local time when entering the mempool - double dPriority; //! Priority when entering the mempool - unsigned int nHeight; //! Chain height when entering the mempool - bool hadNoDependencies; //! Not dependent on any other txs when it entered the mempool + CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups + size_t nTxSize; //!< ... and avoid recomputing tx size + size_t nModSize; //!< ... and modified size for priority + size_t nUsageSize; //!< ... and total memory usage + int64_t nTime; //!< Local time when entering the mempool + double entryPriority; //!< Priority when entering the mempool + unsigned int entryHeight; //!< Chain height when entering the mempool + bool hadNoDependencies; //!< Not dependent on any other txs when it entered the mempool + CAmount inChainInputValue; //!< Sum of all txin values that are already in blockchain + bool spendsCoinbase; //!< keep track of transactions that spend a coinbase + unsigned int sigOpCount; //!< Legacy sig ops plus P2SH sig op count + int64_t feeDelta; //!< Used for determining the priority of the transaction for mining in a block + LockPoints lockPoints; //!< Track the height and time at which tx was final // Information about descendants of this transaction that are in the // mempool; if we remove this transaction we must remove all of these // descendants as well. if nCountWithDescendants is 0, treat this entry as - // dirty, and nSizeWithDescendants and nFeesWithDescendants will not be + // dirty, and nSizeWithDescendants and nModFeesWithDescendants will not be // correct. - uint64_t nCountWithDescendants; //! number of descendant transactions - uint64_t nSizeWithDescendants; //! ... and size - CAmount nFeesWithDescendants; //! ... and total fees (all including us) + uint64_t nCountWithDescendants; //!< number of descendant transactions + uint64_t nSizeWithDescendants; //!< ... and size + CAmount nModFeesWithDescendants; //!< ... and total fees (all including us) + + // Analogous statistics for ancestor transactions + uint64_t nCountWithAncestors; + uint64_t nSizeWithAncestors; + CAmount nModFeesWithAncestors; + unsigned int nSigOpCountWithAncestors; public: CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, - int64_t _nTime, double _dPriority, unsigned int _nHeight, bool poolHasNoInputsOf = false); + int64_t _nTime, double _entryPriority, unsigned int _entryHeight, + bool poolHasNoInputsOf, CAmount _inChainInputValue, bool spendsCoinbase, + unsigned int nSigOps, LockPoints lp); CTxMemPoolEntry(const CTxMemPoolEntry& other); const CTransaction& GetTx() const { return this->tx; } + /** + * Fast calculation of lower bound of current priority as update + * from entry priority. Only inputs that were originally in-chain will age. + */ double GetPriority(unsigned int currentHeight) const; - CAmount GetFee() const { return nFee; } + const CAmount& GetFee() const { return nFee; } size_t GetTxSize() const { return nTxSize; } int64_t GetTime() const { return nTime; } - unsigned int GetHeight() const { return nHeight; } + unsigned int GetHeight() const { return entryHeight; } bool WasClearAtEntry() const { return hadNoDependencies; } + unsigned int GetSigOpCount() const { return sigOpCount; } + int64_t GetModifiedFee() const { return nFee + feeDelta; } size_t DynamicMemoryUsage() const { return nUsageSize; } + const LockPoints& GetLockPoints() const { return lockPoints; } // Adjusts the descendant state, if this entry is not dirty. - void UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount); - - /** We can set the entry to be dirty if doing the full calculation of in- - * mempool descendants will be too expensive, which can potentially happen - * when re-adding transactions from a block back to the mempool. - */ - void SetDirty(); - bool IsDirty() const { return nCountWithDescendants == 0; } + void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount); + // Adjusts the ancestor state + void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps); + // Updates the fee delta used for mining priority score, and the + // modified fees with descendants. + void UpdateFeeDelta(int64_t feeDelta); + // Update the LockPoints after a reorg + void UpdateLockPoints(const LockPoints& lp); uint64_t GetCountWithDescendants() const { return nCountWithDescendants; } uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; } - CAmount GetFeesWithDescendants() const { return nFeesWithDescendants; } + CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; } + + bool GetSpendsCoinbase() const { return spendsCoinbase; } + + uint64_t GetCountWithAncestors() const { return nCountWithAncestors; } + uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; } + CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; } + unsigned int GetSigOpCountWithAncestors() const { return nSigOpCountWithAncestors; } }; // Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index. @@ -113,7 +156,7 @@ struct update_descendant_state {} void operator() (CTxMemPoolEntry &e) - { e.UpdateState(modifySize, modifyFee, modifyCount); } + { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); } private: int64_t modifySize; @@ -121,10 +164,40 @@ struct update_descendant_state int64_t modifyCount; }; -struct set_dirty +struct update_ancestor_state { + update_ancestor_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount, int _modifySigOps) : + modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount), modifySigOps(_modifySigOps) + {} + void operator() (CTxMemPoolEntry &e) - { e.SetDirty(); } + { e.UpdateAncestorState(modifySize, modifyFee, modifyCount, modifySigOps); } + + private: + int64_t modifySize; + CAmount modifyFee; + int64_t modifyCount; + int modifySigOps; +}; + +struct update_fee_delta +{ + update_fee_delta(int64_t _feeDelta) : feeDelta(_feeDelta) { } + + void operator() (CTxMemPoolEntry &e) { e.UpdateFeeDelta(feeDelta); } + +private: + int64_t feeDelta; +}; + +struct update_lock_points +{ + update_lock_points(const LockPoints& _lp) : lp(_lp) { } + + void operator() (CTxMemPoolEntry &e) { e.UpdateLockPoints(lp); } + +private: + const LockPoints& lp; }; // extracts a TxMemPoolEntry's transaction hash @@ -137,43 +210,61 @@ struct mempoolentry_txid } }; -/** \class CompareTxMemPoolEntryByFee +/** \class CompareTxMemPoolEntryByDescendantScore * - * Sort an entry by max(feerate of entry's tx, feerate with all descendants). + * Sort an entry by max(score/size of entry's tx, score/size with all descendants). */ -class CompareTxMemPoolEntryByFee +class CompareTxMemPoolEntryByDescendantScore { public: bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) { - bool fUseADescendants = UseDescendantFeeRate(a); - bool fUseBDescendants = UseDescendantFeeRate(b); + bool fUseADescendants = UseDescendantScore(a); + bool fUseBDescendants = UseDescendantScore(b); - double aFees = fUseADescendants ? a.GetFeesWithDescendants() : a.GetFee(); + double aModFee = fUseADescendants ? a.GetModFeesWithDescendants() : a.GetModifiedFee(); double aSize = fUseADescendants ? a.GetSizeWithDescendants() : a.GetTxSize(); - double bFees = fUseBDescendants ? b.GetFeesWithDescendants() : b.GetFee(); + double bModFee = fUseBDescendants ? b.GetModFeesWithDescendants() : b.GetModifiedFee(); double bSize = fUseBDescendants ? b.GetSizeWithDescendants() : b.GetTxSize(); // Avoid division by rewriting (a/b > c/d) as (a*d > c*b). - double f1 = aFees * bSize; - double f2 = aSize * bFees; + double f1 = aModFee * bSize; + double f2 = aSize * bModFee; if (f1 == f2) { - return a.GetTime() < b.GetTime(); + return a.GetTime() >= b.GetTime(); } - return f1 > f2; + return f1 < f2; } - // Calculate which feerate to use for an entry (avoiding division). - bool UseDescendantFeeRate(const CTxMemPoolEntry &a) + // Calculate which score to use for an entry (avoiding division). + bool UseDescendantScore(const CTxMemPoolEntry &a) { - double f1 = (double)a.GetFee() * a.GetSizeWithDescendants(); - double f2 = (double)a.GetFeesWithDescendants() * a.GetTxSize(); + double f1 = (double)a.GetModifiedFee() * a.GetSizeWithDescendants(); + double f2 = (double)a.GetModFeesWithDescendants() * a.GetTxSize(); return f2 > f1; } }; +/** \class CompareTxMemPoolEntryByScore + * + * Sort by score of entry ((fee+delta)/size) in descending order + */ +class CompareTxMemPoolEntryByScore +{ +public: + bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) + { + double f1 = (double)a.GetModifiedFee() * b.GetTxSize(); + double f2 = (double)b.GetModifiedFee() * a.GetTxSize(); + if (f1 == f2) { + return b.GetTx().GetHash() < a.GetTx().GetHash(); + } + return f1 > f2; + } +}; + class CompareTxMemPoolEntryByEntryTime { public: @@ -183,6 +274,35 @@ public: } }; +class CompareTxMemPoolEntryByAncestorFee +{ +public: + bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) + { + double aFees = a.GetModFeesWithAncestors(); + double aSize = a.GetSizeWithAncestors(); + + double bFees = b.GetModFeesWithAncestors(); + double bSize = b.GetSizeWithAncestors(); + + // Avoid division by rewriting (a/b > c/d) as (a*d > c*b). + double f1 = aFees * bSize; + double f2 = aSize * bFees; + + if (f1 == f2) { + return a.GetTx().GetHash() < b.GetTx().GetHash(); + } + + return f1 > f2; + } +}; + +// Multi_index tag names +struct descendant_score {}; +struct entry_time {}; +struct mining_score {}; +struct ancestor_score {}; + class CBlockPolicyEstimator; /** An inpoint - a combination of a transaction and an index n into its vin */ @@ -211,9 +331,11 @@ public: * * CTxMemPool::mapTx, and CTxMemPoolEntry bookkeeping: * - * mapTx is a boost::multi_index that sorts the mempool on 2 criteria: + * mapTx is a boost::multi_index that sorts the mempool on 4 criteria: * - transaction hash * - feerate [we use max(feerate of tx, feerate of tx with all descendants)] + * - time in mempool + * - mining score (feerate modified by any fee deltas from PrioritiseTransaction) * * Note: the term "descendant" refers to in-mempool transactions that depend on * this one, while "ancestor" refers to in-mempool transactions that a given @@ -277,14 +399,25 @@ public: class CTxMemPool { private: - bool fSanityCheck; //! Normally false, true if -checkmempool or -regtest + uint32_t nCheckFrequency; //!< Value n means that n times in 2^32 we check. unsigned int nTransactionsUpdated; CBlockPolicyEstimator* minerPolicyEstimator; - uint64_t totalTxSize; //! sum of all mempool tx' byte sizes - uint64_t cachedInnerUsage; //! sum of dynamic memory usage of all the map elements (NOT the maps themselves) + uint64_t totalTxSize; //!< sum of all mempool tx' byte sizes + uint64_t cachedInnerUsage; //!< sum of dynamic memory usage of all the map elements (NOT the maps themselves) + + CFeeRate minReasonableRelayFee; + + mutable int64_t lastRollingFeeUpdate; + mutable bool blockSinceLastRollingFeeBump; + mutable double rollingMinimumFeeRate; //!< minimum fee to get into the pool, decreases exponentially + + void trackPackageRemoved(const CFeeRate& rate); public: + + static const int ROLLING_FEE_HALFLIFE = 60 * 60 * 12; // public only for testing + typedef boost::multi_index_container< CTxMemPoolEntry, boost::multi_index::indexed_by< @@ -292,8 +425,27 @@ public: boost::multi_index::ordered_unique, // sorted by fee rate boost::multi_index::ordered_non_unique< + boost::multi_index::tag, boost::multi_index::identity, - CompareTxMemPoolEntryByFee + CompareTxMemPoolEntryByDescendantScore + >, + // sorted by entry time + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + boost::multi_index::identity, + CompareTxMemPoolEntryByEntryTime + >, + // sorted by score (for mining prioritization) + boost::multi_index::ordered_unique< + boost::multi_index::tag, + boost::multi_index::identity, + CompareTxMemPoolEntryByScore + >, + // sorted by fee rate with ancestors + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + boost::multi_index::identity, + CompareTxMemPoolEntryByAncestorFee > > > indexed_transaction_set; @@ -308,6 +460,8 @@ public: }; typedef std::set setEntries; + const setEntries & GetMemPoolParents(txiter entry) const; + const setEntries & GetMemPoolChildren(txiter entry) const; private: typedef std::map cacheMap; @@ -319,8 +473,6 @@ private: typedef std::map txlinksMap; txlinksMap mapLinks; - const setEntries & GetMemPoolParents(txiter entry) const; - const setEntries & GetMemPoolChildren(txiter entry) const; void UpdateParent(txiter entry, txiter parent, bool add); void UpdateChild(txiter entry, txiter child, bool add); @@ -328,7 +480,12 @@ public: std::map mapNextTx; std::map > mapDeltas; - CTxMemPool(const CFeeRate& _minRelayFee); + /** Create a new CTxMemPool. + * minReasonableRelayFee should be a feerate which is, roughly, somewhere + * around what it "costs" to relay a transaction around the network and + * below which we would reasonably say a transaction has 0-effective-fee. + */ + CTxMemPool(const CFeeRate& _minReasonableRelayFee); ~CTxMemPool(); /** @@ -338,7 +495,7 @@ public: * check does nothing. */ void check(const CCoinsViewCache *pcoins) const; - void setSanityCheck(bool _fSanityCheck) { fSanityCheck = _fSanityCheck; } + void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = dFrequency * 4294967295.0; } // addUnchecked must updated state for all ancestors of a given transaction, // to track size/count of descendant transactions. First version of @@ -347,12 +504,13 @@ public: bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true); bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate = true); - void remove(const CTransaction &tx, std::list& removed, bool fRecursive = false); - void removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight); + void removeRecursive(const CTransaction &tx, std::list& removed); + void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags); void removeConflicts(const CTransaction &tx, std::list& removed); void removeForBlock(const std::vector& vtx, unsigned int nBlockHeight, std::list& conflicts, bool fCurrentEstimate = true); void clear(); + void _clear(); //lock free void queryHashes(std::vector& vtxid); void pruneSpent(const uint256& hash, CCoins &coins); unsigned int GetTransactionsUpdated() const; @@ -365,14 +523,18 @@ public: /** Affect CreateNewBlock prioritisation of transactions */ void PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, const CAmount& nFeeDelta); - void ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta); + void ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const; void ClearPrioritisation(const uint256 hash); public: /** Remove a set of transactions from the mempool. * If a transaction is in this set, then all in-mempool descendants must - * also be in the set.*/ - void RemoveStaged(setEntries &stage); + * also be in the set, unless this transaction is being removed for being + * in a block. + * Set updateDescendants to true when removing a tx that was in a block, so + * that any in-mempool descendants have their ancestor state updated. + */ + void RemoveStaged(setEntries &stage, bool updateDescendants); /** When adding transactions from a disconnected block back to the mempool, * new mempool entries may have children in the mempool (which is generally @@ -395,7 +557,29 @@ public: * fSearchForParents = whether to search a tx's vin for in-mempool parents, or * look up parents from mapLinks. Must be true for entries not in the mempool */ - 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); + 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; + + /** Populate setDescendants with all in-mempool descendants of hash. + * Assumes that setDescendants includes all in-mempool descendants of anything + * already in it. */ + void CalculateDescendants(txiter it, setEntries &setDescendants); + + /** The minimum fee to get into the mempool, which may itself not be enough + * for larger-sized transactions. + * The minReasonableRelayFee constructor arg is used to bound the time it + * takes the fee rate to go back down all the way to 0. When the feerate + * would otherwise be half of this, it is set to 0 instead. + */ + CFeeRate GetMinFee(size_t sizelimit) const; + + /** Remove transactions from the mempool until its dynamic size is <= sizelimit. + * pvNoSpendsRemaining, if set, will be populated with the list of transactions + * which are not in mempool which no longer have any spends in this mempool. + */ + void TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRemaining=NULL); + + /** Expire all transaction (and their dependencies) in the mempool older than time. Return the number of removed transactions. */ + int Expire(int64_t time); unsigned long size() { @@ -416,10 +600,23 @@ public: } bool lookup(uint256 hash, CTransaction& result) const; + bool lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const; + + /** Estimate fee rate needed to get into the next nBlocks + * If no answer can be given at nBlocks, return an estimate + * at the lowest number of blocks where one can be given + */ + CFeeRate estimateSmartFee(int nBlocks, int *answerFoundAtBlocks = NULL) const; /** Estimate fee rate needed to get into the next nBlocks */ CFeeRate estimateFee(int nBlocks) const; + /** Estimate priority needed to get into the next nBlocks + * If no answer can be given at nBlocks, return an estimate + * at the lowest number of blocks where one can be given + */ + double estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks = NULL) const; + /** Estimate priority needed to get into the next nBlocks */ double estimatePriority(int nBlocks) const; @@ -439,27 +636,23 @@ private: * updated and hence their state is already reflected in the parent * state). * - * If updating an entry requires looking at more than maxDescendantsToVisit - * transactions, outside of the ones in setExclude, then give up. - * * cachedDescendants will be updated with the descendants of the transaction * being updated, so that future invocations don't need to walk the * same transaction again, if encountered in another transaction chain. */ - bool UpdateForDescendants(txiter updateIt, - int maxDescendantsToVisit, + void UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set &setExclude); /** Update ancestors of hash to add/remove it as a descendant transaction. */ void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors); - /** For each transaction being removed, update ancestors and any direct children. */ - void UpdateForRemoveFromMempool(const setEntries &entriesToRemove); + /** Set ancestor state for an entry */ + void UpdateEntryForAncestors(txiter it, const setEntries &setAncestors); + /** For each transaction being removed, update ancestors and any direct children. + * If updateDescendants is true, then also update in-mempool descendants' + * ancestor state. */ + void UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants); /** Sever link between specified transaction and direct children. */ void UpdateChildrenForRemoval(txiter entry); - /** Populate setDescendants with all in-mempool descendants of hash. - * Assumes that setDescendants includes all in-mempool descendants of anything - * already in it. */ - void CalculateDescendants(txiter it, setEntries &setDescendants); /** Before calling removeUnchecked for a given transaction, * UpdateForRemoveFromMempool must be called on the entire (dependent) set @@ -487,4 +680,17 @@ public: bool HaveCoins(const uint256 &txid) const; }; +// We want to sort transactions by coin age priority +typedef std::pair TxCoinAgePriority; + +struct TxCoinAgePriorityCompare +{ + bool operator()(const TxCoinAgePriority& a, const TxCoinAgePriority& b) + { + if (a.first == b.first) + return CompareTxMemPoolEntryByScore()(*(b.second), *(a.second)); //Reverse order to make sort less than + return a.first < b.first; + } +}; + #endif // BITCOIN_TXMEMPOOL_H diff --git a/src/ui_interface.h b/src/ui_interface.h index e40247993..0b51d52e6 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2012 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,6 +15,7 @@ class CBasicKeyStore; class CWallet; class uint256; +class CBlockIndex; /** General change type (added, updated, removed). */ enum ChangeType @@ -82,10 +83,9 @@ public: boost::signals2::signal NotifyNumConnectionsChanged; /** - * New, updated or cancelled alert. - * @note called with lock cs_mapAlerts held. + * Status bar alerts changed. */ - boost::signals2::signal NotifyAlertChanged; + boost::signals2::signal NotifyAlertChanged; /** A wallet has been loaded. */ boost::signals2::signal LoadWallet; @@ -94,7 +94,7 @@ public: boost::signals2::signal ShowProgress; /** New block has been accepted */ - boost::signals2::signal NotifyBlockTip; + boost::signals2::signal NotifyBlockTip; /** Banlist did change. */ boost::signals2::signal BannedListChanged; diff --git a/src/uint256.cpp b/src/uint256.cpp index 25148808c..c58c88bf4 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/uint256.h b/src/uint256.h index 6d016ab16..bcdb6dd7c 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,6 +12,7 @@ #include #include #include +#include "crypto/common.h" /** Template base class for fixed-sized opaque blobs. */ template @@ -41,9 +42,11 @@ public: memset(data, 0, sizeof(data)); } - friend inline bool operator==(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) == 0; } - friend inline bool operator!=(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) != 0; } - friend inline bool operator<(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) < 0; } + inline int Compare(const base_blob& other) const { return memcmp(data, other.data, sizeof(data)); } + + friend inline bool operator==(const base_blob& a, const base_blob& b) { return a.Compare(b) == 0; } + friend inline bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; } + friend inline bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; } std::string GetHex() const; void SetHex(const char* psz); @@ -119,13 +122,10 @@ public: * used when the contents are considered uniformly random. It is not appropriate * when the value can easily be influenced from outside as e.g. a network adversary could * provide values to trigger worst-case behavior. - * @note The result of this function is not stable between little and big endian. */ uint64_t GetCheapHash() const { - uint64_t result; - memcpy((void*)&result, (void*)data, 8); - return result; + return ReadLE64(data); } /** A more secure, salted hash function. diff --git a/src/undo.h b/src/undo.h index b8171245e..0af903c8c 100644 --- a/src/undo.h +++ b/src/undo.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/univalue/.gitignore b/src/univalue/.gitignore index a7a2ca919..19e42f814 100644 --- a/src/univalue/.gitignore +++ b/src/univalue/.gitignore @@ -18,6 +18,7 @@ univalue-config.h* test-driver libtool ltmain.sh +test-suite.log *.a *.la diff --git a/src/univalue/.travis.yml b/src/univalue/.travis.yml index af632c78d..d318d9cc8 100644 --- a/src/univalue/.travis.yml +++ b/src/univalue/.travis.yml @@ -36,7 +36,7 @@ script: - ./configure --cache-file=config.cache $UNIVALUE_CONFIG_ALL $UNIVALUE_CONFIG || ( cat config.log && false) - make -s $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL ; false ) - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib - - if [ "$RUN_TESTS" = "true" ]; then make check; fi + - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi matrix: fast_finish: true diff --git a/src/univalue/Makefile.am b/src/univalue/Makefile.am index df9e66229..34fe9e3f1 100644 --- a/src/univalue/Makefile.am +++ b/src/univalue/Makefile.am @@ -70,6 +70,9 @@ TEST_FILES = \ $(TEST_DATA_DIR)/fail32.json \ $(TEST_DATA_DIR)/fail33.json \ $(TEST_DATA_DIR)/fail34.json \ + $(TEST_DATA_DIR)/fail35.json \ + $(TEST_DATA_DIR)/fail36.json \ + $(TEST_DATA_DIR)/fail37.json \ $(TEST_DATA_DIR)/fail3.json \ $(TEST_DATA_DIR)/fail4.json \ $(TEST_DATA_DIR)/fail5.json \ @@ -79,6 +82,7 @@ TEST_FILES = \ $(TEST_DATA_DIR)/fail9.json \ $(TEST_DATA_DIR)/pass1.json \ $(TEST_DATA_DIR)/pass2.json \ - $(TEST_DATA_DIR)/pass3.json + $(TEST_DATA_DIR)/pass3.json \ + $(TEST_DATA_DIR)/round1.json EXTRA_DIST=$(TEST_FILES) $(GEN_SRCS) diff --git a/src/univalue/configure.ac b/src/univalue/configure.ac index 6cd951622..0515b632b 100644 --- a/src/univalue/configure.ac +++ b/src/univalue/configure.ac @@ -14,7 +14,7 @@ m4_define([libunivalue_age], [m4_eval(libunivalue_binary_age - libunivalue_inter m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()]) -AC_INIT([univalue], [1.0.0], +AC_INIT([univalue], [1.0.1], [http://github.com/jgarzik/univalue/]) dnl make the compilation flags quiet unless V=1 is used diff --git a/src/univalue/gen/gen.cpp b/src/univalue/gen/gen.cpp index 5e5a4d4ae..17f361941 100644 --- a/src/univalue/gen/gen.cpp +++ b/src/univalue/gen/gen.cpp @@ -8,7 +8,6 @@ // $ ./gen > univalue_escapes.h // -#include #include #include #include "univalue.h" @@ -16,10 +15,17 @@ using namespace std; static bool initEscapes; -static const char *escapes[256]; +static std::string escapes[256]; static void initJsonEscape() { + // Escape all lower control characters (some get overridden with smaller sequences below) + for (int ch=0x00; ch<0x20; ++ch) { + char tmpbuf[20]; + snprintf(tmpbuf, sizeof(tmpbuf), "\\u%04x", ch); + escapes[ch] = std::string(tmpbuf); + } + escapes[(int)'"'] = "\\\""; escapes[(int)'\\'] = "\\\\"; escapes[(int)'\b'] = "\\b"; @@ -27,6 +33,7 @@ static void initJsonEscape() escapes[(int)'\n'] = "\\n"; escapes[(int)'\r'] = "\\r"; escapes[(int)'\t'] = "\\t"; + escapes[(int)'\x7f'] = "\\u007f"; // U+007F DELETE initEscapes = true; } @@ -39,13 +46,13 @@ static void outputEscape() "static const char *escapes[256] = {\n"); for (unsigned int i = 0; i < 256; i++) { - if (!escapes[i]) { + if (escapes[i].empty()) { printf("\tNULL,\n"); } else { printf("\t\""); unsigned int si; - for (si = 0; si < strlen(escapes[i]); si++) { + for (si = 0; si < escapes[i].size(); si++) { char ch = escapes[i][si]; switch (ch) { case '"': diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index ac0511601..8428b1c68 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -243,8 +243,41 @@ extern enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed, const char *raw); extern const char *uvTypeName(UniValue::VType t); +static inline bool jsonTokenIsValue(enum jtokentype jtt) +{ + switch (jtt) { + case JTOK_KW_NULL: + case JTOK_KW_TRUE: + case JTOK_KW_FALSE: + case JTOK_NUMBER: + case JTOK_STRING: + return true; + + default: + return false; + } + + // not reached +} + +static inline bool json_isspace(int ch) +{ + switch (ch) { + case 0x20: + case 0x09: + case 0x0a: + case 0x0d: + return true; + + default: + return false; + } + + // not reached +} + extern const UniValue NullUniValue; const UniValue& find_value( const UniValue& obj, const std::string& name); -#endif // __UNIVALUE_H__ \ No newline at end of file +#endif // __UNIVALUE_H__ diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp index 883e8651f..0076d6678 100644 --- a/src/univalue/lib/univalue.cpp +++ b/src/univalue/lib/univalue.cpp @@ -4,7 +4,6 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include -#include #include #include #include @@ -21,7 +20,7 @@ static bool ParsePrechecks(const std::string& str) { if (str.empty()) // No empty string allowed return false; - if (str.size() >= 1 && (isspace(str[0]) || isspace(str[str.size()-1]))) // No padding allowed + if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed return false; if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed return false; @@ -210,7 +209,7 @@ bool UniValue::pushKVs(const UniValue& obj) for (unsigned int i = 0; i < obj.keys.size(); i++) { keys.push_back(obj.keys[i]); - values.push_back(obj.values[i]); + values.push_back(obj.values.at(i)); } return true; @@ -234,7 +233,7 @@ bool UniValue::checkObject(const std::map& t) if (idx < 0) return false; - if (values[idx].getType() != it->second) + if (values.at(idx).getType() != it->second) return false; } @@ -250,7 +249,7 @@ const UniValue& UniValue::operator[](const std::string& key) const if (index < 0) return NullUniValue; - return values[index]; + return values.at(index); } const UniValue& UniValue::operator[](unsigned int index) const @@ -260,7 +259,7 @@ const UniValue& UniValue::operator[](unsigned int index) const if (index >= values.size()) return NullUniValue; - return values[index]; + return values.at(index); } const char *uvTypeName(UniValue::VType t) @@ -278,15 +277,11 @@ const char *uvTypeName(UniValue::VType t) return NULL; } -const UniValue& find_value( const UniValue& obj, const std::string& name) +const UniValue& find_value(const UniValue& obj, const std::string& name) { for (unsigned int i = 0; i < obj.keys.size(); i++) - { - if( obj.keys[i] == name ) - { - return obj.values[i]; - } - } + if (obj.keys[i] == name) + return obj.values.at(i); return NullUniValue; } diff --git a/src/univalue/lib/univalue_escapes.h b/src/univalue/lib/univalue_escapes.h index 4133b24ca..74596aab6 100644 --- a/src/univalue/lib/univalue_escapes.h +++ b/src/univalue/lib/univalue_escapes.h @@ -2,38 +2,38 @@ #ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H #define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H static const char *escapes[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + "\\u0000", + "\\u0001", + "\\u0002", + "\\u0003", + "\\u0004", + "\\u0005", + "\\u0006", + "\\u0007", "\\b", "\\t", "\\n", - NULL, + "\\u000b", "\\f", "\\r", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + "\\u000e", + "\\u000f", + "\\u0010", + "\\u0011", + "\\u0012", + "\\u0013", + "\\u0014", + "\\u0015", + "\\u0016", + "\\u0017", + "\\u0018", + "\\u0019", + "\\u001a", + "\\u001b", + "\\u001c", + "\\u001d", + "\\u001e", + "\\u001f", NULL, NULL, "\\\"", @@ -129,7 +129,7 @@ static const char *escapes[256] = { NULL, NULL, NULL, - NULL, + "\\u007f", NULL, NULL, NULL, diff --git a/src/univalue/lib/univalue_read.cpp b/src/univalue/lib/univalue_read.cpp index 64591234c..c7516b962 100644 --- a/src/univalue/lib/univalue_read.cpp +++ b/src/univalue/lib/univalue_read.cpp @@ -9,6 +9,11 @@ using namespace std; +static bool json_isdigit(int ch) +{ + return ((ch >= '0') && (ch <= '9')); +} + // convert hexadecimal string to unsigned integer static const char *hatoui(const char *first, const char *last, unsigned int& out) @@ -17,7 +22,7 @@ static const char *hatoui(const char *first, const char *last, for (; first != last; ++first) { int digit; - if (isdigit(*first)) + if (json_isdigit(*first)) digit = *first - '0'; else if (*first >= 'a' && *first <= 'f') @@ -44,7 +49,7 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, const char *rawStart = raw; - while ((*raw) && (isspace(*raw))) // skip whitespace + while ((*raw) && (json_isspace(*raw))) // skip whitespace raw++; switch (*raw) { @@ -113,18 +118,18 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, const char *first = raw; const char *firstDigit = first; - if (!isdigit(*firstDigit)) + if (!json_isdigit(*firstDigit)) firstDigit++; - if ((*firstDigit == '0') && isdigit(firstDigit[1])) + if ((*firstDigit == '0') && json_isdigit(firstDigit[1])) return JTOK_ERR; numStr += *raw; // copy first char raw++; - if ((*first == '-') && (!isdigit(*raw))) + if ((*first == '-') && (!json_isdigit(*raw))) return JTOK_ERR; - while ((*raw) && isdigit(*raw)) { // copy digits + while ((*raw) && json_isdigit(*raw)) { // copy digits numStr += *raw; raw++; } @@ -134,9 +139,9 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, numStr += *raw; // copy . raw++; - if (!isdigit(*raw)) + if (!json_isdigit(*raw)) return JTOK_ERR; - while ((*raw) && isdigit(*raw)) { // copy digits + while ((*raw) && json_isdigit(*raw)) { // copy digits numStr += *raw; raw++; } @@ -152,9 +157,9 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, raw++; } - if (!isdigit(*raw)) + if (!json_isdigit(*raw)) return JTOK_ERR; - while ((*raw) && isdigit(*raw)) { // copy digits + while ((*raw) && json_isdigit(*raw)) { // copy digits numStr += *raw; raw++; } @@ -236,12 +241,23 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, } } +enum expect_bits { + EXP_OBJ_NAME = (1U << 0), + EXP_COLON = (1U << 1), + EXP_ARR_VALUE = (1U << 2), + EXP_VALUE = (1U << 3), + EXP_NOT_VALUE = (1U << 4), +}; + +#define expect(bit) (expectMask & (EXP_##bit)) +#define setExpect(bit) (expectMask |= EXP_##bit) +#define clearExpect(bit) (expectMask &= ~EXP_##bit) + bool UniValue::read(const char *raw) { clear(); - bool expectName = false; - bool expectColon = false; + uint32_t expectMask = 0; vector stack; string tokenVal; @@ -256,6 +272,41 @@ bool UniValue::read(const char *raw) return false; raw += consumed; + bool isValueOpen = jsonTokenIsValue(tok) || + tok == JTOK_OBJ_OPEN || tok == JTOK_ARR_OPEN; + + if (expect(VALUE)) { + if (!isValueOpen) + return false; + clearExpect(VALUE); + + } else if (expect(ARR_VALUE)) { + bool isArrValue = isValueOpen || (tok == JTOK_ARR_CLOSE); + if (!isArrValue) + return false; + + clearExpect(ARR_VALUE); + + } else if (expect(OBJ_NAME)) { + bool isObjName = (tok == JTOK_OBJ_CLOSE || tok == JTOK_STRING); + if (!isObjName) + return false; + + } else if (expect(COLON)) { + if (tok != JTOK_COLON) + return false; + clearExpect(COLON); + + } else if (!expect(COLON) && (tok == JTOK_COLON)) { + return false; + } + + if (expect(NOT_VALUE)) { + if (isValueOpen) + return false; + clearExpect(NOT_VALUE); + } + switch (tok) { case JTOK_OBJ_OPEN: @@ -277,13 +328,15 @@ bool UniValue::read(const char *raw) } if (utyp == VOBJ) - expectName = true; + setExpect(OBJ_NAME); + else + setExpect(ARR_VALUE); break; } case JTOK_OBJ_CLOSE: case JTOK_ARR_CLOSE: { - if (!stack.size() || expectColon || (last_tok == JTOK_COMMA)) + if (!stack.size() || (last_tok == JTOK_COMMA)) return false; VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR); @@ -292,37 +345,40 @@ bool UniValue::read(const char *raw) return false; stack.pop_back(); - expectName = false; + clearExpect(OBJ_NAME); + setExpect(NOT_VALUE); break; } case JTOK_COLON: { - if (!stack.size() || expectName || !expectColon) + if (!stack.size()) return false; UniValue *top = stack.back(); if (top->getType() != VOBJ) return false; - expectColon = false; + setExpect(VALUE); break; } case JTOK_COMMA: { - if (!stack.size() || expectName || expectColon || + if (!stack.size() || (last_tok == JTOK_COMMA) || (last_tok == JTOK_ARR_OPEN)) return false; UniValue *top = stack.back(); if (top->getType() == VOBJ) - expectName = true; + setExpect(OBJ_NAME); + else + setExpect(ARR_VALUE); break; } case JTOK_KW_NULL: case JTOK_KW_TRUE: case JTOK_KW_FALSE: { - if (!stack.size() || expectName || expectColon) + if (!stack.size()) return false; UniValue tmpVal; @@ -342,17 +398,19 @@ bool UniValue::read(const char *raw) UniValue *top = stack.back(); top->values.push_back(tmpVal); + setExpect(NOT_VALUE); break; } case JTOK_NUMBER: { - if (!stack.size() || expectName || expectColon) + if (!stack.size()) return false; UniValue tmpVal(VNUM, tokenVal); UniValue *top = stack.back(); top->values.push_back(tmpVal); + setExpect(NOT_VALUE); break; } @@ -362,15 +420,16 @@ bool UniValue::read(const char *raw) UniValue *top = stack.back(); - if (expectName) { + if (expect(OBJ_NAME)) { top->keys.push_back(tokenVal); - expectName = false; - expectColon = true; + clearExpect(OBJ_NAME); + setExpect(COLON); } else { UniValue tmpVal(VSTR, tokenVal); top->values.push_back(tmpVal); } + setExpect(NOT_VALUE); break; } diff --git a/src/univalue/lib/univalue_write.cpp b/src/univalue/lib/univalue_write.cpp index bce3997af..ceb4cc916 100644 --- a/src/univalue/lib/univalue_write.cpp +++ b/src/univalue/lib/univalue_write.cpp @@ -2,7 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include #include #include #include @@ -25,10 +24,10 @@ static string json_escape(const string& inS) if (escStr) outS += escStr; - else if (isprint(ch)) + else if (ch < 0x80) outS += ch; - else { + else { // TODO handle UTF-8 properly char tmpesc[16]; sprintf(tmpesc, "\\u%04x", ch); outS += tmpesc; @@ -113,7 +112,7 @@ void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, s += "\"" + json_escape(keys[i]) + "\":"; if (prettyIndent) s += " "; - s += values[i].write(prettyIndent, indentLevel + 1); + s += values.at(i).write(prettyIndent, indentLevel + 1); if (i != (values.size() - 1)) s += ","; if (prettyIndent) diff --git a/src/univalue/test/.gitignore b/src/univalue/test/.gitignore index 4afa094b1..3d9347fe7 100644 --- a/src/univalue/test/.gitignore +++ b/src/univalue/test/.gitignore @@ -1 +1,4 @@ unitester + +*.trs +*.log diff --git a/src/univalue/test/fail35.json b/src/univalue/test/fail35.json new file mode 100644 index 000000000..de30ca5c4 --- /dev/null +++ b/src/univalue/test/fail35.json @@ -0,0 +1 @@ +[ true true true [] [] [] ] diff --git a/src/univalue/test/fail36.json b/src/univalue/test/fail36.json new file mode 100644 index 000000000..f82eb8e1f --- /dev/null +++ b/src/univalue/test/fail36.json @@ -0,0 +1 @@ +{"a":} diff --git a/src/univalue/test/fail37.json b/src/univalue/test/fail37.json new file mode 100644 index 000000000..3294dc3a4 --- /dev/null +++ b/src/univalue/test/fail37.json @@ -0,0 +1 @@ +{"a":1 "b":2} diff --git a/src/univalue/test/round1.json b/src/univalue/test/round1.json new file mode 100644 index 000000000..a711e7308 --- /dev/null +++ b/src/univalue/test/round1.json @@ -0,0 +1 @@ +["\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"] diff --git a/src/univalue/test/unitester.cpp b/src/univalue/test/unitester.cpp index 835556e03..5a052fe92 100644 --- a/src/univalue/test/unitester.cpp +++ b/src/univalue/test/unitester.cpp @@ -19,24 +19,37 @@ using namespace std; string srcdir(JSON_TEST_SRC); +static bool test_failed = false; + +#define d_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", filename.c_str()); } } + +static std::string rtrim(std::string s) +{ + s.erase(s.find_last_not_of(" \n\r\t")+1); + return s; +} static void runtest(string filename, const string& jdata) { - fprintf(stderr, "test %s\n", filename.c_str()); - string prefix = filename.substr(0, 4); - bool wantPass = (prefix == "pass"); + bool wantPass = (prefix == "pass") || (prefix == "roun"); bool wantFail = (prefix == "fail"); + bool wantRoundTrip = (prefix == "roun"); assert(wantPass || wantFail); UniValue val; bool testResult = val.read(jdata); if (wantPass) { - assert(testResult == true); + d_assert(testResult == true); } else { - assert(testResult == false); + d_assert(testResult == false); + } + + if (wantRoundTrip) { + std::string odata = val.write(0, 0); + assert(odata == rtrim(jdata)); } } @@ -92,6 +105,9 @@ static const char *filenames[] = { "fail32.json", "fail33.json", "fail34.json", + "fail35.json", + "fail36.json", + "fail37.json", "fail3.json", "fail4.json", // extra comma "fail5.json", @@ -102,6 +118,7 @@ static const char *filenames[] = { "pass1.json", "pass2.json", "pass3.json", + "round1.json", // round-trip test }; int main (int argc, char *argv[]) @@ -110,6 +127,6 @@ int main (int argc, char *argv[]) runtest_file(filenames[fidx]); } - return 0; + return test_failed ? 1 : 0; } diff --git a/src/util.cpp b/src/util.cpp index 1151002e2..ba4fab1d0 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -99,6 +99,9 @@ namespace boost { using namespace std; +const char * const BITCOIN_CONF_FILENAME = "lbrycrd.conf"; +const char * const BITCOIN_PID_FILENAME = "lbrycrd.pid"; + map mapArgs; map > mapMultiArgs; bool fDebug = false; @@ -107,8 +110,9 @@ bool fPrintToDebugLog = true; bool fDaemon = false; bool fServer = false; string strMiscWarning; -bool fLogTimestamps = false; -bool fLogIPs = false; +bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS; +bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS; +bool fLogIPs = DEFAULT_LOGIPS; volatile bool fReopenDebugLog = false; CTranslationInterface translationInterface; @@ -263,9 +267,13 @@ static std::string LogTimestampStr(const std::string &str, bool *fStartedNewLine if (!fLogTimestamps) return str; - if (*fStartedNewLine) - strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()) + ' ' + str; - else + if (*fStartedNewLine) { + int64_t nTimeMicros = GetLogTimeMicros(); + strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTimeMicros/1000000); + if (fLogTimeMicros) + strStamped += strprintf(".%06d", nTimeMicros%1000000); + strStamped += ' ' + str; + } else strStamped = str; if (!str.empty() && str[str.size()-1] == '\n') @@ -442,7 +450,6 @@ void PrintExceptionContinue(const std::exception* pex, const char* pszThread) std::string message = FormatException(pex, pszThread); LogPrintf("\n\n************************\n%s\n", message); fprintf(stderr, "\n\n************************\n%s\n", message.c_str()); - strMiscWarning = message; } boost::filesystem::path GetDefaultDataDir() @@ -464,9 +471,7 @@ boost::filesystem::path GetDefaultDataDir() pathRet = fs::path(pszHome); #ifdef MAC_OSX // Mac - pathRet /= "Library/Application Support"; - TryCreateDirectory(pathRet); - return pathRet / "lbrycrd"; + return pathRet / "Library/Application Support/lbrycrd"; #else // Unix return pathRet / ".lbrycrd"; @@ -516,7 +521,7 @@ void ClearDatadirCache() boost::filesystem::path GetConfigFile() { - boost::filesystem::path pathConfigFile(GetArg("-conf", "lbrycrd.conf")); + boost::filesystem::path pathConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)); if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile; @@ -550,7 +555,7 @@ void ReadConfigFile(map& mapSettingsRet, #ifndef WIN32 boost::filesystem::path GetPidFile() { - boost::filesystem::path pathPidFile(GetArg("-pid", "lbrycrdd.pid")); + boost::filesystem::path pathPidFile(GetArg("-pid", BITCOIN_PID_FILENAME)); if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile; return pathPidFile; } @@ -731,28 +736,6 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) } #endif -boost::filesystem::path GetTempPath() { -#if BOOST_FILESYSTEM_VERSION == 3 - return boost::filesystem::temp_directory_path(); -#else - // TODO: remove when we don't support filesystem v2 anymore - boost::filesystem::path path; -#ifdef WIN32 - char pszPath[MAX_PATH] = ""; - - if (GetTempPathA(MAX_PATH, pszPath)) - path = boost::filesystem::path(pszPath); -#else - path = boost::filesystem::path("/tmp"); -#endif - if (path.empty() || !boost::filesystem::is_directory(path)) { - LogPrintf("GetTempPath(): failed to find temp path\n"); - return boost::filesystem::path(""); - } - return path; -#endif -} - void runCommand(const std::string& strCommand) { int nErr = ::system(strCommand.c_str()); @@ -829,3 +812,14 @@ int GetNumCores() #endif } +std::string CopyrightHolders(const std::string& strPrefix) +{ + std::string strCopyrightHolders = strPrefix + _(COPYRIGHT_HOLDERS); + if (strCopyrightHolders.find("%s") != strCopyrightHolders.npos) { + strCopyrightHolders = strprintf(strCopyrightHolders, _(COPYRIGHT_HOLDERS_SUBSTITUTION)); + } + if (strCopyrightHolders.find("Bitcoin Core developers") == strCopyrightHolders.npos) { + strCopyrightHolders += "\n" + strPrefix + "The Bitcoin Core developers"; + } + return strCopyrightHolders; +} diff --git a/src/util.h b/src/util.h index 0b2dc01ac..ac099f118 100644 --- a/src/util.h +++ b/src/util.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -28,6 +28,10 @@ #include #include +static const bool DEFAULT_LOGTIMEMICROS = false; +static const bool DEFAULT_LOGIPS = false; +static const bool DEFAULT_LOGTIMESTAMPS = true; + /** Signals for translation. */ class CTranslationInterface { @@ -44,10 +48,14 @@ extern bool fPrintToDebugLog; extern bool fServer; extern std::string strMiscWarning; extern bool fLogTimestamps; +extern bool fLogTimeMicros; extern bool fLogIPs; extern volatile bool fReopenDebugLog; extern CTranslationInterface translationInterface; +extern const char * const BITCOIN_CONF_FILENAME; +extern const char * const BITCOIN_PID_FILENAME; + /** * Translation function: Call Translate signal on UI interface, which returns a boost::optional result. * If no translation slot is registered, nothing is returned, and simply return the input. @@ -125,7 +133,6 @@ void ReadConfigFile(std::map& mapSettingsRet, std::map #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif -boost::filesystem::path GetTempPath(); void OpenDebugLog(); void ShrinkDebugFile(); void runCommand(const std::string& strCommand); @@ -239,4 +246,6 @@ template void TraceThread(const char* name, Callable func) } } +std::string CopyrightHolders(const std::string& strPrefix); + #endif // BITCOIN_UTIL_H diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp index 0f3203432..bebe56130 100644 --- a/src/utilmoneystr.cpp +++ b/src/utilmoneystr.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/utilmoneystr.h b/src/utilmoneystr.h index 99c3ba830..5839b0734 100644 --- a/src/utilmoneystr.h +++ b/src/utilmoneystr.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index c5a2b5cdb..0f9334cbe 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -478,34 +478,40 @@ bool ParseDouble(const std::string& str, double *out) std::string FormatParagraph(const std::string& in, size_t width, size_t indent) { std::stringstream out; - size_t col = 0; size_t ptr = 0; - while(ptr < in.size()) + size_t indented = 0; + while (ptr < in.size()) { - // Find beginning of next word - ptr = in.find_first_not_of(' ', ptr); - if (ptr == std::string::npos) - break; - // Find end of next word - size_t endword = in.find_first_of(' ', ptr); - if (endword == std::string::npos) - endword = in.size(); - // Add newline and indentation if this wraps over the allowed width - if (col > 0) - { - if ((col + endword - ptr) > width) - { - out << '\n'; - for(size_t i=0; i 0); + return now; } void SetMockTime(int64_t nMockTimeIn) @@ -30,14 +32,26 @@ void SetMockTime(int64_t nMockTimeIn) int64_t GetTimeMillis() { - return (boost::posix_time::microsec_clock::universal_time() - - boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds(); + int64_t now = (boost::posix_time::microsec_clock::universal_time() - + boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds(); + assert(now > 0); + return now; } int64_t GetTimeMicros() { - return (boost::posix_time::microsec_clock::universal_time() - - boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds(); + int64_t now = (boost::posix_time::microsec_clock::universal_time() - + boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds(); + assert(now > 0); + return now; +} + +/** Return a time useful for the debug log */ +int64_t GetLogTimeMicros() +{ + if (nMockTime) return nMockTime*1000000; + + return GetTimeMicros(); } void MilliSleep(int64_t n) diff --git a/src/utiltime.h b/src/utiltime.h index 900992f87..b2807267d 100644 --- a/src/utiltime.h +++ b/src/utiltime.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,6 +12,7 @@ int64_t GetTime(); int64_t GetTimeMillis(); int64_t GetTimeMicros(); +int64_t GetLogTimeMicros(); void SetMockTime(int64_t nMockTimeIn); void MilliSleep(int64_t n); diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 81f3b775f..8da0c7285 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -14,7 +14,7 @@ CMainSignals& GetMainSignals() void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1)); - g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); + g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3)); g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); @@ -32,7 +32,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); - g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); + g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3)); g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1)); } @@ -48,6 +48,6 @@ void UnregisterAllValidationInterfaces() { g_signals.UpdatedBlockTip.disconnect_all_slots(); } -void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) { - g_signals.SyncTransaction(tx, pblock); +void SyncWithWallets(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock) { + g_signals.SyncTransaction(tx, pindex, pblock); } diff --git a/src/validationinterface.h b/src/validationinterface.h index ffb56d266..01b8e4765 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,6 +10,7 @@ #include class CBlock; +class CBlockIndex; struct CBlockLocator; class CBlockIndex; class CReserveScript; @@ -27,12 +28,12 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn); /** Unregister all wallets from core */ void UnregisterAllValidationInterfaces(); /** Push an updated transaction to all registered wallets */ -void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL); +void SyncWithWallets(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock = NULL); class CValidationInterface { protected: virtual void UpdatedBlockTip(const CBlockIndex *pindex) {} - virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {} + virtual void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock) {} virtual void SetBestChain(const CBlockLocator &locator) {} virtual void UpdatedTransaction(const uint256 &hash) {} virtual void Inventory(const uint256 &hash) {} @@ -49,7 +50,7 @@ struct CMainSignals { /** Notifies listeners of updated block chain tip */ boost::signals2::signal UpdatedBlockTip; /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */ - boost::signals2::signal SyncTransaction; + boost::signals2::signal SyncTransaction; /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ boost::signals2::signal UpdatedTransaction; /** Notifies listeners of a new active block chain. */ diff --git a/src/version.h b/src/version.h index 6cdddf925..0e1d8a63c 100644 --- a/src/version.h +++ b/src/version.h @@ -9,7 +9,7 @@ * network protocol versioning */ -static const int PROTOCOL_VERSION = 70011; +static const int PROTOCOL_VERSION = 70013; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; @@ -24,10 +24,6 @@ static const int MIN_PEER_PROTO_VERSION = GETHEADERS_VERSION; //! if possible, avoid requesting addresses nodes older than this static const int CADDR_TIME_VERSION = 31402; -//! only request blocks from nodes outside this range of versions -static const int NOBLKS_VERSION_START = 32000; -static const int NOBLKS_VERSION_END = 32400; - //! BIP 0031, pong message, is enabled for all versions AFTER this one static const int BIP0031_VERSION = 60000; @@ -37,4 +33,10 @@ static const int MEMPOOL_GD_VERSION = 60002; //! "filter*" commands are disabled without NODE_BLOOM after and including this version static const int NO_BLOOM_VERSION = 70011; +//! "sendheaders" command and announcing blocks with headers starts with this version +static const int SENDHEADERS_VERSION = 70012; + +//! "feefilter" tells peers to filter invs to you by fee starts with this version +static const int FEEFILTER_VERSION = 70013; + #endif // BITCOIN_VERSION_H diff --git a/src/versionbits.cpp b/src/versionbits.cpp new file mode 100644 index 000000000..78feb8ab0 --- /dev/null +++ b/src/versionbits.cpp @@ -0,0 +1,133 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "versionbits.h" + +ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const +{ + int nPeriod = Period(params); + int nThreshold = Threshold(params); + int64_t nTimeStart = BeginTime(params); + int64_t nTimeTimeout = EndTime(params); + + // 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. + if (pindexPrev != NULL) { + pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod)); + } + + // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known + std::vector vToCompute; + while (cache.count(pindexPrev) == 0) { + if (pindexPrev == NULL) { + // The genesis block is by definition defined. + cache[pindexPrev] = THRESHOLD_DEFINED; + break; + } + if (pindexPrev->GetMedianTimePast() < nTimeStart) { + // Optimization: don't recompute down further, as we know every earlier block will be before the start time + cache[pindexPrev] = THRESHOLD_DEFINED; + break; + } + vToCompute.push_back(pindexPrev); + pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod); + } + + // At this point, cache[pindexPrev] is known + assert(cache.count(pindexPrev)); + ThresholdState state = cache[pindexPrev]; + + // Now walk forward and compute the state of descendants of pindexPrev + while (!vToCompute.empty()) { + ThresholdState stateNext = state; + pindexPrev = vToCompute.back(); + vToCompute.pop_back(); + + switch (state) { + case THRESHOLD_DEFINED: { + if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { + stateNext = THRESHOLD_FAILED; + } else if (pindexPrev->GetMedianTimePast() >= nTimeStart) { + stateNext = THRESHOLD_STARTED; + } + break; + } + case THRESHOLD_STARTED: { + if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { + stateNext = THRESHOLD_FAILED; + break; + } + // We need to count + const CBlockIndex* pindexCount = pindexPrev; + int count = 0; + for (int i = 0; i < nPeriod; i++) { + if (Condition(pindexCount, params)) { + count++; + } + pindexCount = pindexCount->pprev; + } + if (count >= nThreshold) { + stateNext = THRESHOLD_LOCKED_IN; + } + break; + } + case THRESHOLD_LOCKED_IN: { + // Always progresses into ACTIVE. + stateNext = THRESHOLD_ACTIVE; + break; + } + case THRESHOLD_FAILED: + case THRESHOLD_ACTIVE: { + // Nothing happens, these are terminal states. + break; + } + } + cache[pindexPrev] = state = stateNext; + } + + return state; +} + +namespace +{ +/** + * Class to implement versionbits logic. + */ +class VersionBitsConditionChecker : public AbstractThresholdConditionChecker { +private: + const Consensus::DeploymentPos id; + +protected: + int64_t BeginTime(const Consensus::Params& params) const { return params.vDeployments[id].nStartTime; } + int64_t EndTime(const Consensus::Params& params) const { return params.vDeployments[id].nTimeout; } + int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; } + int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; } + + bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const + { + return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0); + } + +public: + VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {} + uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; } +}; + +} + +ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache) +{ + return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, cache.caches[pos]); +} + +uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos) +{ + return VersionBitsConditionChecker(pos).Mask(params); +} + +void VersionBitsCache::Clear() +{ + for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) { + caches[d].clear(); + } +} diff --git a/src/versionbits.h b/src/versionbits.h new file mode 100644 index 000000000..04f473827 --- /dev/null +++ b/src/versionbits.h @@ -0,0 +1,59 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CONSENSUS_VERSIONBITS +#define BITCOIN_CONSENSUS_VERSIONBITS + +#include "chain.h" +#include + +/** What block version to use for new blocks (pre versionbits) */ +static const int32_t VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4; +/** What bits to set in version for versionbits blocks */ +static const int32_t VERSIONBITS_TOP_BITS = 0x20000000UL; +/** What bitmask determines whether versionbits is in use */ +static const int32_t VERSIONBITS_TOP_MASK = 0xE0000000UL; +/** Total bits available for versionbits */ +static const int32_t VERSIONBITS_NUM_BITS = 29; + +enum ThresholdState { + THRESHOLD_DEFINED, + THRESHOLD_STARTED, + THRESHOLD_LOCKED_IN, + THRESHOLD_ACTIVE, + THRESHOLD_FAILED, +}; + +// A map that gives the state for blocks whose height is a multiple of Period(). +// The map is indexed by the block's parent, however, so all keys in the map +// will either be NULL or a block with (height + 1) % Period() == 0. +typedef std::map ThresholdConditionCache; + +/** + * Abstract class that implements BIP9-style threshold logic, and caches results. + */ +class AbstractThresholdConditionChecker { +protected: + virtual bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const =0; + virtual int64_t BeginTime(const Consensus::Params& params) const =0; + virtual int64_t EndTime(const Consensus::Params& params) const =0; + virtual int Period(const Consensus::Params& params) const =0; + virtual int Threshold(const Consensus::Params& params) const =0; + +public: + // Note that the function below takes a pindexPrev as input: they compute information for block B based on its parent. + ThresholdState GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const; +}; + +struct VersionBitsCache +{ + ThresholdConditionCache caches[Consensus::MAX_VERSION_BITS_DEPLOYMENTS]; + + void Clear(); +}; + +ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache); +uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos); + +#endif diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index c86ad9758..95aa4c259 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index 70aeb7672..eb06a7866 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index e5bc653c3..c906785e9 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -85,7 +85,7 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn) LogPrintf("CDBEnv::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string()); unsigned int nEnvFlags = 0; - if (GetBoolArg("-privdb", true)) + if (GetBoolArg("-privdb", DEFAULT_WALLET_PRIVDB)) nEnvFlags |= DB_PRIVATE; dbenv->set_lg_dir(pathLogDir.string().c_str()); @@ -165,6 +165,11 @@ CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFu return (fRecovered ? RECOVER_OK : RECOVER_FAIL); } +/* End of headers, beginning of key/value data */ +static const char *HEADER_END = "HEADER=END"; +/* End of key/value data */ +static const char *DATA_END = "DATA=END"; + bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector& vResult) { LOCK(cs_db); @@ -193,24 +198,35 @@ bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vectortxn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0); + bitdb.dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0); } void CDB::Close() diff --git a/src/wallet/db.h b/src/wallet/db.h index 64071caa3..01b8c71a0 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -20,6 +20,9 @@ #include +static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100; +static const bool DEFAULT_WALLET_PRIVDB = true; + extern unsigned int nWalletDBUpdated; class CDBEnv diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 4b8d19199..9aea50c38 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -1,10 +1,10 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "base58.h" #include "chain.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "init.h" #include "main.h" #include "script/script.h" @@ -13,6 +13,8 @@ #include "util.h" #include "utiltime.h" #include "wallet.h" +#include "merkleblock.h" +#include "core_io.h" #include #include @@ -192,7 +194,7 @@ UniValue importaddress(const UniValue& params, bool fHelp) "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n" "4. p2sh (boolean, optional, default=false) Add the P2SH version of the script as well\n" "\nNote: This call can take minutes to complete if rescan is true.\n" - "If you have the full public key, you should call importpublickey instead of this.\n" + "If you have the full public key, you should call importpubkey instead of this.\n" "\nExamples:\n" "\nImport a script with rescan\n" + HelpExampleCli("importaddress", "\"myscript\"") + @@ -243,6 +245,109 @@ UniValue importaddress(const UniValue& params, bool fHelp) return NullUniValue; } +UniValue importprunedfunds(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() < 2 || params.size() > 3) + throw runtime_error( + "importprunedfunds\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" + "\nArguments:\n" + "1. \"rawtransaction\" (string, required) A raw transaction in hex funding an already-existing address in wallet\n" + "2. \"txoutproof\" (string, required) The hex output from gettxoutproof that contains the transaction\n" + "3. \"label\" (string, optional) An optional label\n" + ); + + CTransaction tx; + if (!DecodeHexTx(tx, params[0].get_str())) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + uint256 hashTx = tx.GetHash(); + CWalletTx wtx(pwalletMain,tx); + + CDataStream ssMB(ParseHexV(params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION); + CMerkleBlock merkleBlock; + ssMB >> merkleBlock; + + string strLabel = ""; + if (params.size() == 3) + strLabel = params[2].get_str(); + + //Search partial merkle tree in proof for our transaction and index in valid block + vector vMatch; + vector vIndex; + unsigned int txnIndex = 0; + if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) { + + LOCK(cs_main); + + if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()])) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); + + vector::const_iterator it; + if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx))==vMatch.end()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof"); + } + + txnIndex = vIndex[it - vMatch.begin()]; + } + else { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Something wrong with merkleblock"); + } + + wtx.nIndex = txnIndex; + wtx.hashBlock = merkleBlock.header.GetHash(); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + if (pwalletMain->IsMine(tx)) { + CWalletDB walletdb(pwalletMain->strWalletFile, "r+", false); + pwalletMain->AddToWallet(wtx, false, &walletdb); + return NullUniValue; + } + + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No addresses in wallet correspond to included transaction"); +} + +UniValue removeprunedfunds(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() != 1) + throw runtime_error( + "removeprunedfunds \"txid\"\n" + "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will effect wallet balances.\n" + "\nArguments:\n" + "1. \"txid\" (string, required) The hex-encoded id of the transaction you are deleting\n" + "\nExamples:\n" + + HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") + + "\nAs a JSON-RPC call\n" + + HelpExampleRpc("removprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + uint256 hash; + hash.SetHex(params[0].get_str()); + vector vHash; + vHash.push_back(hash); + vector vHashOut; + + if(pwalletMain->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not properly delete the transaction."); + } + + if(vHashOut.empty()) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction does not exist in wallet."); + } + + ThreadFlushWalletDB(pwalletMain->strWalletFile); + + return NullUniValue; +} + UniValue importpubkey(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0537c2618..d1c5cbb17 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,7 +11,8 @@ #include "main.h" #include "net.h" #include "netbase.h" -#include "rpcserver.h" +#include "policy/rbf.h" +#include "rpc/server.h" #include "timedata.h" #include "util.h" #include "utilmoneystr.h" @@ -66,6 +67,8 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); entry.push_back(Pair("blockindex", wtx.nIndex)); entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime())); + } else { + entry.push_back(Pair("trusted", wtx.IsTrusted())); } uint256 hash = wtx.GetHash(); entry.push_back(Pair("txid", hash.GetHex())); @@ -75,6 +78,19 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) entry.push_back(Pair("walletconflicts", conflicts)); entry.push_back(Pair("time", wtx.GetTxTime())); entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived)); + + // Add opt-in RBF status + std::string rbfStatus = "no"; + if (confirms <= 0) { + LOCK(mempool.cs); + RBFTransactionState rbfState = IsRBFOptIn(wtx, mempool); + if (rbfState == RBF_TRANSACTIONSTATE_UNKNOWN) + rbfStatus = "unknown"; + else if (rbfState == RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125) + rbfStatus = "yes"; + } + entry.push_back(Pair("bip125-replaceable", rbfStatus)); + BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue) entry.push_back(Pair(item.first, item.second)); } @@ -91,7 +107,7 @@ UniValue getnewaddress(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() > 1) throw runtime_error( "getnewaddress ( \"account\" )\n" @@ -136,26 +152,25 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false) CAccount account; walletdb.ReadAccount(strAccount, account); - bool bKeyUsed = false; - - // Check if the current key has been used - if (account.vchPubKey.IsValid()) - { - CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID()); - for (map::iterator it = pwalletMain->mapWallet.begin(); - it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid(); - ++it) - { - const CWalletTx& wtx = (*it).second; - BOOST_FOREACH(const CTxOut& txout, wtx.vout) - if (txout.scriptPubKey == scriptPubKey) - bKeyUsed = true; + if (!bForceNew) { + if (!account.vchPubKey.IsValid()) + bForceNew = true; + else { + // Check if the current key has been used + CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID()); + for (map::iterator it = pwalletMain->mapWallet.begin(); + it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid(); + ++it) + BOOST_FOREACH(const CTxOut& txout, (*it).second.vout) + if (txout.scriptPubKey == scriptPubKey) { + bForceNew = true; + break; + } } } // Generate a new key - if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed) - { + if (bForceNew) { if (!pwalletMain->GetKeyFromPool(account.vchPubKey)) throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); @@ -170,7 +185,7 @@ UniValue getaccountaddress(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() != 1) throw runtime_error( "getaccountaddress \"account\"\n" @@ -202,7 +217,7 @@ UniValue getrawchangeaddress(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() > 1) throw runtime_error( "getrawchangeaddress\n" @@ -237,7 +252,7 @@ UniValue setaccount(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "setaccount \"lbrycrdaddress\" \"account\"\n" @@ -283,7 +298,7 @@ UniValue getaccount(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() != 1) throw runtime_error( "getaccount \"lbrycrdaddress\"\n" @@ -315,7 +330,7 @@ UniValue getaddressesbyaccount(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() != 1) throw runtime_error( "getaddressesbyaccount \"account\"\n" @@ -771,10 +786,9 @@ UniValue listnameclaims(const UniValue& params, bool fHelp) UniValue ret(UniValue::VARR); - std::list acentries; - CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount); + const CWallet::TxItems& txOrdered = pwalletMain->wtxOrdered; - for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { CWalletTx *const pwtx = (*it).second.first; if (pwtx != 0 && pwtx->GetDepthInMainChain() >= nMinDepth) @@ -918,22 +932,22 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr throw JSONRPCError(RPC_WALLET_ERROR, strError); } if (!pwalletMain->CommitTransaction(wtxNew, reservekey)) - throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); + throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of the wallet and coins were spent in the copy but not marked as spent here."); } UniValue sendtoaddress(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() < 2 || params.size() > 5) throw runtime_error( "sendtoaddress \"lbrycrdaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n" - "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n" + "\nSend an amount to a given address.\n" + HelpRequiringPassphrase() + "\nArguments:\n" "1. \"lbrycrdaddress\" (string, required) The lbrycrd address to send to.\n" - "2. \"amount\" (numeric, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n" + "2. \"amount\" (numeric or string, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n" "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n" " This is not part of the transaction, just kept in your wallet.\n" "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n" @@ -983,7 +997,7 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp) throw runtime_error( "listaddressgroupings\n" @@ -1034,7 +1048,7 @@ UniValue signmessage(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() != 2) throw runtime_error( "signmessage \"lbrycrdaddress\" \"message\"\n" @@ -1090,7 +1104,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "getreceivedbyaddress \"lbrycrdaddress\" ( minconf )\n" @@ -1148,7 +1162,7 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "getreceivedbyaccount \"account\" ( minconf )\n" @@ -1237,7 +1251,7 @@ UniValue getbalance(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() > 3) throw runtime_error( "getbalance ( \"account\" minconf includeWatchonly )\n" @@ -1312,7 +1326,7 @@ UniValue getunconfirmedbalance(const UniValue ¶ms, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() > 0) throw runtime_error( "getunconfirmedbalance\n" @@ -1328,7 +1342,7 @@ UniValue movecmd(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() < 3 || params.size() > 5) throw runtime_error( "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n" @@ -1378,7 +1392,7 @@ UniValue movecmd(const UniValue& params, bool fHelp) debit.nTime = nNow; debit.strOtherAccount = strTo; debit.strComment = strComment; - walletdb.WriteAccountingEntry(debit); + pwalletMain->AddAccountingEntry(debit, walletdb); // Credit CAccountingEntry credit; @@ -1388,7 +1402,7 @@ UniValue movecmd(const UniValue& params, bool fHelp) credit.nTime = nNow; credit.strOtherAccount = strFrom; credit.strComment = strComment; - walletdb.WriteAccountingEntry(credit); + pwalletMain->AddAccountingEntry(credit, walletdb); if (!walletdb.TxnCommit()) throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); @@ -1401,17 +1415,16 @@ UniValue sendfrom(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() < 3 || params.size() > 6) throw runtime_error( "sendfrom \"fromaccount\" \"tolbrycrdaddress\" amount ( minconf \"comment\" \"comment-to\" )\n" "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a lbrycrd address.\n" - "The amount is a real and is rounded to the nearest 0.00000001." + HelpRequiringPassphrase() + "\n" "\nArguments:\n" "1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n" "2. \"tolbrycrdaddress\" (string, required) The lbrycrd address to send funds to.\n" - "3. amount (numeric, required) The amount in " + CURRENCY_UNIT + " (transaction fee is added on top).\n" + "3. amount (numeric or string, required) The amount in " + CURRENCY_UNIT + " (transaction fee is added on top).\n" "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n" "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n" " This is not part of the transaction, just kept in your wallet.\n" @@ -1466,7 +1479,7 @@ UniValue sendmany(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() < 2 || params.size() > 5) throw runtime_error( "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n" @@ -1476,7 +1489,7 @@ UniValue sendmany(const UniValue& params, bool fHelp) "1. \"fromaccount\" (string, required) DEPRECATED. The account to send the funds from. Should be \"\" for the default account\n" "2. \"amounts\" (string, required) A json object with addresses and amounts\n" " {\n" - " \"address\":amount (numeric) The lbrycrd address is the key, the numeric amount in " + CURRENCY_UNIT + " is the value\n" + " \"address\":amount (numeric or string) The lbrycrd address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value\n" " ,...\n" " }\n" "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n" @@ -1573,14 +1586,14 @@ UniValue sendmany(const UniValue& params, bool fHelp) return wtx.GetHash().GetHex(); } -// Defined in rpcmisc.cpp +// Defined in rpc/misc.cpp extern CScript _createmultisig_redeemScript(const UniValue& params); UniValue addmultisigaddress(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() < 2 || params.size() > 3) { string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" @@ -1725,6 +1738,8 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) obj.push_back(Pair("account", strAccount)); obj.push_back(Pair("amount", ValueFromAmount(nAmount))); obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); + if (!fByAccounts) + obj.push_back(Pair("label", strAccount)); UniValue transactions(UniValue::VARR); if (it != mapTally.end()) { @@ -1761,14 +1776,14 @@ UniValue listreceivedbyaddress(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() > 3) throw runtime_error( "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n" "\nList balances by receiving address.\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" - "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n" + "2. includeempty (bool, optional, default=false) Whether to include addresses that haven't received any payments.\n" "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n" "\nResult:\n" @@ -1778,7 +1793,8 @@ UniValue listreceivedbyaddress(const UniValue& params, bool fHelp) " \"address\" : \"receivingaddress\", (string) The receiving address\n" " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n" " \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n" - " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n" + " \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n" + " \"label\" : \"label\" (string) A comment for the address/transaction, if any\n" " }\n" " ,...\n" "]\n" @@ -1798,14 +1814,14 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() > 3) throw runtime_error( "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n" "\nDEPRECATED. List balances by account.\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" - "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n" + "2. includeempty (bool, optional, default=false) Whether to include accounts that haven't received any payments.\n" "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n" "\nResult:\n" @@ -1814,7 +1830,8 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n" " \"account\" : \"accountname\", (string) The account name of the receiving account\n" " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n" - " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n" + " \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n" + " \"label\" : \"label\" (string) A comment for the address/transaction, if any\n" " }\n" " ,...\n" "]\n" @@ -1861,10 +1878,13 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe MaybePushAddress(entry, s.destination); entry.push_back(Pair("category", "send")); entry.push_back(Pair("amount", ValueFromAmount(-s.amount))); + if (pwalletMain->mapAddressBook.count(s.destination)) + entry.push_back(Pair("label", pwalletMain->mapAddressBook[s.destination].name)); entry.push_back(Pair("vout", s.vout)); entry.push_back(Pair("fee", ValueFromAmount(-nFee))); if (fLong) WalletTxToJSON(wtx, entry); + entry.push_back(Pair("abandoned", wtx.isAbandoned())); ret.push_back(entry); } } @@ -1898,6 +1918,8 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe entry.push_back(Pair("category", "receive")); } entry.push_back(Pair("amount", ValueFromAmount(r.amount))); + if (pwalletMain->mapAddressBook.count(r.destination)) + entry.push_back(Pair("label", account)); entry.push_back(Pair("vout", r.vout)); if (fLong) WalletTxToJSON(wtx, entry); @@ -1928,7 +1950,7 @@ UniValue listtransactions(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() > 4) throw runtime_error( "listtransactions ( \"account\" count from includeWatchonly)\n" @@ -1952,23 +1974,30 @@ UniValue listtransactions(const UniValue& params, bool fHelp) " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the\n" " 'move' category for moves outbound. It is positive for the 'receive' category,\n" " and for the 'move' category for inbound funds.\n" - " \"vout\" : n, (numeric) the vout value\n" + " \"vout\": n, (numeric) the vout value\n" " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n" " 'send' category of transactions.\n" + " \"abandoned\": xxx (bool) 'true' if the transaction has been abandoned (inputs are respendable).\n" " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n" - " 'receive' category of transactions.\n" + " 'receive' category of transactions. Negative confirmations indicate the\n" + " transaction conflicts with the block chain\n" + " \"trusted\": xxx (bool) Whether we consider the outputs of this unconfirmed transaction safe to spend.\n" " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n" " category of transactions.\n" - " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n" + " \"blockindex\": n, (numeric) The index of the transaction in the block that includes it. Available for 'send' and 'receive'\n" " category of transactions.\n" + " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n" " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n" " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n" " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n" " for 'send' and 'receive' category of transactions.\n" " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n" + " \"label\": \"label\" (string) A comment for the address/transaction, if any\n" " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n" " from (for receiving funds, positive amounts), or went to (for sending funds,\n" " negative amounts).\n" + " \"bip125-replaceable\": \"yes|no|unknown\" (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n" + " may be unknown for unconfirmed transactions not in the mempool\n" " }\n" "]\n" @@ -2004,11 +2033,10 @@ UniValue listtransactions(const UniValue& params, bool fHelp) UniValue ret(UniValue::VARR); - std::list acentries; - CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount); + const CWallet::TxItems & txOrdered = pwalletMain->wtxOrdered; // iterate backwards until we have nCount items to return: - for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { CWalletTx *const pwtx = (*it).second.first; if (pwtx != 0) @@ -2049,7 +2077,7 @@ UniValue listaccounts(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() > 2) throw runtime_error( "listaccounts ( minconf includeWatchonly)\n" @@ -2113,8 +2141,7 @@ UniValue listaccounts(const UniValue& params, bool fHelp) } } - list acentries; - CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries); + const list & acentries = pwalletMain->laccentries; BOOST_FOREACH(const CAccountingEntry& entry, acentries) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; @@ -2129,7 +2156,7 @@ UniValue listsinceblock(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp) throw runtime_error( "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n" @@ -2150,12 +2177,13 @@ UniValue listsinceblock(const UniValue& params, bool fHelp) " \"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" " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n" " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n" - " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n" + " \"blockindex\": n, (numeric) The index of the transaction in the block that includes it. Available for 'send' and 'receive' category of transactions.\n" " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n" " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n" " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n" " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n" " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n" + " \"label\" : \"label\" (string) A comment for the address/transaction, if any\n" " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n" " ],\n" " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n" @@ -2220,7 +2248,7 @@ UniValue gettransaction(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "gettransaction \"txid\" ( includeWatchonly )\n" @@ -2233,17 +2261,20 @@ UniValue gettransaction(const UniValue& params, bool fHelp) " \"amount\" : x.xxx, (numeric) The transaction amount in " + CURRENCY_UNIT + "\n" " \"confirmations\" : n, (numeric) The number of confirmations\n" " \"blockhash\" : \"hash\", (string) The block hash\n" - " \"blockindex\" : xx, (numeric) The block index\n" + " \"blockindex\" : xx, (numeric) The index of the transaction in the block that includes it\n" " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n" " \"txid\" : \"transactionid\", (string) The transaction id.\n" " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n" " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n" + " \"bip125-replaceable\": \"yes|no|unknown\" (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n" + " may be unknown for unconfirmed transactions not in the mempool\n" " \"details\" : [\n" " {\n" " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n" " \"address\" : \"lbrycrdaddress\", (string) The lbrycrd address involved in the transaction\n" " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n" - " \"amount\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n" + " \"amount\" : x.xxx, (numeric) The amount in " + CURRENCY_UNIT + "\n" + " \"label\" : \"label\", (string) A comment for the address/transaction, if any\n" " \"vout\" : n, (numeric) the vout value\n" " }\n" " ,...\n" @@ -2293,16 +2324,50 @@ UniValue gettransaction(const UniValue& params, bool fHelp) return entry; } +UniValue abandontransaction(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() != 1) + throw runtime_error( + "abandontransaction \"txid\"\n" + "\nMark in-wallet transaction as abandoned\n" + "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n" + "for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n" + "It only works on transactions which are not included in a block and are not currently in the mempool.\n" + "It has no effect on transactions which are already conflicted or abandoned.\n" + "\nArguments:\n" + "1. \"txid\" (string, required) The transaction id\n" + "\nResult:\n" + "\nExamples:\n" + + HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + + HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + uint256 hash; + hash.SetHex(params[0].get_str()); + + if (!pwalletMain->mapWallet.count(hash)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); + if (!pwalletMain->AbandonTransaction(hash)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment"); + + return NullUniValue; +} + UniValue backupwallet(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() != 1) throw runtime_error( "backupwallet \"destination\"\n" - "\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n" + "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n" "\nArguments:\n" "1. \"destination\" (string) The destination directory or file\n" "\nExamples:\n" @@ -2324,7 +2389,7 @@ UniValue keypoolrefill(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() > 1) throw runtime_error( "keypoolrefill ( newsize )\n" @@ -2368,7 +2433,7 @@ UniValue walletpassphrase(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) throw runtime_error( "walletpassphrase \"passphrase\" timeout\n" @@ -2428,7 +2493,7 @@ UniValue walletpassphrasechange(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) throw runtime_error( "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n" @@ -2474,7 +2539,7 @@ UniValue walletlock(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0)) throw runtime_error( "walletlock\n" @@ -2513,7 +2578,7 @@ UniValue encryptwallet(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1)) throw runtime_error( "encryptwallet \"passphrase\"\n" @@ -2570,19 +2635,20 @@ UniValue lockunspent(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( - "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n" + "lockunspent unlock ([{\"txid\":\"txid\",\"vout\":n},...])\n" "\nUpdates list of temporarily unspendable outputs.\n" "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n" + "If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n" "A locked transaction output will not be chosen by automatic coin selection, when spending LBC.\n" "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n" "is always cleared (by virtue of process exit) when a node stops or fails.\n" "Also see the listunspent call\n" "\nArguments:\n" "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n" - "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n" + "2. \"transactions\" (string, optional) A json array of objects. Each object the txid (string) vout (numeric)\n" " [ (json array of json objects)\n" " {\n" " \"txid\":\"id\", (string) The transaction id\n" @@ -2654,7 +2720,7 @@ UniValue listlockunspent(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() > 0) throw runtime_error( "listlockunspent\n" @@ -2703,13 +2769,13 @@ UniValue settxfee(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() < 1 || params.size() > 1) throw runtime_error( "settxfee amount\n" - "\nSet the transaction fee per kB.\n" + "\nSet the transaction fee per kB. Overwrites the paytxfee parameter.\n" "\nArguments:\n" - "1. amount (numeric, required) The transaction fee in " + CURRENCY_UNIT + "/kB rounded to the nearest 0.00000001\n" + "1. amount (numeric or sting, required) The transaction fee in " + CURRENCY_UNIT + "/kB\n" "\nResult\n" "true|false (boolean) Returns true if successful\n" "\nExamples:\n" @@ -2730,7 +2796,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() != 0) throw runtime_error( "getwalletinfo\n" @@ -2772,7 +2838,7 @@ UniValue resendwallettransactions(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() != 0) throw runtime_error( "resendwallettransactions\n" @@ -2797,7 +2863,7 @@ UniValue listunspent(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - + if (fHelp || params.size() > 3) throw runtime_error( "listunspent ( minconf maxconf [\"address\",...] )\n" @@ -2913,22 +2979,29 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( - "fundrawtransaction \"hexstring\" includeWatching\n" + "fundrawtransaction \"hexstring\" ( options )\n" "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n" "This will not modify existing inputs, and will add one change output to the outputs.\n" "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n" "The inputs added will not be signed, use signrawtransaction for that.\n" "Note that all existing inputs must have their previous output transaction be in the wallet.\n" - "Note that all inputs selected must be of standard form and P2SH scripts must be" + "Note that all inputs selected must be of standard form and P2SH scripts must be\n" "in the wallet using importaddress or addmultisigaddress (to calculate fees).\n" "Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n" "\nArguments:\n" - "1. \"hexstring\" (string, required) The hex string of the raw transaction\n" - "2. includeWatching (boolean, optional, default false) Also select inputs which are watch only\n" + "1. \"hexstring\" (string, required) The hex string of the raw transaction\n" + "2. options (object, optional)\n" + " {\n" + " \"changeAddress\" (string, optional, default pool address) The bitcoin address to receive the change\n" + " \"changePosition\" (numeric, optional, default random) The index of the change output\n" + " \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n" + " \"lockUnspents\" (boolean, optional, default false) Lock selected unspent outputs\n" + " }\n" + " for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}\n" "\nResult:\n" "{\n" " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n" - " \"fee\": n, (numeric) The fee added to the transaction\n" + " \"fee\": n, (numeric) Fee the resulting transaction pays\n" " \"changepos\": n (numeric) The position of the added change output, or -1\n" "}\n" "\"hex\" \n" @@ -2943,28 +3016,132 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"") ); - RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)); + + CTxDestination changeAddress = CNoDestination(); + int changePosition = -1; + bool includeWatching = false; + bool lockUnspents = false; + + if (params.size() > 1) { + if (params[1].type() == UniValue::VBOOL) { + // backward compatibility bool only fallback + includeWatching = params[1].get_bool(); + } + else { + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VOBJ)); + + UniValue options = params[1]; + + RPCTypeCheckObj(options, boost::assign::map_list_of("changeAddress", UniValue::VSTR)("changePosition", UniValue::VNUM)("includeWatching", UniValue::VBOOL)("lockUnspents", UniValue::VBOOL), true, true); + + if (options.exists("changeAddress")) { + CBitcoinAddress address(options["changeAddress"].get_str()); + + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "changeAddress must be a valid bitcoin address"); + + changeAddress = address.Get(); + } + + if (options.exists("changePosition")) + changePosition = options["changePosition"].get_int(); + + if (options.exists("includeWatching")) + includeWatching = options["includeWatching"].get_bool(); + + if (options.exists("lockUnspents")) + lockUnspents = options["lockUnspents"].get_bool(); + } + } // parse hex string from parameter CTransaction origTx; if (!DecodeHexTx(origTx, params[0].get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); - bool includeWatching = false; - if (params.size() > 1) - includeWatching = true; + if (origTx.vout.size() == 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output"); + + if (changePosition != -1 && (changePosition < 0 || changePosition > origTx.vout.size())) + throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds"); CMutableTransaction tx(origTx); CAmount nFee; string strFailReason; - int nChangePos = -1; - if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason, includeWatching)) + + if(!pwalletMain->FundTransaction(tx, nFee, changePosition, strFailReason, includeWatching, lockUnspents, changeAddress)) throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason); UniValue result(UniValue::VOBJ); result.push_back(Pair("hex", EncodeHexTx(tx))); - result.push_back(Pair("changepos", nChangePos)); + result.push_back(Pair("changepos", changePosition)); result.push_back(Pair("fee", ValueFromAmount(nFee))); return result; } + +extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp +extern UniValue importprivkey(const UniValue& params, bool fHelp); +extern UniValue importaddress(const UniValue& params, bool fHelp); +extern UniValue importpubkey(const UniValue& params, bool fHelp); +extern UniValue dumpwallet(const UniValue& params, bool fHelp); +extern UniValue importwallet(const UniValue& params, bool fHelp); +extern UniValue importprunedfunds(const UniValue& params, bool fHelp); +extern UniValue removeprunedfunds(const UniValue& params, bool fHelp); + +static const CRPCCommand commands[] = +{ // category name actor (function) okSafeMode + // --------------------- ------------------------ ----------------------- ---------- + { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false }, + { "hidden", "resendwallettransactions", &resendwallettransactions, true }, + { "wallet", "abandontransaction", &abandontransaction, false }, + { "wallet", "addmultisigaddress", &addmultisigaddress, true }, + { "wallet", "backupwallet", &backupwallet, true }, + { "wallet", "dumpprivkey", &dumpprivkey, true }, + { "wallet", "dumpwallet", &dumpwallet, true }, + { "wallet", "encryptwallet", &encryptwallet, true }, + { "wallet", "getaccountaddress", &getaccountaddress, true }, + { "wallet", "getaccount", &getaccount, true }, + { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true }, + { "wallet", "getbalance", &getbalance, false }, + { "wallet", "getnewaddress", &getnewaddress, true }, + { "wallet", "getrawchangeaddress", &getrawchangeaddress, true }, + { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false }, + { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false }, + { "wallet", "gettransaction", &gettransaction, false }, + { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false }, + { "wallet", "getwalletinfo", &getwalletinfo, false }, + { "wallet", "importprivkey", &importprivkey, true }, + { "wallet", "importwallet", &importwallet, true }, + { "wallet", "importaddress", &importaddress, true }, + { "wallet", "importprunedfunds", &importprunedfunds, true }, + { "wallet", "importpubkey", &importpubkey, true }, + { "wallet", "keypoolrefill", &keypoolrefill, true }, + { "wallet", "listaccounts", &listaccounts, false }, + { "wallet", "listaddressgroupings", &listaddressgroupings, false }, + { "wallet", "listlockunspent", &listlockunspent, false }, + { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false }, + { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false }, + { "wallet", "listsinceblock", &listsinceblock, false }, + { "wallet", "listtransactions", &listtransactions, false }, + { "wallet", "listunspent", &listunspent, false }, + { "wallet", "lockunspent", &lockunspent, true }, + { "wallet", "move", &movecmd, false }, + { "wallet", "sendfrom", &sendfrom, false }, + { "wallet", "sendmany", &sendmany, false }, + { "wallet", "sendtoaddress", &sendtoaddress, false }, + { "wallet", "setaccount", &setaccount, true }, + { "wallet", "settxfee", &settxfee, true }, + { "wallet", "signmessage", &signmessage, true }, + { "wallet", "walletlock", &walletlock, true }, + { "wallet", "walletpassphrasechange", &walletpassphrasechange, true }, + { "wallet", "walletpassphrase", &walletpassphrase, true }, + { "wallet", "removeprunedfunds", &removeprunedfunds, true }, +}; + +void RegisterWalletRPCCommands(CRPCTable &tableRPC) +{ + for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) + tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); +} diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h new file mode 100644 index 000000000..a5de7e2de --- /dev/null +++ b/src/wallet/rpcwallet.h @@ -0,0 +1,12 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_WALLET_RPCWALLET_H +#define BITCOIN_WALLET_RPCWALLET_H + +class CRPCTable; + +void RegisterWalletRPCCommands(CRPCTable &tableRPC); + +#endif //BITCOIN_WALLET_RPCWALLET_H diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index a5bc52b8d..e84d58802 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2014 The Bitcoin Core developers +// Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -117,7 +117,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) // try making 34 cents from 1,2,5,10,20 - we can't do it exactly BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); - BOOST_CHECK_GT(nValueRet, 34 * CENT); // but should get more than 34 cents + BOOST_CHECK_EQUAL(nValueRet, 35 * CENT); // but 35 cents is closest 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) // when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5 @@ -185,33 +185,34 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); - // empty the wallet and start again, now with fractions of a cent, to test sub-cent change avoidance + // empty the wallet and start again, now with fractions of a cent, to test small change avoidance + empty_wallet(); - add_coin(0.1*CENT); - add_coin(0.2*CENT); - add_coin(0.3*CENT); - add_coin(0.4*CENT); - add_coin(0.5*CENT); + add_coin(0.1*MIN_CHANGE); + add_coin(0.2*MIN_CHANGE); + add_coin(0.3*MIN_CHANGE); + add_coin(0.4*MIN_CHANGE); + add_coin(0.5*MIN_CHANGE); - // try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 = 1.5 cents - // we'll get sub-cent change whatever happens, so can expect 1.0 exactly - BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); - BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); + // try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE + // we'll get change smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE exactly + BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); - // but if we add a bigger coin, making it possible to avoid sub-cent change, things change: - add_coin(1111*CENT); + // but if we add a bigger coin, small change is avoided + add_coin(1111*MIN_CHANGE); - // try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 cents - BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); - BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount + // try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount - // if we add more sub-cent coins: - add_coin(0.6*CENT); - add_coin(0.7*CENT); + // if we add more small coins: + add_coin(0.6*MIN_CHANGE); + add_coin(0.7*MIN_CHANGE); - // and try again to make 1.0 cents, we can still make 1.0 cents - BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); - BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount + // and try again to make 1.0 * MIN_CHANGE + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount // run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf) // they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change @@ -223,45 +224,65 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins - // if there's not enough in the smaller coins to make at least 1 cent change (0.5+0.6+0.7 < 1.0+1.0), + // 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), // we need to try finding an exact subset anyway // sometimes it will fail, and so we use the next biggest coin: empty_wallet(); - add_coin(0.5 * CENT); - add_coin(0.6 * CENT); - add_coin(0.7 * CENT); - add_coin(1111 * CENT); - BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); - BOOST_CHECK_EQUAL(nValueRet, 1111 * CENT); // we get the bigger coin + add_coin(0.5 * MIN_CHANGE); + add_coin(0.6 * MIN_CHANGE); + add_coin(0.7 * MIN_CHANGE); + add_coin(1111 * MIN_CHANGE); + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1111 * MIN_CHANGE); // we get the bigger coin BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // but sometimes it's possible, and we use an exact subset (0.4 + 0.6 = 1.0) empty_wallet(); - add_coin(0.4 * CENT); - add_coin(0.6 * CENT); - add_coin(0.8 * CENT); - add_coin(1111 * CENT); - BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); - BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount + add_coin(0.4 * MIN_CHANGE); + add_coin(0.6 * MIN_CHANGE); + add_coin(0.8 * MIN_CHANGE); + add_coin(1111 * MIN_CHANGE); + BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); // we should get the exact amount BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6 - // test avoiding sub-cent change + // test avoiding small change empty_wallet(); - add_coin(0.0005 * COIN); - add_coin(0.01 * COIN); - add_coin(1 * COIN); + add_coin(0.05 * MIN_CHANGE); + add_coin(1 * MIN_CHANGE); + add_coin(100 * MIN_CHANGE); - // trying to make 1.0001 from these three coins - BOOST_CHECK( wallet.SelectCoinsMinConf(1.0001 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); - BOOST_CHECK_EQUAL(nValueRet, 1.0105 * COIN); // we should get all coins + // trying to make 100.01 from these three coins + BOOST_CHECK( wallet.SelectCoinsMinConf(100.01 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 101.05 * MIN_CHANGE); // we should get all coins BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); - // but if we try to make 0.999, we should take the bigger of the two small coins to avoid sub-cent change - BOOST_CHECK( wallet.SelectCoinsMinConf(0.999 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); - BOOST_CHECK_EQUAL(nValueRet, 1.01 * COIN); // we should get 1 + 0.01 + // but if we try to make 99.9, we should take the bigger of the two small coins to avoid small change + BOOST_CHECK( wallet.SelectCoinsMinConf(99.9 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); + // test with many inputs + for (CAmount amt=1500; amt < COIN; amt*=10) { + empty_wallet(); + // Create 676 inputs (= MAX_STANDARD_TX_SIZE / 148 bytes per input) + for (uint16_t j = 0; j < 676; j++) + add_coin(amt); + BOOST_CHECK(wallet.SelectCoinsMinConf(2000, 1, 1, vCoins, setCoinsRet, nValueRet)); + if (amt - 2000 < MIN_CHANGE) { + // needs more than one input: + uint16_t returnSize = std::ceil((2000.0 + MIN_CHANGE)/amt); + CAmount returnValue = amt * returnSize; + BOOST_CHECK_EQUAL(nValueRet, returnValue); + BOOST_CHECK_EQUAL(setCoinsRet.size(), returnSize); + } else { + // one input is sufficient: + BOOST_CHECK_EQUAL(nValueRet, amt); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); + } + } + // test randomness { empty_wallet(); @@ -307,4 +328,37 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) empty_wallet(); } +BOOST_AUTO_TEST_CASE(ApproximateBestSubset) +{ + CoinSet setCoinsRet; + CAmount nValueRet; + + LOCK(wallet.cs_wallet); + + empty_wallet(); + + // Test vValue sort order + for (int i = 0; i < 1000; i++) + add_coin(1000 * COIN); + add_coin(3 * COIN); + + BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); + + empty_wallet(); + + // Test trimming + for (int i = 0; i < 100; i++) + add_coin(10 * COIN); + for (int i = 0; i < 100; i++) + add_coin(1000 * COIN); + + BOOST_CHECK(wallet.SelectCoinsMinConf(100001 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet)); + // We need all 100 larger coins and exactly one small coin. + // Superfluous small coins must be trimmed from the set: + BOOST_CHECK_EQUAL(nValueRet, 100010 * COIN); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 101); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 55ef7e3a7..03aaf686a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -34,21 +34,28 @@ using namespace std; -/** - * Settings - */ +CWallet* pwalletMain = NULL; +/** Transaction fee set by the user */ CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); -CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET; -bool bSpendZeroConfChange = true; -bool fSendFreeTransactions = false; -bool fPayAtLeastCustomFee = true; +bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE; +bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS; + +const char * DEFAULT_WALLET_DAT = "wallet.dat"; /** * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) * Override with -mintxfee */ -CFeeRate CWallet::minTxFee = CFeeRate(1000); +CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE); +/** + * If fee estimation does not have enough data to provide estimates, use this fee instead. + * Has no effect if not using fee estimation + * Override with -fallbackfee + */ +CFeeRate CWallet::fallbackFee = CFeeRate(DEFAULT_FALLBACK_FEE); + +const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); /** @defgroup mapWallet * @@ -359,8 +366,33 @@ void CWallet::Flush(bool shutdown) bitdb.Flush(shutdown); } -bool CWallet::Verify(const string& walletFile, string& warningString, string& errorString) +bool static UIError(const std::string &str) { + uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR); + return false; +} + +void static UIWarning(const std::string &str) +{ + uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING); +} + +static std::string AmountErrMsg(const char * const optname, const std::string& strValue) +{ + return strprintf(_("Invalid amount for -%s=: '%s'"), optname, strValue); +} + +bool CWallet::Verify() +{ + std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); + + LogPrintf("Using wallet %s\n", walletFile); + uiInterface.InitMessage(_("Verifying wallet...")); + + // Wallet file must be a plain filename without a directory + if (walletFile != boost::filesystem::basename(walletFile) + boost::filesystem::extension(walletFile)) + return UIError(strprintf(_("Wallet %s resides outside data directory %s"), walletFile, GetDataDir().string())); + if (!bitdb.Open(GetDataDir())) { // try moving the database env out of the way @@ -376,9 +408,7 @@ bool CWallet::Verify(const string& walletFile, string& warningString, string& er // try again if (!bitdb.Open(GetDataDir())) { // if it still fails, it probably means we can't even create the database env - string msg = strprintf(_("Error initializing wallet database environment %s!"), GetDataDir()); - errorString += msg; - return true; + return UIError(strprintf(_("Error initializing wallet database environment %s!"), GetDataDir())); } } @@ -394,13 +424,14 @@ bool CWallet::Verify(const string& walletFile, string& warningString, string& er CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover); if (r == CDBEnv::RECOVER_OK) { - warningString += strprintf(_("Warning: wallet.dat corrupt, data salvaged!" - " Original wallet.dat saved as wallet.{timestamp}.bak in %s; if" - " your balance or transactions are incorrect you should" - " restore from a backup."), GetDataDir()); + UIWarning(strprintf(_("Warning: Wallet file corrupt, data salvaged!" + " Original %s saved as %s in %s; if" + " your balance or transactions are incorrect you should" + " restore from a backup."), + walletFile, "wallet.{timestamp}.bak", GetDataDir())); } if (r == CDBEnv::RECOVER_FAIL) - errorString += _("wallet.dat corrupt, salvage failed"); + return UIError(strprintf(_("%s corrupt, salvage failed"), walletFile)); } return true; @@ -457,8 +488,11 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const { const uint256& wtxid = it->second; std::map::const_iterator mit = mapWallet.find(wtxid); - if (mit != mapWallet.end() && mit->second.GetDepthInMainChain() >= 0) - return true; // Spent + if (mit != mapWallet.end()) { + int depth = mit->second.GetDepthInMainChain(); + if (depth > 0 || (depth == 0 && !mit->second.isAbandoned())) + return true; // Spent + } } return false; } @@ -589,31 +623,6 @@ int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) return nRet; } -CWallet::TxItems CWallet::OrderedTxItems(std::list& acentries, std::string strAccount) -{ - AssertLockHeld(cs_wallet); // mapWallet - CWalletDB walletdb(strWalletFile); - - // First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap. - TxItems txOrdered; - - // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry - // would make this much faster for applications that do this a lot. - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) - { - CWalletTx* wtx = &((*it).second); - txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0))); - } - acentries.clear(); - walletdb.ListAccountCreditDebit(strAccount, acentries); - BOOST_FOREACH(CAccountingEntry& entry, acentries) - { - txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); - } - - return txOrdered; -} - void CWallet::MarkDirty() { { @@ -630,8 +639,18 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD if (fFromLoadWallet) { mapWallet[hash] = wtxIn; - mapWallet[hash].BindWallet(this); + CWalletTx& wtx = mapWallet[hash]; + wtx.BindWallet(this); + wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); AddToSpends(hash); + BOOST_FOREACH(const CTxIn& txin, wtx.vin) { + if (mapWallet.count(txin.prevout.hash)) { + CWalletTx& prevtx = mapWallet[txin.prevout.hash]; + if (prevtx.nIndex == -1 && !prevtx.hashUnset()) { + MarkConflicted(prevtx.hashBlock, wtx.GetHash()); + } + } + } } else { @@ -645,9 +664,10 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD { wtx.nTimeReceived = GetAdjustedTime(); wtx.nOrderPos = IncOrderPosNext(pwalletdb); + wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); wtx.nTimeSmart = wtx.nTimeReceived; - if (!wtxIn.hashBlock.IsNull()) + if (!wtxIn.hashUnset()) { if (mapBlockIndex.count(wtxIn.hashBlock)) { @@ -656,9 +676,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD { // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future int64_t latestTolerated = latestNow + 300; - std::list acentries; - TxItems txOrdered = OrderedTxItems(acentries); - for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + const TxItems & txOrdered = wtxOrdered; + for (TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { CWalletTx *const pwtx = (*it).second.first; if (pwtx == &wtx) @@ -698,7 +717,13 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD if (!fInsertedNew) { // Merge - if (!wtxIn.hashBlock.IsNull() && wtxIn.hashBlock != wtx.hashBlock) + if (!wtxIn.hashUnset() && wtxIn.hashBlock != wtx.hashBlock) + { + wtx.hashBlock = wtxIn.hashBlock; + fUpdated = true; + } + // If no longer abandoned, update + if (wtxIn.hashBlock.IsNull() && wtx.isAbandoned()) { wtx.hashBlock = wtxIn.hashBlock; fUpdated = true; @@ -751,6 +776,20 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl { { AssertLockHeld(cs_wallet); + + if (pblock) { + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + std::pair range = mapTxSpends.equal_range(txin.prevout); + while (range.first != range.second) { + if (range.first->second != tx.GetHash()) { + LogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), pblock->GetHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n); + MarkConflicted(pblock->GetHash(), range.first->second); + } + range.first++; + } + } + } + bool fExisted = mapWallet.count(tx.GetHash()) != 0; if (fExisted && !fUpdate) return false; if (fExisted || IsMine(tx) || IsFromMe(tx)) @@ -771,9 +810,127 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl return false; } -void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock) +bool CWallet::AbandonTransaction(const uint256& hashTx) { LOCK2(cs_main, cs_wallet); + + // Do not flush the wallet here for performance reasons + CWalletDB walletdb(strWalletFile, "r+", false); + + std::set todo; + std::set done; + + // Can't mark abandoned if confirmed or in mempool + assert(mapWallet.count(hashTx)); + CWalletTx& origtx = mapWallet[hashTx]; + if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) { + return false; + } + + todo.insert(hashTx); + + while (!todo.empty()) { + uint256 now = *todo.begin(); + todo.erase(now); + done.insert(now); + assert(mapWallet.count(now)); + CWalletTx& wtx = mapWallet[now]; + int currentconfirm = wtx.GetDepthInMainChain(); + // If the orig tx was not in block, none of its spends can be + assert(currentconfirm <= 0); + // if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon} + if (currentconfirm == 0 && !wtx.isAbandoned()) { + // If the orig tx was not in block/mempool, none of its spends can be in mempool + assert(!wtx.InMempool()); + wtx.nIndex = -1; + wtx.setAbandoned(); + wtx.MarkDirty(); + wtx.WriteToDisk(&walletdb); + NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED); + // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too + TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(hashTx, 0)); + while (iter != mapTxSpends.end() && iter->first.hash == now) { + if (!done.count(iter->second)) { + todo.insert(iter->second); + } + iter++; + } + // If a transaction changes 'conflicted' state, that changes the balance + // available of the outputs it spends. So force those to be recomputed + BOOST_FOREACH(const CTxIn& txin, wtx.vin) + { + if (mapWallet.count(txin.prevout.hash)) + mapWallet[txin.prevout.hash].MarkDirty(); + } + } + } + + return true; +} + +void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) +{ + LOCK2(cs_main, cs_wallet); + + int conflictconfirms = 0; + if (mapBlockIndex.count(hashBlock)) { + CBlockIndex* pindex = mapBlockIndex[hashBlock]; + if (chainActive.Contains(pindex)) { + conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1); + } + } + // If number of conflict confirms cannot be determined, this means + // that the block is still unknown or not yet part of the main chain, + // for example when loading the wallet during a reindex. Do nothing in that + // case. + if (conflictconfirms >= 0) + return; + + // Do not flush the wallet here for performance reasons + CWalletDB walletdb(strWalletFile, "r+", false); + + std::set todo; + std::set done; + + todo.insert(hashTx); + + while (!todo.empty()) { + uint256 now = *todo.begin(); + todo.erase(now); + done.insert(now); + assert(mapWallet.count(now)); + CWalletTx& wtx = mapWallet[now]; + int currentconfirm = wtx.GetDepthInMainChain(); + if (conflictconfirms < currentconfirm) { + // Block is 'more conflicted' than current confirm; update. + // Mark transaction as conflicted with this block. + wtx.nIndex = -1; + wtx.hashBlock = hashBlock; + wtx.MarkDirty(); + wtx.WriteToDisk(&walletdb); + // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too + TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0)); + while (iter != mapTxSpends.end() && iter->first.hash == now) { + if (!done.count(iter->second)) { + todo.insert(iter->second); + } + iter++; + } + // If a transaction changes 'conflicted' state, that changes the balance + // available of the outputs it spends. So force those to be recomputed + BOOST_FOREACH(const CTxIn& txin, wtx.vin) + { + if (mapWallet.count(txin.prevout.hash)) + mapWallet[txin.prevout.hash].MarkDirty(); + } + } + } +} + +void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock) +{ + LOCK2(cs_main, cs_wallet); + if (!AddToWalletIfInvolvingMe(tx, pblock, true)) return; // Not one of ours @@ -927,7 +1084,7 @@ int CWalletTx::GetRequestCount() const if (IsCoinBase()) { // Generated block - if (!hashBlock.IsNull()) + if (!hashUnset()) { map::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); if (mi != pwallet->mapRequestCount.end()) @@ -943,7 +1100,7 @@ int CWalletTx::GetRequestCount() const nRequests = (*mi).second; // How about the block it's in? - if (nRequests == 0 && !hashBlock.IsNull()) + if (nRequests == 0 && !hashUnset()) { map::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); if (mi != pwallet->mapRequestCount.end()) @@ -993,7 +1150,8 @@ void CWalletTx::GetAmounts(list& listReceived, // In either case, we need to get the destination address CTxDestination address; const CScript& scriptPubKey = StripClaimScriptPrefix(txout.scriptPubKey); - if (!ExtractDestination(scriptPubKey, address)) + + if (!ExtractDestination(scriptPubKey, address) && !scriptPubKey.IsUnspendable()) { LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", this->GetHash().ToString()); @@ -1083,7 +1241,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); CBlock block; - ReadBlockFromDisk(block, pindex); + ReadBlockFromDisk(block, pindex, Params().GetConsensus()); BOOST_FOREACH(CTransaction& tx, block.vtx) { if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) @@ -1117,7 +1275,7 @@ void CWallet::ReacceptWalletTransactions() int nDepth = wtx.GetDepthInMainChain(); - if (!wtx.IsCoinBase() && nDepth < 0) { + if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) { mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx)); } } @@ -1128,7 +1286,7 @@ void CWallet::ReacceptWalletTransactions() CWalletTx& wtx = *(item.second); LOCK(mempool.cs); - wtx.AcceptToMemoryPool(false); + wtx.AcceptToMemoryPool(false, maxTxFee); } } @@ -1137,9 +1295,11 @@ bool CWalletTx::RelayWalletTransaction() assert(pwallet->GetBroadcastTransactions()); if (!IsCoinBase()) { - if (GetDepthInMainChain() == 0) { + if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) { LogPrintf("Relaying wtx %s\n", GetHash().ToString()); - RelayTransaction((CTransaction)*this); + CFeeRate feeRate; + mempool.lookupFeeRate(GetHash(), feeRate); + RelayTransaction((CTransaction)*this, feeRate); return true; } } @@ -1318,6 +1478,15 @@ CAmount CWalletTx::GetChange() const return nChangeCached; } +bool CWalletTx::InMempool() const +{ + LOCK(mempool.cs); + if (mempool.exists(GetHash())) { + return true; + } + return false; +} + bool CWalletTx::IsTrusted() const { // Quick answer in most cases @@ -1331,6 +1500,10 @@ bool CWalletTx::IsTrusted() const if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit return false; + // Don't trust unconfirmed transactions from us unless they are in the mempool. + if (!InMempool()) + return false; + // Trusted if all inputs are from us and are in the mempool: BOOST_FOREACH(const CTxIn& txin, vin) { @@ -1436,7 +1609,7 @@ CAmount CWallet::GetUnconfirmedBalance() const for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; - if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0)) + if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool()) nTotal += pcoin->GetAvailableCredit(); } } @@ -1481,7 +1654,7 @@ CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; - if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0)) + if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool()) nTotal += pcoin->GetAvailableWatchOnlyCredit(); } } @@ -1502,9 +1675,6 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const return nTotal; } -/** - * populate vCoins with vector of available COutputs. - */ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue) const { vCoins.clear(); @@ -1529,11 +1699,16 @@ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const if (nDepth < 0) continue; + // We should not consider coins which aren't at least in our mempool + // It's possible for these to be conflicted via ancestors which we may never be able to detect + if (nDepth == 0 && !pcoin->InMempool()) + continue; + for (unsigned int i = 0; i < pcoin->vout.size(); i++) { isminetype mine = IsMine(pcoin->vout[i]); if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && !IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) && - (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected((*it).first, i))) + (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected(COutPoint((*it).first, i)))) vCoins.push_back(COutput(pcoin, i, nDepth, ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO))); @@ -1586,6 +1761,16 @@ static void ApproximateBestSubset(vector= nTargetValue ) + { + vfBest[i] = false; + nBest -= vValue[i].first; + } + } } bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector vCoins, @@ -1624,7 +1809,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nValueRet += coin.first; return true; } - else if (n < nTargetValue + CENT) + else if (n < nTargetValue + MIN_CHANGE) { vValue.push_back(coin); nTotalLower += n; @@ -1655,18 +1840,19 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int } // Solve subset sum by stochastic approximation - sort(vValue.rbegin(), vValue.rend(), CompareValueOnly()); + std::sort(vValue.begin(), vValue.end(), CompareValueOnly()); + std::reverse(vValue.begin(), vValue.end()); vector vfBest; CAmount nBest; - ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, 1000); - if (nBest != nTargetValue && nTotalLower >= nTargetValue + CENT) - ApproximateBestSubset(vValue, nTotalLower, nTargetValue + CENT, vfBest, nBest, 1000); + ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest); + if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE) + ApproximateBestSubset(vValue, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest); // If we have a bigger coin and (either the stochastic approximation didn't find a good solution, // or the next bigger coin is closer), return the bigger coin if (coinLowestLarger.second.first && - ((nBest != nTargetValue && nBest < nTargetValue + CENT) || coinLowestLarger.first <= nBest)) + ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || coinLowestLarger.first <= nBest)) { setCoinsRet.insert(coinLowestLarger.second); nValueRet += coinLowestLarger.first; @@ -1689,10 +1875,9 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int return true; } -bool CWallet::SelectCoins(const CAmount& nTargetValue, set >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const +bool CWallet::SelectCoins(const vector& vAvailableCoins, const CAmount& nTargetValue, set >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const { - vector vCoins; - AvailableCoins(vCoins, true, coinControl); + vector vCoins(vAvailableCoins); // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs) @@ -1752,7 +1937,7 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set vecSend; @@ -1764,6 +1949,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nC } CCoinControl coinControl; + coinControl.destChange = destChange; coinControl.fAllowOtherInputs = true; coinControl.fAllowWatchOnly = includeWatching; BOOST_FOREACH(const CTxIn& txin, tx.vin) @@ -1771,36 +1957,36 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nC CReserveKey reservekey(this); CWalletTx wtx; - if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosRet, strFailReason, &coinControl, false)) + if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, &coinControl, false)) return false; - if (nChangePosRet != -1) - tx.vout.insert(tx.vout.begin() + nChangePosRet, wtx.vout[nChangePosRet]); + if (nChangePosInOut != -1) + tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.vout[nChangePosInOut]); // Add new txins (keeping original txin scriptSig/order) BOOST_FOREACH(const CTxIn& txin, wtx.vin) { - bool found = false; - BOOST_FOREACH(const CTxIn& origTxIn, tx.vin) + if (!coinControl.IsSelected(txin.prevout)) { - if (txin.prevout.hash == origTxIn.prevout.hash && txin.prevout.n == origTxIn.prevout.n) + tx.vin.push_back(txin); + + if (lockUnspents) { - found = true; - break; + LOCK2(cs_main, cs_wallet); + LockCoin(txin.prevout); } } - if (!found) - tx.vin.push_back(txin); } return true; } bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, - int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl, bool sign, + int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign, const CWalletTx* pwtxIn, unsigned int nTxOut) { CAmount nValue = 0; + int nChangePosRequest = nChangePosInOut; unsigned int nSubtractFeeFromAmount = 0; BOOST_FOREACH (const CRecipient& recipient, vecSend) { @@ -1828,15 +2014,25 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt // Discourage fee sniping. // - // However because of a off-by-one-error in previous versions we need to - // neuter it by setting nLockTime to at least one less than nBestHeight. - // Secondly currently propagation of transactions created for block heights - // corresponding to blocks that were just mined may be iffy - transactions - // aren't re-accepted into the mempool - we additionally neuter the code by - // going ten blocks back. Doesn't yet do anything for sniping, but does act - // to shake out wallet bugs like not showing nLockTime'd transactions at - // all. - txNew.nLockTime = std::max(0, chainActive.Height() - 10); + // For a large miner the value of the transactions in the best block and + // the mempool can exceed the cost of deliberately attempting to mine two + // blocks to orphan the current best block. By setting nLockTime such that + // only the next block can include the transaction, we discourage this + // practice as the height restricted and limited blocksize gives miners + // considering fee sniping fewer options for pulling off this attack. + // + // A simple way to think about this is from the wallet's point of view we + // always want the blockchain to move forward. By setting nLockTime this + // way we're basically making the statement that we only want this + // transaction to appear in the next block; we don't want to potentially + // encourage reorgs by allowing transactions to appear at lower heights + // than the next block in forks of the best chain. + // + // Of course, the subsidy is high enough, and transaction volume low + // enough, that fee sniping isn't a problem yet, but by implementing a fix + // now we ensure code won't be written that makes assumptions about + // nLockTime that preclude a fix later. + txNew.nLockTime = chainActive.Height(); // Secondly occasionally randomly pick a nLockTime even further back, so // that transactions that are delayed after signing for whatever reason, @@ -1851,13 +2047,17 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt { LOCK2(cs_main, cs_wallet); { + std::vector vAvailableCoins; + AvailableCoins(vAvailableCoins, true, coinControl); + nFeeRet = 0; + // Start with no fee and loop until there is enough fee while (true) { + nChangePosInOut = nChangePosRequest; txNew.vin.clear(); txNew.vout.clear(); wtxNew.fFromMe = true; - nChangePosRet = -1; bool fFirst = true; CAmount nValueToSelect = nValue; @@ -1907,7 +2107,7 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt CAmount nValueIn = 0; if (!fUsingWtxIn || nValueNeeded > 0) { - if (!SelectCoins(nValueNeeded, setCoins, nValueIn, coinControl)) + if (!SelectCoins(vAvailableCoins, nValueNeeded, setCoins, nValueIn, coinControl)) { strFailReason = _("Insufficient funds"); return false; @@ -1921,6 +2121,7 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt //a chance at a free transaction. //But mempool inputs might still be in the mempool, so their age stays 0 int age = pcoin.first->GetDepthInMainChain(); + assert(age >= 0); if (age != 0) age += 1; dPriority += (double)nCredit * age; @@ -1991,14 +2192,24 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt // add the dust to the fee. if (newTxOut.IsDust(::minRelayTxFee)) { + nChangePosInOut = -1; nFeeRet += nChange; reservekey.ReturnKey(); } else { - // Insert change txn at random position: - nChangePosRet = GetRandInt(txNew.vout.size()+1); - vector::iterator position = txNew.vout.begin()+nChangePosRet; + if (nChangePosInOut == -1) + { + // Insert change txn at random position: + nChangePosInOut = GetRandInt(txNew.vout.size()+1); + } + else if (nChangePosInOut > txNew.vout.size()) + { + strFailReason = _("Change index out of range"); + return false; + } + + vector::iterator position = txNew.vout.begin()+nChangePosInOut; txNew.vout.insert(position, newTxOut); } } @@ -2058,17 +2269,16 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE) { // Not enough fee: enough priority? - double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget); - // Not enough mempool history to estimate: use hard-coded AllowFree. - if (dPriorityNeeded <= 0 && AllowFree(dPriority)) - break; - - // Small enough, and priority high enough, to send for free - if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded) + double dPriorityNeeded = mempool.estimateSmartPriority(nTxConfirmTarget); + // Require at least hard-coded AllowFree. + if (dPriority >= dPriorityNeeded && AllowFree(dPriority)) break; } CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool); + if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) { + nFeeNeeded = coinControl->nMinimumTotalFee; + } // If we made it here and we aren't even able to meet the relay fee on the next pass, give up // because we must be at the maximum allowed fee. @@ -2131,7 +2341,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) if (fBroadcastTransactions) { // Broadcast - if (!wtxNew.AcceptToMemoryPool(false)) + if (!wtxNew.AcceptToMemoryPool(false, maxTxFee)) { // This must not fail. The transaction has already been signed and recorded. LogPrintf("CommitTransaction(): Error: Transaction not valid\n"); @@ -2143,23 +2353,37 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) return true; } +bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB & pwalletdb) +{ + if (!pwalletdb.WriteAccountingEntry_Backend(acentry)) + return false; + + laccentries.push_back(acentry); + CAccountingEntry & entry = laccentries.back(); + wtxOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); + + return true; +} + +CAmount CWallet::GetRequiredFee(unsigned int nTxBytes) +{ + return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes)); +} + CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool) { // payTxFee is user-set "I want to pay this much" CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes); - // user selected total at least (default=true) - if (fPayAtLeastCustomFee && nFeeNeeded > 0 && nFeeNeeded < payTxFee.GetFeePerK()) - nFeeNeeded = payTxFee.GetFeePerK(); // User didn't set: use -txconfirmtarget to estimate... - if (nFeeNeeded == 0) - nFeeNeeded = pool.estimateFee(nConfirmTarget).GetFee(nTxBytes); - // ... unless we don't have enough mempool data, in which case fall - // back to a hard-coded fee - if (nFeeNeeded == 0) - nFeeNeeded = minTxFee.GetFee(nTxBytes); - // prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee - if (nFeeNeeded < ::minRelayTxFee.GetFee(nTxBytes)) - nFeeNeeded = ::minRelayTxFee.GetFee(nTxBytes); + if (nFeeNeeded == 0) { + int estimateFoundTarget = nConfirmTarget; + nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes); + // ... unless we don't have enough mempool data for estimatefee, then use fallbackFee + if (nFeeNeeded == 0) + nFeeNeeded = fallbackFee.GetFee(nTxBytes); + } + // prevent user from paying a fee below minRelayTxFee or minTxFee + nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes)); // But always obey the maximum if (nFeeNeeded > maxTxFee) nFeeNeeded = maxTxFee; @@ -2196,6 +2420,31 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) return DB_LOAD_OK; } +DBErrors CWallet::ZapSelectTx(vector& vHashIn, vector& vHashOut) +{ + if (!fFileBacked) + return DB_LOAD_OK; + DBErrors nZapSelectTxRet = CWalletDB(strWalletFile,"cr+").ZapSelectTx(this, vHashIn, vHashOut); + if (nZapSelectTxRet == DB_NEED_REWRITE) + { + if (CDB::Rewrite(strWalletFile, "\x04pool")) + { + LOCK(cs_wallet); + setKeyPool.clear(); + // Note: can't top-up keypool here, because wallet is locked. + // User will be prompted to unlock wallet the next operation + // that requires a new key. + } + } + + if (nZapSelectTxRet != DB_LOAD_OK) + return nZapSelectTxRet; + + MarkDirty(); + + return DB_LOAD_OK; + +} DBErrors CWallet::ZapWalletTx(std::vector& vWtx) { @@ -2293,7 +2542,7 @@ bool CWallet::NewKeyPool() if (IsLocked()) return false; - int64_t nKeys = max(GetArg("-keypool", 100), (int64_t)0); + int64_t nKeys = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t)0); for (int i = 0; i < nKeys; i++) { int64_t nIndex = i+1; @@ -2320,7 +2569,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize) if (kpSize > 0) nTargetSize = kpSize; else - nTargetSize = max(GetArg("-keypool", 100), (int64_t) 0); + nTargetSize = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0); while (setKeyPool.size() < (nTargetSize + 1)) { @@ -2636,13 +2885,13 @@ void CWallet::GetScriptForMining(boost::shared_ptr &script) script->reserveScript = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; } -void CWallet::LockCoin(COutPoint& output) +void CWallet::LockCoin(const COutPoint& output) { AssertLockHeld(cs_wallet); // setLockedCoins setLockedCoins.insert(output); } -void CWallet::UnlockCoin(COutPoint& output) +void CWallet::UnlockCoin(const COutPoint& output) { AssertLockHeld(cs_wallet); // setLockedCoins setLockedCoins.erase(output); @@ -2800,6 +3049,246 @@ bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, st return false; } +std::string CWallet::GetWalletHelpString(bool showDebug) +{ + std::string strUsage = HelpMessageGroup(_("Wallet options:")); + strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); + strUsage += HelpMessageOpt("-keypool=", strprintf(_("Set key pool size to (default: %u)"), DEFAULT_KEYPOOL_SIZE)); + strUsage += HelpMessageOpt("-fallbackfee=", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"), + CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE))); + strUsage += HelpMessageOpt("-mintxfee=", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"), + CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE))); + strUsage += HelpMessageOpt("-paytxfee=", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), + CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); + strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup")); + strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup")); + if (showDebug) + strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS)); + strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE)); + strUsage += HelpMessageOpt("-txconfirmtarget=", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET)); + strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup")); + strUsage += HelpMessageOpt("-wallet=", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT)); + strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST)); + strUsage += HelpMessageOpt("-walletnotify=", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)")); + strUsage += HelpMessageOpt("-zapwallettxes=", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") + + " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)")); + + if (showDebug) + { + strUsage += HelpMessageGroup(_("Wallet debugging/testing options:")); + + strUsage += HelpMessageOpt("-dblogsize=", strprintf("Flush wallet database activity from memory to disk log every megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE)); + strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET)); + strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB)); + } + + return strUsage; +} + +bool CWallet::InitLoadWallet() +{ + std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); + + // needed to restore wallet transaction meta data after -zapwallettxes + std::vector vWtx; + + if (GetBoolArg("-zapwallettxes", false)) { + uiInterface.InitMessage(_("Zapping all transactions from wallet...")); + + CWallet *tempWallet = new CWallet(walletFile); + DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx); + if (nZapWalletRet != DB_LOAD_OK) { + return UIError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); + } + + delete tempWallet; + tempWallet = NULL; + } + + uiInterface.InitMessage(_("Loading wallet...")); + + int64_t nStart = GetTimeMillis(); + bool fFirstRun = true; + CWallet *walletInstance = new CWallet(walletFile); + DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun); + if (nLoadWalletRet != DB_LOAD_OK) + { + if (nLoadWalletRet == DB_CORRUPT) + return UIError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); + else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) + { + UIWarning(strprintf(_("Error reading %s! All keys read correctly, but transaction data" + " or address book entries might be missing or incorrect."), + walletFile)); + } + else if (nLoadWalletRet == DB_TOO_NEW) + return UIError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), + walletFile, _(PACKAGE_NAME))); + else if (nLoadWalletRet == DB_NEED_REWRITE) + { + return UIError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME))); + } + else + return UIError(strprintf(_("Error loading %s"), walletFile)); + } + + if (GetBoolArg("-upgradewallet", fFirstRun)) + { + int nMaxVersion = GetArg("-upgradewallet", 0); + if (nMaxVersion == 0) // the -upgradewallet without argument case + { + LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST); + nMaxVersion = CLIENT_VERSION; + walletInstance->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately + } + else + LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion); + if (nMaxVersion < walletInstance->GetVersion()) + { + return UIError(_("Cannot downgrade wallet")); + } + walletInstance->SetMaxVersion(nMaxVersion); + } + + if (fFirstRun) + { + // Create new keyUser and set as default key + RandAddSeedPerfmon(); + + CPubKey newDefaultKey; + if (walletInstance->GetKeyFromPool(newDefaultKey)) { + walletInstance->SetDefaultKey(newDefaultKey); + if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) + return UIError(_("Cannot write default address") += "\n"); + } + + walletInstance->SetBestChain(chainActive.GetLocator()); + } + + LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart); + + RegisterValidationInterface(walletInstance); + + CBlockIndex *pindexRescan = chainActive.Tip(); + if (GetBoolArg("-rescan", false)) + pindexRescan = chainActive.Genesis(); + else + { + CWalletDB walletdb(walletFile); + CBlockLocator locator; + if (walletdb.ReadBestBlock(locator)) + pindexRescan = FindForkInGlobalIndex(chainActive, locator); + else + pindexRescan = chainActive.Genesis(); + } + if (chainActive.Tip() && chainActive.Tip() != pindexRescan) + { + //We can't rescan beyond non-pruned blocks, stop and throw an error + //this might happen if a user uses a old wallet within a pruned node + // or if he ran -disablewallet for a longer time, then decided to re-enable + if (fPruneMode) + { + CBlockIndex *block = chainActive.Tip(); + while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block) + block = block->pprev; + + if (pindexRescan != block) + return UIError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)")); + } + + uiInterface.InitMessage(_("Rescanning...")); + LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight); + nStart = GetTimeMillis(); + walletInstance->ScanForWalletTransactions(pindexRescan, true); + LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); + walletInstance->SetBestChain(chainActive.GetLocator()); + nWalletDBUpdated++; + + // Restore wallet transaction metadata after -zapwallettxes=1 + if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") + { + CWalletDB walletdb(walletFile); + + BOOST_FOREACH(const CWalletTx& wtxOld, vWtx) + { + uint256 hash = wtxOld.GetHash(); + std::map::iterator mi = walletInstance->mapWallet.find(hash); + if (mi != walletInstance->mapWallet.end()) + { + const CWalletTx* copyFrom = &wtxOld; + CWalletTx* copyTo = &mi->second; + copyTo->mapValue = copyFrom->mapValue; + copyTo->vOrderForm = copyFrom->vOrderForm; + copyTo->nTimeReceived = copyFrom->nTimeReceived; + copyTo->nTimeSmart = copyFrom->nTimeSmart; + copyTo->fFromMe = copyFrom->fFromMe; + copyTo->strFromAccount = copyFrom->strFromAccount; + copyTo->nOrderPos = copyFrom->nOrderPos; + copyTo->WriteToDisk(&walletdb); + } + } + } + } + walletInstance->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); + + pwalletMain = walletInstance; + return true; +} + +bool CWallet::ParameterInteraction() +{ + if (mapArgs.count("-mintxfee")) + { + CAmount n = 0; + if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0) + CWallet::minTxFee = CFeeRate(n); + else + return UIError(AmountErrMsg("mintxfee", mapArgs["-mintxfee"])); + } + if (mapArgs.count("-fallbackfee")) + { + CAmount nFeePerK = 0; + if (!ParseMoney(mapArgs["-fallbackfee"], nFeePerK)) + return UIError(strprintf(_("Invalid amount for -fallbackfee=: '%s'"), mapArgs["-fallbackfee"])); + if (nFeePerK > HIGH_TX_FEE_PER_KB) + UIWarning(_("-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.")); + CWallet::fallbackFee = CFeeRate(nFeePerK); + } + if (mapArgs.count("-paytxfee")) + { + CAmount nFeePerK = 0; + if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK)) + return UIError(AmountErrMsg("paytxfee", mapArgs["-paytxfee"])); + if (nFeePerK > HIGH_TX_FEE_PER_KB) + UIWarning(_("-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); + payTxFee = CFeeRate(nFeePerK, 1000); + if (payTxFee < ::minRelayTxFee) + { + return UIError(strprintf(_("Invalid amount for -paytxfee=: '%s' (must be at least %s)"), + mapArgs["-paytxfee"], ::minRelayTxFee.ToString())); + } + } + if (mapArgs.count("-maxtxfee")) + { + CAmount nMaxFee = 0; + if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee)) + return UIError(AmountErrMsg("maxtxfee", mapArgs["-maxtxfee"])); + if (nMaxFee > HIGH_MAX_TX_FEE) + UIWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.")); + maxTxFee = nMaxFee; + if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) + { + return UIError(strprintf(_("Invalid amount for -maxtxfee=: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), + mapArgs["-maxtxfee"], ::minRelayTxFee.ToString())); + } + } + nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); + bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); + fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS); + + return true; +} + CKeyPool::CKeyPool() { nTime = GetTime(); @@ -2847,10 +3336,11 @@ int CMerkleTx::SetMerkleBranch(const CBlock& block) return chainActive.Height() - pindex->nHeight + 1; } -int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const +int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const { - if (hashBlock.IsNull() || nIndex == -1) + if (hashUnset()) return 0; + AssertLockHeld(cs_main); // Find the block it claims to be in @@ -2862,17 +3352,7 @@ int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const return 0; pindexRet = pindex; - return chainActive.Height() - pindex->nHeight + 1; -} - -int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const -{ - AssertLockHeld(cs_main); - int nResult = GetDepthInMainChainINTERNAL(pindexRet); - if (nResult == 0 && !mempool.exists(GetHash())) - return -1; // Not in chain, not in mempool - - return nResult; + return ((nIndex == -1) ? (-1) : 1) * (chainActive.Height() - pindex->nHeight + 1); } int CMerkleTx::GetBlocksToMaturity() const @@ -2883,9 +3363,8 @@ int CMerkleTx::GetBlocksToMaturity() const } -bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee) +bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee) { CValidationState state; - return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee); + return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, NULL, false, nAbsurdFee); } - diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 1112e6896..5e027b1ff 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,6 +15,7 @@ #include "wallet/crypter.h" #include "wallet/wallet_ismine.h" #include "wallet/walletdb.h" +#include "wallet/rpcwallet.h" #include #include @@ -27,30 +28,37 @@ #include +extern CWallet* pwalletMain; + /** * Settings */ extern CFeeRate payTxFee; -extern CAmount maxTxFee; extern unsigned int nTxConfirmTarget; extern bool bSpendZeroConfChange; extern bool fSendFreeTransactions; -extern bool fPayAtLeastCustomFee; +static const unsigned int DEFAULT_KEYPOOL_SIZE = 100; //! -paytxfee default static const CAmount DEFAULT_TRANSACTION_FEE = 0; -//! -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB -static const CAmount nHighTransactionFeeWarning = 0.01 * COIN; -//! -maxtxfee default -static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN; +//! -fallbackfee default +static const CAmount DEFAULT_FALLBACK_FEE = 20000; +//! -mintxfee default +static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000; +//! minimum change amount +static const CAmount MIN_CHANGE = CENT; +//! Default for -spendzeroconfchange +static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true; +//! Default for -sendfreetransactions +static const bool DEFAULT_SEND_FREE_TRANSACTIONS = false; //! -txconfirmtarget default static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 2; -//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis) -static const CAmount nHighTransactionMaxFeeWarning = 100 * nHighTransactionFeeWarning; //! Largest (in bytes) free transaction we're willing to create static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000; +static const bool DEFAULT_WALLETBROADCAST = true; + +extern const char * DEFAULT_WALLET_DAT; -class CAccountingEntry; class CBlockIndex; class CCoinControl; class COutput; @@ -147,10 +155,17 @@ struct COutputEntry class CMerkleTx : public CTransaction { private: - int GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const; + /** Constant used in hashBlock to indicate tx has been abandoned */ + static const uint256 ABANDON_HASH; public: uint256 hashBlock; + + /* An nIndex == -1 means that hashBlock (in nonzero) refers to the earliest + * block in the chain we know this or any in-wallet dependency conflicts + * with. Older clients interpret nIndex == -1 as unconfirmed for backward + * compatibility. + */ int nIndex; CMerkleTx() @@ -183,18 +198,21 @@ public: int SetMerkleBranch(const CBlock& block); - /** * Return depth of transaction in blockchain: - * -1 : not in blockchain, and not in memory pool (conflicted transaction) + * <0 : conflicts with a transaction this deep in the blockchain * 0 : in memory pool, waiting to be included in a block * >=1 : this many blocks deep in the main chain */ int GetDepthInMainChain(const CBlockIndex* &pindexRet) const; int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); } - bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; } + bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet) > 0; } int GetBlocksToMaturity() const; - bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectAbsurdFee=true); + /** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */ + bool AcceptToMemoryPool(bool fLimitFree, const CAmount nAbsurdFee); + bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); } + bool isAbandoned() const { return (hashBlock == ABANDON_HASH); } + void setAbandoned() { hashBlock = ABANDON_HASH; } }; /** @@ -210,11 +228,11 @@ public: mapValue_t mapValue; std::vector > vOrderForm; unsigned int fTimeReceivedIsTxTime; - unsigned int nTimeReceived; //! time received by this node + unsigned int nTimeReceived; //!< time received by this node unsigned int nTimeSmart; char fFromMe; std::string strFromAccount; - int64_t nOrderPos; //! position in ordered transaction list + int64_t nOrderPos; //!< position in ordered transaction list // memory only mutable bool fDebitCached; @@ -306,7 +324,7 @@ public: } READWRITE(*(CMerkleTx*)this); - std::vector vUnused; //! Used to be vtxPrev + std::vector vUnused; //!< Used to be vtxPrev READWRITE(vUnused); READWRITE(mapValue); READWRITE(vOrderForm); @@ -373,6 +391,7 @@ public: // True if only scriptSigs are different bool IsEquivalentTo(const CWalletTx& tx) const; + bool InMempool() const; bool IsTrusted() const; bool WriteToDisk(CWalletDB *pwalletdb); @@ -433,369 +452,7 @@ public: } }; - - -/** - * A CWallet is an extension of a keystore, which also maintains a set of transactions and balances, - * and provides the ability to create new transactions. - */ -class CWallet : public CCryptoKeyStore, public CValidationInterface -{ -private: - bool SelectCoins(const CAmount& nTargetValue, std::set >& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const; - - CWalletDB *pwalletdbEncryption; - - //! the current wallet version: clients below this version are not able to load the wallet - int nWalletVersion; - - //! the maximum wallet format version: memory-only variable that specifies to what version this wallet may be upgraded - int nWalletMaxVersion; - - int64_t nNextResend; - int64_t nLastResend; - bool fBroadcastTransactions; - - /** - * Used to keep track of spent outpoints, and - * detect and report conflicts (double-spends or - * mutated transactions where the mutant gets mined). - */ - typedef std::multimap TxSpends; - TxSpends mapTxSpends; - void AddToSpends(const COutPoint& outpoint, const uint256& wtxid); - void AddToSpends(const uint256& wtxid); - - void SyncMetaData(std::pair); - -public: - /* - * Main wallet lock. - * This lock protects all the fields added by CWallet - * except for: - * fFileBacked (immutable after instantiation) - * strWalletFile (immutable after instantiation) - */ - mutable CCriticalSection cs_wallet; - - bool fFileBacked; - std::string strWalletFile; - - std::set setKeyPool; - std::map mapKeyMetadata; - - typedef std::map MasterKeyMap; - MasterKeyMap mapMasterKeys; - unsigned int nMasterKeyMaxID; - - CWallet() - { - SetNull(); - } - - CWallet(const std::string& strWalletFileIn) - { - SetNull(); - - strWalletFile = strWalletFileIn; - fFileBacked = true; - } - - ~CWallet() - { - delete pwalletdbEncryption; - pwalletdbEncryption = NULL; - } - - void SetNull() - { - nWalletVersion = FEATURE_BASE; - nWalletMaxVersion = FEATURE_BASE; - fFileBacked = false; - nMasterKeyMaxID = 0; - pwalletdbEncryption = NULL; - nOrderPosNext = 0; - nNextResend = 0; - nLastResend = 0; - nTimeFirstKey = 0; - fBroadcastTransactions = false; - } - - std::map mapWallet; - - int64_t nOrderPosNext; - std::map mapRequestCount; - - std::map mapAddressBook; - - CPubKey vchDefaultKey; - - std::set setLockedCoins; - - int64_t nTimeFirstKey; - - const CWalletTx* GetWalletTx(const uint256& hash) const; - - //! check whether we are allowed to upgrade (or already support) to the named feature - bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; } - - void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false) const; - bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, CAmount& nValueRet) const; - - bool IsSpent(const uint256& hash, unsigned int n) const; - - bool IsLockedCoin(uint256 hash, unsigned int n) const; - void LockCoin(COutPoint& output); - void UnlockCoin(COutPoint& output); - void UnlockAllCoins(); - void ListLockedCoins(std::vector& vOutpts); - - /** - * keystore implementation - * Generate a new key - */ - CPubKey GenerateNewKey(); - //! Adds a key to the store, and saves it to disk. - bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); - //! Adds a key to the store, without saving it to disk (used by LoadWallet) - bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); } - //! Load metadata (used by LoadWallet) - bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata); - - bool LoadMinVersion(int nVersion) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } - - //! Adds an encrypted key to the store, and saves it to disk. - bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); - //! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) - bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); - bool AddCScript(const CScript& redeemScript); - bool LoadCScript(const CScript& redeemScript); - - //! Adds a destination data tuple to the store, and saves it to disk - bool AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value); - //! Erases a destination data tuple in the store and on disk - bool EraseDestData(const CTxDestination &dest, const std::string &key); - //! Adds a destination data tuple to the store, without saving it to disk - bool LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value); - //! Look up a destination data tuple in the store, return true if found false otherwise - bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const; - - //! Adds a watch-only address to the store, and saves it to disk. - bool AddWatchOnly(const CScript &dest); - bool RemoveWatchOnly(const CScript &dest); - //! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet) - bool LoadWatchOnly(const CScript &dest); - - bool Unlock(const SecureString& strWalletPassphrase); - bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); - bool EncryptWallet(const SecureString& strWalletPassphrase); - - void GetKeyBirthTimes(std::map &mapKeyBirth) const; - - /** - * Increment the next transaction order id - * @return next transaction order id - */ - int64_t IncOrderPosNext(CWalletDB *pwalletdb = NULL); - - typedef std::pair TxPair; - typedef std::multimap TxItems; - - /** - * Get the wallet's activity log - * @return multimap of ordered transactions and accounting entries - * @warning Returned pointers are *only* valid within the scope of passed acentries - */ - TxItems OrderedTxItems(std::list& acentries, std::string strAccount = ""); - - void MarkDirty(); - bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb); - void SyncTransaction(const CTransaction& tx, const CBlock* pblock); - bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate); - int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); - void ReacceptWalletTransactions(); - void ResendWalletTransactions(int64_t nBestBlockTime); - std::vector ResendWalletTransactionsBefore(int64_t nTime); - CAmount GetBalance() const; - CAmount GetUnconfirmedBalance() const; - CAmount GetImmatureBalance() const; - CAmount GetWatchOnlyBalance() const; - CAmount GetUnconfirmedWatchOnlyBalance() const; - CAmount GetImmatureWatchOnlyBalance() const; - bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason, bool includeWatching); - bool CreateTransaction(const std::vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet, - std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true, const CWalletTx* pwtxIn = NULL, unsigned int nTxOut = -1); - bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); - - static CFeeRate minTxFee; - static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool); - - bool NewKeyPool(); - bool TopUpKeyPool(unsigned int kpSize = 0); - void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool); - void KeepKey(int64_t nIndex); - void ReturnKey(int64_t nIndex); - bool GetKeyFromPool(CPubKey &key); - int64_t GetOldestKeyPoolTime(); - void GetAllReserveKeys(std::set& setAddress) const; - - std::set< std::set > GetAddressGroupings(); - std::map GetAddressBalances(); - - std::set GetAccountAddresses(const std::string& strAccount) const; - - isminetype IsMine(const CTxIn& txin) const; - CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const; - isminetype IsMine(const CTxOut& txout) const; - CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const; - bool IsChange(const CTxOut& txout) const; - CAmount GetChange(const CTxOut& txout) const; - bool IsMine(const CTransaction& tx) const; - /** should probably be renamed to IsRelevantToMe */ - bool IsFromMe(const CTransaction& tx) const; - CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const; - CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const; - CAmount GetChange(const CTransaction& tx) const; - void SetBestChain(const CBlockLocator& loc); - - DBErrors LoadWallet(bool& fFirstRunRet); - DBErrors ZapWalletTx(std::vector& vWtx); - - bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose); - - bool DelAddressBook(const CTxDestination& address); - - void UpdatedTransaction(const uint256 &hashTx); - - void Inventory(const uint256 &hash) - { - { - LOCK(cs_wallet); - std::map::iterator mi = mapRequestCount.find(hash); - if (mi != mapRequestCount.end()) - (*mi).second++; - } - } - - void GetScriptForMining(boost::shared_ptr &script); - void ResetRequestCount(const uint256 &hash) - { - LOCK(cs_wallet); - mapRequestCount[hash] = 0; - }; - - unsigned int GetKeyPoolSize() - { - AssertLockHeld(cs_wallet); // setKeyPool - return setKeyPool.size(); - } - - bool SetDefaultKey(const CPubKey &vchPubKey); - - //! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower - bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = NULL, bool fExplicit = false); - - //! change which version we're allowed to upgrade to (note that this does not immediately imply upgrading to that format) - bool SetMaxVersion(int nVersion); - - //! get the current wallet format (the oldest client version guaranteed to understand this wallet) - int GetVersion() { LOCK(cs_wallet); return nWalletVersion; } - - //! Get wallet transactions that conflict with given transaction (spend same outputs) - std::set GetConflicts(const uint256& txid) const; - - //! Flush wallet (bitdb flush) - void Flush(bool shutdown=false); - - //! Verify the wallet database and perform salvage if required - static bool Verify(const std::string& walletFile, std::string& warningString, std::string& errorString); - - /** - * Address book entry changed. - * @note called with lock cs_wallet held. - */ - boost::signals2::signal NotifyAddressBookChanged; - - /** - * Wallet transaction added, removed or updated. - * @note called with lock cs_wallet held. - */ - boost::signals2::signal NotifyTransactionChanged; - - /** Show progress e.g. for rescan */ - boost::signals2::signal ShowProgress; - - /** Watch-only address added */ - boost::signals2::signal NotifyWatchonlyChanged; - - /** Inquire whether this wallet broadcasts transactions. */ - bool GetBroadcastTransactions() const { return fBroadcastTransactions; } - /** Set whether this wallet broadcasts transactions. */ - void SetBroadcastTransactions(bool broadcast) { fBroadcastTransactions = broadcast; } -}; - -/** A key allocated from the key pool. */ -class CReserveKey : public CReserveScript -{ -protected: - CWallet* pwallet; - int64_t nIndex; - CPubKey vchPubKey; -public: - CReserveKey(CWallet* pwalletIn) - { - nIndex = -1; - pwallet = pwalletIn; - } - - ~CReserveKey() - { - ReturnKey(); - } - - void ReturnKey(); - bool GetReservedKey(CPubKey &pubkey); - void KeepKey(); - void KeepScript() { KeepKey(); } -}; - - -/** - * Account information. - * Stored in wallet with key "acc"+string account name. - */ -class CAccount -{ -public: - CPubKey vchPubKey; - - CAccount() - { - SetNull(); - } - - void SetNull() - { - vchPubKey = CPubKey(); - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) - READWRITE(nVersion); - READWRITE(vchPubKey); - } -}; - - - -/** +/** * Internal transfers. * Database key is acentry. */ @@ -808,7 +465,7 @@ public: std::string strOtherAccount; std::string strComment; mapValue_t mapValue; - int64_t nOrderPos; //! position in ordered transaction list + int64_t nOrderPos; //!< position in ordered transaction list uint64_t nEntryNo; CAccountingEntry() @@ -876,4 +533,412 @@ private: std::vector _ssExtra; }; + +/** + * A CWallet is an extension of a keystore, which also maintains a set of transactions and balances, + * and provides the ability to create new transactions. + */ +class CWallet : public CCryptoKeyStore, public CValidationInterface +{ +private: + /** + * Select a set of coins such that nValueRet >= nTargetValue and at least + * all coins from coinControl are selected; Never select unconfirmed coins + * if they are not ours + */ + bool SelectCoins(const std::vector& vAvailableCoins, const CAmount& nTargetValue, std::set >& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const; + + CWalletDB *pwalletdbEncryption; + + //! the current wallet version: clients below this version are not able to load the wallet + int nWalletVersion; + + //! the maximum wallet format version: memory-only variable that specifies to what version this wallet may be upgraded + int nWalletMaxVersion; + + int64_t nNextResend; + int64_t nLastResend; + bool fBroadcastTransactions; + + /** + * Used to keep track of spent outpoints, and + * detect and report conflicts (double-spends or + * mutated transactions where the mutant gets mined). + */ + typedef std::multimap TxSpends; + TxSpends mapTxSpends; + void AddToSpends(const COutPoint& outpoint, const uint256& wtxid); + void AddToSpends(const uint256& wtxid); + + /* Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */ + void MarkConflicted(const uint256& hashBlock, const uint256& hashTx); + + void SyncMetaData(std::pair); + +public: + /* + * Main wallet lock. + * This lock protects all the fields added by CWallet + * except for: + * fFileBacked (immutable after instantiation) + * strWalletFile (immutable after instantiation) + */ + mutable CCriticalSection cs_wallet; + + bool fFileBacked; + std::string strWalletFile; + + std::set setKeyPool; + std::map mapKeyMetadata; + + typedef std::map MasterKeyMap; + MasterKeyMap mapMasterKeys; + unsigned int nMasterKeyMaxID; + + CWallet() + { + SetNull(); + } + + CWallet(const std::string& strWalletFileIn) + { + SetNull(); + + strWalletFile = strWalletFileIn; + fFileBacked = true; + } + + ~CWallet() + { + delete pwalletdbEncryption; + pwalletdbEncryption = NULL; + } + + void SetNull() + { + nWalletVersion = FEATURE_BASE; + nWalletMaxVersion = FEATURE_BASE; + fFileBacked = false; + nMasterKeyMaxID = 0; + pwalletdbEncryption = NULL; + nOrderPosNext = 0; + nNextResend = 0; + nLastResend = 0; + nTimeFirstKey = 0; + fBroadcastTransactions = false; + } + + std::map mapWallet; + std::list laccentries; + + typedef std::pair TxPair; + typedef std::multimap TxItems; + TxItems wtxOrdered; + + int64_t nOrderPosNext; + std::map mapRequestCount; + + std::map mapAddressBook; + + CPubKey vchDefaultKey; + + std::set setLockedCoins; + + int64_t nTimeFirstKey; + + const CWalletTx* GetWalletTx(const uint256& hash) const; + + //! check whether we are allowed to upgrade (or already support) to the named feature + bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; } + + /** + * populate vCoins with vector of available COutputs. + */ + void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false) const; + + /** + * Shuffle and select coins until nTargetValue is reached while avoiding + * small change; This method is stochastic for some inputs and upon + * completion the coin set and corresponding actual target value is + * assembled + */ + bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, CAmount& nValueRet) const; + + bool IsSpent(const uint256& hash, unsigned int n) const; + + bool IsLockedCoin(uint256 hash, unsigned int n) const; + void LockCoin(const COutPoint& output); + void UnlockCoin(const COutPoint& output); + void UnlockAllCoins(); + void ListLockedCoins(std::vector& vOutpts); + + /** + * keystore implementation + * Generate a new key + */ + CPubKey GenerateNewKey(); + //! Adds a key to the store, and saves it to disk. + bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); + //! Adds a key to the store, without saving it to disk (used by LoadWallet) + bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); } + //! Load metadata (used by LoadWallet) + bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata); + + bool LoadMinVersion(int nVersion) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } + + //! Adds an encrypted key to the store, and saves it to disk. + bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); + //! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) + bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); + bool AddCScript(const CScript& redeemScript); + bool LoadCScript(const CScript& redeemScript); + + //! Adds a destination data tuple to the store, and saves it to disk + bool AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value); + //! Erases a destination data tuple in the store and on disk + bool EraseDestData(const CTxDestination &dest, const std::string &key); + //! Adds a destination data tuple to the store, without saving it to disk + bool LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value); + //! Look up a destination data tuple in the store, return true if found false otherwise + bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const; + + //! Adds a watch-only address to the store, and saves it to disk. + bool AddWatchOnly(const CScript &dest); + bool RemoveWatchOnly(const CScript &dest); + //! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet) + bool LoadWatchOnly(const CScript &dest); + + bool Unlock(const SecureString& strWalletPassphrase); + bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); + bool EncryptWallet(const SecureString& strWalletPassphrase); + + void GetKeyBirthTimes(std::map &mapKeyBirth) const; + + /** + * Increment the next transaction order id + * @return next transaction order id + */ + int64_t IncOrderPosNext(CWalletDB *pwalletdb = NULL); + + void MarkDirty(); + bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb); + void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock); + bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate); + int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); + void ReacceptWalletTransactions(); + void ResendWalletTransactions(int64_t nBestBlockTime); + std::vector ResendWalletTransactionsBefore(int64_t nTime); + CAmount GetBalance() const; + CAmount GetUnconfirmedBalance() const; + CAmount GetImmatureBalance() const; + CAmount GetWatchOnlyBalance() const; + CAmount GetUnconfirmedWatchOnlyBalance() const; + CAmount GetImmatureWatchOnlyBalance() const; + + /** + * Insert additional inputs into the transaction by + * calling CreateTransaction(); + */ + bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const CTxDestination& destChange = CNoDestination()); + + /** + * Create a new transaction paying the recipients with a set of coins + * selected by SelectCoins(); Also create the change output, when needed + * @note passing nChangePosInOut as -1 will result in setting a random position + */ + bool CreateTransaction(const std::vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut, + std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true, const CWalletTx* pwtxIn = NULL, unsigned int nTxOut = -1); + bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); + + bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb); + + static CFeeRate minTxFee; + static CFeeRate fallbackFee; + /** + * Estimate the minimum fee considering user set parameters + * and the required fee + */ + static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool); + /** + * Return the minimum required fee taking into account the + * floating relay fee and user set minimum transaction fee + */ + static CAmount GetRequiredFee(unsigned int nTxBytes); + + bool NewKeyPool(); + bool TopUpKeyPool(unsigned int kpSize = 0); + void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool); + void KeepKey(int64_t nIndex); + void ReturnKey(int64_t nIndex); + bool GetKeyFromPool(CPubKey &key); + int64_t GetOldestKeyPoolTime(); + void GetAllReserveKeys(std::set& setAddress) const; + + std::set< std::set > GetAddressGroupings(); + std::map GetAddressBalances(); + + std::set GetAccountAddresses(const std::string& strAccount) const; + + isminetype IsMine(const CTxIn& txin) const; + CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const; + isminetype IsMine(const CTxOut& txout) const; + CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const; + bool IsChange(const CTxOut& txout) const; + CAmount GetChange(const CTxOut& txout) const; + bool IsMine(const CTransaction& tx) const; + /** should probably be renamed to IsRelevantToMe */ + bool IsFromMe(const CTransaction& tx) const; + CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const; + CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const; + CAmount GetChange(const CTransaction& tx) const; + void SetBestChain(const CBlockLocator& loc); + + DBErrors LoadWallet(bool& fFirstRunRet); + DBErrors ZapWalletTx(std::vector& vWtx); + DBErrors ZapSelectTx(std::vector& vHashIn, std::vector& vHashOut); + + bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose); + + bool DelAddressBook(const CTxDestination& address); + + void UpdatedTransaction(const uint256 &hashTx); + + void Inventory(const uint256 &hash) + { + { + LOCK(cs_wallet); + std::map::iterator mi = mapRequestCount.find(hash); + if (mi != mapRequestCount.end()) + (*mi).second++; + } + } + + void GetScriptForMining(boost::shared_ptr &script); + void ResetRequestCount(const uint256 &hash) + { + LOCK(cs_wallet); + mapRequestCount[hash] = 0; + }; + + unsigned int GetKeyPoolSize() + { + AssertLockHeld(cs_wallet); // setKeyPool + return setKeyPool.size(); + } + + bool SetDefaultKey(const CPubKey &vchPubKey); + + //! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower + bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = NULL, bool fExplicit = false); + + //! change which version we're allowed to upgrade to (note that this does not immediately imply upgrading to that format) + bool SetMaxVersion(int nVersion); + + //! get the current wallet format (the oldest client version guaranteed to understand this wallet) + int GetVersion() { LOCK(cs_wallet); return nWalletVersion; } + + //! Get wallet transactions that conflict with given transaction (spend same outputs) + std::set GetConflicts(const uint256& txid) const; + + //! Flush wallet (bitdb flush) + void Flush(bool shutdown=false); + + //! Verify the wallet database and perform salvage if required + static bool Verify(); + + /** + * Address book entry changed. + * @note called with lock cs_wallet held. + */ + boost::signals2::signal NotifyAddressBookChanged; + + /** + * Wallet transaction added, removed or updated. + * @note called with lock cs_wallet held. + */ + boost::signals2::signal NotifyTransactionChanged; + + /** Show progress e.g. for rescan */ + boost::signals2::signal ShowProgress; + + /** Watch-only address added */ + boost::signals2::signal NotifyWatchonlyChanged; + + /** Inquire whether this wallet broadcasts transactions. */ + bool GetBroadcastTransactions() const { return fBroadcastTransactions; } + /** Set whether this wallet broadcasts transactions. */ + void SetBroadcastTransactions(bool broadcast) { fBroadcastTransactions = broadcast; } + + /* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */ + bool AbandonTransaction(const uint256& hashTx); + + /* Returns the wallets help message */ + static std::string GetWalletHelpString(bool showDebug); + + /* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */ + static bool InitLoadWallet(); + + /* Wallets parameter interaction */ + static bool ParameterInteraction(); +}; + +/** A key allocated from the key pool. */ +class CReserveKey : public CReserveScript +{ +protected: + CWallet* pwallet; + int64_t nIndex; + CPubKey vchPubKey; +public: + CReserveKey(CWallet* pwalletIn) + { + nIndex = -1; + pwallet = pwalletIn; + } + + ~CReserveKey() + { + ReturnKey(); + } + + void ReturnKey(); + bool GetReservedKey(CPubKey &pubkey); + void KeepKey(); + void KeepScript() { KeepKey(); } +}; + + +/** + * Account information. + * Stored in wallet with key "acc"+string account name. + */ +class CAccount +{ +public: + CPubKey vchPubKey; + + CAccount() + { + SetNull(); + } + + void SetNull() + { + vchPubKey = CPubKey(); + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + if (!(nType & SER_GETHASH)) + READWRITE(nVersion); + READWRITE(vchPubKey); + } +}; + #endif // BITCOIN_WALLET_WALLET_H diff --git a/src/wallet/wallet_ismine.cpp b/src/wallet/wallet_ismine.cpp index 688cae6d4..e45027fa4 100644 --- a/src/wallet/wallet_ismine.cpp +++ b/src/wallet/wallet_ismine.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/wallet_ismine.h b/src/wallet/wallet_ismine.h index 8a5334e8a..69c019059 100644 --- a/src/wallet/wallet_ismine.h +++ b/src/wallet/wallet_ismine.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -17,7 +17,7 @@ class CScript; enum isminetype { ISMINE_NO = 0, - //! Indicates that we dont know how to create a scriptSig that would solve this if we were given the appropriate private keys + //! Indicates that we don't know how to create a scriptSig that would solve this if we were given the appropriate private keys ISMINE_WATCH_UNSOLVABLE = 1, //! Indicates that we know how to create a scriptSig that would solve this if we were given the appropriate private keys ISMINE_WATCH_SOLVABLE = 2, diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 0624e442d..f2b5408e9 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,6 +15,7 @@ #include "utiltime.h" #include "wallet/wallet.h" +#include #include #include #include @@ -113,19 +114,19 @@ bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey) bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript) { nWalletDBUpdated++; - return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false); + return Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false); } bool CWalletDB::WriteWatchOnly(const CScript &dest) { nWalletDBUpdated++; - return Write(std::make_pair(std::string("watchs"), dest), '1'); + return Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1'); } bool CWalletDB::EraseWatchOnly(const CScript &dest) { nWalletDBUpdated++; - return Erase(std::make_pair(std::string("watchs"), dest)); + return Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest))); } bool CWalletDB::WriteBestBlock(const CBlockLocator& locator) @@ -191,7 +192,7 @@ bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccount return Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry); } -bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry) +bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry) { return WriteAccountingEntry(++nAccountingEntryNumber, acentry); } @@ -421,7 +422,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, else if (strType == "watchs") { CScript script; - ssKey >> script; + ssKey >> *(CScriptBase*)(&script); char fYes; ssValue >> fYes; if (fYes == '1') @@ -512,8 +513,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, } else if (strType == "ckey") { - vector vchPubKey; + CPubKey vchPubKey; ssKey >> vchPubKey; + if (!vchPubKey.IsValid()) + { + strErr = "Error reading wallet database: CPubKey corrupt"; + return false; + } vector vchPrivKey; ssValue >> vchPrivKey; wss.nCKeys++; @@ -570,7 +576,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, uint160 hash; ssKey >> hash; CScript script; - ssValue >> script; + ssValue >> *(CScriptBase*)(&script); if (!pwallet->LoadCScript(script)) { strErr = "Error reading wallet database: LoadCScript failed"; @@ -704,6 +710,12 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if (wss.fAnyUnordered) result = ReorderTransactions(pwallet); + pwallet->laccentries.clear(); + ListAccountCreditDebit("*", pwallet->laccentries); + BOOST_FOREACH(CAccountingEntry& entry, pwallet->laccentries) { + pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair((CWalletTx*)0, &entry))); + } + return result; } @@ -773,6 +785,45 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector& vTxHash, vec return result; } +DBErrors CWalletDB::ZapSelectTx(CWallet* pwallet, vector& vTxHashIn, vector& vTxHashOut) +{ + // build list of wallet TXs and hashes + vector vTxHash; + vector vWtx; + DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx); + if (err != DB_LOAD_OK) { + return err; + } + + std::sort(vTxHash.begin(), vTxHash.end()); + std::sort(vTxHashIn.begin(), vTxHashIn.end()); + + // erase each matching wallet TX + bool delerror = false; + vector::iterator it = vTxHashIn.begin(); + BOOST_FOREACH (uint256 hash, vTxHash) { + while (it < vTxHashIn.end() && (*it) < hash) { + it++; + } + if (it == vTxHashIn.end()) { + break; + } + else if ((*it) == hash) { + pwallet->mapWallet.erase(hash); + if(!EraseTx(hash)) { + LogPrint("db", "Transaction was found for deletion but returned database error: %s\n", hash.GetHex()); + delerror = true; + } + vTxHashOut.push_back(hash); + } + } + + if (delerror) { + return DB_CORRUPT; + } + return DB_LOAD_OK; +} + DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector& vWtx) { // build list of wallet TXs @@ -799,7 +850,7 @@ void ThreadFlushWalletDB(const string& strFile) if (fOneThread) return; fOneThread = true; - if (!GetBoolArg("-flushwallet", true)) + if (!GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) return; unsigned int nLastSeen = nWalletDBUpdated; @@ -835,16 +886,16 @@ void ThreadFlushWalletDB(const string& strFile) map::iterator mi = bitdb.mapFileUseCount.find(strFile); if (mi != bitdb.mapFileUseCount.end()) { - LogPrint("db", "Flushing wallet.dat\n"); + LogPrint("db", "Flushing %s\n", strFile); nLastFlushed = nWalletDBUpdated; int64_t nStart = GetTimeMillis(); - // Flush wallet.dat so it's self contained + // Flush wallet file so it's self contained bitdb.CloseDb(strFile); bitdb.CheckpointLSN(strFile); bitdb.mapFileUseCount.erase(mi++); - LogPrint("db", "Flushed wallet.dat %dms\n", GetTimeMillis() - nStart); + LogPrint("db", "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart); } } } @@ -867,7 +918,7 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) bitdb.CheckpointLSN(wallet.strWalletFile); bitdb.mapFileUseCount.erase(wallet.strWalletFile); - // Copy wallet.dat + // Copy wallet file boost::filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile; boost::filesystem::path pathDest(strDest); if (boost::filesystem::is_directory(pathDest)) @@ -879,10 +930,10 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) #else boost::filesystem::copy_file(pathSrc, pathDest); #endif - LogPrintf("copied wallet.dat to %s\n", pathDest.string()); + LogPrintf("copied %s to %s\n", wallet.strWalletFile, pathDest.string()); return true; } catch (const boost::filesystem::filesystem_error& e) { - LogPrintf("error copying wallet.dat to %s - %s\n", pathDest.string(), e.what()); + LogPrintf("error copying %s to %s - %s\n", wallet.strWalletFile, pathDest.string(), e.what()); return false; } } @@ -893,15 +944,15 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) } // -// Try to (very carefully!) recover wallet.dat if there is a problem. +// Try to (very carefully!) recover wallet file if there is a problem. // bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys) { // Recovery procedure: - // move wallet.dat to wallet.timestamp.bak + // move wallet file to wallet.timestamp.bak // Call Salvage with fAggressive=true to // get as much data as possible. - // Rewrite salvaged data to wallet.dat + // Rewrite salvaged data to fresh wallet file // Set -rescan so any missing transactions will be // found. int64_t now = GetTime(); @@ -949,8 +1000,13 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKe CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION); CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION); string strType, strErr; - bool fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue, + bool fReadOK; + { + // Required in LoadKeyMetadata(): + LOCK(dummyWallet.cs_wallet); + fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue, wss, strType, strErr); + } if (!IsKeyType(strType)) continue; if (!fReadOK) diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 270f826ae..fe6c36634 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,6 +16,8 @@ #include #include +static const bool DEFAULT_FLUSHWALLET = true; + class CAccount; class CAccountingEntry; struct CBlockLocator; @@ -71,7 +73,7 @@ public: } }; -/** Access to the wallet database (wallet.dat) */ +/** Access to the wallet database */ class CWalletDB : public CDB { public: @@ -110,6 +112,9 @@ public: bool WriteMinVersion(int nVersion); + /// This writes directly to the database, and will not update the CWallet's cached accounting entries! + /// Use wallet.AddAccountingEntry instead, to write *and* update its caches. + bool WriteAccountingEntry_Backend(const CAccountingEntry& acentry); bool ReadAccount(const std::string& strAccount, CAccount& account); bool WriteAccount(const std::string& strAccount, const CAccount& account); @@ -118,7 +123,6 @@ public: /// Erase destination data tuple from wallet database bool EraseDestData(const std::string &address, const std::string &key); - bool WriteAccountingEntry(const CAccountingEntry& acentry); CAmount GetAccountCreditDebit(const std::string& strAccount); void ListAccountCreditDebit(const std::string& strAccount, std::list& acentries); @@ -126,6 +130,7 @@ public: DBErrors LoadWallet(CWallet* pwallet); DBErrors FindWalletTx(CWallet* pwallet, std::vector& vTxHash, std::vector& vWtx); DBErrors ZapWalletTx(CWallet* pwallet, std::vector& vWtx); + DBErrors ZapSelectTx(CWallet* pwallet, std::vector& vHashIn, std::vector& vHashOut); static bool Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys); static bool Recover(CDBEnv& dbenv, const std::string& filename); diff --git a/src/zmq/zmqconfig.h b/src/zmq/zmqconfig.h index 6057f5d1a..610d7fbda 100644 --- a/src/zmq/zmqconfig.h +++ b/src/zmq/zmqconfig.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015 The Bitcoin Core developers +// Copyright (c) 2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index 388b86707..870553242 100644 --- a/src/zmq/zmqnotificationinterface.cpp +++ b/src/zmq/zmqnotificationinterface.cpp @@ -12,7 +12,7 @@ void zmqError(const char *str) { - LogPrint("zmq", "Error: %s, errno=%s\n", str, zmq_strerror(errno)); + LogPrint("zmq", "zmq: Error: %s, errno=%s\n", str, zmq_strerror(errno)); } CZMQNotificationInterface::CZMQNotificationInterface() : pcontext(NULL) @@ -21,8 +21,7 @@ CZMQNotificationInterface::CZMQNotificationInterface() : pcontext(NULL) CZMQNotificationInterface::~CZMQNotificationInterface() { - // ensure Shutdown if Initialize is called - assert(!pcontext); + Shutdown(); for (std::list::iterator i=notifiers.begin(); i!=notifiers.end(); ++i) { @@ -59,6 +58,12 @@ CZMQNotificationInterface* CZMQNotificationInterface::CreateWithArguments(const { notificationInterface = new CZMQNotificationInterface(); notificationInterface->notifiers = notifiers; + + if (!notificationInterface->Initialize()) + { + delete notificationInterface; + notificationInterface = NULL; + } } return notificationInterface; @@ -67,7 +72,7 @@ CZMQNotificationInterface* CZMQNotificationInterface::CreateWithArguments(const // Called at startup to conditionally set up ZMQ socket(s) bool CZMQNotificationInterface::Initialize() { - LogPrint("zmq", "Initialize notification interface\n"); + LogPrint("zmq", "zmq: Initialize notification interface\n"); assert(!pcontext); pcontext = zmq_init(1); @@ -95,17 +100,16 @@ bool CZMQNotificationInterface::Initialize() if (i!=notifiers.end()) { - Shutdown(); return false; } - return false; + return true; } // Called during shutdown sequence void CZMQNotificationInterface::Shutdown() { - LogPrint("zmq", "Shutdown notification interface\n"); + LogPrint("zmq", "zmq: Shutdown notification interface\n"); if (pcontext) { for (std::list::iterator i=notifiers.begin(); i!=notifiers.end(); ++i) @@ -137,7 +141,7 @@ void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindex) } } -void CZMQNotificationInterface::SyncTransaction(const CTransaction &tx, const CBlock *pblock) +void CZMQNotificationInterface::SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, const CBlock* pblock) { for (std::list::iterator i = notifiers.begin(); i!=notifiers.end(); ) { diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h index 8eea15c06..7b52e7775 100644 --- a/src/zmq/zmqnotificationinterface.h +++ b/src/zmq/zmqnotificationinterface.h @@ -19,11 +19,12 @@ public: static CZMQNotificationInterface* CreateWithArguments(const std::map &args); +protected: bool Initialize(); void Shutdown(); -protected: // CValidationInterface - void SyncTransaction(const CTransaction &tx, const CBlock *pblock); + // CValidationInterface + void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock); void UpdatedBlockTip(const CBlockIndex *pindex); private: diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index 4c3eb8f2d..f5839620f 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "chainparams.h" #include "zmqpublishnotifier.h" #include "main.h" #include "util.h" @@ -68,6 +69,7 @@ bool CZMQAbstractPublishNotifier::Initialize(void *pcontext) if (rc!=0) { zmqError("Failed to bind address"); + zmq_close(psocket); return false; } @@ -77,7 +79,7 @@ bool CZMQAbstractPublishNotifier::Initialize(void *pcontext) } else { - LogPrint("zmq", " Reuse socket for address %s\n", address); + LogPrint("zmq", "zmq: Reusing socket for address %s\n", address); psocket = i->second->psocket; mapPublishNotifiers.insert(std::make_pair(address, this)); @@ -119,7 +121,7 @@ void CZMQAbstractPublishNotifier::Shutdown() bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { uint256 hash = pindex->GetBlockHash(); - LogPrint("zmq", "Publish hash block %s\n", hash.GetHex()); + LogPrint("zmq", "zmq: Publish hashblock %s\n", hash.GetHex()); char data[32]; for (unsigned int i = 0; i < 32; i++) data[31 - i] = hash.begin()[i]; @@ -130,7 +132,7 @@ bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex) bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction) { uint256 hash = transaction.GetHash(); - LogPrint("zmq", "Publish hash transaction %s\n", hash.GetHex()); + LogPrint("zmq", "zmq: Publish hashtx %s\n", hash.GetHex()); char data[32]; for (unsigned int i = 0; i < 32; i++) data[31 - i] = hash.begin()[i]; @@ -140,13 +142,14 @@ bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &t bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { - LogPrint("zmq", "Publish raw block %s\n", pindex->GetBlockHash().GetHex()); + LogPrint("zmq", "zmq: Publish rawblock %s\n", pindex->GetBlockHash().GetHex()); + const Consensus::Params& consensusParams = Params().GetConsensus(); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); { LOCK(cs_main); CBlock block; - if(!ReadBlockFromDisk(block, pindex)) + if(!ReadBlockFromDisk(block, pindex, consensusParams)) { zmqError("Can't read block from disk"); return false; @@ -162,7 +165,7 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction) { uint256 hash = transaction.GetHash(); - LogPrint("zmq", "Publish raw transaction %s\n", hash.GetHex()); + LogPrint("zmq", "zmq: Publish rawtx %s\n", hash.GetHex()); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << transaction; int rc = zmq_send_multipart(psocket, "rawtx", 5, &(*ss.begin()), ss.size(), 0);