#!/usr/bin/perl -w # ..::[ The Bitcoin Foundation ]::.. # Who: mod6 # GPG Finger Print: 027A 8D7C 0FB8 A166 4372 0F40 7217 05A8 B71E ADAF # What: Perl Script to Automate Bitcoin v0.5.3 Patching & Compilation # When: 20150129 # Version: v0.0.1 # NOTE: If you don't have the dependencies already plugged in on # Debian 6 (squeeze), you'll want to run following commands: # # sudo apt-get update && sudo apt-get -y upgrade # sudo apt-get install -y build-essential libssl-dev libdb4.8-dev \ # libdb4.8++-dev libboost-all-dev wget git curl gnupg my $who = "mod6 0x721705A8B71EADAF"; my $when = "20150130"; my $where = "http://www.thebitcoin.foundation/"; my $version = "v0.0.2"; print "#####################################################################\n"; print "## ##\n"; print "## ..::[ The Bitcoin Foundation Patch & Compile Script ]::.. ##\n"; print "## ##\n"; print "## author: $who ##\n"; print "## when: $when ##\n"; print "## where: $where ##\n"; print "## version: $version ##\n"; print "## ##\n"; print "## If you should encounter problems with this script, ##\n"; print "## please enquire with mod6 at irc.freenode.net channel ##\n"; print "## #bitcoin-assets or write to modsix at gmail dot com ##\n"; print "## Thank you! ##\n"; print "## ##\n"; print "#####################################################################\n"; # Bitcoin Dev Home # XXX Make sure that you set HOME to your build directory! my $HOME="CHANGEME"; # XXX Set this to TRUE to clean out all build components from build directory my $FULL_CLEAN="TRUE"; my $SHA256="/usr/bin/sha256sum"; my $v053="https://codeload.github.com/bitcoin/bitcoin/legacy.tar.gz/v0.5.3"; my $v053_hash="aab1f8ea8c7f131ff69dfa3b9437ba35531018be760132dd6373f41a591f6382"; my $chicken="http://thebitcoin.foundation/chicken.tar.gz"; my $chicken_hash="63164ea54f042226a6aa8768b98b0f323d66f08693c6fd271a850c00308517ad"; my $upnp="http://thebitcoin.foundation/rm_rf_upnp.tar.gz"; my $upnp_hash="f5f27b806b90b0ffd3d2d73e240eba02f13c5dec3d693b37e08686d04164861a"; my $https="http://thebitcoin.foundation/https-snipsnip.tar.gz"; my $https_hash="047844a601bc575d7660826b02f0d640f02ae84cd641f45552c825b72bc116f4"; my $alert="http://thebitcoin.foundation/turdmeister-alert-snip.tar.gz"; my $alert_hash="39b5aac2b6de016eda23a96fe6f9a565dbbe4f4aa46e8584c102ee71fa4fe7f4"; my $win32="http://thebitcoin.foundation/goodbye-win32.tar.gz"; my $win32_hash="5149a481629e0f10b659d38fee0736e0b6e631ab3bbeb6cde449aa61226cdbb3"; my $dbconfig="http://thebitcoin.foundation/db_config.tar.gz"; my $dbconfig_hash="b315dc1494334d24606622b7bd3a2569b53e5ad970971ee666ae7adc28fc7d65"; my $revbump="http://thebitcoin.foundation/rev_bump.tar.gz"; my $revbump_hash="5efe5de69b6fdb97ff445a1a37a5cc227dd77b59a8553b3ee235a378f352903a"; my $bitcoin = "bitcoin-bitcoin-a8def6b"; # Check to make sure HOME is set to something other than CHANGEME if($HOME =~ m/CHANGEME/) { print "Error! HOME variable not set!\n"; print "Be sure to set HOME to your build directory.\n"; exit 1; } # Get bitcoin-v0.5.3.tar.gz base code & verify checksum hash print "Downloading bitcoin-v0.5.3.tar.gz\n"; `curl $v053 -s -o $HOME/bitcoin-v0.5.3.tar.gz`; print "Checking bitcoin-v0.5.3.tar.gz hash...\n"; $h = `$SHA256 bitcoin-v0.5.3.tar.gz`; $h =~ /^(.*) .*$/; if($1 !~ m/$v053_hash/) { print "Error! bitcoin-v0_5_3.tar.gz hash did not match!\n"; print "hash: |$hash|\n"; print "v053_hash: |$v053_hash|\n"; exit 1; } else { print "bitcoin-v0.5.3.tar.gz hash verified.\n"; } # Unpack the Bitcoin v0.5.3 code: print "Unpacking bitcoin-v0.5.3.tar.gz\n"; `tar -xf $HOME/bitcoin-v0.5.3.tar.gz`; # Download Patch Tarballs: print "Downloading chicken.tar.gz\n"; `curl $chicken -s -o $HOME/chicken.tar.gz`; print "Downloading rm_rf_upnp.tar.gz\n"; `curl $upnp -s -o $HOME/rm_rf_upnp.tar.gz`; print "Downloading https-snipsnip.tar.gz\n"; `curl $https -s -o $HOME/https-snipsnip.tar.gz`; print "Downloading turdmeister-alert-snip.tar.gz\n"; `curl $alert -s -o $HOME/turdmeister-alert-snip.tar.gz`; print "Downloading goodbye-win32.tar.gz\n"; `curl $win32 -s -o $HOME/goodbye-win32.tar.gz`; print "Downloading db_config.tar.gz\n"; `curl $dbconfig -s -o $HOME/db_config.tar.gz`; print "Downloading rev_bump.tar.gz\n"; `curl $revbump -s -o $HOME/rev_bump.tar.gz`; # Check SHA256 Hashes of Patch Tarballs: print "Checking chicken.tar.gz hash...\n"; $h = `$SHA256 $HOME/chicken.tar.gz`; $h =~ /^(.*) .*$/; if($1 !~ m/$chicken_hash/) { print "Error! chicken.tar.gz checksum did not match!\n"; print "hash: |$hash|\n"; print "chicken_hash: |$chicken_hash|\n"; exit 1; } else { print "chicken.tar.gz hash verified.\n"; } print "Checking rm_rf_upnp.tar.gz hash...\n"; $h = `$SHA256 $HOME/rm_rf_upnp.tar.gz`; $h =~ /^(.*) .*$/; if($1 !~ m/$upnp_hash/) { print "Error! rm_rf_upnp.tar.gz checksum did not match!\n"; print "hash: |$hash|\n"; print "upnp_hash: |$upnp_hash|\n"; exit 1; } else { print "rm_rf_upnp.tar.gz hash verified.\n"; } print "Checking https-snipsnip.tar.gz hash...\n"; $h = `$SHA256 $HOME/https-snipsnip.tar.gz`; $h =~ /^(.*) .*$/; if($1 !~ m/$https_hash/) { print "Error! https-snipsnip.tar.gz checksum did not match!\n"; print "hash: |$hash|\n"; print "https_hash: |$https_hash|\n"; exit 1; } else { print "https-snipsnip.tar.gz hash verified.\n"; } print "Checking turdmeister-alert-snip.tar.gz hash...\n"; $h = `$SHA256 $HOME/turdmeister-alert-snip.tar.gz`; $h =~ /^(.*) .*$/; if($1 !~ m/$alert_hash/) { print "Error! turdmeister-alert-snip.tar.gz checksum did not match!\n"; print "hash: |$hash|\n"; print "alert_hash: |$alert_hash|\n"; exit 1; } else { print "turdmeister-alert-snip.tar.gz hash verified.\n"; } print "Checking goodbye-win32.tar.gz hash...\n"; $h = `$SHA256 $HOME/goodbye-win32.tar.gz`; $h =~ /^(.*) .*$/; if($1 !~ m/$win32_hash/) { print "Error! goodbye-win32.tar.gz checksum did not match!\n"; print "hash: |$hash|\n"; print "win32_hash: |$win32_hash|\n"; exit 1; } else { print "goodbye-win32.tar.gz hash verified.\n"; } print "Checking db_config.tar.gz hash...\n"; $h = `$SHA256 $HOME/db_config.tar.gz`; $h =~ /^(.*) .*$/; if($1 !~ m/$dbconfig_hash/) { print "Error! db_config.tar.gz checksum did not match!\n"; print "hash: |$hash|\n"; print "dbconfig_hash: |$dbconfig_hash|\n"; exit 1; } else { print "db_config.tar.gz hash verified.\n"; } print "Checking rev_bump.tar.gz hash...\n"; $h = `$SHA256 $HOME/rev_bump.tar.gz`; $h =~ /^(.*) .*$/; if($1 !~ m/$revbump_hash/) { print "Error! rev_bump.tar.gz checksum did not match!\n"; print "hash: |$hash|\n"; print "dbconfig_hash: |$revbump_hash|\n"; exit 1; } else { print "rev_bump.tar.gz hash verified.\n"; } # Unpack Patches: print "Unpacking patch tarballs...\n"; `mkdir -p $HOME/chicken && tar -xf $HOME/chicken.tar.gz -C $HOME/chicken`; `tar -xf $HOME/rm_rf_upnp.tar.gz`; `mkdir -p $HOME/https-snipsnip && tar -xf $HOME/https-snipsnip.tar.gz -C $HOME/https-snipsnip`; `mkdir -p $HOME/alert-snip && tar -xf $HOME/turdmeister-alert-snip.tar.gz -C $HOME/alert-snip`; `mkdir -p $HOME/goodbye-win32 && tar -xf $HOME/goodbye-win32.tar.gz -C $HOME/goodbye-win32`; `tar -xf $HOME/db_config.tar.gz`; `tar -xf $HOME/rev_bump.tar.gz`; # Load PubKeys: print "Downloading public keys...\n"; `mkdir -p $HOME/pubkeys`; `curl -s "http://pgp.mit.edu/pks/lookup?op=get&search=0x2AFA1A9FD2D031DA" | sed -n "/-----BEGIN PGP PUBLIC KEY BLOCK-----/,/-----END PGP PUBLIC KEY BLOCK-----/p" > $HOME/pubkeys/ben_vulpes.pub.asc`; `curl -s "http://pgp.mit.edu/pks/lookup?op=get&search=0x721705A8B71EADAF" | sed -n "/-----BEGIN PGP PUBLIC KEY BLOCK-----/,/-----END PGP PUBLIC KEY BLOCK-----/p" > $HOME/pubkeys/mod6.pub.asc`; `curl -s "http://pgp.mit.edu/pks/lookup?op=get&search=0xB98228A001ABFFC7" | sed -n "/-----BEGIN PGP PUBLIC KEY BLOCK-----/,/-----END PGP PUBLIC KEY BLOCK-----/p" > $HOME/pubkeys/asciilifefrm.pub.asc`; # Verify GPG PubKey import print "Importing public keys to $HOME/.gnupg keyring...\n"; `gpg --homedir $HOME/.gnupg --logger-fd 1 --import $HOME/pubkeys/*.asc > gpg_import.log `; @import = `cat gpg_import.log`; foreach(@import) { if($_ =~ /^.*imported: (\d+).*$/) { if($1 ne "3") { print "Error! GnuPG did not import 3 keys!\n"; exit 1; } } } print "Verifing patch signatures..\n"; # Verify Patch Signatures: $chicken_sig = "FALSE"; `gpg --homedir $HOME/.gnupg --logger-fd 1 --verify $HOME/chicken/bitcoin-asciilifeform.1.patch.sig > chicken_sig.log`; @verify = `cat chicken_sig.log`; foreach(@verify) { if($_ =~ /^.*Good signature.*$/) { $chicken_sig = "TRUE"; print "Signature verified for bitcoin-asciilifeform.1.patch\n"; } } if($chicken_sig =~ m/FALSE/) { print "Error! Possible bad signature on:\n"; print "$HOME/chicken/bitcoin-asciilifeform.1.patch.sig\n"; print "sig: $chicken_sig\n"; exit 1; } $upnp_sig = "FALSE"; `gpg --homedir $HOME/.gnupg --logger-fd 1 --verify $HOME/rm_rf_upnp/rm_rf_upnp.patch.sig > upnp_sig.log`; @verify = `cat upnp_sig.log`; foreach(@verify) { if($_ =~ /^.*Good signature.*$/) { $upnp_sig = "TRUE"; print "Signature verified for rm_rf_upnp.patch\n"; } } if($upnp_sig =~ m/FALSE/) { print "Error! Possible bad signature on:\n"; print "$HOME/rm_rf_upnp/rm_rf_upnp.patch.sig\n"; print "sig: $upnp_sig\n"; exit 1; } $https_sig = "FALSE"; `gpg --homedir $HOME/.gnupg --logger-fd 1 --verify $HOME/https-snipsnip/bitcoin-asciilifeform.2-https_snipsnip.patch.sig > https_sig.log`; @verify = `cat https_sig.log`; foreach(@verify) { if($_ =~ /^.*Good signature.*$/) { $https_sig = "TRUE"; print "Signature verified for bitcoin-asciilifeform.2-https_snipsnip.patch\n"; } } if($https_sig =~ m/FALSE/) { print "Error! Possible bad signature on:\n"; print "$HOME/https-snipsnip/bitcoin-asciilifeform.2-https_snipsnip.patch.sig\n"; print "sig: $https_sig\n"; exit 1; } $alert_sig = "FALSE"; `gpg --homedir $HOME/.gnupg --logger-fd 1 --verify $HOME/alert-snip/bitcoin-asciilifeform.3-turdmeister-alert-snip.patch.sig > alert_sig.log`; @verify = `cat alert_sig.log`; foreach(@verify) { if($_ =~ /^.*Good signature.*$/) { $alert_sig = "TRUE"; print "Signature verified for bitcoin-asciilifeform.3-turdmeister-alert-snip.patch\n"; } } if($alert_sig =~ m/FALSE/) { print "Error! Possible bad signature on:\n"; print "$HOME/alert-snip/bitcoin-asciilifeform.3-turdmeister-alert-snip.patch.sig\n"; print "sig: $alert_sig\n"; exit 1; } $win32_sig = "FALSE"; `gpg --homedir $HOME/.gnupg --logger-fd 1 --verify $HOME/goodbye-win32/bitcoin-asciilifeform.4-goodbye-win32.patch.sig > win32_sig.log`; @verify = `cat win32_sig.log`; foreach(@verify) { if($_ =~ /^.*Good signature.*$/) { $win32_sig = "TRUE"; print "Signature verified for bitcoin-asciilifeform.4-goodbye-win32.patch\n"; } } if($win32_sig =~ m/FALSE/) { print "Error! Possible bad signature on:\n"; print "$HOME/goodbye-win32/bitcoin-asciilifeform.4-goodbye-win32.patch.sig\n"; print "sig: $win32_sig\n"; exit 1; } $dbconfig_sig = "FALSE"; `gpg --homedir $HOME/.gnupg --logger-fd 1 --verify $HOME/db_config/bitcoin-v0_5_3-db_config.6.patch.sig > dbconfig_sig.log`; @verify = `cat dbconfig_sig.log`; foreach(@verify) { if($_ =~ /^.*Good signature.*$/) { $dbconfig_sig = "TRUE"; print "Signature verified for bitcoin-v0_5_3-db_config.6.patch\n"; } } if($dbconfig_sig =~ m/FLASE/) { print "Error! Possible bad signature on:\n"; print "$HOME/db_config/bitcoin-v0_5_3-db_config.6.patch.sig\n"; print "sig: $dbconfig_sig\n"; exit 1; } $revbump_sig = "FALSE"; `gpg --homedir $HOME/.gnupg --logger-fd 1 --verify $HOME/rev_bump/bitcoin-v0_5_3_1-rev_bump.7.patch.sig > revbump_sig.log`; @verify = `cat revbump_sig.log`; foreach(@verify) { if($_ =~ /^.*Good signature.*$/) { $revbump_sig = "TRUE"; print "Signature verified for bitcoin-v0_5_3_1-rev_bump.7.patch\n"; } } if($revbump_sig =~ /FALSE/) { print "Error! Possible bad signature on:\n"; print "$HOME/rev_bump/bitcoin-v0_5_3_1-rev_bump.7.patch.sig\n"; print "sig: $revbump_sig\n"; exit 1; } # Backup original source directory print "Backing up original bitcoin directory...\n"; `mv $HOME/$bitcoin $HOME/$bitcoin.orig`; if(! -e "$HOME/$bitcoin.orig") { print "Back-up of original source failed!\n"; exit 1; } print "Pruning files from v0.5.3 code base not contained in the manifest...\n"; my $chickenManifest = "$HOME/chicken/bitcoin-0.5.3-no-crud.sha256.manifest"; my $pruned = "bitcoin-v0_5_3_1"; `mkdir -p $HOME/$pruned`; chdir("$HOME/$bitcoin.orig") or die $!; # Extract filenames from manifest and copy them into new directory `for i in \`cut -d \' \' -f 3- $chickenManifest\`; do cp --parents \$i $HOME/$pruned; done`; chdir("$HOME") or die $!; my $count1 = `find $pruned -xtype f -print0 | xargs -0 sha256sum | wc -l`; my $count2 = `cat $HOME/chicken/bitcoin-0.5.3-no-crud.sha256.manifest | wc -l`; if($count1 ne $count2) { print "Error! The resulting file count after pruning did not match\n"; print "the file count from the manifest.\n"; print "post-pruning: $count1\n"; print " manifest: $count2\n"; exit 1; } # Patch Bitcoin v0.5.3 Source Base & Clean Up: print "Patching v0.5.3 source files...\n"; `patch -d $pruned/src < $HOME/chicken/bitcoin-asciilifeform.1.patch`; print ">> Patched: chicken/bitcoin-asciilifeform.1.patch\n"; `patch -d $pruned/src < $HOME/rm_rf_upnp/rm_rf_upnp.patch`; print ">> Patched: rm_rf_upnp/rm_rf_upnp.patch\n"; `patch -d $pruned/src < $HOME/https-snipsnip/bitcoin-asciilifeform.2-https_snipsnip.patch`; print ">> Patched: https-snipsnip/bitcoin-asciilifeform.2-https_snipsnip.patch\n"; `patch -d $pruned/src < $HOME/alert-snip/bitcoin-asciilifeform.3-turdmeister-alert-snip.patch`; print ">> Patched: alert-snip/bitcoin-asciilifeform.3-turdmeister-alert-snip.patch\n"; `patch -d $pruned/src < $HOME/goodbye-win32/bitcoin-asciilifeform.4-goodbye-win32.patch`; print ">> Patched: goodbye-win32/bitcoin-asciilifeform.4-goodbye-win32.patch\n"; `patch -d $pruned/src < $HOME/db_config/bitcoin-v0_5_3-db_config.6.patch`; print ">> Patched: db_config/bitcoin-v0_5_3-db_config.6.patch\n"; `patch -d $pruned/src < $HOME/rev_bump/bitcoin-v0_5_3_1-rev_bump.7.patch`; print ">> Patched: rev_bump/bitcoin-v0_5_3_1-rev_bump.7.patch\n"; if($FULL_CLEAN =~ m/TRUE/i) { print "Performing FULL CLEAN...\n"; `rm -rf $HOME/chicken`; `rm -rf $HOME/rm_rf_upnp`; `rm -rf $HOME/https-snipsnip`; `rm -rf $HOME/alert-snip`; `rm -rf $HOME/goodbye-win32`; `rm -rf $HOME/db_config`; `rm -rf $HOME/rev_bump`; `rm -rf $HOME/pubkeys`; `rm -rf $HOME/.gnupg`; `rm -rf $HOME/*.tar.gz`; `rm -rf $HOME/*.log`; `rm -rf $HOME/prune_manifest.sh`; `rm -rf $HOME/$bitcoin.orig`; } # Compile Patched Source: chdir("$HOME/$pruned/src") or die $!; print "Compiling bitcoind...\n"; `make -f makefile.unix`; print "Done!\n";