From 0fe39eb4d19267402e80015bc2547874f57c9800 Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 27 Jun 2022 17:34:54 -0700 Subject: [PATCH] ... --- cold-setup | 157 +++++++++++++++++- test/setup.sh | 112 ++++++------- ...wallet_multisig_spend_correctness.tests.sh | 11 +- 3 files changed, 218 insertions(+), 62 deletions(-) diff --git a/cold-setup b/cold-setup index 62afaf9..06ef97d 100755 --- a/cold-setup +++ b/cold-setup @@ -27,6 +27,12 @@ bitcoin_core_start() { log_info "bitcoin core started" } +bitcoin_core_start_interactive() { + log_msg "start bitcoin core:\n\n\tbitcoind --daemonwait\n" + + confirm "confirm bitcoin core started" +} + bitcoin_core_stop() { RUNNING=`ps -A | ( grep bitcoind > /dev/null && echo "1" ) || echo "0"` if [[ "$RUNNING" -eq 0 ]]; then @@ -41,6 +47,22 @@ bitcoin_core_stop() { log_info "bitcoin core stopped" } +bitcoin_core_stop_interactive() { + log_msg "stop bitcoin core:\n\n\tbitcoin-cli stop\n" +} + +confirm() { + local RESULT + while true; do + read -n 1 -p "$1: [Y/n] " RESULT + if [[ "$RESULT" == "Y" ]]; then + break; + fi + log_error "\nfailed...\n" + done + log_error "\n" +} + depends() { PATH="$PATH:/sbin" @@ -116,10 +138,51 @@ multisig_create() { echo -n '", "active": true, "timestamp": "now", "internal": true}]' >> "$DUMPFILE" } +multisig_create_interactive() { + log_msg "Creating multi-signature descriptors..." + + log_msg "create output file 'main.descriptors':\n\n\techo -n \"wsh(sortedmulti(3,\" > main.descriptors" + confirm "confirm main.descriptors created" + + for((i = 1; i <= $N; i++)); do + log_msg "added descriptors from wallet$i to main.descriptors\n\n\tbitcoin-cli -rpcwallet=wallet$i listdescriptors | jq -j '.descriptors | map(select(.desc | startswith(\"wpkh\"))) | map(select(.internal == false)) | map(.desc | ltrimstr(\"wpkh(\")) | .[] | split(\")\") | .[0]' >> main.descriptors" + confirm "confirm descriptors from wallet$i added to main.descriptors" + done + + log_msg "finish formatting for main.descriptors:\n\n\techo \"))\" >> main.descriptors" + confirm "confirm main.descriptors file fully created" + + log_msg "Use bitcoin core to get information on fully formed descriptors and output result to descriptors.txt:\n\n\tcat main.descriptors | bitcoin-cli -stdin getdescriptorinfo | jq -j '.descriptor' >> descriptors.txt" + confirm "confirm descriptors.txt created" + + log_msg "create output file 'change.descriptors':\n\n\techo -n \"wsh(sortedmulti(3,\" > change.descriptors" + confirm "confirm change.descriptors created" + + for((i = 1; i <= $N; i++)); do + log_msg "added change descriptors from wallet$i to change.descriptors\n\n\tbitcoin-cli -rpcwallet=wallet$i listdescriptors | jq -j '.descriptors | map(select(.desc | startswith(\"wpkh\"))) | map(select(.internal == true)) | map(.desc | ltrimstr(\"wpkh(\")) | .[] | split(\")\") | .[0]' >> change.descriptors" + confirm "confirm change descriptors from wallet$i added to change.descriptors" + done + + log_msg "finish formatting for change.descriptors:\n\n\techo \"))\" >> change.descriptors" + confirm "confirm change.descriptors file fully created" + + log_msg "Format descriptors.txt to be ready to append change descriptors:\n\n\techo -n ',{\"desc\": \"' >> descriptors.txt" + confirm "confirm descriptors.txt formatted correctly" + + log_msg "Use bitcoin core to get information on fully formed change descriptors and output result to descriptors.txt:\n\n\tcat change.descriptors | bitcoin-cli -stdin getdescriptorinfo | jq -j '.descriptor' >> descriptors.txt" + confirm "confirm change descriptors added to descriptors.txt" +} + network_off() { nmcli networking off } +network_off_interactive() { + log_msg "shut off networking:\n\n\tnmcli networking off\n" + + confirm "confirm networking shut off" +} + parse_arguments() { # transform long options into short opts for arg in "$@"; do @@ -330,6 +393,67 @@ usbs() { done } +usbs_interactive() { + # export to usbs + for((i = 1; i <= $N; i++)); do + log_msg "insert usb drive..." + USB_PATH="`usb_detect`" + log_msg "usb drive detected at $USB_PATH" + confirm "use usb drive at $USB_PATH?" + + log_msg "wipe filesystem on $USB_PATH\n\n\twipefs -a $USB_PATH" + confirm "usb drive wiped" + + if [[ -n "$ENCRYPTION" ]]; then + log_msg "format usb device for encryption:\n\n\tcryptsetup luksFormat --type luks2 $USB_PATH" + confirm "usb drive formatted for encryption" + + log_msg "open encrypted drive:\n\n\tcryptsetup luksOpen $USB_PATH $USB_DECRYPT_NAME" + confirm "usb drive opened" + + USB_PATH_PRE_DECRYPT="$USB_PATH" + USB_PATH="/dev/mapper/$USB_DECRYPT_NAME" + fi + + log_msg "fill drive with zeros:\n\n\tdd if=/dev/zero of=$USB_PATH" + confirm "drive filled with zeros" + + log_msg "make filesystem on usb drive:\n\n\tmkfs.ext4 $USB_PATH" + confirm "filesystem setup on usb drive" + + log_msg "mount usb drive:\n\n\tmount $USB_PATH $USB_DIRECTORY" + confirm "usb drive mounted at $USB_DIRECTORY" + + log_msg "dump descriptors for wallet$i:\n\n\tbitcoin-cli -named -rpcwallet=wallet$i listdescriptors private=true > wallet$i.descriptors" + confirm "descriptors dumped into wallet$i.descriptors" + + log_msg "copy descriptors for wallet$i to $USB_DIRECTORY:\n\n\tcp wallet$i.descriptors $USB_DIRECTORY/" + confirm "descriptors copied to $USB_DIRECTORY" + + log_msg "copy multi-signature descriptors to $USB_DIRECTORY:\n\n\tcp descriptors.txt $USB_DIRECTORY/" + confirm "multi-signature descriptors copied to $USB_DIRECTORY" + + log_msg "verify integrity sum of copied files matches:\n\n\tb2sum wallet$i.descriptors $USB_DIRECTORY/wallet$i.descriptors descriptors.txt $USB_DIRECTORY/descriptors.txt" + confirm "copied files' integrity matches" + + log_msg "shred wallet$i.descriptors:\n\n\tshred -u wallet$i.descriptors" + confirm "wallet$i.descriptors shredded" + + log_msg "unmount usb drive:\n\n\tumount $USB_DIRECTORY" + confirm "usb drive unmounted" + + if [[ -z "$ENCRYPTION" ]]; then + log_msg "close encrypted drive:\n\n\tcryptsetup luksClose $USB_PATH" + confirm "usb drive closed" + + USB_PATH="$USB_PATH_PRE_DECRYPT" + fi + + log_msg "eject device:\n\n\teject $USB_PATH" + confirm "usb drive ejected" + done +} + validate_parameters() { if [[ "$M" -gt "$N" ]]; then log_error "ERROR: threshold>wallets ($M>$N)" @@ -429,10 +553,24 @@ wallets() { done } +wallets_interactive() { + log_msg "Creating $N wallets..." + for((i = 1; i <= $N; i++)); do + log_msg "create wallet$i:\n\tbitcoin-cli -named createwallet wallet_name=wallet$i descriptors=true\n" + confirm "confirm wallet$i was created" + done +} + wallets_clean() { find "$DATA_DIRECTORY" -name "wallet.dat" -exec shred -u {} \; } +wallets_clean_interactive() { + log_msg "clean up wallet files:\n\n\tfind ~/.bitcoin -name \"wallet.dat\" -exec shred -u {} \;" + + confirm "wallet files deleted" +} + main() { depends @@ -461,8 +599,23 @@ main() { main_interactive() { log_msg "interactive mode started..." - log_error "ERROR: interactive mode not implemented" - exit 1 + log_msg "A series of commands to fully setup a cold storage solution with be output." + log_msg "All commands should be run in a separate shell." + + bitcoin_core_start_interactive + + network_off_interactive + + wallets_interactive + multisig_create_interactive + + usbs_interactive + + wallets_clean_interactive + + bitcoin_core_stop_interactive + + log_msg "Successfully completed setup." } main "$@" diff --git a/test/setup.sh b/test/setup.sh index 36c6bfd..01a3473 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -36,7 +36,7 @@ setup_test_descriptors() { "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -47,7 +47,7 @@ setup_test_descriptors() { "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -58,7 +58,7 @@ setup_test_descriptors() { "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -69,7 +69,7 @@ setup_test_descriptors() { "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -80,7 +80,7 @@ setup_test_descriptors() { "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -91,7 +91,7 @@ setup_test_descriptors() { "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -102,7 +102,7 @@ setup_test_descriptors() { "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -113,7 +113,7 @@ setup_test_descriptors() { "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 } @@ -132,7 +132,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -143,7 +143,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -154,7 +154,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -165,7 +165,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -176,7 +176,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -187,7 +187,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -198,7 +198,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -209,7 +209,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 } @@ -228,7 +228,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -239,7 +239,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -250,7 +250,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -261,7 +261,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -272,7 +272,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -283,7 +283,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -294,7 +294,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -305,7 +305,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 } @@ -324,7 +324,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -335,7 +335,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -346,7 +346,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -357,7 +357,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -368,7 +368,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -379,7 +379,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -390,7 +390,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -401,7 +401,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 } @@ -420,7 +420,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -431,7 +431,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -442,7 +442,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -453,7 +453,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -464,7 +464,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -475,7 +475,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -486,7 +486,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -497,7 +497,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 } @@ -516,7 +516,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -527,7 +527,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -538,7 +538,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -549,7 +549,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -560,7 +560,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -571,7 +571,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -582,7 +582,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -593,7 +593,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 } @@ -612,7 +612,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -623,7 +623,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -634,7 +634,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -645,7 +645,7 @@ EOF "internal": false, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -656,7 +656,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -667,7 +667,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -678,7 +678,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 }, @@ -689,7 +689,7 @@ EOF "internal": true, "range": [ 0, - 999 + 2999 ], "next": 0 } diff --git a/test/wallet_multisig_spend_correctness.tests.sh b/test/wallet_multisig_spend_correctness.tests.sh index 8eb67c8..095150f 100755 --- a/test/wallet_multisig_spend_correctness.tests.sh +++ b/test/wallet_multisig_spend_correctness.tests.sh @@ -56,7 +56,7 @@ sign() { } spend() { - local CMD="$BITCOIN_CLI -rpcwallet=live walletcreatefundedpsbt '[]' '[{\"$1\":$2}]'" + local CMD="$BITCOIN_CLI -rpcwallet=live -named walletcreatefundedpsbt outputs='[{\"$1\":$2}]' options='{\"subtract_fee_from_outputs\":[]}'" local UNSIGNED="`eval "$CMD" | jq -r '.psbt'`" local WALLETS=($(shuf -n "$M" -e {1..7})) for i in "${WALLETS[@]}"; do @@ -166,7 +166,6 @@ assert "$EXPECTED" "$( /dev/null @@ -194,10 +193,14 @@ assert "$EXPECTED" "$( /dev/null spend "$ADDRESS" 100 +eval "$BITCOIN_CLI -rpcwallet=dummy -generate 100" > /dev/null spend "$ADDRESS" 100 +eval "$BITCOIN_CLI -rpcwallet=dummy -generate 100" > /dev/null spend "$ADDRESS" 100 -spend "$ADDRESS" 99.99758 +eval "$BITCOIN_CLI -rpcwallet=dummy -generate 100" > /dev/null +spend "$ADDRESS" "99.99" eval "$BITCOIN_CLI -rpcwallet=dummy -generate 100" > /dev/null @@ -206,7 +209,7 @@ EXPECTED='{ "walletname": "live", "walletversion": 169900, "format": "sqlite", - "balance": 0.00000000, + "balance": 0.00599563, "unconfirmed_balance": 0.00000000, "immature_balance": 0.00000000, "txcount": 2005, -- 2.39.5