#! /bin/sh -e # Wherever we are, we want to be in daemon/test dir. cd `git rev-parse --show-toplevel`/daemon/test . scripts/vars.sh . scripts/helpers.sh if [ x"$1" = x"manual-commit" ]; then MANUALCOMMIT=1 shift fi parse_cmdline 2 "$@" setup_lightning 2 if [ -n "$MANUALCOMMIT" ]; then # Aka. never. echo 'commit-time=1h' >> $DIR1/config echo 'commit-time=1h' >> $DIR2/config fi start_lightningd 2 fund_lightningd # Check IDs match logs [ `$LCLI1 getlog | sed -n 's/.*"ID: \([0-9a-f]*\)".*/\1/p'` = $ID1 ] [ `$LCLI2 getlog | sed -n 's/.*"ID: \([0-9a-f]*\)".*/\1/p'` = $ID2 ] lcli1 connect localhost $PORT2 $FUND_INPUT_TX & # Expect them to be waiting for anchor, and ack from other side. check_peerstate lcli1 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE check_peerstate lcli2 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE # Enable reconnect from here. DO_RECONNECT=$RECONNECT # Now make it pass anchor (should be in mempool: one block to bury it) check_tx_spend $CLI generate 1 check_peerstate lcli1 STATE_NORMAL check_peerstate lcli2 STATE_NORMAL # We turn off routing failure for the moment. lcli1 dev-routefail false lcli2 dev-routefail false A_AMOUNT=$(($AMOUNT - $NO_HTLCS_FEE)) A_FEE=$NO_HTLCS_FEE B_AMOUNT=0 B_FEE=0 check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" # This is 10,000 satoshi, so not dust! HTLC_AMOUNT=10000000 EXPIRY=$(( $(blockheight) + 10)) SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'` HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` if [ -n "$MANUALCOMMIT" ]; then # They should register a staged htlc. check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_HTLC } " $B_AMOUNT $B_FEE "" # Now commit it. lcli1 dev-commit $ID2 # Node 1 hasn't got it committed, but node2 should have told it to stage. check_status_single lcli1 $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_REVOCATION } " $B_AMOUNT $B_FEE "" # Check channel status A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT)) A_FEE=$(($A_FEE + $EXTRA_FEE)) # Node 2 has it committed. check_status_single lcli2 $B_AMOUNT $B_FEE "" $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_REVOCATION } " # There should be no "both committed" here yet if lcli1 getlog debug | $FGREP "Both committed"; then echo "Node1 thinks they are both committed"; exit 1 fi if lcli2 getlog debug | $FGREP "Both committed"; then echo "Node2 thinks they are both committed"; exit 1 fi # Now node2 gives commitment to node1. lcli2 dev-commit $ID1 # After revocation, they should know they're both committed. check lcli1 "getlog debug | $FGREP 'Both committed to ADD of our HTLC'" check lcli2 "getlog debug | $FGREP 'Both committed to ADD of their HTLC'" else A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT)) A_FEE=$(($A_FEE + $EXTRA_FEE)) fi # Both should have committed tx. check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE "" lcli2 dev-fulfillhtlc $ID1 $HTLCID $SECRET [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 # Without manual commit, this check is racy. if [ -n "$MANUALCOMMIT" ]; then if lcli1 getlog debug | $FGREP 'Both committed to FULFILL'; then echo "Node1 thinks they are both committed"; exit 1 fi if lcli2 getlog debug | $FGREP 'Both committed to FULFILL'; then echo "Node2 thinks they are both committed"; exit 1 fi fi [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 # If we're very slow, manually committed above, and we're restarting, # we may restart *after* this and thus not see it in the log. [ "$RECONNECT$MANUALCOMMIT" = restart1 ] || check lcli1 "getlog debug | $FGREP 'Both committed to FULFILL of our HTLC'" check lcli2 "getlog debug | $FGREP 'Both committed to FULFILL of their HTLC'" # We've transferred the HTLC amount to 2, who now has to pay fees, # so no net change for A who saves on fees. B_FEE=$HTLC_AMOUNT # With no HTLCs, extra fee no longer required. A_FEE=$(($A_FEE - $EXTRA_FEE - $B_FEE)) A_AMOUNT=$(($A_AMOUNT + $EXTRA_FEE + $HTLC_AMOUNT)) check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" # A new one, at 10x the amount. HTLC_AMOUNT=100000000 HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 # Check channel status A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT)) A_FEE=$(($A_FEE + $EXTRA_FEE)) check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE "" lcli2 dev-failhtlc $ID1 $HTLCID 695 [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 # Back to how we were before. A_AMOUNT=$(($A_AMOUNT + $EXTRA_FEE + $HTLC_AMOUNT)) A_FEE=$(($A_FEE - $EXTRA_FEE)) check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" # Same again, but this time it expires. HTLC_AMOUNT=10000001 HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 # Check channel status A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT)) A_FEE=$(($A_FEE + $EXTRA_FEE)) check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE "" # Make sure node1 accepts the expiry packet. while [ $(blockheight) != $EXPIRY ]; do $CLI generate 1 done # This should make node2 send it. $CLI generate 1 if [ -n "$MANUALCOMMIT" ]; then check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_REMOVE_HTLC } " $B_AMOUNT $B_FEE "" lcli2 dev-commit $ID1 lcli1 dev-commit $ID2 fi # Back to how we were before. A_AMOUNT=$(($A_AMOUNT + $EXTRA_FEE + $HTLC_AMOUNT)) A_FEE=$(($A_FEE - $EXTRA_FEE)) check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" # First, give more money to node2, so it can offer HTLCs. EXPIRY=$(( $(blockheight) + 10)) HTLC_AMOUNT=100000000 HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE "" lcli2 dev-fulfillhtlc $ID1 $HTLCID $SECRET [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 # Both now pay equal fees. A_FEE=$(($NO_HTLCS_FEE / 2)) B_FEE=$(($NO_HTLCS_FEE / 2)) # We transferred 10000000 before, and $HTLC_AMOUNT now. A_AMOUNT=$(($AMOUNT - 10000000 - $HTLC_AMOUNT - $A_FEE)) B_AMOUNT=$((10000000 + $HTLC_AMOUNT - $B_FEE)) check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" # Two failures crossover SECRET2=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfe RHASH2=`lcli1 dev-rhash $SECRET2 | sed 's/.*"\([0-9a-f]*\)".*/\1/'` # This means B will *just* afford it (but can't cover increased fees) HTLC_AMOUNT=$(($B_AMOUNT - $EXTRA_FEE / 2)) HTLCID=`lcli2 dev-newhtlc $ID1 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` # Make sure that's committed, in case lcli1 restarts. lcli2 dev-commit $ID1 >/dev/null || true HTLCID2=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH2 | extract_id` [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 # A covers the extra part of the fee. check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE - $EXTRA_FEE / 2)) $(($A_FEE + $EXTRA_FEE + $EXTRA_FEE / 2)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : SENT_ADD_ACK_REVOCATION } " 0 $(($B_FEE + $EXTRA_FEE / 2)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_ACK_REVOCATION } " # Fail both, to reset. lcli1 dev-failhtlc $ID2 $HTLCID 830 lcli2 dev-failhtlc $ID1 $HTLCID2 829 [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" # Now, two HTLCs at once, one from each direction. # Both sides can afford this. HTLC_AMOUNT=1000000 HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` HTLCID2=`lcli2 dev-newhtlc $ID1 $HTLC_AMOUNT $EXPIRY $RHASH2 | extract_id` [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $(($B_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : RCVD_ADD_ACK_REVOCATION } " lcli1 dev-fulfillhtlc $ID2 $HTLCID2 $SECRET2 lcli2 dev-failhtlc $ID1 $HTLCID 849 [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 # We transferred amount from B to A. A_AMOUNT=$(($A_AMOUNT + $HTLC_AMOUNT)) B_AMOUNT=$(($B_AMOUNT - $HTLC_AMOUNT)) check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" # Now, test making more changes before receiving commit reply. DO_RECONNECT="" lcli2 dev-output $ID1 false HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id` # Make sure node1 sends commit (in the background, since it will block!) [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 & if [ -n "$MANUALCOMMIT" ]; then # node2 will consider this committed. check_status_single lcli2 $(($B_AMOUNT - $EXTRA_FEE/2)) $(($B_FEE + $EXTRA_FEE/2)) "" $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE/2)) $(($A_FEE + $EXTRA_FEE/2)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_REVOCATION } " else # It will start committing by itself check_status_single lcli2 $(($B_AMOUNT - $EXTRA_FEE/2)) $(($B_FEE + $EXTRA_FEE/2)) "" $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE/2)) $(($A_FEE + $EXTRA_FEE/2)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_COMMIT } " fi # node1 will still be awaiting node2's revocation reply. check_status_single lcli1 $(($A_AMOUNT)) $(($A_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_COMMIT } " $B_AMOUNT $B_FEE "" # Now send another offer, and enable node2 output. HTLCID2=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH2 | extract_id` lcli2 dev-output $ID1 true [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 DO_RECONNECT=$RECONNECT # Both sides should be committed to htlcs # We open-code check_status here: HTLCs could be in either order. check_balance_single lcli1 $(($A_AMOUNT - $HTLC_AMOUNT*2 - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) $(($B_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) check_balance_single lcli2 $(($B_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) $(($A_AMOUNT - $HTLC_AMOUNT*2 - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) # Once both balances are correct, this should be right. lcli1 getpeers | tr -s '\012\011" ' ' ' | $FGREP "our_htlcs : [ { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION }, { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : SENT_ADD_ACK_REVOCATION } ], their_htlcs : [ ]" || lcli1 getpeers | tr -s '\012\011" ' ' ' | $FGREP "our_htlcs : [ { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : SENT_ADD_ACK_REVOCATION }, { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } ], their_htlcs : [ ]" lcli2 getpeers | tr -s '\012\011" ' ' ' | $FGREP "our_htlcs : [ ], their_htlcs : [ { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_ACK_REVOCATION }, { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : RCVD_ADD_ACK_REVOCATION } ]" || lcli2 getpeers | tr -s '\012\011" ' ' ' | $FGREP "our_htlcs : [ ], their_htlcs : [ { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : RCVD_ADD_ACK_REVOCATION }, { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_ACK_REVOCATION } ]" # Just for once, reconnect/restart node 2. case "$RECONNECT" in reconnect) echo RECONNECTING NODE2 $LCLI2 dev-reconnect $ID1 >/dev/null sleep 1 ;; restart) echo RESTARTING NODE2 $LCLI2 -- dev-restart $LIGHTNINGD2 >/dev/null 2>&1 || true if ! check "$LCLI2 getlog 2>/dev/null | fgrep -q Hello"; then echo "Node2 dev-restart failed!">&2 exit 1 fi ;; esac if ! check "$LCLI2 getpeers | tr -s '\012\011\" ' ' ' | fgrep -q 'connected : true'"; then echo "Failed to reconnect!">&2 exit 1 fi # Node2 collects the HTLCs. lcli2 dev-fulfillhtlc $ID1 $HTLCID $SECRET lcli2 dev-fulfillhtlc $ID1 $HTLCID2 $SECRET2 [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1 [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 # We transferred 2 * amount from A to B. A_AMOUNT=$(($A_AMOUNT - $HTLC_AMOUNT * 2)) B_AMOUNT=$(($B_AMOUNT + $HTLC_AMOUNT * 2)) check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" lcli1 close $ID2 # They should be negotiating the close. check_peerstate lcli1 STATE_MUTUAL_CLOSING check_peerstate lcli2 STATE_MUTUAL_CLOSING $CLI generate 1 check_peerstate lcli1 STATE_CLOSE_ONCHAIN_MUTUAL check_peerstate lcli2 STATE_CLOSE_ONCHAIN_MUTUAL # Give it forever-1 blocks. $CLI generate 8 # Make sure they saw it! check_peerstate lcli1 STATE_CLOSE_ONCHAIN_MUTUAL check_peerstate lcli2 STATE_CLOSE_ONCHAIN_MUTUAL # Now the final one. $CLI generate 1 check_no_peers lcli1 check_no_peers lcli2 lcli1 stop lcli2 stop all_ok