diff options
Diffstat (limited to 'contrib')
73 files changed, 3441 insertions, 1653 deletions
diff --git a/contrib/README.md b/contrib/README.md index a23b197cc6..6f750106e4 100644 --- a/contrib/README.md +++ b/contrib/README.md @@ -1,17 +1,9 @@ -Wallet Tools ---------------------- - -### [SpendFrom](/contrib/spendfrom) ### - -Use the raw transactions API to send coins received on a particular -address (or addresses). - Repository Tools --------------------- ### [Developer tools](/contrib/devtools) ### Specific tools for developers working on this repository. -Contains the script `github-merge.py` 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.py` script. @@ -45,6 +37,9 @@ Scripts and notes for Mac builds. ### [RPM](/contrib/rpm) ### RPM spec file for building bitcoin-core on RPM based distributions +### [Gitian-build](/contrib/gitian-build.sh) ### +Script for running full Gitian builds. + Test and Verify Tools --------------------- diff --git a/contrib/debian/bitcoin-qt.desktop b/contrib/debian/bitcoin-qt.desktop index 61e1aca6ad..593d7584ab 100644 --- a/contrib/debian/bitcoin-qt.desktop +++ b/contrib/debian/bitcoin-qt.desktop @@ -1,7 +1,8 @@ [Desktop Entry] Encoding=UTF-8 -Name=Bitcoin -Comment=Bitcoin P2P Cryptocurrency +Name=Bitcoin Core +Comment=Connect to the Bitcoin P2P Network +Comment[de]=Verbinde mit dem Bitcoin peer-to-peer Netzwerk Comment[fr]=Bitcoin, monnaie virtuelle cryptographique pair à pair Comment[tr]=Bitcoin, eşten eşe kriptografik sanal para birimi Exec=bitcoin-qt %u diff --git a/contrib/debian/bitcoin-qt.manpages b/contrib/debian/bitcoin-qt.manpages new file mode 100644 index 0000000000..9a3cc31c09 --- /dev/null +++ b/contrib/debian/bitcoin-qt.manpages @@ -0,0 +1 @@ +doc/man/bitcoin-qt.1 diff --git a/contrib/debian/bitcoin-tx.manpages b/contrib/debian/bitcoin-tx.manpages new file mode 100644 index 0000000000..861d49d070 --- /dev/null +++ b/contrib/debian/bitcoin-tx.manpages @@ -0,0 +1 @@ +doc/man/bitcoin-tx.1 diff --git a/contrib/debian/bitcoind.manpages b/contrib/debian/bitcoind.manpages index 6d3e683855..bab644ece1 100644 --- a/contrib/debian/bitcoind.manpages +++ b/contrib/debian/bitcoind.manpages @@ -1,3 +1,2 @@ -debian/manpages/bitcoind.1 -debian/manpages/bitcoin.conf.5 -debian/manpages/bitcoin-cli.1 +doc/man/bitcoind.1 +doc/man/bitcoin-cli.1 diff --git a/contrib/debian/changelog b/contrib/debian/changelog index 110bfe03ef..33dab9b638 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,122 @@ +bitcoin (0.14.1-trusty4) trusty; urgency=medium + + * Re-enable UPnP support. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Fri, 05 May 2017 13:28:00 -0400 + +bitcoin (0.14.1-trusty3) trusty; urgency=medium + + * Build with qt5 if we are on a non-Ubuntu (ie non-Unity) distro. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Thu, 04 May 2017 17:13:00 -0400 + +bitcoin (0.14.1-trusty2) trusty; urgency=medium + + * Bump minimum boost version in deps. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Thu, 04 May 2017 17:12:00 -0400 + +bitcoin (0.14.1-trusty1) trusty; urgency=medium + + * New upstream release. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Sat, 22 Apr 2017 17:10:00 -0400 + +bitcoin (0.14.0-trusty1) trusty; urgency=medium + + * New upstream release. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Wed, 08 Mar 2017 10:30:00 -0500 + +bitcoin (0.13.2-trusty1) trusty; urgency=medium + + * New upstream release. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Thu, 05 Jan 2017 09:59:00 -0500 + +bitcoin (0.13.1-trusty2) trusty; urgency=medium + + * Revert to Qt4, due to https://github.com/bitcoin/bitcoin/issues/9038 + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Mon, 31 Oct 2016 11:16:00 -0400 + +bitcoin (0.13.1-trusty1) trusty; urgency=medium + + * New upstream release. + * Backport updated bitcoin-qt.desktop from upstream master + * Add zmq dependency + * Switch to Qt5 (breaks precise, but that was already broken by C++11) + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Thu, 27 Oct 2016 17:32:00 -0400 + +bitcoin (0.13.0-trusty1) trusty; urgency=medium + + * New upstream release. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Sun, 04 Sep 2016 22:09:00 -0400 + +bitcoin (0.12.1-trusty1) trusty; urgency=medium + + * New upstream release. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Mon, 18 Apr 2016 14:26:00 -0700 + +bitcoin (0.12.0-trusty6) trusty; urgency=medium + + * Fix program-options dep. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Fri, 25 Mar 2016 21:41:00 -0700 + +bitcoin (0.12.0-trusty5) trusty; urgency=medium + + * Test explicit --with-gui + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 23:25:00 -0800 + +bitcoin (0.12.0-trusty4) trusty; urgency=medium + + * Fix libevent-dev dep. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 23:25:00 -0800 + +bitcoin (0.12.0-trusty3) trusty; urgency=medium + + * Fix precise boost dep. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 19:55:00 -0800 + +bitcoin (0.12.0-trusty2) trusty; urgency=medium + + * Fix libevent dep. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 19:53:00 -0800 + +bitcoin (0.12.0-trusty1) trusty; urgency=medium + + * New upstream release + * Various updates to contrib/debian were merged, a few were not + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 19:29:00 -0800 + +bitcoin (0.11.2-trusty1) trusty; urgency=low + + * New upstream release. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Fri, 13 Nov 2015 18:39:00 -0800 + +bitcoin (0.11.1-trusty2) trusty; urgency=low + + * Remove minupnpc builddep. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Wed, 14 Oct 2015 23:06:00 -1000 + +bitcoin (0.11.1-trusty1) trusty; urgency=high + + * New upstream release. + * Disable all UPnP support. + + -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Wed, 14 Oct 2015 13:57:00 -1000 + bitcoin (0.11.0-precise1) precise; urgency=medium * New upstream release. @@ -179,7 +298,7 @@ bitcoin (0.5.3-natty0) natty; urgency=low bitcoin (0.5.2-natty1) natty; urgency=low * Remove mentions on anonymity in package descriptions and manpage. - These should never have been there, bitcoin isn't anonymous without + These should never have been there, bitcoin isnt anonymous without a ton of work that virtually no users will ever be willing and capable of doing @@ -220,7 +339,7 @@ bitcoin (0.5.0~rc1-natty1) natty; urgency=low * Add test_bitcoin to build test * Fix clean - * Remove unnecessary build-dependancies + * Remove uneccessary build-dependancies -- Matt Corallo <matt@bluematt.me> Wed, 26 Oct 2011 14:37:18 -0400 @@ -380,7 +499,7 @@ bitcoin (0.3.20.01~dfsg-1) unstable; urgency=low bitcoin (0.3.19~dfsg-6) unstable; urgency=low - * Fix override aggressive optimizations. + * Fix override agressive optimizations. * Fix tighten build-dependencies to really fit backporting to Lenny: + Add fallback build-dependency on libdb4.6++-dev. + Tighten unversioned Boost build-dependencies to recent versions, diff --git a/contrib/debian/control b/contrib/debian/control index fce6bc0118..0d6ad25e24 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -1,27 +1,30 @@ Source: bitcoin Section: utils Priority: optional -Maintainer: Jonas Smedegaard <dr@jones.dk> -Uploaders: Micah Anderson <micah@debian.org> +Maintainer: Matt Corallo <matt@mattcorallo.com> +Uploaders: Matt Corallo <matt@mattcorallo.com> Build-Depends: debhelper, devscripts, automake, libtool, bash-completion, - libboost-system-dev (>> 1.35) | libboost-system1.35-dev, libdb4.8++-dev, libssl-dev, pkg-config, - libminiupnpc8-dev | libminiupnpc-dev (>> 1.6), - libboost-filesystem-dev (>> 1.35) | libboost-filesystem1.35-dev, - libboost-program-options-dev (>> 1.35) | libboost-program-options1.35-dev, - libboost-thread-dev (>> 1.35) | libboost-thread1.35-dev, - libboost-test-dev (>> 1.35) | libboost-test1.35-dev, - qt4-qmake, - libqt4-dev, + libevent-dev, + libboost-system1.48-dev | libboost-system-dev (>> 1.47), + libboost-filesystem1.48-dev | libboost-filesystem-dev (>> 1.47), + libboost-program-options1.48-dev | libboost-program-options-dev (>> 1.47), + libboost-thread1.48-dev | libboost-thread-dev (>> 1.47), + libboost-test1.48-dev | libboost-test-dev (>> 1.47), + libboost-chrono1.48-dev | libboost-chrono-dev (>> 1.47), + libminiupnpc8-dev | libminiupnpc-dev, + qt4-qmake, libqt4-dev, + qttools5-dev-tools, qttools5-dev, libqrencode-dev, libprotobuf-dev, protobuf-compiler, - python + python, + libzmq3-dev Standards-Version: 3.9.2 Homepage: https://bitcoincore.org/ Vcs-Git: git://github.com/bitcoin/bitcoin.git @@ -31,11 +34,11 @@ Package: bitcoind Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer network based digital currency - daemon - 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. + 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. . This package provides the daemon, bitcoind, and the CLI tool bitcoin-cli to interact with the daemon. @@ -44,11 +47,11 @@ Package: bitcoin-qt Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer network based digital currency - Qt GUI - 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. + 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. . This package provides Bitcoin-Qt, a GUI for Bitcoin based on Qt. @@ -56,11 +59,11 @@ Package: bitcoin-tx Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer digital currency - standalone transaction tool - 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. + 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. . 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 c039a7bae5..72d64ce62d 100644 --- a/contrib/debian/copyright +++ b/contrib/debian/copyright @@ -5,7 +5,7 @@ Upstream-Contact: Satoshi Nakamoto <satoshin@gmx.com> Source: https://github.com/bitcoin/bitcoin Files: * -Copyright: 2009-2016, Bitcoin Core Developers +Copyright: 2009-2017, 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. @@ -15,10 +15,6 @@ Copyright: 2010-2011, Jonas Smedegaard <dr@jones.dk> 2011, Matt Corallo <matt@bluematt.me> License: GPL-2+ -Files: debian/manpages/* -Copyright: Micah Anderson <micah@debian.org> -License: GPL-3+ - Files: src/qt/res/icons/add.png src/qt/res/icons/address-book.png src/qt/res/icons/chevron.png @@ -51,7 +47,10 @@ Comment: Site: https://github.com/stephenhutchings/typicons.font Files: src/qt/res/icons/connect*.png src/qt/res/src/connect-*.svg + src/qt/res/icons/network_disabled.png + src/qt/res/src/network_disabled.svg Copyright: Marco Falke + Luke Dashjr License: Expat Comment: Inspired by Stephan Hutchings Typicons @@ -59,6 +58,10 @@ 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 + src/qt/res/icons/hd_disabled.png + src/qt/res/src/hd_disabled.svg + src/qt/res/icons/hd_enabled.png + src/qt/res/src/hd_enabled.svg Copyright: Jonas Schnelli License: Expat Comment: diff --git a/contrib/debian/examples/bitcoin.conf b/contrib/debian/examples/bitcoin.conf index 2831c07292..1029a51073 100644 --- a/contrib/debian/examples/bitcoin.conf +++ b/contrib/debian/examples/bitcoin.conf @@ -67,9 +67,30 @@ # This option can be specified multiple times (default: bind to all interfaces) #rpcbind=<addr> -# You must set rpcuser and rpcpassword to secure the JSON-RPC api +# If no rpcpassword is set, rpc cookie auth is sought. The default `-rpccookiefile` name +# is .cookie and found in the `-datadir` being used for bitcoind. This option is typically used +# when the server and client are run as the same user. +# +# If not, you must set rpcuser and rpcpassword to secure the JSON-RPC api. The first +# method(DEPRECATED) is to set this pair for the server and client: #rpcuser=Ulysseys #rpcpassword=YourSuperGreatPasswordNumber_DO_NOT_USE_THIS_OR_YOU_WILL_GET_ROBBED_385593 +# +# The second method `rpcauth` can be added to server startup argument. It is set at intialization time +# using the output from the script in share/rpcuser/rpcuser.py after providing a username: +# +# ./share/rpcuser/rpcuser.py alice +# String to be appended to bitcoin.conf: +# rpcauth=alice:f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae +# Your password: +# DONT_USE_THIS_YOU_WILL_GET_ROBBED_8ak1gI25KFTvjovL3gAM967mies3E= +# +# On client-side, you add the normal user/password pair to send commands: +#rpcuser=alice +#rpcpassword=DONT_USE_THIS_YOU_WILL_GET_ROBBED_8ak1gI25KFTvjovL3gAM967mies3E= +# +# You can even add multiple entries of these to the server conf file, and client can use any of them: +# rpcauth=bob:b2dd077cb54591a2f3139e69a897ac$4e71f08d48b4347cf8eff3815c0e25ae2e9a4340474079f55705f40574f4ec99 # How many seconds bitcoin will wait for a complete RPC HTTP request. # after the HTTP connection is established. @@ -95,12 +116,7 @@ # running on another host using this option: #rpcconnect=127.0.0.1 -# Transaction Fee Changes in 0.10.0 - -# Send transactions as zero-fee transactions if possible (default: 0) -#sendfreetransactions=0 - -# Create transactions that have enough fees (or priority) so they are likely to begin confirmation within n blocks (default: 1). +# Create transactions that have enough fees so they are likely to begin confirmation within n blocks (default: 6). # This setting is over-ridden by the -paytxfee option. #txconfirmtarget=n @@ -115,6 +131,13 @@ # be validated sooner. #paytxfee=0.00 +# Enable pruning to reduce storage requirements by deleting old blocks. +# This mode is incompatible with -txindex and -rescan. +# 0 = default (no pruning). +# 1 = allows manual pruning via RPC. +# >=550 = target to stay under in MiB. +#prune=550 + # User interface options # Start Bitcoin minimized diff --git a/contrib/debian/manpages/bitcoin-cli.1 b/contrib/debian/manpages/bitcoin-cli.1 deleted file mode 100644 index 16c338dd3e..0000000000 --- a/contrib/debian/manpages/bitcoin-cli.1 +++ /dev/null @@ -1,21 +0,0 @@ -.TH BITCOIN-CLI "1" "February 2016" "bitcoin-cli 0.12" -.SH NAME -bitcoin-cli \- a remote procedure call client for Bitcoin Core. -.SH SYNOPSIS -bitcoin-cli [options] <command> [params] \- Send command to Bitcoin Core. -.TP -bitcoin-cli [options] help \- Asks Bitcoin Core for a list of supported commands. -.SH DESCRIPTION -This manual page documents the bitcoin-cli program. bitcoin-cli is an RPC client used to send commands to Bitcoin Core. - -.SH OPTIONS -.TP -\fB\-?\fR -Show possible options. - -.SH "SEE ALSO" -\fBbitcoind\fP, \fBbitcoin.conf\fP -.SH AUTHOR -This manual page was written by Ciemon Dunville <ciemon@gmail.com>. Permission is granted to copy, distribute and/or modify this document under the terms of the MIT License. - -The complete text of the MIT License can be found on the web at \fIhttp://opensource.org/licenses/MIT\fP. diff --git a/contrib/debian/manpages/bitcoin-qt.1 b/contrib/debian/manpages/bitcoin-qt.1 deleted file mode 100644 index 685a282080..0000000000 --- a/contrib/debian/manpages/bitcoin-qt.1 +++ /dev/null @@ -1,13 +0,0 @@ -.TH BITCOIN-QT "1" "February 2016" "bitcoin-qt 0.12" -.SH NAME -bitcoin-qt \- peer-to-peer network based digital currency -.SH DESCRIPTION -.SS "Usage:" -.IP -bitcoin\-qt [command\-line options] -.SH OPTIONS -.TP -\-? -List options. -.SH "SEE ALSO" -bitcoind(1) diff --git a/contrib/debian/manpages/bitcoin.conf.5 b/contrib/debian/manpages/bitcoin.conf.5 deleted file mode 100644 index 839dc26c1a..0000000000 --- a/contrib/debian/manpages/bitcoin.conf.5 +++ /dev/null @@ -1,19 +0,0 @@ -.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. 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 "SEE ALSO" -bitcoind(1) -.SH AUTHOR -This manual page was written by Micah Anderson <micah@debian.org> for the Debian system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. - -On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. - diff --git a/contrib/debian/manpages/bitcoind.1 b/contrib/debian/manpages/bitcoind.1 deleted file mode 100644 index 5c3e52f441..0000000000 --- a/contrib/debian/manpages/bitcoind.1 +++ /dev/null @@ -1,30 +0,0 @@ -.TH BITCOIND "1" "February 2016" "bitcoind 0.12" -.SH NAME -bitcoind \- peer-to-peer network based digital currency -.SH SYNOPSIS -bitcoin [options] <command> [params] -.TP -bitcoin [options] help <command> \- Get help for a command -.SH DESCRIPTION -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 -\-? -List of possible options. -.SH COMMANDS -.TP -\fBhelp\fR -List commands. - -.TP -\fBhelp 'command'\fR -Get help for a command. - -.SH "SEE ALSO" -bitcoin.conf(5) -.SH AUTHOR -This manual page was written by Micah Anderson <micah@debian.org> for the Debian system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. - -On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. - diff --git a/contrib/debian/rules b/contrib/debian/rules index 52b357cf01..6885e38521 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -5,9 +5,6 @@ #build/bitcoind:: # $(if $(filter nocheck,$(DEB_BUILD_OPTIONS)),,src/test_bitcoin) -DEB_INSTALL_EXAMPLES_bitcoind += debian/examples/* -DEB_INSTALL_MANPAGES_bitcoind += debian/manpages/* - %: dh --with bash-completion $@ @@ -15,10 +12,12 @@ override_dh_auto_clean: if [ -f Makefile ]; then $(MAKE) distclean; fi rm -rf Makefile.in aclocal.m4 configure src/Makefile.in src/bitcoin-config.h.in src/build-aux src/qt/Makefile.in src/qt/test/Makefile.in src/test/Makefile.in +QT=$(shell dpkg-vendor --derives-from Ubuntu && echo qt4 || echo qt5) + # Yea, autogen should be run on the source archive, but I like doing git archive override_dh_auto_configure: ./autogen.sh - ./configure + ./configure --with-gui=$(QT) override_dh_auto_test: make check diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md index bb8b9246b8..67c5e15a15 100644 --- a/contrib/devtools/README.md +++ b/contrib/devtools/README.md @@ -8,11 +8,6 @@ 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 =================== @@ -25,20 +20,70 @@ 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 -======================== +copyright\_header.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. +Provides utilities for managing copyright headers of `The Bitcoin Core +developers` in repository source files. It has three subcommands: -For example a file changed in 2015 (with 2015 being the current year): +``` +$ ./copyright_header.py report <base_directory> [verbose] +$ ./copyright_header.py update <base_directory> +$ ./copyright_header.py insert <file> +``` +Running these subcommands without arguments displays a usage string. -```// Copyright (c) 2009-2013 The Bitcoin Core developers``` +copyright\_header.py report \<base\_directory\> [verbose] +--------------------------------------------------------- -would be changed to: +Produces a report of all copyright header notices found inside the source files +of a repository. Useful to quickly visualize the state of the headers. +Specifying `verbose` will list the full filenames of files of each category. + +copyright\_header.py update \<base\_directory\> [verbose] +--------------------------------------------------------- +Updates all the copyright headers of `The Bitcoin Core developers` which were +changed in a year more recent than is listed. For example: +``` +// Copyright (c) <firstYear>-<lastYear> The Bitcoin Core developers +``` +will be updated to: +``` +// Copyright (c) <firstYear>-<lastModifiedYear> The Bitcoin Core developers +``` +where `<lastModifiedYear>` is obtained from the `git log` history. + +This subcommand also handles copyright headers that have only a single year. In +those cases: +``` +// Copyright (c) <year> The Bitcoin Core developers +``` +will be updated to: +``` +// Copyright (c) <year>-<lastModifiedYear> The Bitcoin Core developers +``` +where the update is appropriate. + +copyright\_header.py insert \<file\> +------------------------------------ +Inserts a copyright header for `The Bitcoin Core developers` at the top of the +file in either Python or C++ style as determined by the file extension. If the +file is a Python file and it has `#!` starting the first line, the header is +inserted in the line below it. + +The copyright dates will be set to be `<year_introduced>-<current_year>` where +`<year_introduced>` is according to the `git log` history. If +`<year_introduced>` is equal to `<current_year>`, it will be set as a single +year rather than two hyphenated years. + +If the file already has a copyright for `The Bitcoin Core developers`, the +script will exit. + +gen-manpages.sh +=============== -```// Copyright (c) 2009-2015 The Bitcoin Core developers``` +A small script to automatically create manpages in ../../doc/man by running the release binaries with the -help option. +This requires help2man which can be found at: https://www.gnu.org/software/help2man/ git-subtree-check.sh ==================== @@ -51,8 +96,9 @@ maintained: * for `src/secp256k1`: https://github.com/bitcoin-core/secp256k1.git (branch master) * for `src/leveldb`: https://github.com/bitcoin-core/leveldb.git (branch bitcoin-fork) * for `src/univalue`: https://github.com/bitcoin-core/univalue.git (branch master) +* for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master) -Usage: `git-subtree-check.sh DIR COMMIT` +Usage: `git-subtree-check.sh DIR (COMMIT)` `COMMIT` may be omitted, in which case `HEAD` is used. @@ -79,7 +125,7 @@ check or whatever). This means that there are no potential race conditions (where a pullreq gets updated while you're reviewing it, but before you click -merge), and when using GPG signatures, that even a compromised github +merge), and when using GPG signatures, that even a compromised GitHub couldn't mess with the sources. Setup diff --git a/contrib/devtools/check-doc.py b/contrib/devtools/check-doc.py index 9ea0131ac3..445175ec2b 100755 --- a/contrib/devtools/check-doc.py +++ b/contrib/devtools/check-doc.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2015 The Bitcoin Core developers +# Copyright (c) 2015-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. @@ -21,7 +21,7 @@ CMD_GREP_DOCS = r"egrep -r -I 'HelpMessageOpt\(\"\-[^\"=]+?(=|\")' %s" % (CMD_RO 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', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize']) +SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-sendfreetransactions']) def main(): used = check_output(CMD_GREP_ARGS, shell=True) diff --git a/contrib/devtools/clang-format-diff.py b/contrib/devtools/clang-format-diff.py index 13d2573b9f..7ea49b65e1 100755 --- a/contrib/devtools/clang-format-diff.py +++ b/contrib/devtools/clang-format-diff.py @@ -128,7 +128,7 @@ def main(): line_count = int(match.group(3)) if line_count == 0: continue - end_line = start_line + line_count - 1; + end_line = start_line + line_count - 1 lines_by_file.setdefault(filename, []).extend( ['-lines', str(start_line) + ':' + str(end_line)]) @@ -147,7 +147,7 @@ def main(): stderr=None, stdin=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: - sys.exit(p.returncode); + sys.exit(p.returncode) if not args.i: with open(filename) as f: diff --git a/contrib/devtools/clang-format.py b/contrib/devtools/clang-format.py deleted file mode 100755 index cee99047ac..0000000000 --- a/contrib/devtools/clang-format.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/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/commit-script-check.sh b/contrib/devtools/commit-script-check.sh new file mode 100755 index 0000000000..add4bb4883 --- /dev/null +++ b/contrib/devtools/commit-script-check.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# Copyright (c) 2017 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 simple script checks for commits beginning with: scripted-diff: +# If found, looks for a script between the lines -BEGIN VERIFY SCRIPT- and +# -END VERIFY SCRIPT-. If no ending is found, it reads until the end of the +# commit message. + +# The resulting script should exactly transform the previous commit into the current +# one. Any remaining diff signals an error. + +if test "x$1" = "x"; then + echo "Usage: $0 <commit>..." + exit 1 +fi + +RET=0 +PREV_BRANCH=`git name-rev --name-only HEAD` +PREV_HEAD=`git rev-parse HEAD` +for i in `git rev-list --reverse $1`; do + git rev-list -n 1 --pretty="%s" $i | grep -q "^scripted-diff:" || continue + git checkout --quiet $i^ || exit + SCRIPT="`git rev-list --format=%b -n1 $i | sed '/^-BEGIN VERIFY SCRIPT-$/,/^-END VERIFY SCRIPT-$/{//!b};d'`" + if test "x$SCRIPT" = "x"; then + echo "Error: missing script for: $i" + echo "Failed" + RET=1 + else + echo "Running script for: $i" + echo "$SCRIPT" + eval "$SCRIPT" + git --no-pager diff --exit-code $i && echo "OK" || (echo "Failed"; false) || RET=1 + fi + git reset --quiet --hard HEAD +done +git checkout --quiet $PREV_BRANCH 2>/dev/null || git checkout --quiet $PREV_HEAD +exit $RET diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py new file mode 100755 index 0000000000..6d801d3ac7 --- /dev/null +++ b/contrib/devtools/copyright_header.py @@ -0,0 +1,610 @@ +#!/usr/bin/env python3 +# 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. + +import re +import fnmatch +import sys +import subprocess +import datetime +import os + +################################################################################ +# file filtering +################################################################################ + +EXCLUDE = [ + # libsecp256k1: + 'src/secp256k1/include/secp256k1.h', + 'src/secp256k1/include/secp256k1_ecdh.h', + 'src/secp256k1/include/secp256k1_recovery.h', + 'src/secp256k1/include/secp256k1_schnorr.h', + 'src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c', + 'src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h', + 'src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c', + 'src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h', + # auto generated: + 'src/univalue/lib/univalue_escapes.h', + 'src/qt/bitcoinstrings.cpp', + 'src/chainparamsseeds.h', + # other external copyrights: + 'src/tinyformat.h', + 'src/leveldb/util/env_win.cc', + 'src/crypto/ctaes/bench.c', + 'test/functional/test_framework/bignum.py', + # python init: + '*__init__.py', +] +EXCLUDE_COMPILED = re.compile('|'.join([fnmatch.translate(m) for m in EXCLUDE])) + +INCLUDE = ['*.h', '*.cpp', '*.cc', '*.c', '*.py'] +INCLUDE_COMPILED = re.compile('|'.join([fnmatch.translate(m) for m in INCLUDE])) + +def applies_to_file(filename): + return ((EXCLUDE_COMPILED.match(filename) is None) and + (INCLUDE_COMPILED.match(filename) is not None)) + +################################################################################ +# obtain list of files in repo according to INCLUDE and EXCLUDE +################################################################################ + +GIT_LS_CMD = 'git ls-files' + +def call_git_ls(): + out = subprocess.check_output(GIT_LS_CMD.split(' ')) + return [f for f in out.decode("utf-8").split('\n') if f != ''] + +def get_filenames_to_examine(): + filenames = call_git_ls() + return sorted([filename for filename in filenames if + applies_to_file(filename)]) + +################################################################################ +# define and compile regexes for the patterns we are looking for +################################################################################ + + +COPYRIGHT_WITH_C = 'Copyright \(c\)' +COPYRIGHT_WITHOUT_C = 'Copyright' +ANY_COPYRIGHT_STYLE = '(%s|%s)' % (COPYRIGHT_WITH_C, COPYRIGHT_WITHOUT_C) + +YEAR = "20[0-9][0-9]" +YEAR_RANGE = '(%s)(-%s)?' % (YEAR, YEAR) +YEAR_LIST = '(%s)(, %s)+' % (YEAR, YEAR) +ANY_YEAR_STYLE = '(%s|%s)' % (YEAR_RANGE, YEAR_LIST) +ANY_COPYRIGHT_STYLE_OR_YEAR_STYLE = ("%s %s" % (ANY_COPYRIGHT_STYLE, + ANY_YEAR_STYLE)) + +ANY_COPYRIGHT_COMPILED = re.compile(ANY_COPYRIGHT_STYLE_OR_YEAR_STYLE) + +def compile_copyright_regex(copyright_style, year_style, name): + return re.compile('%s %s %s' % (copyright_style, year_style, name)) + +EXPECTED_HOLDER_NAMES = [ + "Satoshi Nakamoto\n", + "The Bitcoin Core developers\n", + "The Bitcoin Core developers \n", + "Bitcoin Core Developers\n", + "the Bitcoin Core developers\n", + "The Bitcoin developers\n", + "The LevelDB Authors\. All rights reserved\.\n", + "BitPay Inc\.\n", + "BitPay, Inc\.\n", + "University of Illinois at Urbana-Champaign\.\n", + "MarcoFalke\n", + "Pieter Wuille\n", + "Pieter Wuille +\*\n", + "Pieter Wuille, Gregory Maxwell +\*\n", + "Pieter Wuille, Andrew Poelstra +\*\n", + "Andrew Poelstra +\*\n", + "Wladimir J. van der Laan\n", + "Jeff Garzik\n", + "Diederik Huys, Pieter Wuille +\*\n", + "Thomas Daede, Cory Fields +\*\n", + "Jan-Klaas Kollhof\n", + "Sam Rushing\n", + "ArtForz -- public domain half-a-node\n", +] + +DOMINANT_STYLE_COMPILED = {} +YEAR_LIST_STYLE_COMPILED = {} +WITHOUT_C_STYLE_COMPILED = {} + +for holder_name in EXPECTED_HOLDER_NAMES: + DOMINANT_STYLE_COMPILED[holder_name] = ( + compile_copyright_regex(COPYRIGHT_WITH_C, YEAR_RANGE, holder_name)) + YEAR_LIST_STYLE_COMPILED[holder_name] = ( + compile_copyright_regex(COPYRIGHT_WITH_C, YEAR_LIST, holder_name)) + WITHOUT_C_STYLE_COMPILED[holder_name] = ( + compile_copyright_regex(COPYRIGHT_WITHOUT_C, ANY_YEAR_STYLE, + holder_name)) + +################################################################################ +# search file contents for copyright message of particular category +################################################################################ + +def get_count_of_copyrights_of_any_style_any_holder(contents): + return len(ANY_COPYRIGHT_COMPILED.findall(contents)) + +def file_has_dominant_style_copyright_for_holder(contents, holder_name): + match = DOMINANT_STYLE_COMPILED[holder_name].search(contents) + return match is not None + +def file_has_year_list_style_copyright_for_holder(contents, holder_name): + match = YEAR_LIST_STYLE_COMPILED[holder_name].search(contents) + return match is not None + +def file_has_without_c_style_copyright_for_holder(contents, holder_name): + match = WITHOUT_C_STYLE_COMPILED[holder_name].search(contents) + return match is not None + +################################################################################ +# get file info +################################################################################ + +def read_file(filename): + return open(os.path.abspath(filename), 'r').read() + +def gather_file_info(filename): + info = {} + info['filename'] = filename + c = read_file(filename) + info['contents'] = c + + info['all_copyrights'] = get_count_of_copyrights_of_any_style_any_holder(c) + + info['classified_copyrights'] = 0 + info['dominant_style'] = {} + info['year_list_style'] = {} + info['without_c_style'] = {} + for holder_name in EXPECTED_HOLDER_NAMES: + has_dominant_style = ( + file_has_dominant_style_copyright_for_holder(c, holder_name)) + has_year_list_style = ( + file_has_year_list_style_copyright_for_holder(c, holder_name)) + has_without_c_style = ( + file_has_without_c_style_copyright_for_holder(c, holder_name)) + info['dominant_style'][holder_name] = has_dominant_style + info['year_list_style'][holder_name] = has_year_list_style + info['without_c_style'][holder_name] = has_without_c_style + if has_dominant_style or has_year_list_style or has_without_c_style: + info['classified_copyrights'] = info['classified_copyrights'] + 1 + return info + +################################################################################ +# report execution +################################################################################ + +SEPARATOR = '-'.join(['' for _ in range(80)]) + +def print_filenames(filenames, verbose): + if not verbose: + return + for filename in filenames: + print("\t%s" % filename) + +def print_report(file_infos, verbose): + print(SEPARATOR) + examined = [i['filename'] for i in file_infos] + print("%d files examined according to INCLUDE and EXCLUDE fnmatch rules" % + len(examined)) + print_filenames(examined, verbose) + + print(SEPARATOR) + print('') + zero_copyrights = [i['filename'] for i in file_infos if + i['all_copyrights'] == 0] + print("%4d with zero copyrights" % len(zero_copyrights)) + print_filenames(zero_copyrights, verbose) + one_copyright = [i['filename'] for i in file_infos if + i['all_copyrights'] == 1] + print("%4d with one copyright" % len(one_copyright)) + print_filenames(one_copyright, verbose) + two_copyrights = [i['filename'] for i in file_infos if + i['all_copyrights'] == 2] + print("%4d with two copyrights" % len(two_copyrights)) + print_filenames(two_copyrights, verbose) + three_copyrights = [i['filename'] for i in file_infos if + i['all_copyrights'] == 3] + print("%4d with three copyrights" % len(three_copyrights)) + print_filenames(three_copyrights, verbose) + four_or_more_copyrights = [i['filename'] for i in file_infos if + i['all_copyrights'] >= 4] + print("%4d with four or more copyrights" % len(four_or_more_copyrights)) + print_filenames(four_or_more_copyrights, verbose) + print('') + print(SEPARATOR) + print('Copyrights with dominant style:\ne.g. "Copyright (c)" and ' + '"<year>" or "<startYear>-<endYear>":\n') + for holder_name in EXPECTED_HOLDER_NAMES: + dominant_style = [i['filename'] for i in file_infos if + i['dominant_style'][holder_name]] + if len(dominant_style) > 0: + print("%4d with '%s'" % (len(dominant_style), + holder_name.replace('\n', '\\n'))) + print_filenames(dominant_style, verbose) + print('') + print(SEPARATOR) + print('Copyrights with year list style:\ne.g. "Copyright (c)" and ' + '"<year1>, <year2>, ...":\n') + for holder_name in EXPECTED_HOLDER_NAMES: + year_list_style = [i['filename'] for i in file_infos if + i['year_list_style'][holder_name]] + if len(year_list_style) > 0: + print("%4d with '%s'" % (len(year_list_style), + holder_name.replace('\n', '\\n'))) + print_filenames(year_list_style, verbose) + print('') + print(SEPARATOR) + print('Copyrights with no "(c)" style:\ne.g. "Copyright" and "<year>" or ' + '"<startYear>-<endYear>":\n') + for holder_name in EXPECTED_HOLDER_NAMES: + without_c_style = [i['filename'] for i in file_infos if + i['without_c_style'][holder_name]] + if len(without_c_style) > 0: + print("%4d with '%s'" % (len(without_c_style), + holder_name.replace('\n', '\\n'))) + print_filenames(without_c_style, verbose) + + print('') + print(SEPARATOR) + + unclassified_copyrights = [i['filename'] for i in file_infos if + i['classified_copyrights'] < i['all_copyrights']] + print("%d with unexpected copyright holder names" % + len(unclassified_copyrights)) + print_filenames(unclassified_copyrights, verbose) + print(SEPARATOR) + +def exec_report(base_directory, verbose): + original_cwd = os.getcwd() + os.chdir(base_directory) + filenames = get_filenames_to_examine() + file_infos = [gather_file_info(f) for f in filenames] + print_report(file_infos, verbose) + os.chdir(original_cwd) + +################################################################################ +# report cmd +################################################################################ + +REPORT_USAGE = """ +Produces a report of all copyright header notices found inside the source files +of a repository. + +Usage: + $ ./copyright_header.py report <base_directory> [verbose] + +Arguments: + <base_directory> - The base directory of a bitcoin source code repository. + [verbose] - Includes a list of every file of each subcategory in the report. +""" + +def report_cmd(argv): + if len(argv) == 2: + sys.exit(REPORT_USAGE) + + base_directory = argv[2] + if not os.path.exists(base_directory): + sys.exit("*** bad <base_directory>: %s" % base_directory) + + if len(argv) == 3: + verbose = False + elif argv[3] == 'verbose': + verbose = True + else: + sys.exit("*** unknown argument: %s" % argv[2]) + + exec_report(base_directory, verbose) + +################################################################################ +# query git for year of last change +################################################################################ + +GIT_LOG_CMD = "git log --pretty=format:%%ai %s" + +def call_git_log(filename): + out = subprocess.check_output((GIT_LOG_CMD % filename).split(' ')) + return out.decode("utf-8").split('\n') + +def get_git_change_years(filename): + git_log_lines = call_git_log(filename) + if len(git_log_lines) == 0: + return [datetime.date.today().year] + # timestamp is in ISO 8601 format. e.g. "2016-09-05 14:25:32 -0600" + return [line.split(' ')[0].split('-')[0] for line in git_log_lines] + +def get_most_recent_git_change_year(filename): + return max(get_git_change_years(filename)) + +################################################################################ +# read and write to file +################################################################################ + +def read_file_lines(filename): + f = open(os.path.abspath(filename), 'r') + file_lines = f.readlines() + f.close() + return file_lines + +def write_file_lines(filename, file_lines): + f = open(os.path.abspath(filename), 'w') + f.write(''.join(file_lines)) + f.close() + +################################################################################ +# update header years execution +################################################################################ + +COPYRIGHT = 'Copyright \(c\)' +YEAR = "20[0-9][0-9]" +YEAR_RANGE = '(%s)(-%s)?' % (YEAR, YEAR) +HOLDER = 'The Bitcoin Core developers' +UPDATEABLE_LINE_COMPILED = re.compile(' '.join([COPYRIGHT, YEAR_RANGE, HOLDER])) + +def get_updatable_copyright_line(file_lines): + index = 0 + for line in file_lines: + if UPDATEABLE_LINE_COMPILED.search(line) is not None: + return index, line + index = index + 1 + return None, None + +def parse_year_range(year_range): + year_split = year_range.split('-') + start_year = year_split[0] + if len(year_split) == 1: + return start_year, start_year + return start_year, year_split[1] + +def year_range_to_str(start_year, end_year): + if start_year == end_year: + return start_year + return "%s-%s" % (start_year, end_year) + +def create_updated_copyright_line(line, last_git_change_year): + copyright_splitter = 'Copyright (c) ' + copyright_split = line.split(copyright_splitter) + # Preserve characters on line that are ahead of the start of the copyright + # notice - they are part of the comment block and vary from file-to-file. + before_copyright = copyright_split[0] + after_copyright = copyright_split[1] + + space_split = after_copyright.split(' ') + year_range = space_split[0] + start_year, end_year = parse_year_range(year_range) + if end_year == last_git_change_year: + return line + return (before_copyright + copyright_splitter + + year_range_to_str(start_year, last_git_change_year) + ' ' + + ' '.join(space_split[1:])) + +def update_updatable_copyright(filename): + file_lines = read_file_lines(filename) + index, line = get_updatable_copyright_line(file_lines) + if not line: + print_file_action_message(filename, "No updatable copyright.") + return + last_git_change_year = get_most_recent_git_change_year(filename) + new_line = create_updated_copyright_line(line, last_git_change_year) + if line == new_line: + print_file_action_message(filename, "Copyright up-to-date.") + return + file_lines[index] = new_line + write_file_lines(filename, file_lines) + print_file_action_message(filename, + "Copyright updated! -> %s" % last_git_change_year) + +def exec_update_header_year(base_directory): + original_cwd = os.getcwd() + os.chdir(base_directory) + for filename in get_filenames_to_examine(): + update_updatable_copyright(filename) + os.chdir(original_cwd) + +################################################################################ +# update cmd +################################################################################ + +UPDATE_USAGE = """ +Updates all the copyright headers of "The Bitcoin Core developers" which were +changed in a year more recent than is listed. For example: + +// Copyright (c) <firstYear>-<lastYear> The Bitcoin Core developers + +will be updated to: + +// Copyright (c) <firstYear>-<lastModifiedYear> The Bitcoin Core developers + +where <lastModifiedYear> is obtained from the 'git log' history. + +This subcommand also handles copyright headers that have only a single year. In those cases: + +// Copyright (c) <year> The Bitcoin Core developers + +will be updated to: + +// Copyright (c) <year>-<lastModifiedYear> The Bitcoin Core developers + +where the update is appropriate. + +Usage: + $ ./copyright_header.py update <base_directory> + +Arguments: + <base_directory> - The base directory of a bitcoin source code repository. +""" + +def print_file_action_message(filename, action): + print("%-52s %s" % (filename, action)) + +def update_cmd(argv): + if len(argv) != 3: + sys.exit(UPDATE_USAGE) + + base_directory = argv[2] + if not os.path.exists(base_directory): + sys.exit("*** bad base_directory: %s" % base_directory) + exec_update_header_year(base_directory) + +################################################################################ +# inserted copyright header format +################################################################################ + +def get_header_lines(header, start_year, end_year): + lines = header.split('\n')[1:-1] + lines[0] = lines[0] % year_range_to_str(start_year, end_year) + return [line + '\n' for line in lines] + +CPP_HEADER = ''' +// Copyright (c) %s The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +''' + +def get_cpp_header_lines_to_insert(start_year, end_year): + return reversed(get_header_lines(CPP_HEADER, start_year, end_year)) + +PYTHON_HEADER = ''' +# Copyright (c) %s The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +''' + +def get_python_header_lines_to_insert(start_year, end_year): + return reversed(get_header_lines(PYTHON_HEADER, start_year, end_year)) + +################################################################################ +# query git for year of last change +################################################################################ + +def get_git_change_year_range(filename): + years = get_git_change_years(filename) + return min(years), max(years) + +################################################################################ +# check for existing core copyright +################################################################################ + +def file_already_has_core_copyright(file_lines): + index, _ = get_updatable_copyright_line(file_lines) + return index != None + +################################################################################ +# insert header execution +################################################################################ + +def file_has_hashbang(file_lines): + if len(file_lines) < 1: + return False + if len(file_lines[0]) <= 2: + return False + return file_lines[0][:2] == '#!' + +def insert_python_header(filename, file_lines, start_year, end_year): + if file_has_hashbang(file_lines): + insert_idx = 1 + else: + insert_idx = 0 + header_lines = get_python_header_lines_to_insert(start_year, end_year) + for line in header_lines: + file_lines.insert(insert_idx, line) + write_file_lines(filename, file_lines) + +def insert_cpp_header(filename, file_lines, start_year, end_year): + header_lines = get_cpp_header_lines_to_insert(start_year, end_year) + for line in header_lines: + file_lines.insert(0, line) + write_file_lines(filename, file_lines) + +def exec_insert_header(filename, style): + file_lines = read_file_lines(filename) + if file_already_has_core_copyright(file_lines): + sys.exit('*** %s already has a copyright by The Bitcoin Core developers' + % (filename)) + start_year, end_year = get_git_change_year_range(filename) + if style == 'python': + insert_python_header(filename, file_lines, start_year, end_year) + else: + insert_cpp_header(filename, file_lines, start_year, end_year) + +################################################################################ +# insert cmd +################################################################################ + +INSERT_USAGE = """ +Inserts a copyright header for "The Bitcoin Core developers" at the top of the +file in either Python or C++ style as determined by the file extension. If the +file is a Python file and it has a '#!' starting the first line, the header is +inserted in the line below it. + +The copyright dates will be set to be: + +"<year_introduced>-<current_year>" + +where <year_introduced> is according to the 'git log' history. If +<year_introduced> is equal to <current_year>, the date will be set to be: + +"<current_year>" + +If the file already has a copyright for "The Bitcoin Core developers", the +script will exit. + +Usage: + $ ./copyright_header.py insert <file> + +Arguments: + <file> - A source file in the bitcoin repository. +""" + +def insert_cmd(argv): + if len(argv) != 3: + sys.exit(INSERT_USAGE) + + filename = argv[2] + if not os.path.isfile(filename): + sys.exit("*** bad filename: %s" % filename) + _, extension = os.path.splitext(filename) + if extension not in ['.h', '.cpp', '.cc', '.c', '.py']: + sys.exit("*** cannot insert for file extension %s" % extension) + + if extension == '.py': + style = 'python' + else: + style = 'cpp' + exec_insert_header(filename, style) + +################################################################################ +# UI +################################################################################ + +USAGE = """ +copyright_header.py - utilities for managing copyright headers of 'The Bitcoin +Core developers' in repository source files. + +Usage: + $ ./copyright_header <subcommand> + +Subcommands: + report + update + insert + +To see subcommand usage, run them without arguments. +""" + +SUBCOMMANDS = ['report', 'update', 'insert'] + +if __name__ == "__main__": + if len(sys.argv) == 1: + sys.exit(USAGE) + subcommand = sys.argv[1] + if subcommand not in SUBCOMMANDS: + sys.exit(USAGE) + if subcommand == 'report': + report_cmd(sys.argv) + elif subcommand == 'update': + update_cmd(sys.argv) + elif subcommand == 'insert': + insert_cmd(sys.argv) diff --git a/contrib/devtools/fix-copyright-headers.py b/contrib/devtools/fix-copyright-headers.py deleted file mode 100755 index b6414a551f..0000000000 --- a/contrib/devtools/fix-copyright-headers.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python -''' -Run this script to update all the copyright headers of files -that were changed this year. - -For example: - -// Copyright (c) 2009-2012 The Bitcoin Core developers - -it will change it to - -// Copyright (c) 2009-2015 The Bitcoin Core developers -''' -import os -import time -import re - -year = time.gmtime()[0] -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" - -FOLDERS = ["./qa", "./src"] -EXTENSIONS = [".cpp",".h", ".py"] - -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 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/gen-manpages.sh b/contrib/devtools/gen-manpages.sh new file mode 100755 index 0000000000..967717e1e0 --- /dev/null +++ b/contrib/devtools/gen-manpages.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +TOPDIR=${TOPDIR:-$(git rev-parse --show-toplevel)} +SRCDIR=${SRCDIR:-$TOPDIR/src} +MANDIR=${MANDIR:-$TOPDIR/doc/man} + +BITCOIND=${BITCOIND:-$SRCDIR/bitcoind} +BITCOINCLI=${BITCOINCLI:-$SRCDIR/bitcoin-cli} +BITCOINTX=${BITCOINTX:-$SRCDIR/bitcoin-tx} +BITCOINQT=${BITCOINQT:-$SRCDIR/qt/bitcoin-qt} + +[ ! -x $BITCOIND ] && echo "$BITCOIND not found or not executable." && exit 1 + +# The autodetected version git tag can screw up manpage output a little bit +BTCVER=($($BITCOINCLI --version | head -n1 | awk -F'[ -]' '{ print $6, $7 }')) + +# Create a footer file with copyright content. +# This gets autodetected fine for bitcoind if --version-string is not set, +# but has different outcomes for bitcoin-qt and bitcoin-cli. +echo "[COPYRIGHT]" > footer.h2m +$BITCOIND --version | sed -n '1!p' >> footer.h2m + +for cmd in $BITCOIND $BITCOINCLI $BITCOINTX $BITCOINQT; do + cmdname="${cmd##*/}" + help2man -N --version-string=${BTCVER[0]} --include=footer.h2m -o ${MANDIR}/${cmdname}.1 ${cmd} + sed -i "s/\\\-${BTCVER[1]}//g" ${MANDIR}/${cmdname}.1 +done + +rm -f footer.h2m diff --git a/contrib/devtools/git-subtree-check.sh b/contrib/devtools/git-subtree-check.sh index 1cb82fe682..2384d66cad 100755 --- a/contrib/devtools/git-subtree-check.sh +++ b/contrib/devtools/git-subtree-check.sh @@ -1,4 +1,7 @@ #!/bin/sh +# 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. DIR="$1" COMMIT="$2" diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py index f82362fe41..8fce648fc2 100755 --- a/contrib/devtools/github-merge.py +++ b/contrib/devtools/github-merge.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016 Bitcoin Core Developers +# Copyright (c) 2016-2017 Bitcoin Core Developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,9 +15,10 @@ # 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 +import os from sys import stdin,stdout,stderr import argparse +import hashlib import subprocess import json,codecs try: @@ -69,6 +70,67 @@ def ask_prompt(text): print("",file=stderr) return reply +def get_symlink_files(): + files = sorted(subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', 'HEAD']).splitlines()) + ret = [] + for f in files: + if (int(f.decode('utf-8').split(" ")[0], 8) & 0o170000) == 0o120000: + ret.append(f.decode('utf-8').split("\t")[1]) + return ret + +def tree_sha512sum(commit='HEAD'): + # request metadata for entire tree, recursively + files = [] + blob_by_name = {} + for line in subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', commit]).splitlines(): + name_sep = line.index(b'\t') + metadata = line[:name_sep].split() # perms, 'blob', blobid + assert(metadata[1] == b'blob') + name = line[name_sep+1:] + files.append(name) + blob_by_name[name] = metadata[2] + + files.sort() + # open connection to git-cat-file in batch mode to request data for all blobs + # this is much faster than launching it per file + p = subprocess.Popen([GIT, 'cat-file', '--batch'], stdout=subprocess.PIPE, stdin=subprocess.PIPE) + overall = hashlib.sha512() + for f in files: + blob = blob_by_name[f] + # request blob + p.stdin.write(blob + b'\n') + p.stdin.flush() + # read header: blob, "blob", size + reply = p.stdout.readline().split() + assert(reply[0] == blob and reply[1] == b'blob') + size = int(reply[2]) + # hash the blob data + intern = hashlib.sha512() + ptr = 0 + while ptr < size: + bs = min(65536, size - ptr) + piece = p.stdout.read(bs) + if len(piece) == bs: + intern.update(piece) + else: + raise IOError('Premature EOF reading git cat-file output') + ptr += bs + dig = intern.hexdigest() + assert(p.stdout.read(1) == b'\n') # ignore LF that follows blob data + # update overall hash with file hash + overall.update(dig.encode("utf-8")) + overall.update(" ".encode("utf-8")) + overall.update(f) + overall.update("\n".encode("utf-8")) + p.stdin.close() + if p.wait(): + raise IOError('Non-zero return value executing git cat-file') + return overall.hexdigest() + +def print_merge_details(pull, title, branch, base_branch, head_branch): + 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]) + def parse_arguments(): epilog = ''' In addition, you can set the following git configuration variables: @@ -112,7 +174,7 @@ def main(): info = retrieve_pr_info(repo,pull) if info is None: exit(1) - title = info['title'] + title = info['title'].strip() # precedence order for destination branch argument: # - command line argument # - githubmerge.branch setting @@ -157,6 +219,9 @@ def main(): subprocess.check_call([GIT,'checkout','-q','-b',local_merge_branch]) try: + # Go up to the repository's root. + toplevel = subprocess.check_output([GIT,'rev-parse','--show-toplevel']).strip() + os.chdir(toplevel) # Create unsigned merge commit. if title: firstline = 'Merge #%s: %s' % (pull,title) @@ -175,14 +240,30 @@ def main(): 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]) + symlink_files = get_symlink_files() + for f in symlink_files: + print("ERROR: File %s was a symlink" % f) + if len(symlink_files) > 0: + exit(4) + + # Put tree SHA512 into the message + try: + first_sha512 = tree_sha512sum() + message += '\n\nTree-SHA512: ' + first_sha512 + except subprocess.CalledProcessError as e: + printf("ERROR: Unable to compute tree hash") + exit(4) + try: + subprocess.check_call([GIT,'commit','--amend','-m',message.encode('utf-8')]) + except subprocess.CalledProcessError as e: + printf("ERROR: Cannot update message.",file=stderr) + exit(4) + + print_merge_details(pull, title, branch, 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) @@ -197,12 +278,6 @@ def main(): 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) @@ -211,24 +286,26 @@ def main(): 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) + + second_sha512 = tree_sha512sum() + if first_sha512 != second_sha512: + print("ERROR: Tree hash changed unexpectedly",file=stderr) + exit(8) # 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) + print_merge_details(pull, title, branch, base_branch, head_branch) + while True: + reply = ask_prompt("Type 's' to sign off on the above merge, or 'x' to reject and exit.").lower() + if reply == 's': + try: + subprocess.check_call([GIT,'commit','-q','--gpg-sign','--amend','--no-edit']) + break + except subprocess.CalledProcessError as e: + print("Error signing, exiting.",file=stderr) + exit(1) + elif reply == 'x': + print("Not signing off on merge, 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]) @@ -242,9 +319,13 @@ def main(): 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]) + while True: + reply = ask_prompt("Type 'push' to push the result to %s, branch %s, or 'x' to exit without pushing." % (host_repo,branch)).lower() + if reply == 'push': + subprocess.check_call([GIT,'push',host_repo,'refs/heads/'+branch]) + break + elif reply == 'x': + exit(1) if __name__ == '__main__': main() diff --git a/contrib/devtools/optimize-pngs.py b/contrib/devtools/optimize-pngs.py index 799e0cc7d0..9286ab731f 100755 --- a/contrib/devtools/optimize-pngs.py +++ b/contrib/devtools/optimize-pngs.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# 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. ''' Run this script every time you change one of the png files. Using pngcrush, it will optimize the png files, remove various color profiles, remove ancillary chunks (alla) and text chunks (text). #pngcrush -brute -ow -rem gAMA -rem cHRM -rem iCCP -rem sRGB -rem alla -rem text @@ -36,7 +39,7 @@ for folder in folders: if extension.lower() == '.png': print("optimizing "+file+"..."), file_path = os.path.join(absFolder, file) - fileMetaMap = {'file' : file, 'osize': os.path.getsize(file_path), 'sha256Old' : file_hash(file_path)}; + fileMetaMap = {'file' : file, 'osize': os.path.getsize(file_path), 'sha256Old' : file_hash(file_path)} fileMetaMap['contentHashPre'] = content_hash(file_path) pngCrushOutput = "" diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index 301fea85c1..c90541e271 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -1,4 +1,7 @@ -#!/usr/bin/python2 +#!/usr/bin/env python +# Copyright (c) 2015-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. ''' Perform basic ELF security checks on a series of executables. Exit status will be 0 if successful, and the program will be silent. @@ -12,6 +15,7 @@ import os READELF_CMD = os.getenv('READELF', '/usr/bin/readelf') OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump') +NONFATAL = {'HIGH_ENTROPY_VA'} # checks which are non-fatal for now but only generate a warning def check_ELF_PIE(executable): ''' @@ -114,26 +118,50 @@ def check_ELF_Canary(executable): def get_PE_dll_characteristics(executable): ''' - Get PE DllCharacteristics bits + Get PE DllCharacteristics bits. + Returns a tuple (arch,bits) where arch is 'i386:x86-64' or 'i386' + and bits is the DllCharacteristics value. ''' 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') + arch = '' + bits = 0 for line in stdout.split('\n'): tokens = line.split() + if len(tokens)>=2 and tokens[0] == 'architecture:': + arch = tokens[1].rstrip(',') if len(tokens)>=2 and tokens[0] == 'DllCharacteristics': - return int(tokens[1],16) - return 0 + bits = int(tokens[1],16) + return (arch,bits) +IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020 +IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040 +IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100 -def check_PE_PIE(executable): +def check_PE_DYNAMIC_BASE(executable): '''PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR)''' - return bool(get_PE_dll_characteristics(executable) & 0x40) + (arch,bits) = get_PE_dll_characteristics(executable) + reqbits = IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE + return (bits & reqbits) == reqbits + +# On 64 bit, must support high-entropy 64-bit address space layout randomization in addition to DYNAMIC_BASE +# to have secure ASLR. +def check_PE_HIGH_ENTROPY_VA(executable): + '''PIE: DllCharacteristics bit 0x20 signifies high-entropy ASLR''' + (arch,bits) = get_PE_dll_characteristics(executable) + if arch == 'i386:x86-64': + reqbits = IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA + else: # Unnecessary on 32-bit + assert(arch == 'i386') + reqbits = 0 + return (bits & reqbits) == reqbits def check_PE_NX(executable): '''NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP)''' - return bool(get_PE_dll_characteristics(executable) & 0x100) + (arch,bits) = get_PE_dll_characteristics(executable) + return (bits & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT) == IMAGE_DLL_CHARACTERISTICS_NX_COMPAT CHECKS = { 'ELF': [ @@ -143,7 +171,8 @@ CHECKS = { ('Canary', check_ELF_Canary) ], 'PE': [ - ('PIE', check_PE_PIE), + ('DYNAMIC_BASE', check_PE_DYNAMIC_BASE), + ('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA), ('NX', check_PE_NX) ] } @@ -168,12 +197,18 @@ if __name__ == '__main__': continue failed = [] + warning = [] for (name, func) in CHECKS[etype]: if not func(filename): - failed.append(name) + if name in NONFATAL: + warning.append(name) + else: + failed.append(name) if failed: print('%s: failed %s' % (filename, ' '.join(failed))) retval = 1 + if warning: + print('%s: warning %s' % (filename, ' '.join(warning))) except IOError: print('%s: cannot open' % filename) retval = 1 diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index e26c0fbb94..8f8685006e 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/env python # 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/devtools/test-security-check.py b/contrib/devtools/test-security-check.py index fed7626aab..18f9835faa 100755 --- a/contrib/devtools/test-security-check.py +++ b/contrib/devtools/test-security-check.py @@ -1,10 +1,12 @@ -#!/usr/bin/python2 +#!/usr/bin/env python2 +# Copyright (c) 2015-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. ''' Test script for security-check.py ''' from __future__ import division,print_function import subprocess -import sys import unittest def write_testcode(filename): diff --git a/contrib/devtools/update-translations.py b/contrib/devtools/update-translations.py index 2b6e807b47..2011841005 100755 --- a/contrib/devtools/update-translations.py +++ b/contrib/devtools/update-translations.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # 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. @@ -65,6 +65,14 @@ def split_format_specifiers(specifiers): else: other.append(s) + # If both numeric format specifiers and "others" are used, assume we're dealing + # with a Qt-formatted message. In the case of Qt formatting (see https://doc.qt.io/qt-5/qstring.html#arg) + # only numeric formats are replaced at all. This means "(percentage: %1%)" is valid, without needing + # any kind of escaping that would be necessary for strprintf. Without this, this function + # would wrongly detect '%)' as a printf format specifier. + if numeric: + other = [] + # numeric (Qt) can be present in any order, others (strprintf) must be in specified order return set(numeric),other diff --git a/contrib/gitian-build.sh b/contrib/gitian-build.sh new file mode 100755 index 0000000000..6ee5df4703 --- /dev/null +++ b/contrib/gitian-build.sh @@ -0,0 +1,392 @@ +# 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. + +# What to do +sign=false +verify=false +build=false +setupenv=false + +# Systems to build +linux=true +windows=true +osx=true + +# Other Basic variables +SIGNER= +VERSION= +commit=false +url=https://github.com/bitcoin/bitcoin +proc=2 +mem=2000 +lxc=true +osslTarUrl=http://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz +osslPatchUrl=https://bitcoincore.org/cfields/osslsigncode-Backports-to-1.7.1.patch +scriptName=$(basename -- "$0") +signProg="gpg --detach-sign" +commitFiles=true + +# Help Message +read -d '' usage <<- EOF +Usage: $scriptName [-c|u|v|b|s|B|o|h|j|m|] signer version + +Run this script from the directory containing the bitcoin, gitian-builder, gitian.sigs, and bitcoin-detached-sigs. + +Arguments: +signer GPG signer to sign each build assert file +version Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified + +Options: +-c|--commit Indicate that the version argument is for a commit or branch +-u|--url Specify the URL of the repository. Default is https://github.com/bitcoin/bitcoin +-v|--verify Verify the gitian build +-b|--build Do a gitian build +-s|--sign Make signed binaries for Windows and Mac OSX +-B|--buildsign Build both signed and unsigned binaries +-o|--os Specify which Operating Systems the build is for. Default is lwx. l for linux, w for windows, x for osx +-j Number of processes to use. Default 2 +-m Memory to allocate in MiB. Default 2000 +--kvm Use KVM instead of LXC +--setup Setup the gitian building environment. Uses KVM. If you want to use lxc, use the --lxc option. Only works on Debian-based systems (Ubuntu, Debian) +--detach-sign Create the assert file for detached signing. Will not commit anything. +--no-commit Do not commit anything to git +-h|--help Print this help message +EOF + +# Get options and arguments +while :; do + case $1 in + # Verify + -v|--verify) + verify=true + ;; + # Build + -b|--build) + build=true + ;; + # Sign binaries + -s|--sign) + sign=true + ;; + # Build then Sign + -B|--buildsign) + sign=true + build=true + ;; + # PGP Signer + -S|--signer) + if [ -n "$2" ] + then + SIGNER=$2 + shift + else + echo 'Error: "--signer" requires a non-empty argument.' + exit 1 + fi + ;; + # Operating Systems + -o|--os) + if [ -n "$2" ] + then + linux=false + windows=false + osx=false + if [[ "$2" = *"l"* ]] + then + linux=true + fi + if [[ "$2" = *"w"* ]] + then + windows=true + fi + if [[ "$2" = *"x"* ]] + then + osx=true + fi + shift + else + echo 'Error: "--os" requires an argument containing an l (for linux), w (for windows), or x (for Mac OSX)\n' + exit 1 + fi + ;; + # Help message + -h|--help) + echo "$usage" + exit 0 + ;; + # Commit or branch + -c|--commit) + commit=true + ;; + # Number of Processes + -j) + if [ -n "$2" ] + then + proc=$2 + shift + else + echo 'Error: "-j" requires an argument' + exit 1 + fi + ;; + # Memory to allocate + -m) + if [ -n "$2" ] + then + mem=$2 + shift + else + echo 'Error: "-m" requires an argument' + exit 1 + fi + ;; + # URL + -u) + if [ -n "$2" ] + then + url=$2 + shift + else + echo 'Error: "-u" requires an argument' + exit 1 + fi + ;; + # kvm + --kvm) + lxc=false + ;; + # Detach sign + --detach-sign) + signProg="true" + commitFiles=false + ;; + # Commit files + --no-commit) + commitFiles=false + ;; + # Setup + --setup) + setup=true + ;; + *) # Default case: If no more options then break out of the loop. + break + esac + shift +done + +# Set up LXC +if [[ $lxc = true ]] +then + export USE_LXC=1 + export LXC_BRIDGE=lxcbr0 + sudo ifconfig lxcbr0 up 10.0.2.2 +fi + +# Check for OSX SDK +if [[ ! -e "gitian-builder/inputs/MacOSX10.11.sdk.tar.gz" && $osx == true ]] +then + echo "Cannot build for OSX, SDK does not exist. Will build for other OSes" + osx=false +fi + +# Get signer +if [[ -n"$1" ]] +then + SIGNER=$1 + shift +fi + +# Get version +if [[ -n "$1" ]] +then + VERSION=$1 + COMMIT=$VERSION + shift +fi + +# Check that a signer is specified +if [[ $SIGNER == "" ]] +then + echo "$scriptName: Missing signer." + echo "Try $scriptName --help for more information" + exit 1 +fi + +# Check that a version is specified +if [[ $VERSION == "" ]] +then + echo "$scriptName: Missing version." + echo "Try $scriptName --help for more information" + exit 1 +fi + +# Add a "v" if no -c +if [[ $commit = false ]] +then + COMMIT="v${VERSION}" +fi +echo ${COMMIT} + +# Setup build environment +if [[ $setup = true ]] +then + sudo apt-get install ruby apache2 git apt-cacher-ng python-vm-builder qemu-kvm qemu-utils + git clone https://github.com/bitcoin-core/gitian.sigs.git + git clone https://github.com/bitcoin-core/bitcoin-detached-sigs.git + git clone https://github.com/devrandom/gitian-builder.git + pushd ./gitian-builder + if [[ -n "$USE_LXC" ]] + then + sudo apt-get install lxc + bin/make-base-vm --suite trusty --arch amd64 --lxc + else + bin/make-base-vm --suite trusty --arch amd64 + fi + popd +fi + +# Set up build +pushd ./bitcoin +git fetch +git checkout ${COMMIT} +popd + +# Build +if [[ $build = true ]] +then + # Make output folder + mkdir -p ./bitcoin-binaries/${VERSION} + + # Build Dependencies + echo "" + echo "Building Dependencies" + echo "" + pushd ./gitian-builder + mkdir -p inputs + wget -N -P inputs $osslPatchUrl + wget -N -P inputs $osslTarUrl + make -C ../bitcoin/depends download SOURCES_PATH=`pwd`/cache/common + + # Linux + if [[ $linux = true ]] + then + echo "" + echo "Compiling ${VERSION} Linux" + echo "" + ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml + mv build/out/bitcoin-*.tar.gz build/out/src/bitcoin-*.tar.gz ../bitcoin-binaries/${VERSION} + fi + # Windows + if [[ $windows = true ]] + then + echo "" + echo "Compiling ${VERSION} Windows" + echo "" + ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-unsigned --destination ../gitian.sigs/ ../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 ../bitcoin-binaries/${VERSION} + fi + # Mac OSX + if [[ $osx = true ]] + then + echo "" + echo "Compiling ${VERSION} Mac OSX" + echo "" + ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../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 ../bitcoin-binaries/${VERSION} + fi + popd + + if [[ $commitFiles = true ]] + then + # Commit to gitian.sigs repo + echo "" + echo "Committing ${VERSION} Unsigned Sigs" + echo "" + pushd gitian.sigs + git add ${VERSION}-linux/${SIGNER} + git add ${VERSION}-win-unsigned/${SIGNER} + git add ${VERSION}-osx-unsigned/${SIGNER} + git commit -a -m "Add ${VERSION} unsigned sigs for ${SIGNER}" + popd + fi +fi + +# Verify the build +if [[ $verify = true ]] +then + # Linux + pushd ./gitian-builder + echo "" + echo "Verifying v${VERSION} Linux" + echo "" + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-linux ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml + # Windows + echo "" + echo "Verifying v${VERSION} Windows" + echo "" + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-win.yml + # Mac OSX + echo "" + echo "Verifying v${VERSION} Mac OSX" + echo "" + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml + # Signed Windows + echo "" + echo "Verifying v${VERSION} Signed Windows" + echo "" + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml + # Signed Mac OSX + echo "" + echo "Verifying v${VERSION} Signed Mac OSX" + echo "" + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml + popd +fi + +# Sign binaries +if [[ $sign = true ]] +then + + pushd ./gitian-builder + # Sign Windows + if [[ $windows = true ]] + then + echo "" + echo "Signing ${VERSION} Windows" + echo "" + ./bin/gbuild -i --commit signature=${COMMIT} ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml + mv build/out/bitcoin-*win64-setup.exe ../bitcoin-binaries/${VERSION} + mv build/out/bitcoin-*win32-setup.exe ../bitcoin-binaries/${VERSION} + fi + # Sign Mac OSX + if [[ $osx = true ]] + then + echo "" + echo "Signing ${VERSION} Mac OSX" + echo "" + ./bin/gbuild -i --commit signature=${COMMIT} ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml + mv build/out/bitcoin-osx-signed.dmg ../bitcoin-binaries/${VERSION}/bitcoin-${VERSION}-osx.dmg + fi + popd + + if [[ $commitFiles = true ]] + then + # Commit Sigs + pushd gitian.sigs + echo "" + echo "Committing ${VERSION} Signed Sigs" + echo "" + git add ${VERSION}-win-signed/${SIGNER} + git add ${VERSION}-osx-signed/${SIGNER} + git commit -a -m "Add ${VERSION} signed binary sigs for ${SIGNER}" + popd + fi +fi diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index aaff127b5e..3da8510cfb 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "bitcoin-linux-0.13" +name: "bitcoin-linux-0.15" enable_cache: true suites: - "trusty" diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 318fb03ef2..206db7c19e 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -1,5 +1,5 @@ --- -name: "bitcoin-osx-0.13" +name: "bitcoin-osx-0.15" enable_cache: true suites: - "trusty" diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 63177375ef..1d4d70494b 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -1,5 +1,5 @@ --- -name: "bitcoin-win-0.13" +name: "bitcoin-win-0.15" enable_cache: true suites: - "trusty" @@ -27,7 +27,7 @@ remotes: files: [] script: | WRAP_DIR=$HOME/wrapped - HOSTS="x86_64-w64-mingw32 i686-w64-mingw32" + HOSTS="i686-w64-mingw32 x86_64-w64-mingw32" CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests" FAKETIME_HOST_PROGS="g++ ar ranlib nm windres strip objcopy" FAKETIME_PROGS="date makensis zip" @@ -147,6 +147,7 @@ script: | make ${MAKEOPTS} -C src check-security make deploy make install DESTDIR=${INSTALLPATH} + rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe cp -f bitcoin-*setup*.exe $OUTDIR/ cd installed mv ${DISTNAME}/bin/*.dll ${DISTNAME}/lib/ @@ -160,9 +161,11 @@ script: | cd ../../ rm -rf distsrc-${i} done - cd $OUTDIR - rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe - find . -name "*-setup-unsigned.exe" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz + cp -rf contrib/windeploy $BUILD_DIR + cd $BUILD_DIR/windeploy + mkdir unsigned + cp $OUTDIR/bitcoin-*setup-unsigned.exe unsigned/ + find . | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz mv ${OUTDIR}/${DISTNAME}-x86_64-*-debug.zip ${OUTDIR}/${DISTNAME}-win64-debug.zip mv ${OUTDIR}/${DISTNAME}-i686-*-debug.zip ${OUTDIR}/${DISTNAME}-win32-debug.zip mv ${OUTDIR}/${DISTNAME}-x86_64-*.zip ${OUTDIR}/${DISTNAME}-win64.zip diff --git a/contrib/gitian-keys/README.md b/contrib/gitian-keys/README.md new file mode 100644 index 0000000000..439910330d --- /dev/null +++ b/contrib/gitian-keys/README.md @@ -0,0 +1,16 @@ +PGP keys +======== + +This folder contains the public keys of developers and active contributors. + +The keys are mainly used to sign git commits or the build results of gitian +builds. + +You can import the keys into gpg as follows. Also, make sure to fetch the +latest version from the key server to see if any key was revoked in the +meantime. + +```sh +gpg --import ./*.pgp +gpg --refresh-keys +``` diff --git a/contrib/gitian-keys/btcdrak-key.pgp b/contrib/gitian-keys/btcdrak-key.pgp Binary files differindex 60d76c0ec7..f00dc729d5 100644 --- a/contrib/gitian-keys/btcdrak-key.pgp +++ b/contrib/gitian-keys/btcdrak-key.pgp diff --git a/contrib/gitian-keys/jtimon-key.pgp b/contrib/gitian-keys/jtimon-key.pgp Binary files differnew file mode 100644 index 0000000000..88d0de1503 --- /dev/null +++ b/contrib/gitian-keys/jtimon-key.pgp diff --git a/contrib/init/README.md b/contrib/init/README.md index eb5d30acce..1a949f3c07 100644 --- a/contrib/init/README.md +++ b/contrib/init/README.md @@ -1,12 +1,12 @@ Sample configuration files for: - +``` SystemD: bitcoind.service 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. See doc/init.md for more information. diff --git a/contrib/linearize/README.md b/contrib/linearize/README.md index 06f278f3b3..f2a2ab2768 100644 --- a/contrib/linearize/README.md +++ b/contrib/linearize/README.md @@ -1,33 +1,55 @@ # Linearize -Construct a linear, no-fork, best version of the blockchain. +Construct a linear, no-fork, best version of the Bitcoin blockchain. The scripts +run using Python 3 but are compatible with Python 2. ## Step 1: Download hash list $ ./linearize-hashes.py linearize.cfg > hashlist.txt Required configuration file settings for linearize-hashes: -* RPC: rpcuser, rpcpassword +* RPC: `datadir` (Required if `rpcuser` and `rpcpassword` are not specified) +* RPC: `rpcuser`, `rpcpassword` (Required if `datadir` is not specified) Optional config file setting for linearize-hashes: -* RPC: host, port -* Block chain: min_height, max_height +* RPC: `host` (Default: `127.0.0.1`) +* RPC: `port` (Default: `8332`) +* Blockchain: `min_height`, `max_height` +* `rev_hash_bytes`: If true, the written block hash list will be +byte-reversed. (In other words, the hash returned by getblockhash will have its +bytes reversed.) False by default. Intended for generation of +standalone hash lists but safe to use with linearize-data.py, which will output +the same data no matter which byte format is chosen. + +The `linearize-hashes` script requires a connection, local or remote, to a +JSON-RPC server. Running `bitcoind` or `bitcoin-qt -server` will be sufficient. ## Step 2: Copy local block data $ ./linearize-data.py linearize.cfg Required configuration file settings: -* "input": bitcoind blocks/ directory containing blkNNNNN.dat -* "hashlist": text file containing list of block hashes, linearized-hashes.py -output. -* "output_file": bootstrap.dat +* `output_file`: The file that will contain the final blockchain. or -* "output": output directory for linearized blocks/blkNNNNN.dat output +* `output`: Output directory for linearized `blocks/blkNNNNN.dat` output. Optional config file setting for linearize-data: -* "netmagic": network magic number -* "max_out_sz": maximum output file size (default `1000*1000*1000`) -* "split_timestamp": Split files when a new month is first seen, in addition to -reaching a maximum file size. -* "file_timestamp": Set each file's last-modified time to that of the -most recent block in that file. +* `debug_output`: Some printouts may not always be desired. If true, such output +will be printed. +* `file_timestamp`: Set each file's last-accessed and last-modified times, +respectively, to the current time and to the timestamp of the most recent block +written to the script's blockchain. +* `genesis`: The hash of the genesis block in the blockchain. +* `input`: bitcoind blocks/ directory containing blkNNNNN.dat +* `hashlist`: text file containing list of block hashes created by +linearize-hashes.py. +* `max_out_sz`: Maximum size for files created by the `output_file` option. +(Default: `1000*1000*1000 bytes`) +* `netmagic`: Network magic number. +* `out_of_order_cache_sz`: If out-of-order blocks are being read, the block can +be written to a cache so that the blockchain doesn't have to be seeked again. +This option specifies the cache size. (Default: `100*1000*1000 bytes`) +* `rev_hash_bytes`: If true, the block hash list written by linearize-hashes.py +will be byte-reversed when read by linearize-data.py. See the linearize-hashes +entry for more information. +* `split_timestamp`: Split blockchain files when a new month is first seen, in +addition to reaching a maximum file size (`max_out_sz`). diff --git a/contrib/linearize/example-linearize.cfg b/contrib/linearize/example-linearize.cfg index 38da02e66c..d019b06b6c 100644 --- a/contrib/linearize/example-linearize.cfg +++ b/contrib/linearize/example-linearize.cfg @@ -1,7 +1,7 @@ - # bitcoind RPC settings (linearize-hashes) rpcuser=someuser rpcpassword=somepassword +#datadir=~/.bitcoin host=127.0.0.1 port=8332 #port=18332 @@ -21,9 +21,23 @@ input=/home/example/.bitcoin/blocks #genesis=000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943 #input=/home/example/.bitcoin/testnet3/blocks +# "output" option causes blockchain files to be written to the given location, +# with "output_file" ignored. If not used, "output_file" is used instead. +# output=/home/example/blockchain_directory output_file=/home/example/Downloads/bootstrap.dat hashlist=hashlist.txt -split_year=1 -# Maxmimum size in bytes of out-of-order blocks cache in memory +# Maximum size in bytes of out-of-order blocks cache in memory out_of_order_cache_sz = 100000000 + +# Do we want the reverse the hash bytes coming from getblockhash? +rev_hash_bytes = False + +# On a new month, do we want to set the access and modify times of the new +# blockchain file? +file_timestamp = 0 +# Do we want to split the blockchain files given a new month or specific height? +split_timestamp = 0 + +# Do we want debug printouts? +debug_output = False diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py index 0f6fde2a6e..afcec2b60a 100755 --- a/contrib/linearize/linearize-data.py +++ b/contrib/linearize/linearize-data.py @@ -1,30 +1,34 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # linearize-data.py: Construct a linear, no-fork version of the chain. # -# Copyright (c) 2013-2014 The Bitcoin Core developers +# Copyright (c) 2013-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 __future__ import print_function, division -import json import struct import re import os import os.path -import base64 -import httplib import sys import hashlib import datetime import time from collections import namedtuple +from binascii import hexlify, unhexlify settings = {} +##### Switch endian-ness ##### +def hex_switchEndian(s): + """ Switches the endianness of a hex string (in pairs of hex chars) """ + pairList = [s[i:i+2].encode() for i in range(0, len(s), 2)] + return b''.join(pairList[::-1]).decode() + def uint32(x): - return x & 0xffffffffL + return x & 0xffffffff def bytereverse(x): return uint32(( ((x) << 24) | (((x) << 8) & 0x00ff0000) | @@ -35,14 +39,14 @@ def bufreverse(in_buf): for i in range(0, len(in_buf), 4): word = struct.unpack('@I', in_buf[i:i+4])[0] out_words.append(struct.pack('@I', bytereverse(word))) - return ''.join(out_words) + return b''.join(out_words) def wordreverse(in_buf): out_words = [] for i in range(0, len(in_buf), 4): out_words.append(in_buf[i:i+4]) out_words.reverse() - return ''.join(out_words) + return b''.join(out_words) def calc_hdr_hash(blk_hdr): hash1 = hashlib.sha256() @@ -59,7 +63,7 @@ def calc_hash_str(blk_hdr): hash = calc_hdr_hash(blk_hdr) hash = bufreverse(hash) hash = wordreverse(hash) - hash_str = hash.encode('hex') + hash_str = hexlify(hash).decode('utf-8') return hash_str def get_blk_dt(blk_hdr): @@ -69,17 +73,21 @@ def get_blk_dt(blk_hdr): dt_ym = datetime.datetime(dt.year, dt.month, 1) return (dt_ym, nTime) +# When getting the list of block hashes, undo any byte reversals. def get_block_hashes(settings): blkindex = [] f = open(settings['hashlist'], "r") for line in f: line = line.rstrip() + if settings['rev_hash_bytes'] == 'true': + line = hex_switchEndian(line) blkindex.append(line) print("Read " + str(len(blkindex)) + " hashes") return blkindex +# The block map shouldn't give or receive byte-reversed hashes. def mkblockmap(blkindex): blkmap = {} for height,hash in enumerate(blkindex): @@ -126,7 +134,7 @@ class BlockDataCopier: if not self.fileOutput and ((self.outsz + blockSizeOnDisk) > self.maxOutSz): self.outF.close() if self.setFileTime: - os.utime(outFname, (int(time.time()), highTS)) + os.utime(self.outFname, (int(time.time()), self.highTS)) self.outF = None self.outFname = None self.outFn = self.outFn + 1 @@ -134,12 +142,12 @@ class BlockDataCopier: (blkDate, blkTS) = get_blk_dt(blk_hdr) if self.timestampSplit and (blkDate > self.lastDate): - print("New month " + blkDate.strftime("%Y-%m") + " @ " + hash_str) - lastDate = blkDate - if outF: - outF.close() - if setFileTime: - os.utime(outFname, (int(time.time()), highTS)) + print("New month " + blkDate.strftime("%Y-%m") + " @ " + self.hash_str) + self.lastDate = blkDate + if self.outF: + self.outF.close() + if self.setFileTime: + os.utime(self.outFname, (int(time.time()), self.highTS)) self.outF = None self.outFname = None self.outFn = self.outFn + 1 @@ -147,11 +155,11 @@ class BlockDataCopier: if not self.outF: if self.fileOutput: - outFname = self.settings['output_file'] + self.outFname = self.settings['output_file'] else: - outFname = os.path.join(self.settings['output'], "blk%05d.dat" % self.outFn) - print("Output file " + outFname) - self.outF = open(outFname, "wb") + self.outFname = os.path.join(self.settings['output'], "blk%05d.dat" % self.outFn) + print("Output file " + self.outFname) + self.outF = open(self.outFname, "wb") self.outF.write(inhdr) self.outF.write(blk_hdr) @@ -207,7 +215,7 @@ class BlockDataCopier: inMagic = inhdr[:4] if (inMagic != self.settings['netmagic']): - print("Invalid magic: " + inMagic.encode('hex')) + print("Invalid magic: " + hexlify(inMagic).decode('utf-8')) return inLenLE = inhdr[4:] su = struct.unpack("<I", inLenLE) @@ -215,13 +223,16 @@ class BlockDataCopier: blk_hdr = self.inF.read(80) inExtent = BlockExtent(self.inFn, self.inF.tell(), inhdr, blk_hdr, inLen) - hash_str = calc_hash_str(blk_hdr) - if not hash_str in blkmap: - print("Skipping unknown block " + hash_str) + self.hash_str = calc_hash_str(blk_hdr) + if not self.hash_str in blkmap: + # Because blocks can be written to files out-of-order as of 0.10, the script + # may encounter blocks it doesn't know about. Treat as debug output. + if settings['debug_output'] == 'true': + print("Skipping unknown block " + self.hash_str) self.inF.seek(inLen, os.SEEK_CUR) continue - blkHeight = self.blkmap[hash_str] + blkHeight = self.blkmap[self.hash_str] self.blkCountIn += 1 if self.blkCountOut == blkHeight: @@ -265,6 +276,12 @@ if __name__ == '__main__': settings[m.group(1)] = m.group(2) f.close() + # Force hash byte format setting to be lowercase to make comparisons easier. + # Also place upfront in case any settings need to know about it. + if 'rev_hash_bytes' not in settings: + settings['rev_hash_bytes'] = 'false' + settings['rev_hash_bytes'] = settings['rev_hash_bytes'].lower() + if 'netmagic' not in settings: settings['netmagic'] = 'f9beb4d9' if 'genesis' not in settings: @@ -278,15 +295,18 @@ if __name__ == '__main__': if 'split_timestamp' not in settings: settings['split_timestamp'] = 0 if 'max_out_sz' not in settings: - settings['max_out_sz'] = 1000L * 1000 * 1000 + settings['max_out_sz'] = 1000 * 1000 * 1000 if 'out_of_order_cache_sz' not in settings: settings['out_of_order_cache_sz'] = 100 * 1000 * 1000 + if 'debug_output' not in settings: + settings['debug_output'] = 'false' - settings['max_out_sz'] = long(settings['max_out_sz']) + settings['max_out_sz'] = int(settings['max_out_sz']) settings['split_timestamp'] = int(settings['split_timestamp']) settings['file_timestamp'] = int(settings['file_timestamp']) - settings['netmagic'] = settings['netmagic'].decode('hex') + settings['netmagic'] = unhexlify(settings['netmagic'].encode('utf-8')) settings['out_of_order_cache_sz'] = int(settings['out_of_order_cache_sz']) + settings['debug_output'] = settings['debug_output'].lower() if 'output_file' not in settings and 'output' not in settings: print("Missing output file / directory") @@ -295,9 +315,8 @@ if __name__ == '__main__': blkindex = get_block_hashes(settings) blkmap = mkblockmap(blkindex) + # Block hash map won't be byte-reversed. Neither should the genesis hash. if not settings['genesis'] in blkmap: print("Genesis block not found in hashlist") else: BlockDataCopier(settings, blkindex, blkmap).run() - - diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py index 854cf1f9ee..db8eb7021e 100755 --- a/contrib/linearize/linearize-hashes.py +++ b/contrib/linearize/linearize-hashes.py @@ -1,39 +1,55 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # linearize-hashes.py: List blocks in a linear, no-fork version of the chain. # -# Copyright (c) 2013-2014 The Bitcoin Core developers +# Copyright (c) 2013-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 __future__ import print_function +try: # Python 3 + import http.client as httplib +except ImportError: # Python 2 + import httplib import json -import struct import re import base64 -import httplib import sys +import os +import os.path settings = {} +##### Switch endian-ness ##### +def hex_switchEndian(s): + """ Switches the endianness of a hex string (in pairs of hex chars) """ + pairList = [s[i:i+2].encode() for i in range(0, len(s), 2)] + return b''.join(pairList[::-1]).decode() + class BitcoinRPC: def __init__(self, host, port, username, password): authpair = "%s:%s" % (username, password) - self.authhdr = "Basic %s" % (base64.b64encode(authpair)) - self.conn = httplib.HTTPConnection(host, port, False, 30) + authpair = authpair.encode('utf-8') + self.authhdr = b"Basic " + base64.b64encode(authpair) + self.conn = httplib.HTTPConnection(host, port=port, timeout=30) def execute(self, obj): - self.conn.request('POST', '/', json.dumps(obj), - { 'Authorization' : self.authhdr, - 'Content-type' : 'application/json' }) + try: + self.conn.request('POST', '/', json.dumps(obj), + { 'Authorization' : self.authhdr, + 'Content-type' : 'application/json' }) + except ConnectionRefusedError: + print('RPC connection refused. Check RPC settings and the server status.', + file=sys.stderr) + return None resp = self.conn.getresponse() if resp is None: print("JSON-RPC: no response", file=sys.stderr) return None - body = resp.read() + body = resp.read().decode('utf-8') resp_obj = json.loads(body) return resp_obj @@ -64,16 +80,29 @@ def get_block_hashes(settings, max_blocks_per_call=10000): batch.append(rpc.build_request(x, 'getblockhash', [height + x])) reply = rpc.execute(batch) + if reply is None: + print('Cannot continue. Program will halt.') + return None for x,resp_obj in enumerate(reply): if rpc.response_is_error(resp_obj): print('JSON-RPC: error at height', height+x, ': ', resp_obj['error'], file=sys.stderr) exit(1) assert(resp_obj['id'] == x) # assume replies are in-sequence + if settings['rev_hash_bytes'] == 'true': + resp_obj['result'] = hex_switchEndian(resp_obj['result']) print(resp_obj['result']) height += num_blocks +def get_rpc_cookie(): + # Open the cookie file + with open(os.path.join(os.path.expanduser(settings['datadir']), '.cookie'), 'r') as f: + combined = f.readline() + combined_split = combined.split(":") + settings['rpcuser'] = combined_split[0] + settings['rpcpassword'] = combined_split[1] + if __name__ == '__main__': if len(sys.argv) != 2: print("Usage: linearize-hashes.py CONFIG-FILE") @@ -101,13 +130,28 @@ if __name__ == '__main__': settings['min_height'] = 0 if 'max_height' not in settings: settings['max_height'] = 313000 + if 'rev_hash_bytes' not in settings: + settings['rev_hash_bytes'] = 'false' + + use_userpass = True + use_datadir = False if 'rpcuser' not in settings or 'rpcpassword' not in settings: - print("Missing username and/or password in cfg file", file=stderr) + use_userpass = False + if 'datadir' in settings and not use_userpass: + use_datadir = True + if not use_userpass and not use_datadir: + print("Missing datadir or username and/or password in cfg file", file=stderr) sys.exit(1) settings['port'] = int(settings['port']) settings['min_height'] = int(settings['min_height']) settings['max_height'] = int(settings['max_height']) - get_block_hashes(settings) + # Force hash byte format setting to be lowercase to make comparisons easier. + settings['rev_hash_bytes'] = settings['rev_hash_bytes'].lower() + # Get the rpc user and pass from the cookie if the datadir is set + if use_datadir: + get_rpc_cookie() + + get_block_hashes(settings) diff --git a/contrib/macdeploy/custom_dsstore.py b/contrib/macdeploy/custom_dsstore.py index 03e2325fc0..e6ecabace1 100755 --- a/contrib/macdeploy/custom_dsstore.py +++ b/contrib/macdeploy/custom_dsstore.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2013-2015 The Bitcoin Core developers +# Copyright (c) 2013-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 __future__ import division,print_function,unicode_literals diff --git a/contrib/macdeploy/detached-sig-apply.sh b/contrib/macdeploy/detached-sig-apply.sh index 781fe315ed..91674a92e6 100755 --- a/contrib/macdeploy/detached-sig-apply.sh +++ b/contrib/macdeploy/detached-sig-apply.sh @@ -1,4 +1,8 @@ #!/bin/sh +# 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. + set -e UNSIGNED="$1" diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh index 89a2da32f7..7f017bb4f1 100755 --- a/contrib/macdeploy/detached-sig-create.sh +++ b/contrib/macdeploy/detached-sig-create.sh @@ -1,4 +1,8 @@ #!/bin/sh +# 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. + set -e ROOTDIR=dist @@ -6,7 +10,7 @@ BUNDLE="${ROOTDIR}/Bitcoin-Qt.app" CODESIGN=codesign TEMPDIR=sign.temp TEMPLIST=${TEMPDIR}/signatures.txt -OUT=signature.tar.gz +OUT=signature-osx.tar.gz OUTROOT=osx if [ ! -n "$1" ]; then diff --git a/contrib/macdeploy/extract-osx-sdk.sh b/contrib/macdeploy/extract-osx-sdk.sh new file mode 100755 index 0000000000..ff9fbd58df --- /dev/null +++ b/contrib/macdeploy/extract-osx-sdk.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# 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. + +set -e + +INPUTFILE="Xcode_7.3.1.dmg" +HFSFILENAME="5.hfs" +SDKDIR="Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk" + +7z x "${INPUTFILE}" "${HFSFILENAME}" +SDKNAME="$(basename "${SDKDIR}")" +SDKDIRINODE=$(ifind -n "${SDKDIR}" "${HFSFILENAME}") +fls "${HFSFILENAME}" -rpF ${SDKDIRINODE} | + while read type inode filename; do + inode="${inode::-1}" + if [ "${filename:0:14}" = "usr/share/man/" ]; then + continue + fi + filename="${SDKNAME}/$filename" + echo "Extracting $filename ..." + mkdir -p "$(dirname "$filename")" + if [ "$type" = "l/l" ]; then + ln -s "$(icat "${HFSFILENAME}" $inode)" "$filename" + else + icat "${HFSFILENAME}" $inode >"$filename" + fi +done +echo "Building ${SDKNAME}.tar.gz ..." +MTIME="$(istat "${HFSFILENAME}" "${SDKDIRINODE}" | perl -nle 'm/Content Modified:\s+(.*?)\s\(/ && print $1')" +find "${SDKNAME}" | sort | tar --no-recursion --mtime="${MTIME}" --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > "${SDKNAME}.tar.gz" +echo 'All done!' diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index f8201e72c6..23a568ad13 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -302,7 +302,6 @@ def copyFramework(framework, path, verbose): if os.path.exists(fromContentsDir): toContentsDir = os.path.join(path, framework.destinationVersionContentsDirectory) shutil.copytree(fromContentsDir, toContentsDir, symlinks=True) - contentslinkfrom = os.path.join(path, framework.destinationContentsDirectory) if verbose >= 3: print("Copied Contents:", fromContentsDir) print(" to:", toContentsDir) @@ -340,7 +339,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym # install_name_tool the new id into the binary changeInstallName(framework.installName, framework.deployedInstallName, binaryPath, verbose) - # Copy farmework to app bundle. + # Copy framework to app bundle. deployedBinaryPath = copyFramework(framework, bundlePath, verbose) # Skip the rest if already was deployed. if deployedBinaryPath is None: @@ -492,7 +491,7 @@ ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, h ap.add_argument("-sign", dest="sign", action="store_true", default=False, help="sign .app bundle with codesign tool") ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image; if basename is not specified, a camel-cased version of the app name is used") ap.add_argument("-fancy", nargs=1, metavar="plist", default=[], help="make a fancy looking disk image using the given plist file with instructions; requires -dmg to work") -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("-add-qt-tr", nargs=1, metavar="languages", default=[], help="add Qt translation files to the bundle's resources; 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") @@ -675,9 +674,8 @@ else: if verbose >= 2: print("+ Installing qt.conf +") -f = open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") -f.write(qt_conf.encode()) -f.close() +with open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") as f: + f.write(qt_conf.encode()) # ------------------------------------------------ @@ -791,7 +789,7 @@ if config.dmg is not None: except subprocess.CalledProcessError as e: sys.exit(e.returncode) - m = re.search("/Volumes/(.+$)", output) + m = re.search("/Volumes/(.+$)", output.decode()) disk_root = m.group(0) disk_name = m.group(1) @@ -852,7 +850,7 @@ if config.dmg is not None: "items_positions" : "\n ".join(items_positions) } if "window_bounds" in fancy: - params["window.bounds"] = ",".join([str(p) for p in fancy["window_bounds"]]) + params["window_bounds"] = ",".join([str(p) for p in fancy["window_bounds"]]) if "icon_size" in fancy: params["icon_size"] = str(fancy["icon_size"]) if bg_path is not None: @@ -868,7 +866,7 @@ if config.dmg is not None: print(s) p = subprocess.Popen(['osascript', '-'], stdin=subprocess.PIPE) - p.communicate(input=s) + p.communicate(input=s.encode('utf-8')) if p.returncode: print("Error running osascript.") diff --git a/contrib/qos/README.md b/contrib/qos/README.md index 5e0a975fc6..0ded87c58f 100644 --- a/contrib/qos/README.md +++ b/contrib/qos/README.md @@ -1,5 +1,5 @@ -### Qos ### +### QoS (Quality of service) ### -This is a Linux bash script that will set up tc to limit the outgoing bandwidth for connections to the Bitcoin network. It limits outbound TCP traffic with a source or destination port of 8333, but not if the destination IP is within a LAN (defined as 192.168.x.x). +This is a Linux bash script that will set up tc to limit the outgoing bandwidth for connections to the Bitcoin network. It limits outbound TCP traffic with a source or destination port of 8333, but not if the destination IP is within a LAN. This means one can have an always-on bitcoind instance running, and another local bitcoind/bitcoin-qt instance which connects to this node and receives blocks from it. diff --git a/contrib/qos/tc.sh b/contrib/qos/tc.sh index f620604212..0d1dd65b4f 100644 --- a/contrib/qos/tc.sh +++ b/contrib/qos/tc.sh @@ -1,11 +1,17 @@ +# Copyright (c) 2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + #network interface on which to limit traffic IF="eth0" #limit of the network interface in question LINKCEIL="1gbit" #limit outbound Bitcoin protocol traffic to this rate LIMIT="160kbit" -#defines the address space for which you wish to disable rate limiting -LOCALNET="192.168.0.0/16" +#defines the IPv4 address space for which you wish to disable rate limiting +LOCALNET_V4="192.168.0.0/16" +#defines the IPv6 address space for which you wish to disable rate limiting +LOCALNET_V6="fe80::/10" #delete existing rules tc qdisc del dev ${IF} root @@ -24,6 +30,12 @@ tc class add dev ${IF} parent 1:1 classid 1:11 htb rate ${LIMIT} ceil ${LIMIT} p tc filter add dev ${IF} parent 1: protocol ip prio 1 handle 1 fw classid 1:10 tc filter add dev ${IF} parent 1: protocol ip prio 2 handle 2 fw classid 1:11 +if [ ! -z "${LOCALNET_V6}" ] ; then + # v6 cannot have the same priority value as v4 + tc filter add dev ${IF} parent 1: protocol ipv6 prio 3 handle 1 fw classid 1:10 + tc filter add dev ${IF} parent 1: protocol ipv6 prio 4 handle 2 fw classid 1:11 +fi + #delete any existing rules #disable for now #ret=0 @@ -33,9 +45,15 @@ tc filter add dev ${IF} parent 1: protocol ip prio 2 handle 2 fw classid 1:11 #done #limit outgoing traffic to and from port 8333. but not when dealing with a host on the local network -# (defined by $LOCALNET) -# --set-mark marks packages matching these criteria with the number "2" -# these packages are filtered by the tc filter with "handle 2" +# (defined by $LOCALNET_V4 and $LOCALNET_V6) +# --set-mark marks packages matching these criteria with the number "2" (v4) +# --set-mark marks packages matching these criteria with the number "4" (v6) +# these packets are filtered by the tc filter with "handle 2" # this filter sends the packages into the 1:11 class, and this class is limited to ${LIMIT} -iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 8333 ! -d ${LOCALNET} -j MARK --set-mark 0x2 -iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 8333 ! -d ${LOCALNET} -j MARK --set-mark 0x2 +iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 8333 ! -d ${LOCALNET_V4} -j MARK --set-mark 0x2 +iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 8333 ! -d ${LOCALNET_V4} -j MARK --set-mark 0x2 + +if [ ! -z "${LOCALNET_V6}" ] ; then + ip6tables -t mangle -A OUTPUT -p tcp -m tcp --dport 8333 ! -d ${LOCALNET_V6} -j MARK --set-mark 0x4 + ip6tables -t mangle -A OUTPUT -p tcp -m tcp --sport 8333 ! -d ${LOCALNET_V6} -j MARK --set-mark 0x4 +fi diff --git a/contrib/qt_translations.py b/contrib/qt_translations.py deleted file mode 100755 index fd8a8b7129..0000000000 --- a/contrib/qt_translations.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python - -# Helpful little script that spits out a comma-separated list of -# language codes for Qt icons that should be included -# in binary bitcoin distributions - -import glob -import os -import re -import sys - -if len(sys.argv) != 3: - sys.exit("Usage: %s $QTDIR/translations $BITCOINDIR/src/qt/locale"%sys.argv[0]) - -d1 = sys.argv[1] -d2 = sys.argv[2] - -l1 = set([ re.search(r'qt_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d1, 'qt_*.qm')) ]) -l2 = set([ re.search(r'bitcoin_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d2, 'bitcoin_*.qm')) ]) - -print ",".join(sorted(l1.intersection(l2))) - diff --git a/contrib/rpm/README.md b/contrib/rpm/README.md index aecb3ba84f..e1fd0b317b 100644 --- a/contrib/rpm/README.md +++ b/contrib/rpm/README.md @@ -31,7 +31,7 @@ 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. +them from the git repository 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 diff --git a/contrib/rpm/bitcoin.spec b/contrib/rpm/bitcoin.spec index 38ae038180..cc54fcaf3d 100644 --- a/contrib/rpm/bitcoin.spec +++ b/contrib/rpm/bitcoin.spec @@ -27,10 +27,9 @@ 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 +Source20: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/doc/man/bitcoind.1 +Source21: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/doc/man/bitcoin-cli.1 +Source22: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/doc/man/bitcoin-qt.1 #selinux Source30: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/rpm/bitcoin.te @@ -306,17 +305,14 @@ 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 +srcdir=src test/bitcoin-util-test.py +test/functional/test_runner.py --extended %post libs -p /sbin/ldconfig @@ -415,7 +411,6 @@ rm -rf %{buildroot} %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,-) @@ -425,7 +420,6 @@ rm -rf %{buildroot} %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* diff --git a/contrib/seeds/README.md b/contrib/seeds/README.md index c595f83eb9..afe902fd7f 100644 --- a/contrib/seeds/README.md +++ b/contrib/seeds/README.md @@ -1,11 +1,19 @@ -### Seeds ### +# Seeds 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)). +Be sure to update `PATTERN_AGENT` in `makeseeds.py` to include the current version, +and remove old versions as necessary. + 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 + python3 makeseeds.py < seeds_main.txt > nodes_main.txt + python3 generate-seeds.py . > ../../src/chainparamsseeds.h + +## Dependencies + +Ubuntu: + sudo apt-get install python3-dnspython diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py index a3d0352187..b0ac92ae03 100755 --- a/contrib/seeds/generate-seeds.py +++ b/contrib/seeds/generate-seeds.py @@ -1,5 +1,5 @@ -#!/usr/bin/python -# Copyright (c) 2014 Wladimir J. van der Laan +#!/usr/bin/env python3 +# Copyright (c) 2014-2017 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. ''' @@ -31,7 +31,7 @@ The output will be two data structures with the peers in binary format: These should be pasted into `src/chainparamsseeds.h`. ''' -from __future__ import print_function, division + from base64 import b32decode from binascii import a2b_hex import sys, os diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py index 4072405ef5..34f0f57671 100755 --- a/contrib/seeds/makeseeds.py +++ b/contrib/seeds/makeseeds.py @@ -1,4 +1,7 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 +# Copyright (c) 2013-2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. # # Generate seeds.txt from Pieter's DNS seeder # @@ -11,13 +14,13 @@ MIN_BLOCKS = 337600 # These are hosts that have been observed to be behaving strangely (e.g. # aggressively connecting to every node). -SUSPICIOUS_HOSTS = set([ +SUSPICIOUS_HOSTS = { "130.211.129.106", "178.63.107.226", "83.81.130.26", "88.198.17.7", "148.251.238.178", "176.9.46.6", "54.173.72.127", "54.174.10.182", "54.183.64.54", "54.194.231.211", "54.66.214.167", "54.66.220.137", "54.67.33.14", "54.77.251.214", "54.94.195.96", "54.94.200.247" -]) +} import re import sys @@ -27,7 +30,7 @@ import collections PATTERN_IPV4 = re.compile(r"^((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})):(\d+)$") PATTERN_IPV6 = re.compile(r"^\[([0-9a-z:]+)\]:(\d+)$") PATTERN_ONION = re.compile(r"^([abcdefghijklmnopqrstuvwxyz234567]{16}\.onion):(\d+)$") -PATTERN_AGENT = re.compile(r"^(\/Satoshi:0\.8\.6\/|\/Satoshi:0\.9\.(2|3|4|5)\/|\/Satoshi:0\.10\.\d{1,2}\/|\/Satoshi:0\.11\.\d{1,2}\/)$") +PATTERN_AGENT = re.compile(r"^(/Satoshi:0.12.(0|1|99)/|/Satoshi:0.13.(0|1|2|99)/)$") def parseline(line): sline = line.split() @@ -101,7 +104,7 @@ def filtermultiport(ips): hist = collections.defaultdict(list) for ip in ips: hist[ip['sortkey']].append(ip) - return [value[0] for (key,value) in hist.items() if len(value)==1] + return [value[0] for (key,value) in list(hist.items()) if len(value)==1] # Based on Greg Maxwell's seed_filter.py def filterbyasn(ips, max_per_asn, max_total): @@ -161,9 +164,9 @@ def main(): for ip in ips: if ip['net'] == 'ipv6': - print '[%s]:%i' % (ip['ip'], ip['port']) + print('[%s]:%i' % (ip['ip'], ip['port'])) else: - print '%s:%i' % (ip['ip'], ip['port']) + print('%s:%i' % (ip['ip'], ip['port'])) if __name__ == '__main__': main() diff --git a/contrib/seeds/nodes_main.txt b/contrib/seeds/nodes_main.txt index f1854b27f9..0451771dae 100644 --- a/contrib/seeds/nodes_main.txt +++ b/contrib/seeds/nodes_main.txt @@ -1,937 +1,1168 @@ -5.2.145.201:8333 -5.22.142.214:8333 -5.53.172.197:8333 -5.189.161.164:8333 -5.230.140.166:8333 -5.231.3.130:8333 -5.255.80.103:8333 -14.202.230.49:8333 -18.85.11.130:8333 -23.91.97.25:8333 -23.94.100.122:8333 -23.95.99.132:8333 -24.115.8.206:8333 -24.127.128.191:8333 -24.154.178.25:8333 -24.207.103.43:8333 -24.207.104.105:8333 -24.210.230.150:8333 -24.224.18.84:8333 -24.246.168.106:8333 -27.254.64.47:8333 -31.6.71.123:8333 -31.6.71.124:8333 -31.14.134.13:8333 -31.30.36.220:8333 -31.164.6.104:8333 +2.7.8.12:8333 +2.228.70.198:8333 +5.39.64.7:8333 +5.45.80.34:38333 +5.51.160.38:8333 +5.61.33.33:8333 +5.61.37.12:8333 +5.95.80.47:8333 +5.102.164.173:8333 +5.175.71.130:8333 +5.189.165.22:8333 +5.199.130.228:8333 +5.228.100.222:8333 +5.255.64.231:8333 +13.93.6.133:8333 +18.85.34.10:8333 +18.241.0.63:8333 +23.28.128.65:8333 +23.248.113.52:8333 +23.253.151.73:8333 +24.4.96.121:8333 +24.69.65.191:8333 +24.87.8.43:8333 +24.150.224.110:8333 +24.227.69.146:8333 +27.0.235.33:8333 31.170.106.203:8333 -31.185.134.201:8333 -31.204.128.99:8333 -31.204.128.219:8333 -37.1.219.88:8333 -37.97.132.109:8333 -37.120.160.55:8333 +31.184.197.96:8333 +31.214.240.56:8333 +37.1.202.134:8333 +37.18.74.232:8333 +37.34.48.17:8333 +37.48.64.140:8333 +37.97.141.116:8333 +37.120.164.16:8333 37.120.169.123:8333 -37.139.32.46:8333 -37.221.163.218:8333 -38.130.192.72:8333 -41.75.96.80:8333 -45.3.0.49:8333 -45.33.72.185:8333 -45.33.96.129:8333 -45.56.4.63:8333 -45.79.0.127:8333 -45.79.80.102:8333 -45.79.97.30:8333 -45.79.132.219:8333 -46.21.97.135:8333 -46.28.205.67:8333 -46.28.206.188:8333 -46.29.20.209:8333 -46.50.234.179:8333 -46.101.160.168:8333 -46.166.161.35:8333 -46.166.161.103:8333 -46.182.132.100:8333 -46.218.227.92:8333 -46.226.109.20:8333 -46.227.66.132:8333 -46.227.66.138:8333 -46.229.165.154:8333 -46.229.165.155:8333 +37.143.9.128:8333 +37.153.172.227:8333 +37.193.227.16:8333 +37.205.8.78:8333 +37.220.0.114:8333 +37.232.218.199:8333 +38.140.161.53:8333 +40.87.70.120:8333 +41.162.163.93:8333 +42.2.198.48:8333 +45.20.67.1:8333 +45.55.197.77:8333 +45.56.97.63:8333 +45.58.38.162:8333 +45.63.1.33:8333 +45.79.2.70:8333 +46.16.240.98:8333 +46.19.137.74:8333 +46.28.206.146:8333 +46.32.252.197:8333 +46.59.13.59:8333 +46.59.39.195:8333 +46.148.16.210:8333 +46.160.195.121:8333 +46.166.142.21:8333 +46.166.160.29:8330 +46.188.44.20:8333 46.229.238.187:8333 -46.234.104.48:8333 -46.239.107.74:8333 -46.244.0.138:8333 -46.254.72.195:8333 -50.5.13.44:8333 -50.7.37.114:8333 -50.30.37.103:8333 -50.39.105.60:8333 -50.106.40.231:8333 -52.29.0.37:8333 -52.76.192.246:8333 -54.152.192.179:8333 -54.169.64.174:8333 -54.175.160.22:8333 -54.199.128.0:8333 -58.96.171.129:8333 -58.161.238.57:8333 -60.251.195.221:8333 -61.35.225.19:8333 +46.231.16.149:8333 +47.88.100.130:8333 +47.89.192.134:8333 +47.185.194.160:8333 +47.189.129.218:8333 +49.65.2.140:8333 +50.3.72.129:8333 +50.31.99.225:8333 +51.175.33.95:8333 +52.1.165.219:8333 +52.10.170.186:8333 +52.51.128.216:8333 +54.197.130.244:8333 +58.59.2.22:8333 +58.84.6.81:8333 +59.125.8.143:8333 +59.167.130.139:8333 +61.47.2.20:8333 62.43.130.178:8333 -62.65.39.12:8333 +62.76.96.6:8333 62.107.200.30:8333 +62.133.15.58:8333 62.133.194.2:8333 -62.181.238.186:8333 -62.183.22.50:8333 -62.210.85.120:8333 -62.210.162.89:8333 +62.133.194.156:8333 +62.138.1.95:8333 +62.216.238.3:8333 62.238.34.125:8333 -64.25.171.73:8333 -64.27.166.30:8333 -64.53.137.101:8333 -64.71.72.44:8333 +63.137.40.207:8333 +63.231.96.109:8333 +64.78.240.150:8333 64.83.225.146:8333 -64.121.3.163:8333 -64.203.102.86:8333 -65.94.131.59:8333 -65.188.136.233:8333 -66.11.162.218:8333 -66.23.228.133:8333 -66.90.137.89:8333 -66.114.33.49:8333 -66.150.105.77:8333 +64.137.236.68:8833 +64.156.193.120:8333 +66.79.160.82:8333 +66.91.230.231:8333 +66.135.128.121:8333 66.172.10.4:8333 66.194.38.250:8333 66.194.38.253:8333 -66.194.38.254:8333 -66.231.97.172:8333 +66.215.34.26:8333 66.240.237.155:8333 -67.159.13.34:8333 -67.205.74.206:8333 +67.205.96.108:8333 +67.205.128.5:8333 +67.219.233.140:8333 67.221.193.55:8333 -67.227.72.17:8333 -68.65.120.53:8333 -68.65.205.226:9000 -68.144.4.34:8333 -69.39.49.199:8333 +68.100.196.118:8333 +68.132.193.222:8333 +68.168.118.234:8333 +69.11.97.43:8333 +69.30.229.10:8333 69.50.171.205:8333 -69.65.41.21:8333 -69.113.98.61:8333 -69.119.97.39:8333 -69.146.70.124:8333 -69.193.71.2:8333 -70.46.10.237:8333 -70.80.200.187:8333 -70.185.97.117:8333 -71.254.160.25:8333 -72.28.203.5:8333 -72.52.130.110:8333 -72.83.194.122:8333 -72.128.32.167:8333 -72.179.136.80:8333 -72.235.38.70:8333 -74.50.44.193:8333 -74.72.60.83:8333 -74.80.234.116:8333 -74.207.233.193:8333 -75.112.233.128:8333 -75.118.166.197:8333 -75.140.0.241:8333 -75.159.240.66:8333 -75.174.5.26:8333 -76.72.160.252:8333 -76.72.160.254:8333 -76.74.170.112:8333 -76.79.201.54:8333 -76.175.166.164:8333 -76.179.105.27:8333 -77.68.37.200:8333 -77.234.49.196:8333 -77.247.229.93:8333 -78.24.72.78:8333 -78.47.32.147:8333 -78.84.100.95:8333 -78.121.69.23:8333 -78.129.167.5:8333 -78.193.96.155:8333 -79.19.37.179:8333 +69.125.193.145:8333 +69.162.139.125:8333 +70.35.98.39:8333 +70.112.32.29:8333 +71.126.181.146:8333 +72.180.32.105:8333 +73.226.64.145:8333 +74.83.140.242:8333 +74.84.128.158:9333 +74.122.237.124:8333 +74.215.133.145:8333 +75.76.101.169:8333 +75.85.13.8:8333 +75.86.168.13:8333 +75.170.97.25:8333 +75.177.137.134:8333 +76.76.227.136:8333 +77.53.136.6:8333 +77.110.11.52:8333 +78.25.32.206:8333 +78.34.8.120:8333 +78.46.32.99:8333 +78.56.9.214:8333 +78.56.229.177:8333 +78.129.237.245:8333 +78.196.172.45:8333 79.132.230.144:8333 -79.133.43.63:8333 -79.134.201.66:8333 79.169.35.235:8333 -80.57.227.14:8333 +79.172.194.219:8333 80.64.65.87:8333 -80.86.92.70:8333 -80.100.203.151:8333 -80.101.32.121:8333 -80.161.178.73:8333 -80.240.129.170:8333 -81.7.11.50:8333 -81.7.11.55:8333 -81.17.17.40:9333 -81.30.39.83:8333 -81.90.36.7:9444 -81.136.224.77:8333 -81.162.231.211:8333 -81.184.0.143:8333 -81.198.128.86:8333 +80.89.137.115:8333 +80.93.36.173:8333 +80.101.167.100:8333 +80.114.34.158:8333 +80.127.136.50:8333 +80.188.139.82:8333 +80.222.39.77:8333 +80.223.105.69:8333 +80.229.151.187:8333 +80.240.129.221:8333 +81.7.10.238:8333 +81.7.13.84:8333 +81.27.96.92:8333 +81.35.143.98:8333 +81.82.201.5:8333 +81.83.96.5:8333 +81.169.227.36:8333 +81.171.2.119:8333 +81.171.38.130:8333 +81.175.255.118:8333 +81.207.8.49:8333 +81.228.194.187:8333 +82.9.1.77:8333 82.11.33.229:8333 -82.79.128.134:8333 -82.118.233.111:8333 -82.135.139.30:8333 +82.102.13.117:8333 +82.116.203.240:8333 +82.130.103.16:8333 +82.136.65.227:8333 +82.158.227.238:8333 +82.197.212.25:8333 82.199.102.10:8333 -82.221.106.17:8333 -82.221.108.21:8333 +82.200.204.41:8333 +82.200.204.119:8333 +82.221.105.223:8333 82.221.108.27:8333 -83.137.41.3:8333 -83.142.197.168:8333 +82.221.111.136:8333 +82.221.139.97:8333 +83.137.41.10:8333 83.143.130.19:8333 83.150.9.196:8333 -83.183.17.191:8333 -83.227.173.83:8333 -83.230.5.15:8333 -83.233.105.151:443 -83.246.75.8:8333 -83.250.133.158:8333 -83.255.66.118:8334 -84.24.69.59:8333 +83.169.2.43:8333 +83.217.203.130:8333 +83.249.88.52:8333 +84.26.162.92:8333 84.42.193.6:8333 -84.45.98.87:8333 -84.54.128.11:8333 -84.212.200.24:8333 -84.215.198.109:8333 -84.230.4.177:8333 -85.95.228.83:8333 -85.95.228.123:8333 -85.114.128.134:8333 -85.214.66.168:8333 -85.214.147.162:8333 -85.243.168.4:8333 -86.1.0.18:8333 -87.79.77.106:8333 -87.91.156.110:8333 -87.236.196.222:8333 -88.85.75.152:8333 -88.87.1.230:8333 -88.87.92.102:8333 -88.89.69.202:8333 -88.97.72.229:8333 -88.164.117.99:8333 -88.198.32.131:8333 +84.134.194.115:8333 +84.201.32.115:8333 +84.212.232.71:8333 +84.238.140.176:8333 +85.10.104.34:8333 +85.21.144.226:8333 +85.25.194.12:8333 +85.144.79.190:8333 +85.145.228.192:8333 +85.194.238.130:8333 +85.228.201.80:8333 +85.229.228.174:8333 +85.236.233.87:8333 +86.80.204.185:8333 +86.105.227.190:8333 +86.135.39.40:8333 +87.106.139.127:8333 +87.120.8.5:8333 +87.120.37.230:8333 +87.239.101.102:8333 +87.243.197.82:8333 +88.112.112.173:8333 +88.150.192.17:8333 +88.185.155.134:8333 +88.202.202.221:8333 88.202.230.87:8333 -88.214.193.154:8343 -88.214.194.226:8343 -89.10.155.88:8333 -89.46.101.44:8333 -89.163.224.212:8333 -89.174.248.20:8333 -89.202.231.198:8333 -89.212.75.6:8333 +88.208.39.182:8333 +89.34.99.41:8333 +89.163.224.187:8333 +89.169.233.150:8333 +89.184.65.85:8333 +89.212.91.219:8333 +89.249.178.36:8333 90.149.38.172:8333 -90.169.106.139:8333 -91.64.101.150:8333 -91.65.196.179:8333 -91.121.80.17:8333 -91.126.77.77:8333 -91.145.76.156:8333 -91.152.150.35:8333 -91.192.137.17:8333 -91.196.170.110:8333 +91.65.97.157:8333 +91.107.64.143:8333 +91.114.35.107:8333 +91.135.0.187:8333 +91.145.110.95:8333 +91.157.38.151:8333 91.197.44.133:8333 -91.207.68.144:8333 -91.210.105.28:8333 -91.211.102.101:8333 -91.211.106.34:8333 -91.214.200.205:8333 -91.220.43.146:8333 -91.222.71.89:8333 -91.224.140.242:8333 -91.229.76.14:8333 +91.205.176.54:8333 +91.206.203.10:8333 +91.206.203.18:8333 +91.215.35.130:8333 +91.219.239.159:8333 +91.223.133.2:8333 +91.223.133.40:8333 +91.226.10.90:8333 +91.240.141.169:8333 92.27.7.209:8333 -92.51.167.88:8333 -92.247.229.163:8333 -93.84.114.106:8333 -93.113.36.172:8333 +92.89.67.207:8333 +92.221.201.138:8333 +93.95.187.122:8333 +93.103.73.187:8333 +93.123.80.47:8333 93.188.224.253:8333 -94.75.239.69:8333 -94.190.227.112:8333 -94.214.2.74:8333 -94.224.162.65:8333 -94.236.198.253:8333 +93.190.69.242:8333 +94.19.12.244:8333 +94.156.128.116:8333 +94.177.171.73:8333 +94.181.44.104:8333 +94.237.26.173:8333 94.242.229.158:8333 -95.84.138.99:8333 -95.95.168.87:8333 +94.255.128.98:8333 +95.79.35.50:8333 +95.91.41.39:8333 95.110.234.93:8333 -95.130.9.200:8333 -95.165.168.168:8333 -95.170.235.254:8333 -95.211.130.154:8333 -96.46.68.104:8333 -96.127.202.148:8333 -97.76.171.35:8333 -98.160.160.67:8333 -99.126.197.187:8333 -99.198.173.1:8333 -101.100.174.138:8333 -101.164.201.208:8333 -103.224.165.48:8333 -104.128.225.223:8333 +95.128.48.209:8333 +95.183.48.71:8333 +96.23.67.85:8333 +97.64.177.10:8333 +97.104.201.95:8333 +98.29.197.149:8333 +98.169.2.107:8333 +99.232.48.72:8333 +101.100.141.55:8333 +103.7.32.40:8333 +103.53.225.69:8333 +103.249.106.74:8333 +104.128.224.13:8333 104.128.228.252:8333 -104.131.192.94:8333 -104.155.45.201:8334 -104.194.28.195:8663 -104.211.1.27:8333 -104.221.38.177:8333 -104.236.9.79:8333 -104.236.129.178:8333 -104.236.186.249:8333 -104.236.194.15:8333 -104.238.128.214:8333 +104.155.1.158:8333 +104.168.128.50:8333 +104.199.160.228:8333 +104.204.109.11:8333 +104.219.251.118:8333 +104.223.3.129:8333 +104.223.3.219:8333 104.238.130.182:8333 -106.38.234.84:8333 -106.185.36.204:8333 -106.185.38.67:8333 -107.6.4.145:8333 -107.150.2.6:8333 -107.150.40.234:8333 -107.170.13.184:8333 -107.181.250.216:8333 -107.191.101.111:8333 -107.191.106.115:8333 +104.245.99.227:8333 +106.38.234.89:8333 +106.104.134.218:8333 +107.136.6.71:8333 +107.150.45.210:8333 +107.151.144.103:8333 +107.170.44.99:8333 +107.181.137.133:8333 +107.191.102.13:8333 +108.58.252.82:8333 +108.59.9.167:8333 108.59.12.163:8333 -108.161.129.247:8333 -109.193.160.140:8333 -109.197.13.54:8333 -109.230.7.248:8333 -109.234.106.191:8333 -109.236.137.80:8333 -109.251.161.121:8333 -112.65.231.226:8333 -115.70.166.57:8333 -115.159.42.80:8333 -117.18.73.34:8333 -118.67.201.40:8333 -118.100.86.246:8333 -118.110.104.152:8333 -119.224.64.141:8333 +108.162.106.215:8333 +108.168.133.164:8333 +108.173.202.101:8333 +108.180.110.190:8333 +109.29.75.40:8333 +109.120.194.136:8333 +109.230.230.88:8333 +109.235.67.115:8333 +109.235.69.120:8333 +109.236.90.199:8333 +109.255.0.107:8333 +110.10.130.12:8333 +110.10.176.94:8333 +110.132.172.251:8333 +111.90.158.17:8333 +115.66.205.171:8333 +116.31.123.139:8333 +118.192.48.46:8333 +118.193.164.98:8333 +119.29.156.231:8333 +119.63.44.133:19980 +119.81.99.27:8333 +119.106.12.169:8333 +119.147.137.155:19980 +119.185.1.182:8333 120.55.193.136:8333 -122.106.169.178:8333 -123.203.174.15:8333 -123.255.232.94:8333 -124.148.165.165:8333 -124.232.141.31:8333 -128.30.92.69:8333 -128.39.141.182:8333 -128.84.167.20:8333 -128.111.73.10:8333 -128.127.38.195:8333 +121.254.173.23:8333 +121.254.173.40:8333 +123.56.129.45:8333 +123.203.163.128:8333 +123.206.32.198:8333 +124.189.160.221:8333 +124.189.192.232:8333 128.140.224.162:8333 -128.199.101.104:8333 -128.233.224.35:8333 -128.253.3.193:20020 -130.180.228.138:8333 -130.185.144.213:8333 -130.255.73.207:8333 -133.218.233.11:8333 -134.249.128.23:8333 -136.159.234.234:8333 -137.116.160.176:8333 -139.162.2.145:8333 -139.162.23.117:8333 -141.134.69.253:8333 -141.255.162.215:8333 -144.122.163.187:8333 -145.131.3.54:8333 -145.255.4.94:8333 -146.0.32.101:8337 -147.83.72.91:8333 -148.103.28.68:8333 -149.5.32.102:8333 -149.210.164.195:8333 -150.101.163.241:8333 -151.236.11.189:8333 -152.3.136.56:8333 -154.20.208.25:8333 -158.181.104.149:8333 -159.253.96.226:8333 -160.36.130.180:8333 +128.199.68.205:8333 +130.234.207.115:8333 +131.113.41.123:8333 +131.114.72.104:8333 +132.204.108.155:8333 +134.119.13.230:8333 +134.213.133.206:8333 +134.213.133.207:8333 +135.23.5.3:8333 +137.74.0.66:8333 +138.68.1.45:8333 +138.68.2.194:8333 +138.68.64.19:8333 +138.68.64.28:8333 +139.59.42.248:8333 +139.220.240.153:8333 +140.112.107.118:8333 +140.186.224.112:8333 +141.52.64.141:8333 +142.68.237.107:8333 +142.217.12.106:8333 +146.60.204.92:8333 +146.185.161.209:8333 +148.103.7.119:8333 +149.210.133.244:8333 +150.229.0.143:8333 +151.231.238.25:8333 +151.248.160.227:8333 +153.230.228.15:8333 +155.133.43.249:8333 +158.58.238.145:8333 +158.109.79.13:34821 +159.203.70.208:8333 +160.16.206.31:8333 162.209.1.233:8333 162.209.4.125:8333 -162.209.106.123:8333 -162.210.198.184:8333 -162.248.99.164:53011 +162.216.192.231:8333 +162.243.100.111:8333 +162.246.11.194:8333 162.248.102.117:8333 -162.251.108.53:8333 -163.44.2.48:8333 -163.158.36.17:8333 -166.230.71.67:8333 -167.160.36.62:8333 -167.160.169.92:8333 -168.93.129.220:8333 -169.55.99.84:8333 -169.228.66.43:8333 -172.9.169.242:8333 -173.32.11.194:8333 -173.230.228.136:8333 -173.246.107.34:8333 -173.254.235.34:8333 -174.0.128.222:8333 -174.25.130.148:8333 -174.50.64.101:8333 -175.140.232.141:8333 -176.36.37.62:8333 -176.46.9.96:8333 -176.124.110.27:8333 -177.39.16.102:8333 -178.17.173.2:8333 -178.62.5.248:8333 -178.62.70.16:8333 +162.252.46.83:8333 +163.172.33.78:8333 +163.172.194.30:8333 +169.229.198.106:8333 +170.75.195.168:8333 +172.103.205.197:8333 +172.245.225.126:8333 +173.179.37.8:8333 +173.208.203.74:8333 +173.252.46.16:8333 +174.117.141.124:8333 +175.126.38.158:8333 +175.126.38.177:8333 +175.139.106.119:8333 +175.140.232.66:8333 +176.9.117.100:8333 +176.36.33.121:8333 +176.36.99.222:8333 +176.56.227.36:8333 +176.100.100.206:8333 +176.106.144.183:8333 +176.123.7.148:8333 +176.126.167.10:8333 +176.223.201.198:8333 +178.62.68.62:8333 +178.62.102.56:8333 178.62.203.185:8333 -178.79.160.118:8333 -178.169.206.244:8333 -178.193.234.62:8333 -178.199.96.108:8333 -178.254.18.96:8333 +178.124.197.101:8333 +178.170.138.202:8333 +178.175.129.18:8333 +178.188.47.62:8333 +178.199.240.22:8333 +178.218.209.162:8333 +178.237.35.34:8333 +178.238.224.242:8333 +178.254.34.144:8333 178.254.34.161:8333 -178.255.41.123:8333 -180.210.34.58:9801 -182.92.226.212:8333 -182.171.246.142:8333 -184.23.8.9:8333 -184.58.162.35:8333 -184.154.9.170:8333 -185.8.238.165:8333 +179.43.183.2:8333 +180.200.128.58:8333 +182.93.34.130:8333 +185.8.238.197:8333 +185.11.139.172:8333 185.24.97.11:8333 -185.31.137.139:8333 -185.38.44.64:8333 -185.53.128.180:8333 -185.53.129.244:8333 -185.77.129.119:8333 -185.77.129.156:8333 -185.82.203.92:8333 -188.20.97.18:8333 -188.126.8.14:8333 -188.138.33.239:8333 -188.155.136.70:8333 +185.24.233.100:8333 +185.25.48.71:8333 +185.25.48.114:8333 +185.28.76.179:8333 +185.70.105.152:8339 +185.77.128.69:8333 +185.77.128.241:8333 +185.86.79.87:8333 +185.89.102.2:3333 +185.89.102.53:3333 +185.109.144.155:8333 +185.117.75.50:8333 +185.121.173.223:8333 +185.128.41.157:8333 +185.130.226.106:8333 +185.145.130.76:8333 +188.63.192.104:8333 +188.113.164.231:8333 188.166.229.112:8333 -188.182.108.129:8333 -188.226.225.174:8010 -188.242.171.8:8333 -188.243.4.139:8333 -190.10.9.234:8333 -190.10.10.147:8333 +188.214.128.77:8333 +190.10.8.211:8333 190.81.160.184:8333 -190.85.201.37:8333 -192.34.227.230:8333 -192.77.189.200:8333 -192.124.224.7:8333 -192.146.137.1:8333 -192.203.228.71:8333 -192.206.202.20:8333 -193.0.109.3:8333 -193.41.229.130:8333 -193.41.229.156:8333 +190.111.231.19:8333 +192.131.44.93:8333 +192.206.202.6:8333 +192.227.245.133:8333 +192.241.74.123:8333 +192.241.74.126:8333 +192.254.71.222:8333 +193.10.64.85:8333 +193.46.80.101:8333 193.49.43.219:8333 -193.147.71.120:8333 -193.179.65.233:8333 +193.93.79.215:8333 193.183.99.46:8333 -193.192.37.135:8333 193.234.224.195:8333 -194.58.108.213:8333 -194.187.96.2:8333 -194.255.31.59:8333 -195.36.6.101:8333 -195.58.238.243:8333 -195.197.175.190:8333 -195.239.1.66:8333 -198.48.196.230:8333 -198.50.192.160:8333 -198.57.210.27:8333 -198.84.195.179:8333 -198.167.140.8:8333 +193.239.80.155:8333 +194.63.140.208:8333 +194.87.1.232:8333 +194.187.227.18:8333 +194.247.12.136:8333 +195.91.176.86:8333 +196.28.98.20:8333 +198.44.249.35:8333 +198.84.172.252:8333 198.204.224.106:8333 -199.127.226.245:8333 -199.201.110.8:8333 -199.233.234.90:8333 +198.211.97.46:8333 +199.66.64.198:8333 +199.101.100.58:8333 +199.101.100.59:8333 +199.127.224.50:8333 +200.46.241.71:8333 200.116.98.185:8333 -202.60.70.18:8333 -203.151.140.14:8333 -204.112.203.52:8333 +203.9.225.13:8333 +203.177.142.37:8333 205.200.247.149:8333 -207.226.141.253:8333 -207.255.42.202:8333 -208.53.164.19:8333 -208.66.68.127:8333 -208.66.68.130:8333 -208.71.171.232:8341 -208.76.200.200:8333 -208.82.98.189:8333 -208.85.193.31:8333 -208.111.48.41:8333 -208.111.48.45:8333 -209.34.232.72:8333 -209.81.9.223:8333 -209.90.224.2:8333 +205.209.131.150:13838 +206.53.64.74:8333 +206.72.192.69:8333 +206.123.112.180:8333 +208.66.208.153:8333 +208.68.174.76:8333 +208.107.97.242:8333 +208.111.48.132:8333 +208.118.235.190:8333 +209.6.205.126:8333 +209.40.96.121:8333 +209.58.130.137:8333 +209.73.142.226:8333 209.90.224.4:8333 -209.126.98.174:8333 -209.136.72.69:8333 -209.195.4.74:8333 -209.197.13.62:8333 -211.72.227.8:8333 -212.51.144.42:8333 -212.71.233.127:8333 -212.126.14.122:8333 -212.159.44.50:8333 -213.5.36.58:8333 -213.57.33.10:8333 -213.66.205.194:8333 -213.136.73.125:8333 -213.155.3.216:8333 -213.155.7.24:8333 -213.167.17.6:8333 -213.223.138.13:8333 -216.15.78.182:8333 -216.38.129.164:8333 -216.48.168.8:8333 -216.169.141.169:8333 -216.245.206.181:8333 -216.249.204.161:8333 -216.250.138.230:8333 +209.126.69.243:8333 +209.126.108.91:8333 +209.195.4.18:8333 +209.250.6.190:8333 +210.54.37.225:8333 +210.223.3.44:8333 +211.149.234.109:8333 +212.51.140.183:8333 +212.90.179.206:8333 +212.93.226.90:8333 +212.110.171.118:8333 +212.202.132.17:8333 +213.91.205.134:8333 +213.165.68.218:8333 +213.196.200.213:8333 +216.59.4.212:8333 +216.74.32.109:8333 +216.158.225.70:8333 +216.164.138.13:8333 +216.167.236.247:8333 +216.197.79.74:8333 217.11.225.189:8333 -217.12.34.158:8333 -217.12.202.33:8333 -217.20.171.43:8333 -217.23.1.126:8333 -217.23.11.138:8333 +217.12.199.207:8333 +217.20.130.72:8333 +217.23.6.148:8333 +217.23.140.103:8333 +217.28.96.180:8333 +217.35.130.42:8333 217.111.66.79:8333 -217.155.202.191:8333 217.158.9.102:8333 -217.172.32.18:20993 -220.245.196.37:8333 -[2001:1291:2bf:1::100]:8333 +217.168.143.169:8333 +217.209.32.219:8333 +218.161.33.165:8333 +221.121.144.138:8333 +[2001:0:4137:9e76:2048:3a84:bb91:e846]:8333 +[2001:0:4137:9e76:2066:e9e:b489:f8b8]:8333 +[2001:0:4137:9e76:3854:1211:b5ac:a96b]:8333 +[2001:0:4137:9e76:4e3:1f66:cd4c:829f]:8333 +[2001:0:4137:9e76:ad:1f4:9ea9:fa2e]:8333 +[2001:0:4137:9e76:e5:baa:b66f:f418]:8333 +[2001:0:53aa:64c:20a2:59c4:ad22:93ea]:8333 +[2001:0:53aa:64c:59:617f:a10d:e0]:8333 +[2001:0:5ef5:79fb:200f:3ae5:3cbc:74c9]:8333 +[2001:0:5ef5:79fb:38f2:13b4:b208:5604]:8333 +[2001:0:5ef5:79fd:200b:22a7:cc50:f52d]:8333 +[2001:0:5ef5:79fd:24ef:1aef:a994:303d]:8333 +[2001:0:5ef5:79fd:24fc:b5d:ad4f:4db2]:8333 +[2001:0:5ef5:79fd:28bf:2d23:e02e:c3ef]:8333 +[2001:0:5ef5:79fd:3cd0:3c2e:da44:a759]:8333 +[2001:0:5ef5:79fd:87e:fd7:b1c2:1b4]:8333 +[2001:0:9d38:6ab8:18db:3bda:ab90:e81e]:8333 +[2001:0:9d38:6ab8:4e7:1660:862f:a6d7]:8333 +[2001:0:9d38:6ab8:6:2b:5074:9588]:8333 +[2001:0:9d38:6abd:10f8:a7d7:bb90:f524]:8333 +[2001:13d8:1c01:1000::11]:8333 +[2001:15c0:65ff:610::2]:8333 +[2001:1608:10:156:ae::4adb]:8333 +[2001:1620:b1b:8888:20d:b9ff:fe41:6710]:8333 +[2001:1620:b1b:face:20d:b9ff:fe41:6710]:8333 [2001:1620:f00:282::2]:8333 [2001:1620:f00:8282::1]:8333 -[2001:19f0:5000:8de8:5400:ff:fe12:55e4]:8333 -[2001:19f0:6c00:9103:5400:ff:fe10:a8d3]:8333 -[2001:1b60:3:172:142b:6dff:fe7a:117]:8333 -[2001:410:a000:4050:8463:90b0:fffb:4e58]:8333 +[2001:1680:101:1ae::1]:8333 +[2001:16d8:ff00:85de:20c:29ff:fe52:9594]:8333 +[2001:19f0:4400:434d:5400:ff:fe42:2678]:8333 +[2001:19f0:5000:8c8b:5400:ff:fe1f:c023]:8333 +[2001:19f0:5000:8ce6:5400:ff:fe1b:24a9]:8333 +[2001:19f0:5:314:5400:ff:fe2c:42e8]:8333 +[2001:19f0:5:51b:5400:ff:fe49:fe5b]:8333 +[2001:19f0:5:bc:5400:ff:fe3b:9339]:8333 +[2001:1af8:4020:a020:5::]:8333 +[2001:1bc8:1a0:590e:2e0:f4ff:fe16:3a39]:8333 +[2001:1c04:1401:8f00:f4fe:4fff:fe0c:df40]:8333 +[2001:4128:6135:10:20c:29ff:fe69:9e81]:8333 [2001:4128:6135:2010:21e:bff:fee8:a3c0]:8333 -[2001:41d0:1008:761::17c]:8333 +[2001:4128:6135:e001:5054:ff:fe37:e9eb]:8333 +[2001:41d0:1000:1024::]:8333 +[2001:41d0:1000:1433::]:8333 +[2001:41d0:1004:22ae::]:8333 +[2001:41d0:1004:2996::]:8333 +[2001:41d0:1008:11e0::1a5c:6d9d]:8333 +[2001:41d0:1008:11e0::b74:baf7]:8333 +[2001:41d0:1008:237a::]:8333 +[2001:41d0:1008:2752::]:8333 +[2001:41d0:1008:494::]:8333 [2001:41d0:1:45d8::1]:8333 -[2001:41d0:1:6cd3::]:8333 +[2001:41d0:1:5630::1]:8333 +[2001:41d0:1:6f57::1]:8333 +[2001:41d0:1:801e::1]:8333 +[2001:41d0:1:8852::1]:8333 [2001:41d0:1:8b26::1]:8333 -[2001:41d0:1:afda::]:8200 +[2001:41d0:1:a5b8::1]:8333 [2001:41d0:1:b26b::1]:8333 [2001:41d0:1:c139::1]:8333 [2001:41d0:1:c8d7::1]:8333 -[2001:41d0:1:f59f::33]:8333 -[2001:41d0:1:f7cc::1]:8333 -[2001:41d0:2:1021::1]:8333 -[2001:41d0:2:37c3::]:8200 -[2001:41d0:2:4797:2323:2323:2323:2323]:8333 -[2001:41d0:2:53df::]:8333 +[2001:41d0:1:d227::]:8333 +[2001:41d0:1:dbc4::1]:8333 +[2001:41d0:1:dc5d::1]:8333 +[2001:41d0:1:e13b::1]:8333 +[2001:41d0:1:ef5b::1]:8333 +[2001:41d0:2:16be::1]:8333 +[2001:41d0:2:203c::1]:8333 +[2001:41d0:2:38c5::1]:8333 +[2001:41d0:2:519::]:8333 [2001:41d0:2:9c94::1]:8333 -[2001:41d0:2:9d3e::1]:8333 -[2001:41d0:2:a24f::]:8333 -[2001:41d0:2:a35a::]:8333 -[2001:41d0:2:b2b8::]:8333 -[2001:41d0:2:c1d9::]:8333 -[2001:41d0:2:c6e::]:8333 +[2001:41d0:2:b792::]:8333 +[2001:41d0:2:bf2a::]:8333 +[2001:41d0:2:c793::]:8333 [2001:41d0:2:c9bf::]:8333 -[2001:41d0:2:f1a5::]:8333 -[2001:41d0:52:a00::105f]:8333 -[2001:41d0:52:cff::6f5]:8333 -[2001:41d0:52:d00::6e2]:8333 -[2001:41d0:8:3e75::1]:8333 -[2001:41d0:8:62ab::1]:8333 +[2001:41d0:303:4f0::]:8333 +[2001:41d0:8:1a8a::1]:8333 +[2001:41d0:8:3fa9::1]:8333 +[2001:41d0:8:4670::1]:8333 +[2001:41d0:8:4f48::1]:8333 [2001:41d0:8:6728::]:8333 -[2001:41d0:8:b30a::1]:8333 -[2001:41d0:8:bc26::1]:8333 -[2001:41d0:8:be9a::1]:8333 -[2001:41d0:8:d984::]:8333 -[2001:41d0:8:eb8b::]:8333 -[2001:41d0:a:13a2::1]:8333 -[2001:41d0:a:2b18::1]:8333 -[2001:41d0:a:2d14::]:8333 -[2001:41d0:a:4558::1df2:76d3]:8333 -[2001:41d0:a:4aaa::]:8333 -[2001:41d0:a:635b::1]:8333 -[2001:41d0:a:63d8::1]:8333 +[2001:41d0:8:72c2:d:242:ac11:2]:8333 +[2001:41d0:8:8007::]:8333 +[2001:41d0:8:a71c::]:8333 +[2001:41d0:8:bccc::1]:8333 +[2001:41d0:8:bd45::1]:8333 +[2001:41d0:8:c67c::]:8333 +[2001:41d0:8:de3d::1]:8333 +[2001:41d0:8:e257::1]:8333 +[2001:41d0:8:e3e4::1]:8333 +[2001:41d0:a:14cc::1]:8333 +[2001:41d0:a:15b2::1]:8333 +[2001:41d0:a:1ac9::1]:8333 +[2001:41d0:a:2496::1]:8333 +[2001:41d0:a:308c::]:8333 +[2001:41d0:a:5879::]:8333 +[2001:41d0:a:6810::1]:8333 +[2001:41d0:a:682d::1]:8333 [2001:41d0:a:6c29::1]:8333 -[2001:41d0:a:f9cd::1]:8333 -[2001:41d0:d:20a4::]:8333 +[2001:41d0:a:f52a::1]:8333 +[2001:41d0:d:111c::]:8333 +[2001:41d0:e:1388::1]:8333 [2001:41d0:e:26b::1]:8333 +[2001:41d0:e:f73::1]:8333 [2001:41d0:fc8c:a200:7a24:afff:fe9d:c69b]:8333 +[2001:41f0:61:0:72f3:95ff:fe09:7521]:8333 [2001:41f0:61::7]:8333 -[2001:41f0::2]:8333 -[2001:44b8:41bd:6101:148e:4022:4950:e861]:8333 -[2001:470:1:2f9:0:1:107a:a301]:8333 -[2001:470:1f0b:ad6::2]:8333 -[2001:470:1f11:12d5::ae1:5611]:8333 +[2001:4428:200:8171:db6:2ff4:9c0e:a2da]:8333 +[2001:470:1f07:151c:baac:6fff:feb7:3ba9]:8333 +[2001:470:1f0b:ad6:a60:6eff:fec6:2323]:8333 +[2001:470:1f11:617::10f]:8333 +[2001:470:1f14:73e::2]:8333 [2001:470:1f14:7d::2]:8333 -[2001:470:27:ce::2]:8333 +[2001:470:1f15:11f8::10]:8333 +[2001:470:1f15:1b95:2c3e:8a9a:24e1:7084]:8333 +[2001:470:1f15:e9b::3ef]:8333 +[2001:470:1f1d:3a9::10]:8333 +[2001:470:25:482::2]:8333 +[2001:470:27:19f::2]:8333 +[2001:470:27:665::2]:8333 +[2001:470:28:365::4]:8333 [2001:470:41:6::2]:8333 -[2001:470:507d:0:6ab5:99ff:fe73:ac18]:8333 -[2001:470:583e::2a]:8333 -[2001:470:5f:5f::232]:8333 -[2001:470:66:119::2]:8333 -[2001:470:6c4f::cafe]:8333 -[2001:470:6f:327:913b:7fe:8545:a4f5]:8333 -[2001:470:7dda:1::1]:8333 -[2001:470:95c1::2]:8333 -[2001:470:b1d0:ffff::1000]:8333 -[2001:470:d00d:0:3664:a9ff:fe9a:5150]:8333 -[2001:470:fab7:1::1]:8333 -[2001:4800:7819:104:be76:4eff:fe05:c828]:8333 -[2001:4800:7819:104:be76:4eff:fe05:c9a0]:8333 +[2001:470:727b::11:14]:8333 +[2001:470:7:2f0::2]:8333 +[2001:470:7:65::2]:8333 +[2001:470:7f85::2]:8333 +[2001:470:8:2e1:5825:39df:3e4c:54a8]:8333 +[2001:470:8:2e1::43]:8333 +[2001:470:8:2e1:ae2a:e257:4470:6350]:8333 +[2001:470:a:c13::2]:8333 [2001:4801:7819:74:b745:b9d5:ff10:a61a]:8333 [2001:4801:7819:74:b745:b9d5:ff10:aaec]:8333 [2001:4801:7828:104:be76:4eff:fe10:1325]:8333 -[2001:4802:7800:1:be76:4eff:fe20:f023]:8333 [2001:4802:7800:2:30d7:1775:ff20:1858]:8333 -[2001:4802:7800:2:be76:4eff:fe20:6c26]:8333 -[2001:4802:7802:101:be76:4eff:fe20:256]:8333 -[2001:4802:7802:103:be76:4eff:fe20:2de8]:8333 -[2001:4830:1100:2e8::2]:8333 -[2001:4b98:dc2:41:216:3eff:fe56:f659]:8333 -[2001:4ba0:fffa:5d::93]:8333 -[2001:4ba0:ffff:1be:1:1005:0:1]:8333 -[2001:4dd0:ff00:867f::3]:8333 +[2001:4ba0:babe:832::]:8333 +[2001:4ba0:cafe:379::1]:8333 +[2001:4ba0:ffee:33::10]:8333 [2001:4dd0:ff00:9a67::9]:8333 -[2001:5c0:1400:b::3cc7]:8333 [2001:610:1b19::3]:8333 [2001:610:600:a41::2]:8333 -[2001:67c:26b4::]:8333 -[2001:8d8:840:500::39:1ae]:8333 -[2001:8d8:965:4a00::10:9343]:8333 -[2001:980:4650:1:2e0:53ff:fe13:2449]:8333 +[2001:678:174:4021::2:8333]:8333 +[2001:67c:16dc:1201:5054:ff:fe17:4dac]:8333 +[2001:67c:2128:ffff:6062:36ff:fe30:6532]:8333 +[2001:67c:2564:331:3547:6e28:85a4:fb27]:8333 +[2001:6a0:200:368::2]:8333 +[2001:718:801:311:5054:ff:fe19:c483]:8333 +[2001:7b8:2ff:8f::2]:8333 +[2001:8d8:8a6:4400::3f:86c]:8333 +[2001:8d8:923:8400::87:ebd]:8333 +[2001:960:66d::2]:8333 [2001:981:46:1:ba27:ebff:fe5b:edee]:8333 -[2001:9c8:53e9:369a:226:2dff:fe1b:7472]:8333 -[2001:9d8:cafe:3::87]:8333 -[2001:b10:11:21:3e07:54ff:fe48:7248]:8333 -[2001:ba8:1f1:f34c::2]:8333 -[2001:bc8:2310:100::1]:8333 -[2001:bc8:3427:101:7a4f:8be:2611:6e79]:8333 -[2001:bc8:3505:200::1]:8333 -[2001:cc0:a004::30:1d]:8333 -[2001:e42:102:1209:153:121:76:171]:8333 -[2002:17ea:14eb::17ea:14eb]:8333 -[2002:2f8:2bc5::2f8:2bc5]:8333 -[2002:4047:482c::4047:482c]:8333 -[2002:45c3:8cca::45c3:8cca]:8333 -[2002:46bb:8a41:0:226:b0ff:feed:5f12]:8888 -[2002:46bb:8c3c:0:8d55:8fbb:15fa:f4e0]:8765 -[2002:4c48:a0fe::4c48:a0fe]:8333 -[2002:4d44:25c8::4d44:25c8]:8333 -[2002:505f:aaa2::505f:aaa2]:8333 -[2002:5bc1:799d::5bc1:799d]:8333 -[2002:6dec:5472::6dec:5472]:8333 -[2002:8c6d:6521:9617:12bf:48ff:fed8:1724]:8333 -[2002:ac52:94e2::ac52:94e2]:8333 -[2002:af7e:3eca::af7e:3eca]:8333 -[2002:b009:20c5::b009:20c5]:8333 -[2002:c06f:39a0::c06f:39a0]:8333 -[2002:c23a:738a::c23a:738a]:8333 -[2002:c70f:7442::c70f:7442]:8333 -[2002:cec5:be4f::cec5:be4f]:8333 -[2002:d149:9e3a::d149:9e3a]:8333 +[2001:ba8:1f1:f069::2]:8333 +[2001:bc8:225f:10e:505:6573:7573:d0a]:8333 +[2001:bc8:2706::1]:8333 +[2001:bc8:323c:100::53]:8333 +[2001:bc8:323c:100::80:4]:8333 +[2001:bc8:323c:100::cafe]:8333 +[2001:bc8:3680:4242::1]:8333 +[2001:bc8:399f:f000::1]:8333 +[2001:bc8:3cbf::5]:8333 +[2001:bc8:4700:2300::19:807]:8333 +[2001:e42:102:1805:160:16:206:31]:8333 +[2002:12f1:3f::12f1:3f]:8333 +[2002:1e2:5349::1e2:5349]:8333 +[2002:1e2:5588::1e2:5588]:8333 +[2002:2501:cf62::2501:cf62]:8333 +[2002:268c:a135::268c:a135]:8333 +[2002:2a33:99db::2a33:99db]:8332 +[2002:2ebc:2c14::7]:8333 +[2002:2f59:2c9c::2f59:2c9c]:11885 +[2002:2f5a:3619::2f5a:3619]:8333 +[2002:2f5a:36a4::2f5a:36a4]:8333 +[2002:2f5a:429::2f5a:429]:8333 +[2002:2f5a:562a::2f5a:562a]:8333 +[2002:3a3b:216::3a3b:216]:8333 +[2002:3dfa:5d23::3dfa:5d23]:8333 +[2002:424f:a052::424f:a052]:8333 +[2002:451e:e922::451e:e922]:8333 +[2002:4540:4b30::4540:4b30]:8333 +[2002:51ab:7cc::51ab:7cc]:8333 +[2002:527:de11::527:de11]:8333 +[2002:5395:7d01::5395:7d01]:8333 +[2002:5395:7d2a::5395:7d2a]:8333 +[2002:5669:e3be::5669:e3be]:8333 +[2002:566a:5d6d::566a:5d6d]:8333 +[2002:59b9:f820::59b9:f820]:8333 +[2002:59f8:ac69::59f8:ac69]:8333 +[2002:5bd4:b65a::5bd4:b65a]:8333 +[2002:5c3f:39db::5c3f:39db]:8333 +[2002:5d33:8d03::5d33:8d03]:8333 +[2002:5d67:49bb::5d67:49bb]:8333 +[2002:5dae:5d5f::5dae:5d5f]:8333 +[2002:5dbe:8cc6::5dbe:8cc6]:8333 +[2002:5dbe:9503::5dbe:9503]:8333 +[2002:5fd3:8944::5fd3:8944]:8333 +[2002:5fd3:9467::5fd3:9467]:8333 +[2002:67f9:6a48::67f9:6a48]:8333 +[2002:67f9:6a4a::67f9:6a4a]:8333 +[2002:67f9:6a95::67f9:6a95]:8333 +[2002:6a0e:3ea8::6a0e:3ea8]:10011 +[2002:6b96:375a::6b96:375a]:8333 +[2002:6ca8:cffb::6ca8:cffb]:8333 +[2002:6caf:234::6caf:234]:8333 +[2002:6dec:58f5::6dec:58f5]:8333 +[2002:6dec:5ac7::6dec:5ac7]:8333 +[2002:7237:4a02::7237:4a02]:20033 +[2002:7237:94fd::7237:94fd]:10011 +[2002:7237:e428::7237:e428]:8333 +[2002:7237:fcf6::7237:fcf6]:20188 +[2002:76c0:96e6::76c0:96e6]:8333 +[2002:7819:7e80::7819:7e80]:7743 +[2002:781a:ea86::781a:ea86]:8333 +[2002:781a:f3c2::781a:f3c2]:14475 +[2002:784c:c2c0::784c:c2c0]:8333 +[2002:784c:ec97::784c:ec97]:8333 +[2002:792b:261a::792b:261a]:8333 +[2002:88f3:8cca::88f3:8cca]:8333 +[2002:88f3:a83c::88f3:a83c]:8333 +[2002:8ac9:516f::8ac9:516f]:8333 +[2002:8b81:6d78::8b81:6d78]:50344 +[2002:8b81:6e5c::8b81:6e5c]:38176 +[2002:8bc4:90a6::8bc4:90a6]:8333 +[2002:ac52:b854::ac52:b854]:8333 +[2002:add0:c14a::add0:c14a]:8333 +[2002:b07e:a70a::b07e:a70a]:8333 +[2002:b27c:c565:1::250]:8333 +[2002:b27c:c565::1]:8333 +[2002:b94d:80f1::b94d:80f1]:8333 +[2002:b982:e26a::b982:e26a]:8333 +[2002:bcd5:3145::bcd5:3145]:8333 +[2002:c08a:d22b::c08a:d22b]:8333 +[2002:c0c7:f8e3::c0c7:f8e3]:32771 +[2002:c1a9:fc5a::c1a9:fc5a]:8333 +[2002:c23f:8fc5::c23f:8fc5]:8333 +[2002:d395:ea6d::d395:ea6d]:8333 [2002:d917:ca5::d917:ca5]:8333 -[2400:8900::f03c:91ff:fe50:153f]:8333 -[2400:8900::f03c:91ff:fe6e:823e]:8333 -[2400:8900::f03c:91ff:fea8:1934]:8333 -[2400:8901::f03c:91ff:fe26:c4d6]:8333 +[2002:d917:e91::d917:e91]:8333 +[2002:db71:f434::db71:f434]:8333 +[2400:2651:161:1000:6847:d40f:aaa3:4848]:8333 [2400:8901::f03c:91ff:fec8:4280]:8333 -[2400:8901::f03c:91ff:fec8:660f]:8333 -[2401:1800:7800:102:be76:4eff:fe1c:559]:8333 [2401:1800:7800:102:be76:4eff:fe1c:a7d]:8333 +[2401:2500:203:10:153:120:156:83]:8333 +[2401:a400:3200:5600:14ee:f361:4bdc:1f7c]:8333 +[2403:4200:403:2::ff]:8333 [2405:aa00:2::40]:8333 -[2600:3c00::f03c:91ff:fe18:59b2]:8333 -[2600:3c00::f03c:91ff:fe26:bfb6]:8333 -[2600:3c00::f03c:91ff:fe33:88e3]:8333 -[2600:3c00::f03c:91ff:fe6e:7297]:8333 -[2600:3c00::f03c:91ff:fe84:8a6e]:8333 +[240b:10:ca20:f0:224:e8ff:fe1f:60d9]:8333 +[240b:250:1e0:2400:b9ef:8fe3:a69a:7378]:8333 +[240d:1a:302:8600:8876:a36d:12ee:f285]:8333 +[2600:3c00::f03c:91ff:fe91:3e49]:8333 +[2600:3c00::f03c:91ff:febb:981e]:8333 [2600:3c01::f03c:91ff:fe18:6adf]:8333 -[2600:3c01::f03c:91ff:fe26:c4b8]:8333 -[2600:3c01::f03c:91ff:fe3b:1f76]:8333 -[2600:3c01::f03c:91ff:fe50:5e06]:8333 -[2600:3c01::f03c:91ff:fe61:289b]:8333 [2600:3c01::f03c:91ff:fe69:89e9]:8333 -[2600:3c01::f03c:91ff:fe84:ac15]:8333 -[2600:3c01::f03c:91ff:fe98:68bb]:8333 -[2600:3c02::f03c:91ff:fe26:713]:8333 -[2600:3c02::f03c:91ff:fe26:c49e]:8333 -[2600:3c02::f03c:91ff:fe84:97d8]:8333 -[2600:3c02::f03c:91ff:fec8:8feb]:8333 +[2600:3c01::f03c:91ff:fe91:6a29]:8333 +[2600:3c01::f03c:91ff:fef1:1eaa]:8333 [2600:3c03::f03c:91ff:fe18:da80]:8333 -[2600:3c03::f03c:91ff:fe26:c49b]:8333 -[2600:3c03::f03c:91ff:fe50:5fa7]:8333 +[2600:3c03::f03c:91ff:fe28:1445]:8333 [2600:3c03::f03c:91ff:fe67:d2e]:8333 -[2600:3c03::f03c:91ff:fe6e:1803]:8333 -[2600:3c03::f03c:91ff:fec8:4bbe]:8333 -[2600:3c03::f03c:91ff:fee4:4e16]:8333 -[2601:18d:8300:58a6::2e4]:8333 -[2601:240:4600:40c0:250:56ff:fea4:6305]:8333 -[2601:581:c200:a719:542c:9cd5:4852:f7d9]:8333 -[2601:647:4900:85f1:ca2a:14ff:fe51:bb35]:8333 -[2601:c2:c002:b300:54a0:15b5:19f7:530d]:8333 -[2602:306:ccff:ad7f:b116:52be:64ba:db3a]:8333 -[2602:ae:1982:9400:846:f78c:fec:4d57]:8333 +[2600:3c03::f03c:91ff:fe89:116f]:8333 +[2600:3c03::f03c:91ff:feb0:5fc4]:8333 +[2600:3c03::f03c:91ff:fee0:233e]:8333 +[2600:3c03::f03c:91ff:fee0:51]:8333 +[2600:8805:2400:14e:226:4aff:fe02:2ba4]:8333 +[2600:8807:5080:3301:1487:83b7:33d7:eb97]:8333 +[2601:186:c100:6bcd:16bd:cea1:235d:1c19]:8333 +[2601:18c:4200:28d0:e4d:e9ff:fec5:76d0]:8333 +[2601:247:8201:6251:30e6:7b95:69bf:9248]:8333 +[2601:602:9980:f78:211:11ff:fec5:1ae]:8333 +[2602:ae:1993:de00:2c50:9a44:8f11:77a5]:8333 +[2602:ff68:0:1:21e:bff:feca:db72]:8333 +[2602:ff68:0:1:2bd:27ff:feb0:adf8]:8333 +[2602:ff68:0:1::5]:8333 +[2602:ff68:0:5:2bd:27ff:feb0:adf8]:8333 [2602:ffc5:1f::1f:2d61]:8333 [2602:ffc5:1f::1f:9211]:8333 -[2602:ffc5::75d5:c1c3]:8333 +[2602:ffc5::9e63:27a2]:8333 +[2602:ffc5::c30:1c75]:8333 [2602:ffc5::ffc5:b844]:8333 [2602:ffe8:100:2::457:936b]:8333 -[2602:ffe8:100:2::9d20:2e3c]:8333 -[2602:ffea:1001:72b::578b]:8333 -[2602:ffea:a::24c4:d9fd]:8333 -[2604:0:c1:100:1ec1:deff:fe54:2235]:8333 -[2604:180:1:1af::42a9]:8333 -[2604:180:3:702::c9de]:8333 -[2604:4080:1114:0:3285:a9ff:fe93:850c]:8333 -[2604:6000:ffc0:3c:64a3:94d0:4f1d:1da8]:8333 -[2605:6000:f380:9a01:ba09:8aff:fed4:3511]:8333 -[2605:6001:e00f:7b00:c587:6d91:6eff:eeba]:8333 -[2605:f700:c0:1::25c3:2a3e]:8333 -[2606:6000:a441:9903:5054:ff:fe78:66ff]:8333 -[2607:5300:100:200::1c83]:9334 -[2607:5300:10::a1]:8333 -[2607:5300:60:1c2f::1]:8333 -[2607:5300:60:2b90::1]:8333 -[2607:5300:60:3320::1]:8333 -[2607:5300:60:385::1]:8333 -[2607:5300:60:4a85::]:8333 -[2607:5300:60:65e4::]:8333 -[2607:5300:60:6918::]:8333 -[2607:5300:60:711a:78::a7b5]:8333 -[2607:5300:60:714::1]:8333 -[2607:5300:60:870::1]:8333 -[2607:5300:60:952e:3733::1414]:8333 -[2607:f1c0:848:1000::48:943c]:8333 -[2607:f2e0:f:5df::2]:8333 -[2607:f748:1200:f8:21e:67ff:fe99:8f07]:8333 -[2607:f948:0:1::7]:8333 -[2607:ff68:100:36::131]:8333 -[2803:6900:1::117]:8333 -[2a00:1098:0:80:1000:25:0:1]:8333 -[2a00:1178:2:43:5054:ff:fe84:f86f]:8333 -[2a00:1178:2:43:5054:ff:fee7:2eb6]:8333 -[2a00:1178:2:43:8983:cc27:d72:d97a]:8333 -[2a00:1328:e100:cc42:230:48ff:fe92:55c]:8333 +[2604:180:2:eee::ca46]:8333 +[2604:880:d:85::be37]:8333 +[2604:9a00:2100:a009:2::]:8333 +[2604:a880:2:d0::301:8001]:8333 +[2604:a880:2:d0::4a9:1001]:8333 +[2604:a880:2:d0::53a:c001]:8333 +[2604:a880:400:d0::ad7:e001]:8333 +[2604:a880:400:d0::dcf:f001]:8333 +[2605:4d00::50]:8333 +[2605:6000:edc8:300::ddfe]:8333 +[2605:6000:ffc0:70:74d5:225c:f553:5bb8]:8333 +[2606:6000:c148:7003:5054:ff:fe78:66ff]:8333 +[2606:6000:e6d6:d701:d428:5e44:a2c9:3ff6]:8333 +[2606:c680:1:4a:2016:d1ff:fe93:52a7]:8333 +[2607:5300:203:118:3733::1414]:8333 +[2607:5300:60:13bb::1]:8333 +[2607:5300:60:1966::1]:8333 +[2607:5300:60:2218::]:8333 +[2607:5300:60:3775::]:8333 +[2607:5300:60:3ddf::]:8333 +[2607:5300:60:a654::]:8333 +[2607:5300:60:a7a3::]:8333 +[2607:5300:60:ac0::1]:8333 +[2607:5300:60:cf97::]:8333 +[2607:f0d0:1901:19::6]:8333 +[2607:f128:40:1202:69:162:139:125]:8333 +[2607:f128:40:1703::2]:8333 +[2607:f178:0:8::106]:8333 +[2607:f1c0:84d:8900::7e:cad]:8333 +[2607:f948:0:1::1:40]:8333 +[2607:fcd0:100:2302::6094:635a]:8333 +[2607:fcd0:100:6a00::3a96:1]:8333 +[2607:fcd0:100:6a02::7ff0:1]:8333 +[2607:fcd0:100:8203::8c58:dbc]:8333 +[2607:fea8:1360:9c2:221a:6ff:fe47:776d]:8333 +[2607:fea8:4da0:9ce:5114:a8ec:20f5:a50b]:8333 +[2607:fea8:5df:fda0:feaa:14ff:feda:c79a]:8333 +[2607:fea8:84c0:163:f42c:baff:fecc:6bbf]:8333 +[2607:ff10:c5:502:225:90ff:fe32:d446]:8333 +[2607:ff48:aa81:800::96cf:1]:8333 +[2620:11c:5001:1118:d267:e5ff:fee9:e673]:8333 +[2620:b8:4000:1000::93:1]:8333 +[2800:1a0::9]:8333 +[2a00:1178:2:43:19fd:d43e:b77:edeb]:8333 +[2a00:1178:2:43:b4e3:e562:f811:d761]:8333 [2a00:14f0:e000:80d2:cd1a::1]:8333 +[2a00:1630:14::101]:8333 [2a00:1630:2:1802:188:122:91:11]:8333 -[2a00:18e0:0:1800::1]:8333 -[2a00:18e0:0:dcc5:109:234:106:191]:8333 -[2a00:1a28:1157:87::94c7]:8333 +[2a00:1630:2:500::4]:8333 +[2a00:1768:2001:24::148:218]:8333 +[2a00:1768:2001:27::142:21]:8333 +[2a00:1a48:7810:101:be76:4eff:fe08:c774]:8333 [2a00:1ca8:37::a5fc:40d1]:8333 [2a00:1ca8:37::ab6d:ce2c]:8333 -[2a00:7143:100:0:216:3eff:fe2e:74a3]:8333 -[2a00:7143:100:0:216:3eff:fed3:5c21]:8333 -[2a00:7c80:0:45::123]:8333 +[2a00:1dc0:2255:10::2]:8333 +[2a00:7c80:0:71::8]:8333 +[2a00:7c80:0:97::7]:8333 +[2a00:bbe0:0:42:222:64ff:fe9a:e206]:8333 +[2a00:c98:2050:a020:3::110]:8333 +[2a00:dcc0:eda:98:183:193:1d24:b53a]:8333 [2a00:dcc0:eda:98:183:193:c382:6bdb]:8333 [2a00:dcc0:eda:98:183:193:f72e:d943]:8333 -[2a00:f820:17::4af:1]:8333 -[2a00:f940:2:1:2::101d]:8333 -[2a00:f940:2:1:2::6ac]:8333 -[2a01:1b0:7999:402::131]:8333 -[2a01:238:42dd:f900:7a6c:2bc6:4041:c43]:8333 -[2a01:238:4313:6300:2189:1c97:696b:5ea]:8333 -[2a01:488:66:1000:5c33:91f9:0:1]:8333 -[2a01:488:66:1000:b01c:178d:0:1]:8333 +[2a00:f90:ff0:c100:53c4:97a7:8b59:796a]:8333 +[2a01:238:435c:de00:b110:38cf:192d:b2c]:28333 +[2a01:348:6:7cf::2]:8333 +[2a01:368:e012:8888:216:3eff:fe24:1162]:8333 +[2a01:488:66:1000:53a9:22b:0:1]:8333 +[2a01:488:67:1000:523:ffa7:0:1]:8333 +[2a01:488:67:1000:b01c:3379:0:1]:8333 [2a01:4f8:100:34ce::2]:8333 -[2a01:4f8:100:34e4::2]:8333 [2a01:4f8:100:44e7::2]:8333 -[2a01:4f8:100:510e::2]:8333 -[2a01:4f8:100:5128::2]:8333 -[2a01:4f8:110:5105::2]:8333 -[2a01:4f8:110:516c::2]:8333 +[2a01:4f8:10a:2e4::2]:8333 +[2a01:4f8:10a:34e::2]:8333 +[2a01:4f8:10a:51d::2]:8333 +[2a01:4f8:10a:622::2]:8333 +[2a01:4f8:10a:85f::2]:8333 +[2a01:4f8:10a:864::2]:8333 +[2a01:4f8:10a:d04::2]:8333 +[2a01:4f8:110:334c::2]:8333 +[2a01:4f8:110:536e::2]:8333 [2a01:4f8:120:43e4::2]:8333 -[2a01:4f8:120:62e6::2]:8333 [2a01:4f8:120:702e::2]:8333 -[2a01:4f8:120:8203::2]:8333 -[2a01:4f8:121:234d::2]:8333 -[2a01:4f8:121:261::2]:8333 -[2a01:4f8:130:11ea::2]:8333 +[2a01:4f8:121:4346::2]:8333 [2a01:4f8:130:3332::2]:8333 -[2a01:4f8:130:40ab::2]:8333 -[2a01:4f8:130:632c::2]:8333 -[2a01:4f8:130:6366::2]:8333 -[2a01:4f8:130:934f::2]:8333 +[2a01:4f8:131:33ad::2]:8333 [2a01:4f8:131:33ad:fea1::666]:8333 -[2a01:4f8:140:2195::2]:8333 -[2a01:4f8:140:6333::2]:8333 -[2a01:4f8:140:930d::2]:8333 +[2a01:4f8:140:31b0::2]:8333 +[2a01:4f8:140:4088::2]:8333 +[2a01:4f8:140:931a::2]:8333 [2a01:4f8:140:93b0::2]:8333 -[2a01:4f8:141:1167::2]:8333 +[2a01:4f8:141:13ad::c451]:8333 [2a01:4f8:141:186::2]:8333 -[2a01:4f8:141:53f0::2]:8333 -[2a01:4f8:150:336a::2]:8333 -[2a01:4f8:150:72ee::4202]:8333 -[2a01:4f8:150:8324::2]:9001 -[2a01:4f8:151:21ca::2]:8333 -[2a01:4f8:151:41c2:0:5404:a67e:f250]:8333 -[2a01:4f8:151:5128::2]:8333 +[2a01:4f8:141:22ae::2]:8333 +[2a01:4f8:141:322c::2]:8333 +[2a01:4f8:150:11d4::2]:8333 +[2a01:4f8:150:440f::2]:8333 +[2a01:4f8:150:61ee::2]:8333 +[2a01:4f8:150:726b::2]:8333 +[2a01:4f8:151:30c9::2]:15000 +[2a01:4f8:151:41a2::2]:8333 +[2a01:4f8:151:41cc::2]:8333 [2a01:4f8:151:52c6::154]:8333 -[2a01:4f8:151:6347::2]:9001 -[2a01:4f8:160:5136::2]:8333 -[2a01:4f8:160:72c5::2858:e1c5]:8333 -[2a01:4f8:160:72c5::593b:60d5]:8333 +[2a01:4f8:151:600b::1:1]:8333 +[2a01:4f8:151:7175::2]:8333 +[2a01:4f8:160:41f0::1:33]:8333 +[2a01:4f8:160:5328::27f0:187a]:8333 [2a01:4f8:160:814f::2]:8333 -[2a01:4f8:161:13d0::2]:8333 -[2a01:4f8:161:228f::2]:8333 -[2a01:4f8:161:51c4::2]:8333 -[2a01:4f8:161:60a7::2]:8333 +[2a01:4f8:161:21ad::333:30]:8333 [2a01:4f8:161:7026::2]:8333 -[2a01:4f8:161:9184::2]:8333 -[2a01:4f8:162:2108::2]:8333 -[2a01:4f8:162:218c::2]:8333 -[2a01:4f8:162:4443::2]:8333 -[2a01:4f8:162:51a3::2]:8333 +[2a01:4f8:162:4110::2]:8333 +[2a01:4f8:162:4348::2]:8333 +[2a01:4f8:171:1c1b::2]:8333 +[2a01:4f8:171:1c3::2]:8333 +[2a01:4f8:171:2258::2]:8333 +[2a01:4f8:171:2a70::2]:8333 +[2a01:4f8:171:2e1b::2]:8333 +[2a01:4f8:171:2f28::2]:8333 +[2a01:4f8:171:3248::2]:8333 +[2a01:4f8:171:380c::2]:8333 [2a01:4f8:171:b93::2]:8333 -[2a01:4f8:190:1483::1]:8333 -[2a01:4f8:190:4495::2]:8333 -[2a01:4f8:190:64c9::2]:8333 +[2a01:4f8:171:d0a::2]:8333 +[2a01:4f8:172:116c::2]:8333 +[2a01:4f8:172:1287::2]:8333 +[2a01:4f8:172:17a9::2]:8333 +[2a01:4f8:172:1ca7::2]:8333 +[2a01:4f8:172:2159::2]:8333 +[2a01:4f8:172:3a41::2]:8333 +[2a01:4f8:172:3b42::2]:8333 +[2a01:4f8:172:3ec1::2]:8333 +[2a01:4f8:172:3ec2::2]:8333 +[2a01:4f8:172:aeb::2]:8333 +[2a01:4f8:172:aec::2]:8333 +[2a01:4f8:173:10ab::2]:8333 +[2a01:4f8:173:1551::2]:8333 +[2a01:4f8:173:1bca::2]:8333 +[2a01:4f8:173:1e2e::2]:8333 +[2a01:4f8:173:2162::2]:8333 +[2a01:4f8:173:21e6::2]:8333 +[2a01:4f8:173:42::2]:8333 +[2a01:4f8:173:cc1::2]:8333 +[2a01:4f8:190:1253::2]:8333 +[2a01:4f8:190:24eb::2]:8333 +[2a01:4f8:190:34f0::2]:8333 +[2a01:4f8:190:528d::2]:8333 [2a01:4f8:190:91ce::2]:8333 [2a01:4f8:191:2194::83]:8333 [2a01:4f8:191:40e8::2]:8333 -[2a01:4f8:191:44b4::2]:8333 -[2a01:4f8:191:8242::2]:8333 -[2a01:4f8:191:83a2::2]:8333 -[2a01:4f8:192:11b2::2]:8333 +[2a01:4f8:191:8165::2]:22556 +[2a01:4f8:191:81b7::2]:8333 +[2a01:4f8:191:8328::3]:8333 +[2a01:4f8:192:11b2::2]:8343 [2a01:4f8:192:216c::2]:8333 -[2a01:4f8:192:22b3::2]:8333 +[2a01:4f8:192:22af::2]:8333 +[2a01:4f8:192:2422::2]:8333 +[2a01:4f8:192:34d0::2]:8333 [2a01:4f8:192:440b::2]:8333 +[2a01:4f8:192:5230::2]:8333 [2a01:4f8:192:db::2]:8333 [2a01:4f8:200:1012::2]:8333 -[2a01:4f8:200:23d1::dead:beef]:8333 -[2a01:4f8:200:506d::2]:8333 -[2a01:4f8:200:51f0::2]:8333 -[2a01:4f8:200:5389::2]:8333 -[2a01:4f8:200:53e3::2]:8333 -[2a01:4f8:200:6344::2]:8333 -[2a01:4f8:200:6396::2]:8333 -[2a01:4f8:200:63af::119]:8333 -[2a01:4f8:200:71e3:78b4:f3ff:fead:e8cf]:8333 -[2a01:4f8:201:214c::2]:8333 -[2a01:4f8:201:233:1::3]:8333 -[2a01:4f8:201:3e3::2]:8333 +[2a01:4f8:200:414e::2]:8333 +[2a01:4f8:200:416a::2]:8333 +[2a01:4f8:201:21a7::2]:8333 +[2a01:4f8:201:4017::11]:8333 [2a01:4f8:201:6011::4]:8333 [2a01:4f8:201:60d5::2]:8333 -[2a01:4f8:202:265::2]:8333 -[2a01:4f8:202:3115::2]:8333 +[2a01:4f8:202:12d6::2]:8333 [2a01:4f8:202:31e3::2]:8333 -[2a01:4f8:202:31ef::2]:8333 -[2a01:4f8:202:3392::2]:8333 +[2a01:4f8:202:32c6::2]:8333 [2a01:4f8:202:53c3::2]:8333 -[2a01:4f8:202:63f4::2]:8333 -[2a01:4f8:202:7227::2]:8333 -[2a01:4f8:210:2227::2]:8333 -[2a01:4f8:210:24aa::2]:8333 [2a01:4f8:211:14cf::2]:8333 -[2a01:4f8:211:181b::2]:8333 -[2a01:4f8:212:289e::2]:8333 -[2a01:4f8:212:33db::2]:18333 -[2a01:4f8:a0:112f::2]:8333 -[2a01:4f8:a0:3174::2]:8333 -[2a01:4f8:a0:328c::2]:8333 -[2a01:4f8:a0:5243::2]:8333 -[2a01:4f8:c17:19b9::2]:8333 -[2a01:4f8:c17:1a41::2]:8333 -[2a01:4f8:c17:1a92::2]:8333 -[2a01:4f8:c17:273::2]:8333 -[2a01:4f8:c17:435::2]:8333 -[2a01:4f8:c17:755::2]:8333 -[2a01:4f8:c17:b54::2]:8333 -[2a01:4f8:d16:9384::2]:8333 +[2a01:4f8:211:1ec5::2]:8333 +[2a01:4f8:211:483::2]:8333 +[2a01:4f8:211:d99::8]:8333 +[2a01:4f8:212:1826::2]:8333 +[2a01:4f8:212:27a8::2]:8333 +[2a01:4f8:221:801::2]:8333 +[2a01:4f8:a0:12cc::2]:8333 +[2a01:4f8:a0:746a:101:1:1:2]:8333 +[2a01:4f8:a0:828a::2]:8333 +[2a01:4f8:c17:2eef::2]:8333 +[2a01:4f8:c17:2f3c::2]:3333 +[2a01:4f8:c17:3b02::2]:8333 +[2a01:4f8:c17:4245::2]:8333 +[2a01:4f8:c17:464f::2]:8333 +[2a01:4f8:c17:4a1c::2]:8333 +[2a01:4f8:c17:4c5d::2]:8333 +[2a01:4f8:c17:67f8::2]:8333 +[2a01:4f8:c17:6dd0::2]:8333 +[2a01:4f8:c17:710b::2]:8333 +[2a01:4f8:c17:714::2]:8333 +[2a01:4f8:c17:72c6::2]:8333 [2a01:608:ffff:a009:8bf5:879d:e51a:f837]:8333 -[2a01:680:10:10:f2de:f1ff:fec9:dc0]:8333 -[2a01:7c8:aaac:1f6:5054:ff:fe30:e585]:8333 -[2a01:7c8:aaac:20b:5054:ff:fe24:435e]:8333 +[2a01:680:10:10::1]:8333 +[2a01:6f0:ffff:120::8dcb]:8333 +[2a01:79c:cebc:857c:98c1:88ff:fef5:90de]:8333 +[2a01:79d:7377:2629:7e57:7e57:1:1]:8333 [2a01:7c8:aaac:43d:5054:ff:fe4e:3dd4]:8333 -[2a01:7c8:aaad:256::1]:8333 -[2a01:7c8:aab6:ea:5054:ff:feff:eac3]:8333 -[2a01:7c8:aab9:5a:5054:ff:fe89:7b26]:8333 -[2a01:7c8:aabc:2c8:5054:ff:fe35:6581]:8333 -[2a01:7e00::f03c:91ff:fe18:301e]:8333 -[2a01:7e00::f03c:91ff:fe18:3942]:8333 +[2a01:7c8:aab5:3e6:5054:ff:fed7:4e54]:8333 +[2a01:7c8:aabd:3d5:5054:ff:fe95:f586]:8333 +[2a01:7c8:aac1:453:d0d2:af96:fa88:5d0e]:8333 +[2a01:7c8:aac3:663:5054:ff:fe25:8c69]:8333 +[2a01:7c8:aac3:97:5054:ff:fea7:3780]:8333 +[2a01:7c8:aac4:567:5054:ff:fedc:518a]:8333 [2a01:7e00::f03c:91ff:fe26:8c87]:8333 -[2a01:7e00::f03c:91ff:fe50:6206]:8333 -[2a01:7e00::f03c:91ff:fe67:559d]:8333 -[2a01:7e00::f03c:91ff:fe84:434f]:8333 +[2a01:7e00::f03c:91ff:fe50:94b8]:8333 +[2a01:7e00::f03c:91ff:fe55:2c]:8333 [2a01:7e00::f03c:91ff:fe89:1143]:8333 -[2a01:7e00::f03c:91ff:fe98:2505]:8333 -[2a01:7e00::f03c:91ff:fedb:352e]:8333 -[2a01:7e01::f03c:91ff:fec8:d7b5]:8333 -[2a01:e34:ee33:1640:c504:f677:b28a:ba42]:8333 -[2a01:e35:2e7e:bc0:e079:f55e:cef3:b5d7]:8333 +[2a01:7e00::f03c:91ff:fe89:53fd]:8333 +[2a01:7e00::f03c:91ff:fedf:b70f]:8333 +[2a01:b000::4166:515b:ef9e:b3]:8333 +[2a01:b2e0:2::40]:8333 +[2a01:e34:ec29:24c0:f3:ddaf:9f59:586f]:8333 +[2a01:e34:eed7:6670:ec1b:bf7c:b012:6069]:8333 [2a01:e35:2ee5:610:21f:d0ff:fe4e:7460]:8333 [2a01:e35:8a3f:47c0:c617:feff:fe3c:9fbd]:8333 -[2a01:e35:8aca:6a0:211:aff:fe5e:295e]:8333 -[2a02:180:a:18:81:7:11:50]:8333 -[2a02:1810:1d87:6a00:5604:a6ff:fe60:d87d]:8333 -[2a02:2168:1144:5c01:d63d:7eff:fedd:4f8e]:8333 -[2a02:2498:6d7b:7001:b508:b39d:2cea:5b7a]:8333 -[2a02:2528:503:2::15]:8333 -[2a02:2528:fa:1a56:216:44ff:fe6a:d112]:8333 -[2a02:27f8:2012:0:e9f7:268f:c441:6129]:8333 +[2a01:e35:8bff:70b0:1e1b:dff:fe0b:236d]:8333 +[2a02:1205:34c3:a4e0:d63d:7eff:fe98:10c8]:8333 +[2a02:1205:34da:aa00:5882:249d:ddbf:bc43]:8333 +[2a02:1205:5051:a640:d6ae:52ff:fea3:ac]:8333 +[2a02:1205:c689:d980:baae:edff:feea:9445]:8333 +[2a02:120b:2c2a:5ec0:10dd:31ff:fe42:5079]:8333 +[2a02:120b:2c35:69d0:219:99ff:fe6b:4ec3]:8333 +[2a02:120b:c3c2:ff60:21f:5bff:fec3:a7ad]:24312 +[2a02:13b8:4000:1000:216:e6ff:fe92:8619]:8333 +[2a02:13b8:4000:1000::27]:8333 +[2a02:17d0:2a:4400:40f:3dd4:b053:47ad]:8333 +[2a02:180:1:1::517:afb]:8333 +[2a02:180:6:1::18]:8333 +[2a02:1810:1d11:f900:6872:f28e:8126:f635]:8333 +[2a02:27a8:0:1:52e5:49ff:fee3:3b49]:8333 [2a02:348:86:3011::1]:8333 -[2a02:4780:1:1::1:8a01]:8333 -[2a02:578:5002:116::2]:8333 +[2a02:390:9000:0:218:7dff:fe10:be33]:8333 +[2a02:582:78c1:7600:2d49:6212:29d3:abb]:8333 [2a02:6080::1:190b:69e3]:8333 -[2a02:6080::1:e893:d9d6]:8333 -[2a02:770:4000::139]:8333 +[2a02:750:7:3305::575]:8333 +[2a02:752:100:3::53]:8333 +[2a02:7aa0:1201::7501:d950]:8333 [2a02:7aa0:1201::deb3:81a2]:8333 -[2a02:8010:b001::5860:59b5]:8333 -[2a02:810d:21c0:f00:a248:1cff:feb8:5348]:8333 -[2a02:a50::21b:24ff:fe93:4e39]:8333 -[2a02:a80:0:1200::2]:8333 -[2a02:c200:0:10:2:1:5830:1]:8333 -[2a02:c200:0:10:2:5:4692:1]:8333 -[2a02:c200:0:10:3:0:7158:1]:8333 -[2a02:c200:0:10::2244:1]:8333 -[2a02:c200:1:10:2:3:3339:1]:8333 -[2a02:c200:1:10:2:3:7844:1]:8333 -[2a02:c200:1:10:2:5:6288:1]:8333 -[2a02:c200:1:10:3:0:5912:1]:8333 +[2a02:7aa0:1619::a037:69a6]:8333 +[2a02:810d:14c0:8694:d250:99ff:fe81:23d9]:8333 +[2a02:a50::dacb:8aff:fe36:8d2d]:8333 +[2a02:c200:0:10:3:0:2591:1]:8333 +[2a02:c200:1:10:2:5:9982:1]:8333 +[2a02:c200:1:10:3:0:9290:1]:8333 +[2a02:c205:3000:7158::1]:8333 +[2a02:c205:3001:4522::1]:8333 +[2a02:c205:3001:6549::1]:8333 +[2a02:c207:2008:3772::1]:8333 +[2a02:c207:2008:6519::1]:8333 +[2a02:c207:2009:213::1]:8333 +[2a02:c207:2009:7858::1]:8333 +[2a02:c207:2010:302::1]:8333 +[2a02:c207:3001:5824::1]:8333 +[2a02:ce80:0:20::1]:8333 [2a03:4000:2:496::8]:8333 +[2a03:4000:6:416c::53]:8333 [2a03:4000:6:8009::1]:8333 -[2a03:4000:6:8063::bcd0]:8333 -[2a03:4900:fffc:b::2]:8333 -[2a03:b0c0:1:d0::d:5001]:8333 +[2a03:4000:9:8e::1]:8333 +[2a03:7380:2140:17:51fe:3519:b571:4a13]:8333 +[2a03:b0c0:0:1010::7a3:1001]:8333 +[2a03:b0c0:0:1010::7aa:4001]:8333 +[2a03:b0c0:3:d0::1b99:c001]:8333 +[2a03:b0c0:3:d0::1b99:e001]:8333 +[2a03:b0c0:3:d0::1b9a:3001]:8333 +[2a03:b0c0:3:d0::2208:6001]:8333 +[2a03:b0c0:3:d0::23f7:1001]:8333 +[2a03:b0c0:3:d0::23f7:9001]:8333 +[2a03:b0c0:3:d0::23fb:2001]:8333 +[2a03:b0c0:3:d0::23fb:3001]:8333 +[2a03:b0c0:3:d0::23fb:5001]:8333 +[2a03:b0c0:3:d0::23fb:7001]:8333 +[2a03:b0c0:3:d0::2400:1]:8333 +[2a03:b0c0:3:d0::2400:3001]:8333 +[2a03:b0c0:3:d0::2400:e001]:8333 +[2a03:b0c0:3:d0::2401:e001]:8333 +[2a03:b0c0:3:d0::2402:2001]:8333 +[2a03:b0c0:3:d0::2402:8001]:8333 +[2a03:b0c0:3:d0::2402:9001]:8333 +[2a03:b0c0:3:d0::2402:b001]:8333 +[2a03:b0c0:3:d0::2402:d001]:8333 +[2a03:b0c0:3:d0::2403:1001]:8333 +[2a03:b0c0:3:d0::2403:2001]:8333 +[2a03:b0c0:3:d0::2403:4001]:8333 +[2a03:b0c0:3:d0::2403:6001]:8333 +[2a03:b0c0:3:d0::2403:a001]:8333 +[2a03:b0c0:3:d0::2403:b001]:8333 +[2a03:b0c0:3:d0::2403:f001]:8333 +[2a03:b0c0:3:d0::2404:6001]:8333 +[2a03:b0c0:3:d0::2404:b001]:8333 [2a03:f80:ed15:149:154:155:235:1]:8333 -[2a03:f80:ed15:149:154:155:241:1]:8333 -[2a03:f80:ed16:ca7:ea75:b12d:2af:9e2a]:8333 -[2a04:1980:3100:1aab:290:faff:fe70:a3d8]:8333 -[2a04:1980:3100:1aab:e61d:2dff:fe29:f590]:8333 -[2a04:2f80:6:200::89]:8333 -[2a04:ac00:1:4a0b:5054:ff:fe00:5af5]:8333 -[2a04:ad80:0:68::35da]:8333 -3ffk7iumtx3cegbi.onion:8333 +[2a04:1980:3100:1aac:e61d:2dff:fe29:f241]:8333 +[2a04:1980:3100:1aac:e61d:2dff:fe29:f251]:8333 +[2a04:2180:0:1::5a49:3c06]:8333 +[2a04:2180:1:7::3]:8333 +[2a04:2e00:5:2e:9a4b:e1ff:fe62:6dc0]:8333 +[2a04:3542:1000:910:8492:b8ff:fe91:711d]:8333 +[2a04:dbc3:fffe:0:e61f:13ff:fe95:8401]:8333 +[2a06:9fc0:2a06:9fc0:2a06:9fc1:67c:e706]:8333 +[2c0f:f738:2004:82::]:8333 +2hryb3uh3tzwgnya.onion:8333 3nmbbakinewlgdln.onion:8333 -4j77gihpokxu2kj4.onion:8333 -546esc6botbjfbxb.onion:8333 -5at7sq5nm76xijkd.onion:8333 -77mx2jsxaoyesz2p.onion:8333 -7g7j54btiaxhtsiy.onion:8333 -a6obdgzn67l7exu3.onion:8333 -ab64h7olpl7qpxci.onion:8333 -am2a4rahltfuxz6l.onion:8333 -azuxls4ihrr2mep7.onion:8333 -bitcoin7bi4op7wb.onion:8333 -bitcoinostk4e4re.onion:8333 +3qeri3tmhzmpegyv.onion:8333 +4wdknmecghcmclq5.onion:8333 +53tsjt6zq3iasv5q.onion:8333 +5cg7qeywvwo6vxpt.onion:8333 +5gbcrgqxcbxj253s.onion:8333 +6cn4ilbwkrkh7gwo.onion:8333 +6e4jrnn7igeqxmlf.onion:8333 +6ymgbvnn6d5nfmv4.onion:8333 +6zsh3bfduhpo7ldl.onion:8333 +72fq6phv4fg4rhvh.onion:8333 +7gdqp6npusk4lfwk.onion:8333 +a7emxol55e623lqc.onion:8333 +assbiydziq77zaki.onion:8333 +bafk5ioatlgt7dgl.onion:8333 bk7yp6epnmcllq72.onion:8333 -bmutjfrj5btseddb.onion:8333 -ceeji4qpfs3ms3zc.onion:8333 -clexmzqio7yhdao4.onion:8333 +brwqezn6le54w2bb.onion:8333 +bs4bq6s6qkvt5hpi.onion:8333 +bup5n5e3kurvjzf3.onion:8333 +c2tpqkaz4ihjzwgb.onion:8333 +cernrmrk5zomzozn.onion:8333 +cfyegj64ht3jpodr.onion:8333 +cg5vg54cazzpvoug.onion:8333 +cgk4u2lxrvml4jvb.onion:8333 +cjygd7pu5lqkky5j.onion:8333 +d6wubsdtr46dd5ki.onion:8333 +dfq6yjc3aelplwr4.onion:8333 +dqpxwlpnv3z3hznl.onion:8333 +eamfospuveabaimd.onion:8333 +ep2mjzox3kvb6ax4.onion:8333 +fpbxb4wjudiw2w5a.onion:8333 +fu5hfsbbf5jwsvhv.onion:8333 +g4freoibsczujle3.onion:8333 gb5ypqt63du3wfhn.onion:8333 -h2vlpudzphzqxutd.onion:8333 -n42h7r6oumcfsbrs.onion:4176 -ncwk3lutemffcpc4.onion:8333 +ggdy2pb2avlbtjwq.onion:8333 +gh2aiddzxmvyrnue.onion:8333 +gnxgylbgzvaazkq7.onion:8333 +hnizdxnejel64ubk.onion:8333 +htvdcmlc3abji2ab.onion:8443 +hwuboois4gslupgx.onion:8333 +hxz6gowludlj6d5a.onion:8333 +j6umo4bnsztpsonc.onion:8333 +jdunmaocwbbnw565.onion:8333 +ktv3qlxl7xvmdlf4.onion:8333 +kvd44sw7skb5folw.onion:8333 +kwimnzm6vd4zakvl.onion:8333 +la5xhk3lprxzxmz2.onion:8333 +lc7cx67end26uutp.onion:8352 +mwu5og2agcspmgkx.onion:8333 +mzxkipiyekaoh7my.onion:8333 +n6rwlrtwpqc7qwo7.onion:8333 +nj36424yccqph62z.onion:8333 +o256w7t3vcgktmxk.onion:8333 +o4sl5na6jeqgi3l6.onion:8333 okdzjarwekbshnof.onion:8333 -pjghcivzkoersesd.onion:8333 -rw7ocjltix26mefn.onion:8333 -uws7itep7o3yinxo.onion:8333 -vk3qjdehyy4dwcxw.onion:8333 +oyebydl2pacx6v26.onion:8333 +p5mx2imj75dpmime.onion:8333 +psco6bxjewljrczx.onion:8333 +pxtgswet6tlgrbwj.onion:8333 +rb4v3fhgx2zr4rre.onion:8333 +rjlnp3hwvrsmap6e.onion:8333 +rlafimkctvz63llg.onion:8333 +rxjvy5eyttep5tts.onion:8333 +seoskudzk6vn6mqz.onion:8333 +tpgdufxxsw3jkrdf.onion:8333 +tuiyvqgi3o675pjb.onion:8333 +tx4zd7d5exonnblh.onion:8333 +uokg6avfgbhofls3.onion:8333 +v3gjphgqy5hygcml.onion:8333 +vhdoxqq63xr53ol7.onion:8333 +visevrizz3quyagj.onion:8333 vqpye2k5rcqvj5mq.onion:8333 -wpi7rpvhnndl52ee.onion:8333 +wfsx2gi7djhy22hk.onion:8333 +wg6vwmbrzyyzapun.onion:8333 +xub4w3w4wwk56xiq.onion:8333 +ycivnom44dmxx4ob.onion:8333 +ywskufc62bf2fum4.onion:8333 +z4fax2vxg23t2ddf.onion:8333 +zo5dklwelmdrpo5n.onion:8333 diff --git a/contrib/spendfrom/README.md b/contrib/spendfrom/README.md deleted file mode 100644 index c0a9c9ccf9..0000000000 --- a/contrib/spendfrom/README.md +++ /dev/null @@ -1,35 +0,0 @@ -### SpendFrom ### - -Use the raw transactions API to send coins received on a particular -address (or addresses). - -### Usage: ### -Depends on [jsonrpc](http://json-rpc.org/). - - spendfrom.py --from=FROMADDRESS1[,FROMADDRESS2] --to=TOADDRESS --amount=amount \ - --fee=fee --datadir=/path/to/.bitcoin --testnet --dry_run - -With no arguments, outputs a list of amounts associated with addresses. - -With arguments, sends coins received by the `FROMADDRESS` addresses to the `TOADDRESS`. - -### Notes ### - -- You may explicitly specify how much fee to pay (a fee more than 1% of the amount -will fail, though, to prevent bitcoin-losing accidents). Spendfrom may fail if -it thinks the transaction would never be confirmed (if the amount being sent is -too small, or if the transaction is too many bytes for the fee). - -- If a change output needs to be created, the change will be sent to the last -`FROMADDRESS` (if you specify just one `FROMADDRESS`, change will go back to it). - -- If `--datadir` is not specified, the default datadir is used. - -- The `--dry_run` option will just create and sign the transaction and print -the transaction data (as hexadecimal), instead of broadcasting it. - -- If the transaction is created and broadcast successfully, a transaction id -is printed. - -- If this was a tool for end-users and not programmers, it would have much friendlier -error-handling. diff --git a/contrib/spendfrom/setup.py b/contrib/spendfrom/setup.py deleted file mode 100644 index 01b9768a5b..0000000000 --- a/contrib/spendfrom/setup.py +++ /dev/null @@ -1,9 +0,0 @@ -from distutils.core import setup -setup(name='btcspendfrom', - version='1.0', - description='Command-line utility for bitcoin "coin control"', - author='Gavin Andresen', - author_email='gavin@bitcoinfoundation.org', - requires=['jsonrpc'], - scripts=['spendfrom.py'], - ) diff --git a/contrib/spendfrom/spendfrom.py b/contrib/spendfrom/spendfrom.py deleted file mode 100755 index 72ee0425eb..0000000000 --- a/contrib/spendfrom/spendfrom.py +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/env python -# -# Use the raw transactions API to spend bitcoins received on particular addresses, -# and send any change back to that same address. -# -# Example usage: -# spendfrom.py # Lists available funds -# spendfrom.py --from=ADDRESS --to=ADDRESS --amount=11.00 -# -# Assumes it will talk to a bitcoind or Bitcoin-Qt running -# on localhost. -# -# Depends on jsonrpc -# - -from decimal import * -import getpass -import math -import os -import os.path -import platform -import sys -import time -from jsonrpc import ServiceProxy, json - -BASE_FEE=Decimal("0.001") - -def check_json_precision(): - """Make sure json library being used does not lose precision converting BTC values""" - n = Decimal("20000000.00000003") - satoshis = int(json.loads(json.dumps(float(n)))*1.0e8) - if satoshis != 2000000000000003: - raise RuntimeError("JSON encode/decode loses precision") - -def determine_db_dir(): - """Return the default location of the bitcoin data directory""" - if platform.system() == "Darwin": - return os.path.expanduser("~/Library/Application Support/Bitcoin/") - elif platform.system() == "Windows": - return os.path.join(os.environ['APPDATA'], "Bitcoin") - return os.path.expanduser("~/.bitcoin") - -def read_bitcoin_config(dbdir): - """Read the bitcoin.conf file from dbdir, returns dictionary of settings""" - from ConfigParser import SafeConfigParser - - class FakeSecHead(object): - def __init__(self, fp): - self.fp = fp - self.sechead = '[all]\n' - def readline(self): - if self.sechead: - try: return self.sechead - finally: self.sechead = None - else: - s = self.fp.readline() - if s.find('#') != -1: - s = s[0:s.find('#')].strip() +"\n" - return s - - config_parser = SafeConfigParser() - config_parser.readfp(FakeSecHead(open(os.path.join(dbdir, "bitcoin.conf")))) - return dict(config_parser.items("all")) - -def connect_JSON(config): - """Connect to a bitcoin JSON-RPC server""" - testnet = config.get('testnet', '0') - testnet = (int(testnet) > 0) # 0/1 in config file, convert to True/False - if not 'rpcport' in config: - config['rpcport'] = 18332 if testnet else 8332 - connect = "http://%s:%s@127.0.0.1:%s"%(config['rpcuser'], config['rpcpassword'], config['rpcport']) - try: - result = ServiceProxy(connect) - # ServiceProxy is lazy-connect, so send an RPC command mostly to catch connection errors, - # but also make sure the bitcoind we're talking to is/isn't testnet: - if result.getmininginfo()['testnet'] != testnet: - sys.stderr.write("RPC server at "+connect+" testnet setting mismatch\n") - sys.exit(1) - return result - except: - sys.stderr.write("Error connecting to RPC server at "+connect+"\n") - sys.exit(1) - -def unlock_wallet(bitcoind): - info = bitcoind.getinfo() - if 'unlocked_until' not in info: - return True # wallet is not encrypted - t = int(info['unlocked_until']) - if t <= time.time(): - try: - passphrase = getpass.getpass("Wallet is locked; enter passphrase: ") - bitcoind.walletpassphrase(passphrase, 5) - except: - sys.stderr.write("Wrong passphrase\n") - - info = bitcoind.getinfo() - return int(info['unlocked_until']) > time.time() - -def list_available(bitcoind): - address_summary = dict() - - address_to_account = dict() - for info in bitcoind.listreceivedbyaddress(0): - address_to_account[info["address"]] = info["account"] - - unspent = bitcoind.listunspent(0) - for output in unspent: - # listunspent doesn't give addresses, so: - rawtx = bitcoind.getrawtransaction(output['txid'], 1) - vout = rawtx["vout"][output['vout']] - pk = vout["scriptPubKey"] - - # This code only deals with ordinary pay-to-bitcoin-address - # or pay-to-script-hash outputs right now; anything exotic is ignored. - if pk["type"] != "pubkeyhash" and pk["type"] != "scripthash": - continue - - address = pk["addresses"][0] - if address in address_summary: - address_summary[address]["total"] += vout["value"] - address_summary[address]["outputs"].append(output) - else: - address_summary[address] = { - "total" : vout["value"], - "outputs" : [output], - "account" : address_to_account.get(address, "") - } - - return address_summary - -def select_coins(needed, inputs): - # Feel free to improve this, this is good enough for my simple needs: - outputs = [] - have = Decimal("0.0") - n = 0 - while have < needed and n < len(inputs): - outputs.append({ "txid":inputs[n]["txid"], "vout":inputs[n]["vout"]}) - have += inputs[n]["amount"] - n += 1 - return (outputs, have-needed) - -def create_tx(bitcoind, fromaddresses, toaddress, amount, fee): - all_coins = list_available(bitcoind) - - total_available = Decimal("0.0") - needed = amount+fee - potential_inputs = [] - for addr in fromaddresses: - if addr not in all_coins: - continue - potential_inputs.extend(all_coins[addr]["outputs"]) - total_available += all_coins[addr]["total"] - - if total_available < needed: - sys.stderr.write("Error, only %f BTC available, need %f\n"%(total_available, needed)); - sys.exit(1) - - # - # Note: - # Python's json/jsonrpc modules have inconsistent support for Decimal numbers. - # Instead of wrestling with getting json.dumps() (used by jsonrpc) to encode - # Decimals, I'm casting amounts to float before sending them to bitcoind. - # - outputs = { toaddress : float(amount) } - (inputs, change_amount) = select_coins(needed, potential_inputs) - if change_amount > BASE_FEE: # don't bother with zero or tiny change - change_address = fromaddresses[-1] - if change_address in outputs: - outputs[change_address] += float(change_amount) - else: - outputs[change_address] = float(change_amount) - - rawtx = bitcoind.createrawtransaction(inputs, outputs) - signed_rawtx = bitcoind.signrawtransaction(rawtx) - if not signed_rawtx["complete"]: - sys.stderr.write("signrawtransaction failed\n") - sys.exit(1) - txdata = signed_rawtx["hex"] - - return txdata - -def compute_amount_in(bitcoind, txinfo): - result = Decimal("0.0") - for vin in txinfo['vin']: - in_info = bitcoind.getrawtransaction(vin['txid'], 1) - vout = in_info['vout'][vin['vout']] - result = result + vout['value'] - return result - -def compute_amount_out(txinfo): - result = Decimal("0.0") - for vout in txinfo['vout']: - result = result + vout['value'] - return result - -def sanity_test_fee(bitcoind, txdata_hex, max_fee): - class FeeError(RuntimeError): - pass - try: - txinfo = bitcoind.decoderawtransaction(txdata_hex) - total_in = compute_amount_in(bitcoind, txinfo) - total_out = compute_amount_out(txinfo) - if total_in-total_out > max_fee: - raise FeeError("Rejecting transaction, unreasonable fee of "+str(total_in-total_out)) - - tx_size = len(txdata_hex)/2 - kb = tx_size/1000 # integer division rounds down - if kb > 1 and fee < BASE_FEE: - raise FeeError("Rejecting no-fee transaction, larger than 1000 bytes") - if total_in < 0.01 and fee < BASE_FEE: - raise FeeError("Rejecting no-fee, tiny-amount transaction") - # Exercise for the reader: compute transaction priority, and - # warn if this is a very-low-priority transaction - - except FeeError as err: - sys.stderr.write((str(err)+"\n")) - sys.exit(1) - -def main(): - import optparse - - parser = optparse.OptionParser(usage="%prog [options]") - parser.add_option("--from", dest="fromaddresses", default=None, - help="addresses to get bitcoins from") - parser.add_option("--to", dest="to", default=None, - help="address to get send bitcoins to") - parser.add_option("--amount", dest="amount", default=None, - help="amount to send") - parser.add_option("--fee", dest="fee", default="0.0", - help="fee to include") - parser.add_option("--datadir", dest="datadir", default=determine_db_dir(), - help="location of bitcoin.conf file with RPC username/password (default: %default)") - parser.add_option("--testnet", dest="testnet", default=False, action="store_true", - help="Use the test network") - parser.add_option("--dry_run", dest="dry_run", default=False, action="store_true", - help="Don't broadcast the transaction, just create and print the transaction data") - - (options, args) = parser.parse_args() - - check_json_precision() - config = read_bitcoin_config(options.datadir) - if options.testnet: config['testnet'] = True - bitcoind = connect_JSON(config) - - if options.amount is None: - address_summary = list_available(bitcoind) - for address,info in address_summary.iteritems(): - n_transactions = len(info['outputs']) - if n_transactions > 1: - print("%s %.8f %s (%d transactions)"%(address, info['total'], info['account'], n_transactions)) - else: - print("%s %.8f %s"%(address, info['total'], info['account'])) - else: - fee = Decimal(options.fee) - amount = Decimal(options.amount) - while unlock_wallet(bitcoind) == False: - pass # Keep asking for passphrase until they get it right - txdata = create_tx(bitcoind, options.fromaddresses.split(","), options.to, amount, fee) - sanity_test_fee(bitcoind, txdata, amount*Decimal("0.01")) - if options.dry_run: - print(txdata) - else: - txid = bitcoind.sendrawtransaction(txdata) - print(txid) - -if __name__ == '__main__': - main() diff --git a/contrib/testgen/base58.py b/contrib/testgen/base58.py index b716495145..0d09692b36 100644 --- a/contrib/testgen/base58.py +++ b/contrib/testgen/base58.py @@ -1,3 +1,6 @@ +# Copyright (c) 2012-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. ''' Bitcoin base58 encoding and decoding. @@ -81,7 +84,6 @@ def b58decode_chk(v): result = b58decode(v) if result is None: return None - h3 = checksum(result[:-4]) if result[-4:] == checksum(result[:-4]): return result[:-4] else: diff --git a/contrib/testgen/gen_base58_test_vectors.py b/contrib/testgen/gen_base58_test_vectors.py index 1813436953..86366eb8e3 100755 --- a/contrib/testgen/gen_base58_test_vectors.py +++ b/contrib/testgen/gen_base58_test_vectors.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# Copyright (c) 2012-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. ''' Generate valid and invalid base58 address and private key test vectors. @@ -10,7 +13,7 @@ Usage: # Released under MIT License import os from itertools import islice -from base58 import b58encode, b58decode, b58encode_chk, b58decode_chk, b58chars +from base58 import b58encode_chk, b58decode_chk, b58chars import random from binascii import b2a_hex @@ -42,7 +45,6 @@ def is_valid(v): result = b58decode_chk(v) if result is None: return False - valid = False for template in templates: prefix = str(bytearray(template[0])) suffix = str(bytearray(template[2])) diff --git a/contrib/tidy_datadir.sh b/contrib/tidy_datadir.sh index 5d6d826444..8960f8811d 100755 --- a/contrib/tidy_datadir.sh +++ b/contrib/tidy_datadir.sh @@ -1,4 +1,7 @@ #!/bin/bash +# Copyright (c) 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. if [ -d "$1" ]; then cd "$1" diff --git a/contrib/verify-commits/allow-revsig-commits b/contrib/verify-commits/allow-revsig-commits index e69de29bb2..f0088cdca4 100644 --- a/contrib/verify-commits/allow-revsig-commits +++ b/contrib/verify-commits/allow-revsig-commits @@ -0,0 +1,104 @@ +a06ede9a138d0fb86b0de17c42b936d9fe6e2158 +923dc447eaa8e017985b2afbbb12dd1283fbea0e +71148b8947fe8b4d756822420a7f31c380159425 +6696b4635ceb9b47aaa63244bff9032fa7b08354 +812714fd80e96e28cd288c553c83838cecbfc2d9 +8a445c5651edb9a1f51497055b7ddf4402be9188 +e126d0c12ca66278d9e7b12187c5ff4fc02a7e6c +3908fc4728059719bed0e1c7b1c8b388c2d4a8da +8b66bf74e2a349e71eaa183af81fa63eaee76ad2 +05950427d310654774031764a7141a1a4fd9c6e4 +07fd147b9f12e9205afd66a624edce357977d615 +12e31127948fa4bb01c3bddc1b8c85b432f7465b +8c87f175d335e9d9e93f987d871ae9f05f6a10a7 +46b249e578e8a3dfbe85bc7253a12e82ef4b658b +a55716abe5662ec74c2f8af93023f1e7cca901fc +f646275b90b1de93bc62b4c4d045d75ac0b96eee +c252685aa5867631e9a5ef07ccae7c7c25cae8ff +a7d55c93385359952d85decd5037843ac70ba3d4 +7dac1e5e9e887f5f6ff146e812a05bd3bf281eae +2a524b8e8fe69ef487fd8ea1b4f7a03f473ed201 +ce5c1f4acae43477989cdf9a82ed33703919cda2 +2db4cbcc437f51f5dac82cc4de46f383b92e6f11 +7aa700424cbda387536373d8dfec88aee43f950e +b99a093afed880f23fb279c443cc6ae5e379cc43 +b83264d9c7a8ddb79f64bd9540caddc8632ef31f +57e337d40e94ba33d8cd265c134d6ef857b32b59 +a1dcf2e1087beaf3981739fd2bb74f35ecad630a +d38b0d7a6b6056cba26999b702815775e2437d87 +815640ec6af9a38d6a2da4a4400056e2f4105080 +09c4fd157c5b88df2d97fad4826c79b094db90c9 +2efcfa5acfacb958973d9e8125e1d81f102e2dfd +dc6dee41f7cf2ba93fcd0fea7c157e4b2775d439 +ad826b3df9f763b49f1e3e3d50c4efdd438c7547 +c1a52276848d8caa9a9789dff176408c1aa6b1ed +3bf06e9bac57b5b5a746677b75e297a7b154bdbd +72ae6f8cf0224370e8121d6769b21e612ca15d6f +a143b88dbd4971ecfdd1d39a494489c8f2db0344 +76fec09d878d6dbf214bdb6228d480bd9195db4c +93566e0c37c5ae104095474fea89f00dcb40f551 +407d9232ef5cb1ebf6cff21f3d13e07ea4158eeb +9346f8429957e356d21c665bab59fe45bcf1f74e +6eeac6e30d65f9a972067c1ea8c49978c8e631ac +dc6b9406bdfab2af8c86cb080cb3e6cf8f2385d8 +9f554e03ebe5701c1b75ff03b3d6152095c0cad3 +05009935f9ac070197113954d680bc2c9150b9b3 +508404de98a8a5435f52916cef8f328e82651961 +ed0cc50afed146c27f6d8129c683c225fb940093 +6429cfa8a70308241c576aeb92ffe3db5203b2ef +6898213409811b140843c3d89af43328c3b22fad +5b2ea29cf4fd298346437bb16a54407f8c1f9dca +e2a1a1ee895149c544d4ae295466611f0cec3094 +e82fb872ff5cc8fd22d43327c1ee3e755f61c562 +19b0f33de0efd9da788e8e4f3fdc2a9e159abdb1 +89de1538ce1f8c00f80e8d11f43e1b77e24d7dea +de07fdcf77e97b8613091285e4d0a734f5de7492 +01680195f8aa586c55c44767397380def3a23b54 +05e1c85fb687c82ae477c72d4a7e2d6b0c692167 +c072b8fd95cd4fa84f08189a0cd8b173ea2dbb8e +9a0ed08b40b15ae2b791aa8549b53e69934b4ea7 +53f8f226bd1d627c4a6dec5862a1d4ea5a933e45 +9d0f43b7ca7241d8a018fd35dd3bc01555235ec6 +f12d2b5a8ac397e4bcaefcc19898f8ff5705dea5 +8250de13587ed05ca45df3e12c5dc9bcb1500e2c +d727f77e390426e9e463336bda08d50c451c7086 +484312bda2d43e3ea60047be076332299463adf8 +c7e05b35ab0a791c7a8e2d863e716fdec6f3f671 +b9c1cd81848da9de1baf9c2f29c19c50e549de13 +8ea7d31e384975019733b5778feabbd9955c79d8 +f798b891bcecea9548eedacae70eeb9906c1ddbf +ebefe7a00b46579cdd1e033a8c7fd8ce9aa578e4 +ad087638ee4864d6244ec9381ff764bfa6ee5086 +66db2d62d59817320c9182fc18e75a93b76828ea +7ce9ac5c83b1844a518ef2e12e87aae3cacdfe58 +4286f43025149cf44207c3ad98e4a1f068520ada +cd0c5135ab2291aaa5410ac919bad3fc87249a4a +66ed450d771a8fc01c159a8402648ebd1c35eb4c +a82f03393a32842d49236e8666ee57805ca701f8 +f972b04d63eb8af79ff3cec1dc561ed13dfa6053 +ec45cc5e27668171b55271b0c735194c70e7da41 +715e9fd7454f7a48d7adba7d42f662c20a3e3367 +2e0a99037dcc35bc63ba0d54371bc678af737c8e +7fa8d758598407f3bf0beb0118dc122ea5340736 +6a22373771edbc3c7513cacb9355f880c73c2cbf +b89ef131147f71a96152a7b5c4374266cdf539b2 +01d8359983e2f77b5118fede3ffa947072c666c8 +58f0c929a3d70a4bff79cc200f1c186f71ef1675 +950be19727a581970591d8f8138dfe4725750382 +425278d17bd0edf8a3a7cc81e55016f7fd8e7726 +c028c7b7557da2baff7af8840108e8be4db8e0c6 +47a7cfb0aa2498f6801026d258a59f9de48f60b0 +f6b7df3155ddb4cedfbcf5d3eb3383d4614b3a85 +d72098038f3b55a714ed8adb34fab547b15eb0d5 +c49c825bd9f4764536b45df5a684d97173673fc7 +33799afe83eec4200ff140e9bf5eae83701a4d7f +5c3f8ddcaa1164079105c452429fccf8127b01b6 +1f01443567b03ac75a91c810f1733f5c21b5699d +b3e42b6d02e8d19658a9135e427ebceab5367779 +69b3a6dd9d9a0adf5506c8b9fde42187356bd4a8 +bafd075c5e6a1088ef0f1aa0b0b224e026a3d3e0 +7daa3adb242d9c8728fdb15c6af6596aaad5502f +514993554c370f4cf30a109ac28d5d64893dbf0a +c8d2473e6cb042e7275a10c49d3f6a4a91bf0166 +386f4385ab04b0b2c3d47bddc0dc0f2de7354964 +9f33dba05c01ecc5c56eb1284ab7d64d42f55171 diff --git a/contrib/verify-commits/gpg.sh b/contrib/verify-commits/gpg.sh index 375d711725..b01e2a6d39 100755 --- a/contrib/verify-commits/gpg.sh +++ b/contrib/verify-commits/gpg.sh @@ -1,24 +1,50 @@ #!/bin/sh +# 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. + INPUT=$(cat /dev/stdin) VALID=false REVSIG=false IFS=' ' -for LINE in $(echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null); do +if [ "$BITCOIN_VERIFY_COMMITS_ALLOW_SHA1" = 1 ]; then + GPG_RES="$(echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null)" +else + # Note how we've disabled SHA1 with the --weak-digest option, disabling + # signatures - including selfsigs - that use SHA1. While you might think that + # collision attacks shouldn't be an issue as they'd be an attack on yourself, + # in fact because what's being signed is a commit object that's + # semi-deterministically generated by untrusted input (the pull-req) in theory + # an attacker could construct a pull-req that results in a commit object that + # they've created a collision for. Not the most likely attack, but preventing + # it is pretty easy so we do so as a "belt-and-suspenders" measure. + GPG_RES="" + for LINE in "$(gpg --version)"; do + case "$LINE" in + "gpg (GnuPG) 1.4.1"*|"gpg (GnuPG) 2.0."*) + echo "Please upgrade to at least gpg 2.1.10 to check for weak signatures" > /dev/stderr + GPG_RES="$(echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null)" + ;; + # We assume if you're running 2.1+, you're probably running 2.1.10+ + # gpg will fail otherwise + # We assume if you're running 1.X, it is either 1.4.1X or 1.4.20+ + # gpg will fail otherwise + esac + done + [ "$GPG_RES" = "" ] && GPG_RES="$(echo "$INPUT" | gpg --trust-model always --weak-digest sha1 "$@" 2>/dev/null)" +fi +for LINE in $(echo "$GPG_RES"); do case "$LINE" in "[GNUPG:] VALIDSIG "*) while read KEY; do - case "$LINE" in "[GNUPG:] VALIDSIG $KEY "*) VALID=true;; esac + [ "${LINE#?GNUPG:? VALIDSIG * * * * * * * * * }" = "$KEY" ] && VALID=true 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#????????????????????????} "*) - REVSIG=true - GOODREVSIG="[GNUPG:] GOODSIG ${KEY#????????????????????????} " - esac - done < ./contrib/verify-commits/trusted-keys + REVSIG=true + GOODREVSIG="[GNUPG:] GOODSIG ${LINE#* * *}" ;; esac done @@ -26,7 +52,7 @@ if ! $VALID; then exit 1 fi if $VALID && $REVSIG; then - echo "$INPUT" | gpg --trust-model always "$@" | grep "\[GNUPG:\] \(NEWSIG\|SIG_ID\|VALIDSIG\)" 2>/dev/null + echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null | grep "\[GNUPG:\] \(NEWSIG\|SIG_ID\|VALIDSIG\)" echo "$GOODREVSIG" else echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null diff --git a/contrib/verify-commits/pre-push-hook.sh b/contrib/verify-commits/pre-push-hook.sh index c57222818a..c21febb9e9 100755 --- a/contrib/verify-commits/pre-push-hook.sh +++ b/contrib/verify-commits/pre-push-hook.sh @@ -1,4 +1,8 @@ #!/bin/bash +# 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. + 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 75242c2a97..5610692616 100644 --- a/contrib/verify-commits/trusted-keys +++ b/contrib/verify-commits/trusted-keys @@ -1,4 +1,4 @@ 71A3B16735405025D447E8F274810B012346C9A6 -3F1888C6DCA92A6499C4911FDBA1A67379A1A931 +133EAC179436F14A5CF1B794860FEB804E669320 32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC -FE09B823E6D83A3BC7983EAA2D7F2372E50FE137 +B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B diff --git a/contrib/verify-commits/trusted-sha512-root-commit b/contrib/verify-commits/trusted-sha512-root-commit new file mode 100644 index 0000000000..7d41f90ad7 --- /dev/null +++ b/contrib/verify-commits/trusted-sha512-root-commit @@ -0,0 +1 @@ +309bf16257b2395ce502017be627186b749ee749 diff --git a/contrib/verify-commits/verify-commits.sh b/contrib/verify-commits/verify-commits.sh index 5219331e2e..74b7f38375 100755 --- a/contrib/verify-commits/verify-commits.sh +++ b/contrib/verify-commits/verify-commits.sh @@ -1,58 +1,132 @@ #!/bin/sh -# Not technically POSIX-compliant due to use of "local", but almost every -# shell anyone uses today supports it, so its probably fine +# 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. DIR=$(dirname "$0") [ "/${DIR#/}" != "$DIR" ] && DIR=$(dirname "$(pwd)/$0") +echo "Using verify-commits data from ${DIR}" + VERIFIED_ROOT=$(cat "${DIR}/trusted-git-root") +VERIFIED_SHA512_ROOT=$(cat "${DIR}/trusted-sha512-root-commit") REVSIG_ALLOWED=$(cat "${DIR}/allow-revsig-commits") HAVE_FAILED=false -IS_SIGNED () { - if [ $1 = $VERIFIED_ROOT ]; then - return 0; + +HAVE_GNU_SHA512=1 +[ ! -x "$(which sha512sum)" ] && HAVE_GNU_SHA512=0 + +if [ x"$1" = "x" ]; then + CURRENT_COMMIT="HEAD" +else + CURRENT_COMMIT="$1" +fi + +if [ "${CURRENT_COMMIT#* }" != "$CURRENT_COMMIT" ]; then + echo "Commit must not contain spaces?" > /dev/stderr + exit 1 +fi + +VERIFY_TREE=0 +if [ x"$2" = "x--tree-checks" ]; then + VERIFY_TREE=1 +fi + +NO_SHA1=1 +PREV_COMMIT="" + +while true; do + if [ "$CURRENT_COMMIT" = $VERIFIED_ROOT ]; then + echo "There is a valid path from "$CURRENT_COMMIT" to $VERIFIED_ROOT where all commits are signed!" + exit 0; + fi + + if [ "$CURRENT_COMMIT" = $VERIFIED_SHA512_ROOT ]; then + if [ "$VERIFY_TREE" = "1" ]; then + echo "All Tree-SHA512s matched up to $VERIFIED_SHA512_ROOT" > /dev/stderr + fi + VERIFY_TREE=0 + NO_SHA1=0 fi - if [ "${REVSIG_ALLOWED#*$1}" != "$REVSIG_ALLOWED" ]; then + + if [ "$NO_SHA1" = "1" ]; then + export BITCOIN_VERIFY_COMMITS_ALLOW_SHA1=0 + else + export BITCOIN_VERIFY_COMMITS_ALLOW_SHA1=1 + fi + + if [ "${REVSIG_ALLOWED#*$CURRENT_COMMIT}" != "$REVSIG_ALLOWED" ]; 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 - local PARENTS - PARENTS=$(git show -s --format=format:%P $1) - for PARENT in $PARENTS; do - if IS_SIGNED $PARENT > /dev/null; then - return 0; + + if ! git -c "gpg.program=${DIR}/gpg.sh" verify-commit "$CURRENT_COMMIT" > /dev/null; then + if [ "$PREV_COMMIT" != "" ]; then + echo "No parent of $PREV_COMMIT was signed with a trusted key!" > /dev/stderr + echo "Parents are:" > /dev/stderr + PARENTS=$(git show -s --format=format:%P $PREV_COMMIT) + for PARENT in $PARENTS; do + git show -s $PARENT > /dev/stderr + done + else + echo "$CURRENT_COMMIT was not signed with a trusted key!" > /dev/stderr fi - done - if ! "$HAVE_FAILED"; then - echo "No parent of $1 was signed with a trusted key!" > /dev/stderr - echo "Parents are:" > /dev/stderr - for PARENT in $PARENTS; do - git show -s $PARENT > /dev/stderr - done - HAVE_FAILED=true + exit 1 fi - return 1; -} -if [ x"$1" = "x" ]; then - TEST_COMMIT="HEAD" -else - TEST_COMMIT="$1" -fi + # We always verify the top of the tree + if [ "$VERIFY_TREE" = 1 -o "$PREV_COMMIT" = "" ]; then + IFS_CACHE="$IFS" + IFS=' +' + for LINE in $(git ls-tree --full-tree -r "$CURRENT_COMMIT"); do + case "$LINE" in + "12"*) + echo "Repo contains symlinks" > /dev/stderr + IFS="$IFS_CACHE" + exit 1 + ;; + esac + done + IFS="$IFS_CACHE" -IS_SIGNED "$TEST_COMMIT" -RES=$? -if [ "$RES" = 1 ]; then - if ! "$HAVE_FAILED"; then - echo "$TEST_COMMIT was not signed with a trusted key!" + FILE_HASHES="" + for FILE in $(git ls-tree --full-tree -r --name-only "$CURRENT_COMMIT" | LC_ALL=C sort); do + if [ "$HAVE_GNU_SHA512" = 1 ]; then + HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | sha512sum | { read FIRST OTHER; echo $FIRST; } ) + else + HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | shasum -a 512 | { read FIRST OTHER; echo $FIRST; } ) + fi + [ "$FILE_HASHES" != "" ] && FILE_HASHES="$FILE_HASHES"' +' + FILE_HASHES="$FILE_HASHES$HASH $FILE" + done + + if [ "$HAVE_GNU_SHA512" = 1 ]; then + TREE_HASH="$(echo "$FILE_HASHES" | sha512sum)" + else + TREE_HASH="$(echo "$FILE_HASHES" | shasum -a 512)" + fi + HASH_MATCHES=0 + MSG="$(git show -s --format=format:%B "$CURRENT_COMMIT" | tail -n1)" + + case "$MSG -" in + "Tree-SHA512: $TREE_HASH") + HASH_MATCHES=1;; + esac + + if [ "$HASH_MATCHES" = "0" ]; then + echo "Tree-SHA512 did not match for commit $CURRENT_COMMIT" > /dev/stderr + exit 1 + fi fi -else - echo "There is a valid path from $TEST_COMMIT to $VERIFIED_ROOT where all commits are signed!" -fi -exit $RES + PARENTS=$(git show -s --format=format:%P "$CURRENT_COMMIT") + for PARENT in $PARENTS; do + PREV_COMMIT="$CURRENT_COMMIT" + CURRENT_COMMIT="$PARENT" + break + done +done diff --git a/contrib/verifybinaries/README.md b/contrib/verifybinaries/README.md index 8970f3daa4..ed3e14fb6c 100644 --- a/contrib/verifybinaries/README.md +++ b/contrib/verifybinaries/README.md @@ -1,13 +1,33 @@ ### Verify Binaries + +#### Preparation: + +Make sure you obtain the proper release signing key and verify the fingerprint with several independent sources. + +```sh +$ gpg --fingerprint "Bitcoin Core binary release signing key" +pub 4096R/36C2E964 2015-06-24 [expires: 2017-02-13] + Key fingerprint = 01EA 5486 DE18 A882 D4C2 6845 90C8 019E 36C2 E964 +uid Wladimir J. van der Laan (Bitcoin Core binary release signing key) <laanwj@gmail.com> +``` + +#### Usage: + 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. -Usage: ```sh ./verify.sh bitcoin-core-0.11.2 ./verify.sh bitcoin-core-0.12.0 +./verify.sh bitcoin-core-0.13.0-rc3 +``` + +If you do not want to keep the downloaded binaries, specify anything as the second parameter. + +```sh +./verify.sh bitcoin-core-0.13.0 delete ``` diff --git a/contrib/verifybinaries/verify.sh b/contrib/verifybinaries/verify.sh index 657c3bd33c..e20770c96a 100755 --- a/contrib/verifybinaries/verify.sh +++ b/contrib/verifybinaries/verify.sh @@ -1,4 +1,7 @@ #!/bin/bash +# 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. ### This script attempts to download the signature file SHA256SUMS.asc from bitcoin.org ### It first checks if the signature passes, and then downloads the files specified in @@ -14,11 +17,11 @@ function clean_up { done } -WORKINGDIR="/tmp/bitcoin" +WORKINGDIR="/tmp/bitcoin_verify_binaries" TMPFILE="hashes.tmp" SIGNATUREFILENAME="SHA256SUMS.asc" -RCSUBDIR="test/" +RCSUBDIR="test" BASEDIR="https://bitcoin.org/bin/" VERSIONPREFIX="bitcoin-core-" RCVERSIONSTRING="rc" @@ -43,7 +46,7 @@ if [ -n "$1" ]; then # and simultaneously add RCSUBDIR to BASEDIR, where we will look for SIGNATUREFILENAME if [[ $VERSION == *"$RCVERSIONSTRING"* ]]; then BASEDIR="$BASEDIR${VERSION/%-$RCVERSIONSTRING*}/" - BASEDIR="$BASEDIR$RCSUBDIR" + BASEDIR="$BASEDIR$RCSUBDIR.$RCVERSIONSTRING${VERSION: -1}/" else BASEDIR="$BASEDIR$VERSION/" fi @@ -93,7 +96,7 @@ fi FILES=$(awk '{print $2}' "$TMPFILE") #and download these one by one -for file in in $FILES +for file in $FILES do wget --quiet -N "$BASEDIR$file" done @@ -108,11 +111,16 @@ if [ $? -eq 1 ]; then exit 1 elif [ $? -gt 1 ]; then echo "Error executing 'diff'" - exit 2 + exit 2 fi -#everything matches! clean up the mess -clean_up $FILES $SIGNATUREFILENAME $TMPFILE +if [ -n "$2" ]; then + echo "Clean up the binaries" + clean_up $FILES $SIGNATUREFILENAME $TMPFILE +else + echo "Keep the binaries in $WORKINGDIR" + clean_up $TMPFILE +fi echo -e "Verified hashes of \n$FILES" diff --git a/contrib/windeploy/detached-sig-create.sh b/contrib/windeploy/detached-sig-create.sh new file mode 100755 index 0000000000..bf4978d143 --- /dev/null +++ b/contrib/windeploy/detached-sig-create.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# 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. + +if [ -z "$OSSLSIGNCODE" ]; then + OSSLSIGNCODE=osslsigncode +fi + +if [ ! -n "$1" ]; then + echo "usage: $0 <osslcodesign args>" + echo "example: $0 -key codesign.key" + exit 1 +fi + +OUT=signature-win.tar.gz +SRCDIR=unsigned +WORKDIR=./.tmp +OUTDIR="${WORKDIR}/out" +OUTSUBDIR="${OUTDIR}/win" +TIMESERVER=http://timestamp.comodoca.com +CERTFILE="win-codesign.cert" + +mkdir -p "${OUTSUBDIR}" +basename -a `ls -1 "${SRCDIR}"/*-unsigned.exe` | while read UNSIGNED; do + echo Signing "${UNSIGNED}" + "${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -in "${SRCDIR}/${UNSIGNED}" -out "${WORKDIR}/${UNSIGNED}" "$@" + "${OSSLSIGNCODE}" extract-signature -pem -in "${WORKDIR}/${UNSIGNED}" -out "${OUTSUBDIR}/${UNSIGNED}.pem" && rm "${WORKDIR}/${UNSIGNED}" +done + +rm -f "${OUT}" +tar -C "${OUTDIR}" -czf "${OUT}" . +rm -rf "${WORKDIR}" +echo "Created ${OUT}" diff --git a/contrib/windeploy/win-codesign.cert b/contrib/windeploy/win-codesign.cert new file mode 100644 index 0000000000..200b30a3f0 --- /dev/null +++ b/contrib/windeploy/win-codesign.cert @@ -0,0 +1,99 @@ +-----BEGIN CERTIFICATE----- +MIIFTTCCBDWgAwIBAgIRALlW05RLwG2hMQMX5d/o5J8wDQYJKoZIhvcNAQELBQAw +fTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxIzAhBgNV +BAMTGkNPTU9ETyBSU0EgQ29kZSBTaWduaW5nIENBMB4XDTE2MDIwMzAwMDAwMFoX +DTE5MDMwNTIzNTk1OVowgbUxCzAJBgNVBAYTAlVTMQ4wDAYDVQQRDAU5ODEwNDEL +MAkGA1UECAwCV0ExEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAkMB1N0ZSAzMDAx +FzAVBgNVBAkMDjcxIENvbHVtYmlhIFN0MSUwIwYDVQQKDBxUaGUgQml0Y29pbiBG +b3VuZGF0aW9uLCBJbmMuMSUwIwYDVQQDDBxUaGUgQml0Y29pbiBGb3VuZGF0aW9u +LCBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw37Vrv9Gbku0 ++kuV0t89TuyxtAcmT7QE4GcwESKKjmkxfzD9a0qlhqk8GfQ+fw4DHNN+nLKNv7xB +bk6aS7J2v2DcXkOjrP99P9jqgTkp7MC04VtG3OqVRGB+gum0pptRovYZUQXIdkY7 +GJOok/NDagwKiiUe2V2meZ7UctsZNvYeilQdTgKIIhrMB9NowCOhT8ocVL4Ki55/ +l7hukJn3fueCM3fHTwY2/1gaGsOHoCkFRsD7vokjAVpiY+8rUgvHjb0gxgojiVGd +6a6/F5XJwKJacvUyN4Hfc2K5lRMQjTTmo4aWNWIa0iJ3TK9BHpdSLJBqerMPvmnM +kkapS+ZTNQIDAQABo4IBjTCCAYkwHwYDVR0jBBgwFoAUKZFg/4pN+uv5pmq4z/nm +S71JzhIwHQYDVR0OBBYEFONpQ+cV82URVe+V8G57377KxxexMA4GA1UdDwEB/wQE +AwIHgDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMBEGCWCGSAGG ++EIBAQQEAwIEEDBGBgNVHSAEPzA9MDsGDCsGAQQBsjEBAgEDAjArMCkGCCsGAQUF +BwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8ubmV0L0NQUzBDBgNVHR8EPDA6MDig +NqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9SU0FDb2RlU2lnbmlu +Z0NBLmNybDB0BggrBgEFBQcBAQRoMGYwPgYIKwYBBQUHMAKGMmh0dHA6Ly9jcnQu +Y29tb2RvY2EuY29tL0NPTU9ET1JTQUNvZGVTaWduaW5nQ0EuY3J0MCQGCCsGAQUF +BzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQADggEB +AGnBSi9K/9rgTAyKFKrfGWSfNOwAghmsnsvpZSQ7QyoGWBFKSgCs/70kErl18oHA +g7Y8loQB1yukZmJaCa3OvGud7smn45TCh0TMf4EpP20Wxf4rMQTxwAatasHL3+vi +I+Nl5bsRZ09kWjvayqLII5upjS/yq0JfpmyGl5k2C/fIpztq0iOLvqWlXcL4+51r +cMUAfX6E6EaZQm//ikp+w2+7MEXTKguOuV3gwsrTy0DsvkZl4YDgx/FA4ImzXopv +d+3KJPLvO+OSBqUD3JPwXHnuJqGAbLBFyyCa/feGUjLlR8cxcNWLWdp4qxtoIUPG +3wTsC9YgrglS0F7FKMXlNRY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF4DCCA8igAwIBAgIQLnyHzA6TSlL+lP0ct800rzANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTMwNTA5 +MDAwMDAwWhcNMjgwNTA4MjM1OTU5WjB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEjMCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25p +bmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmmJBjd5E0f4rR +3elnMRHrzB79MR2zuWJXP5O8W+OfHiQyESdrvFGRp8+eniWzX4GoGA8dHiAwDvth +e4YJs+P9omidHCydv3Lj5HWg5TUjjsmK7hoMZMfYQqF7tVIDSzqwjiNLS2PgIpQ3 +e9V5kAoUGFEs5v7BEvAcP2FhCoyi3PbDMKrNKBh1SMF5WgjNu4xVjPfUdpA6M0ZQ +c5hc9IVKaw+A3V7Wvf2pL8Al9fl4141fEMJEVTyQPDFGy3CuB6kK46/BAW+QGiPi +XzjbxghdR7ODQfAuADcUuRKqeZJSzYcPe9hiKaR+ML0btYxytEjy4+gh+V5MYnmL +Agaff9ULAgMBAAGjggFRMIIBTTAfBgNVHSMEGDAWgBS7r34CPfqm8TyEjq3uOJjs +2TIy1DAdBgNVHQ4EFgQUKZFg/4pN+uv5pmq4z/nmS71JzhIwDgYDVR0PAQH/BAQD +AgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYD +VR0gBAowCDAGBgRVHSAAMEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29t +b2RvY2EuY29tL0NPTU9ET1JTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEG +CCsGAQUFBwEBBGUwYzA7BggrBgEFBQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5j +b20vQ09NT0RPUlNBQWRkVHJ1c3RDQS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v +Y3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAAj8COcPu+Mo7id4M +bU2x8U6ST6/COCwEzMVjEasJY6+rotcCP8xvGcM91hoIlP8l2KmIpysQGuCbsQci +GlEcOtTh6Qm/5iR0rx57FjFuI+9UUS1SAuJ1CAVM8bdR4VEAxof2bO4QRHZXavHf +WGshqknUfDdOvf+2dVRAGDZXZxHNTwLk/vPa/HUX2+y392UJI0kfQ1eD6n4gd2HI +TfK7ZU2o94VFB696aSdlkClAi997OlE5jKgfcHmtbUIgos8MbAOMTM1zB5TnWo46 +BLqioXwfy2M6FafUFRunUkcyqfS/ZEfRqh9TTjIwc8Jvt3iCnVz/RrtrIh2IC/gb +qjSm/Iz13X9ljIwxVzHQNuxHoc/Li6jvHBhYxQZ3ykubUa9MCEp6j+KjUuKOjswm +5LLY5TjCqO3GgZw1a6lYYUoKl7RLQrZVnb6Z53BtWfhtKgx/GWBfDJqIbDCsUgmQ +Fhv/K53b0CDKieoofjKOGd97SDMe12X4rsn4gxSTdn1k0I7OvjV9/3IxTZ+evR5s +L6iPDAZQ+4wns3bJ9ObXwzTijIchhmH+v1V04SF3AwpobLvkyanmz1kl63zsRQ55 +ZmjoIs2475iFTZYRPAmK0H+8KCgT+2rKVI2SXM3CZZgGns5IW9S1N5NGQXwH3c/6 +Q++6Z2H/fUnguzB9XIDj5hY5S6c= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE----- diff --git a/contrib/zmq/zmq_sub.py b/contrib/zmq/zmq_sub.py index 6268123dd8..ea398a27ea 100755 --- a/contrib/zmq/zmq_sub.py +++ b/contrib/zmq/zmq_sub.py @@ -1,41 +1,84 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 +# 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. + +""" + ZMQ example using python3's asyncio + + Bitcoin should be started with the command line arguments: + bitcoind -testnet -daemon \ + -zmqpubhashblock=tcp://127.0.0.1:28332 \ + -zmqpubrawtx=tcp://127.0.0.1:28332 \ + -zmqpubhashtx=tcp://127.0.0.1:28332 \ + -zmqpubhashblock=tcp://127.0.0.1:28332 + + We use the asyncio library here. `self.handle()` installs itself as a + future at the end of the function. Since it never returns with the event + loop having an empty stack of futures, this creates an infinite loop. An + alternative is to wrap the contents of `handle` inside `while True`. + + A blocking example using python 2.7 can be obtained from the git history: + https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py +""" -import array import binascii +import asyncio import zmq +import zmq.asyncio +import signal import struct +import sys + +if not (sys.version_info.major >= 3 and sys.version_info.minor >= 5): + print("This example only works with Python 3.5 and greater") + exit(1) port = 28332 -zmqContext = zmq.Context() -zmqSubSocket = zmqContext.socket(zmq.SUB) -zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "hashblock") -zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "hashtx") -zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "rawblock") -zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "rawtx") -zmqSubSocket.connect("tcp://127.0.0.1:%i" % port) - -try: - while True: - msg = zmqSubSocket.recv_multipart() - topic = str(msg[0]) +class ZMQHandler(): + def __init__(self): + self.loop = zmq.asyncio.install() + self.zmqContext = zmq.asyncio.Context() + + self.zmqSubSocket = self.zmqContext.socket(zmq.SUB) + self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashblock") + self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtx") + self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawblock") + self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtx") + self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % port) + + async def handle(self) : + msg = await self.zmqSubSocket.recv_multipart() + topic = msg[0] body = msg[1] - sequence = "Unknown"; + sequence = "Unknown" if len(msg[-1]) == 4: msgSequence = struct.unpack('<I', msg[-1])[-1] sequence = str(msgSequence) - if topic == "hashblock": - print '- HASH BLOCK ('+sequence+') -' - print binascii.hexlify(body) - elif topic == "hashtx": - print '- HASH TX ('+sequence+') -' - print binascii.hexlify(body) - elif topic == "rawblock": - print '- RAW BLOCK HEADER ('+sequence+') -' - print binascii.hexlify(body[:80]) - elif topic == "rawtx": - print '- RAW TX ('+sequence+') -' - print binascii.hexlify(body) - -except KeyboardInterrupt: - zmqContext.destroy() + if topic == b"hashblock": + print('- HASH BLOCK ('+sequence+') -') + print(binascii.hexlify(body)) + elif topic == b"hashtx": + print('- HASH TX ('+sequence+') -') + print(binascii.hexlify(body)) + elif topic == b"rawblock": + print('- RAW BLOCK HEADER ('+sequence+') -') + print(binascii.hexlify(body[:80])) + elif topic == b"rawtx": + print('- RAW TX ('+sequence+') -') + print(binascii.hexlify(body)) + # schedule ourselves to receive the next message + asyncio.ensure_future(self.handle()) + + def start(self): + self.loop.add_signal_handler(signal.SIGINT, self.stop) + self.loop.create_task(self.handle()) + self.loop.run_forever() + + def stop(self): + self.loop.stop() + self.zmqContext.destroy() + +daemon = ZMQHandler() +daemon.start() diff --git a/contrib/zmq/zmq_sub3.4.py b/contrib/zmq/zmq_sub3.4.py new file mode 100755 index 0000000000..1cb7eec0c0 --- /dev/null +++ b/contrib/zmq/zmq_sub3.4.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +# 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. + +""" + ZMQ example using python3's asyncio + + Bitcoin should be started with the command line arguments: + bitcoind -testnet -daemon \ + -zmqpubhashblock=tcp://127.0.0.1:28332 \ + -zmqpubrawtx=tcp://127.0.0.1:28332 \ + -zmqpubhashtx=tcp://127.0.0.1:28332 \ + -zmqpubhashblock=tcp://127.0.0.1:28332 + + We use the asyncio library here. `self.handle()` installs itself as a + future at the end of the function. Since it never returns with the event + loop having an empty stack of futures, this creates an infinite loop. An + alternative is to wrap the contents of `handle` inside `while True`. + + The `@asyncio.coroutine` decorator and the `yield from` syntax found here + was introduced in python 3.4 and has been deprecated in favor of the `async` + and `await` keywords respectively. + + A blocking example using python 2.7 can be obtained from the git history: + https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py +""" + +import binascii +import asyncio +import zmq +import zmq.asyncio +import signal +import struct +import sys + +if not (sys.version_info.major >= 3 and sys.version_info.minor >= 4): + print("This example only works with Python 3.4 and greater") + exit(1) + +port = 28332 + +class ZMQHandler(): + def __init__(self): + self.loop = zmq.asyncio.install() + self.zmqContext = zmq.asyncio.Context() + + self.zmqSubSocket = self.zmqContext.socket(zmq.SUB) + self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashblock") + self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtx") + self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawblock") + self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtx") + self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % port) + + @asyncio.coroutine + def handle(self) : + msg = yield from self.zmqSubSocket.recv_multipart() + topic = msg[0] + body = msg[1] + sequence = "Unknown" + if len(msg[-1]) == 4: + msgSequence = struct.unpack('<I', msg[-1])[-1] + sequence = str(msgSequence) + if topic == b"hashblock": + print('- HASH BLOCK ('+sequence+') -') + print(binascii.hexlify(body)) + elif topic == b"hashtx": + print('- HASH TX ('+sequence+') -') + print(binascii.hexlify(body)) + elif topic == b"rawblock": + print('- RAW BLOCK HEADER ('+sequence+') -') + print(binascii.hexlify(body[:80])) + elif topic == b"rawtx": + print('- RAW TX ('+sequence+') -') + print(binascii.hexlify(body)) + # schedule ourselves to receive the next message + asyncio.ensure_future(self.handle()) + + def start(self): + self.loop.add_signal_handler(signal.SIGINT, self.stop) + self.loop.create_task(self.handle()) + self.loop.run_forever() + + def stop(self): + self.loop.stop() + self.zmqContext.destroy() + +daemon = ZMQHandler() +daemon.start() |