#!/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 # 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="FALSE"; 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"; # 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 `curl $v053 -s -o $HOME/bitcoin-v0.5.3.tar.gz`; $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; } # Unpack the Bitcoin v0.5.3 code: `tar -xf $HOME/bitcoin-v0.5.3.tar.gz`; # Download Patch Tarballs: `curl $chicken -s -o $HOME/chicken.tar.gz`; `curl $upnp -s -o $HOME/rm_rf_upnp.tar.gz`; `curl $https -s -o $HOME/https-snipsnip.tar.gz`; `curl $alert -s -o $HOME/turdmeister-alert-snip.tar.gz`; `curl $win32 -s -o $HOME/goodbye-win32.tar.gz`; `curl $dbconfig -s -o $HOME/db_config.tar.gz`; `curl $revbump -s -o $HOME/rev_bump.tar.gz`; # Check SHA256 Hashes of Patch Tarballs: $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; } $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; } $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; } $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; } $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; } $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; } $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; } # Unpack Patches: `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: `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 `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; } } } # 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"; } } 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"; } } 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"; } } 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"; } } 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"; } } 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"; } } 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"; } } 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; } $prune_manifest = << 'END_OF_PRUNE'; #!/bin/bash ## prune_manifest.sh ## ## Prune Bitcoin Manifests ## ## Author: PinkPosixPXE - 11/2014 ## ### Put path to bitcoin dir and chicken dir within these variables ### bitcoin=$1 chicken=$2 #### MANIFESTS AND FILE LISTS #### chickenManifest="${chicken}/bitcoin-0.5.3-no-crud.sha256.manifest" ### tmp files created for filelists, comparisons, and pruning ### newManifest=/tmp/new-bitcoin.manifest btcManifest=/tmp/bitcoin-a8def6b.manifest btcFiles=/tmp/bitcoin-a8def6b.files newFiles=/tmp/new-bitcoin.files pruneFiles=/tmp/prune-bitcoin.files ### Array to track file varname, for checking before pruning ### fileArr=(newManifest btcManifest chickenManifest btcFiles newFiles pruneFiles) #### INIT #### ### Create required manifests, filelists, and prunelists ### init() { cd ${bitcoin} ### Ensure our src dirs exist ### if [[ ! -d "${bitcoin}" ]]; then echo "Error: Can't find bitcoin src path: ${bitcoin}" exit 1 elif [[ ! -d "${chicken}" ]];then echo "Error: Can't find chicken src path: ${chicken}" exit 1 fi ### clean old tmp files ### rm -v ${newManifest} ${btcFiles} ${newFiles} ${pruneFiles} 2>/dev/null ### Create manifest of current bitcoin src ### find . -xtype f -exec sha256sum {} \; | sort > ${btcManifest} while read line; do mFile=$(echo "${line}" | awk '{print $2}') grep "${mFile}" ${chickenManifest} >> ${newManifest} done < ${btcManifest} ### Manifest parsing ### awk '{print $2}' ${btcManifest} | sort >> ${btcFiles} awk '{print $2}' ${chickenManifest} | sort >> ${newFiles} comm -23 ${btcFiles} ${newFiles} >> ${pruneFiles} } checkFiles() { ## Test files exist, and aren't empty ## for filevar in ${fileArr[*]} do file="${!filevar}" ## Check if file exists, or is mising ## test ! -e "${file}" || test ! -s "${file}" &&{ echo "Error: Required File Missing, or empty: ${file}" exit 1 } done ### Check files marked for pruning ### while read file do egrep '^'${file}'$' ${newFiles} && { echo "Check Failed: required file marked for deletion: ${file}" exit 1 } done< ${pruneFiles} return 0 } pruneFiles() { echo "Checks Passed -> Pruning unneeded files from manifest" ## Prune manifest, dirs, and tmp files ## ## If you want it to remove the files quietly, remove the -v ## rm -fv $( < ${pruneFiles} ) 2>/dev/null rm -fv ${newManifest} ${btcFiles} ${btcManifest} \ ${newFiles} ${pruneFiles} 2>/dev/null rm -rfv ./contrib ./doc ./scripts ./share } init checkFiles pruneFiles END_OF_PRUNE $prune_script = "$HOME/prune_manifest.sh"; open my $file, '>', $prune_script or die $!; print $file $prune_manifest; close $file; my $bitcoin = "bitcoin-bitcoin-a8def6b"; `/bin/bash $HOME/prune_manifest.sh $HOME/$bitcoin $HOME/chicken`; my $count1 = `find $HOME/bitcoin-bitcoin-a8def6b -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: # patch -d bitcoin-bitcoin-a8def6b/src/ < rm_rf_upnp/rm_rf_upnp.patch `patch -d $bitcoin/src < $HOME/chicken/bitcoin-asciilifeform.1.patch`; `patch -d $bitcoin/src < $HOME/rm_rf_upnp/rm_rf_upnp.patch`; `patch -d $bitcoin/src < $HOME/https-snipsnip/bitcoin-asciilifeform.2-https_snipsnip.patch`; `patch -d $bitcoin/src < $HOME/alert-snip/bitcoin-asciilifeform.3-turdmeister-alert-snip.patch`; `patch -d $bitcoin/src < $HOME/goodbye-win32/bitcoin-asciilifeform.4-goodbye-win32.patch`; `patch -d $bitcoin/src < $HOME/db_config/bitcoin-v0_5_3-db_config.6.patch`; `patch -d $bitcoin/src < $HOME/rev_bump/bitcoin-v0_5_3_1-rev_bump.7.patch`; if($FULL_CLEAN =~ /TRUE/i) { `rm -rf $HOME/chicken \ $HOME/rm_rf_upnp \ $HOME/https-snipsnip \ $HOME/alert-snip \ $HOME/goodbye-win32 \ $HOME/db_config \ $HOME/rev_bump \ $HOME/pubkeys \ $HOME/.gnupg \ $HOME/*.tar.gz \ $HOME/*.log`; } # Compile Patched Source: chdir("$HOME/$bitcoin/src") or die $!; `make -f $HOME/$bitcoin/src/makefile.unix`; print "Done!\n";