diff --git a/Makefile b/Makefile index a8a17e613..2faac1cd8 100644 --- a/Makefile +++ b/Makefile @@ -189,7 +189,6 @@ include closingd/Makefile include onchaind/Makefile include lightningd/Makefile include cli/Makefile -include test/Makefile include doc/Makefile include devtools/Makefile diff --git a/test/.gitignore b/test/.gitignore deleted file mode 100644 index 4dce2dd2a..000000000 --- a/test/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -test_onion -test_state_coverage -onion_key diff --git a/test/Makefile b/test/Makefile deleted file mode 100644 index 561b26aef..000000000 --- a/test/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -TEST_PROGRAMS := \ - test/test_protocol - -TEST_COMMON_OBJS := \ - common/utils.o - -$(TEST_PROGRAMS): $(TEST_COMMON_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) - -ALL_TEST_PROGRAMS += $(TEST_PROGRAMS) -ALL_OBJS += $(TEST_PROGRAMS:=.o) - -test-protocol: test/test_protocol - @set -e; TMP=`mktemp`; for f in test/commits/*.script; do if ! $(VALGRIND) test/test_protocol < $$f > $$TMP; then echo "test/test_protocol < $$f FAILED" >&2; exit 1; fi; diff -u $$TMP $$f.expected; done; rm $$TMP - -check: test-protocol -clean: test-clean - -test-clean: - $(RM) $(TEST_PROGRAMS) $(TEST_PROGRAMS:=.o) diff --git a/test/commits/01-offer1.script b/test/commits/01-offer1.script deleted file mode 100644 index 5fdcd0946..000000000 --- a/test/commits/01-offer1.script +++ /dev/null @@ -1,14 +0,0 @@ -# Simple test that we can commit an HTLC -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/01-offer1.script.expected b/test/commits/01-offer1.script.expected deleted file mode 100644 index 35e856e23..000000000 --- a/test/commits/01-offer1.script.expected +++ /dev/null @@ -1,18 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 1: - Our htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 1: - Our htlcs: 1 - SIGNED -***B*** -LOCAL COMMIT: - Commit 1: - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 1: - Their htlcs: 1 - SIGNED diff --git a/test/commits/02-offer2.script b/test/commits/02-offer2.script deleted file mode 100644 index d5bc4d69c..000000000 --- a/test/commits/02-offer2.script +++ /dev/null @@ -1,17 +0,0 @@ -# Simple test that we can commit two HTLCs -A:offer 1 -A:offer 3 -A:commit -B:recvoffer -B:recvoffer -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump - diff --git a/test/commits/02-offer2.script.expected b/test/commits/02-offer2.script.expected deleted file mode 100644 index e4d9689f9..000000000 --- a/test/commits/02-offer2.script.expected +++ /dev/null @@ -1,18 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 1: - Our htlcs: 1 3 - SIGNED -REMOTE COMMIT: - Commit 1: - Our htlcs: 1 3 - SIGNED -***B*** -LOCAL COMMIT: - Commit 1: - Their htlcs: 1 3 - SIGNED -REMOTE COMMIT: - Commit 1: - Their htlcs: 1 3 - SIGNED diff --git a/test/commits/03-fulfill1.script b/test/commits/03-fulfill1.script deleted file mode 100644 index efe56c0fe..000000000 --- a/test/commits/03-fulfill1.script +++ /dev/null @@ -1,24 +0,0 @@ -# Simple test that we can fulfill (remove) an HTLC after fully settled. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke - -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/03-fulfill1.script.expected b/test/commits/03-fulfill1.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/03-fulfill1.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/04-two-commits-onedir.script b/test/commits/04-two-commits-onedir.script deleted file mode 100644 index 811324e59..000000000 --- a/test/commits/04-two-commits-onedir.script +++ /dev/null @@ -1,21 +0,0 @@ -# Test A can commit twice; queueing two commits onto B's queue. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke - -A:offer 3 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke - -B:commit -A:recvcommit -B:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/04-two-commits-onedir.script.expected b/test/commits/04-two-commits-onedir.script.expected deleted file mode 100644 index 3aef37e77..000000000 --- a/test/commits/04-two-commits-onedir.script.expected +++ /dev/null @@ -1,18 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 1: - Our htlcs: 1 3 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 3 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Their htlcs: 1 3 - SIGNED -REMOTE COMMIT: - Commit 1: - Their htlcs: 1 3 - SIGNED diff --git a/test/commits/06-change-while-commit-outstanding.script b/test/commits/06-change-while-commit-outstanding.script deleted file mode 100644 index 65268b2e4..000000000 --- a/test/commits/06-change-while-commit-outstanding.script +++ /dev/null @@ -1,28 +0,0 @@ -# Test changes after committing but before receiving revocation. -A:offer 1 -B:recvoffer -A:commit -A:offer 3 - -# Now B receives that commitment and counter-commits. -B:recvcommit -B:commit - -A:recvrevoke -A:recvcommit -A:commit - -B:recvoffer -B:recvrevoke -B:recvcommit - -B:commit -A:recvrevoke -A:recvcommit -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/06-change-while-commit-outstanding.script.expected b/test/commits/06-change-while-commit-outstanding.script.expected deleted file mode 100644 index 20a8aee2e..000000000 --- a/test/commits/06-change-while-commit-outstanding.script.expected +++ /dev/null @@ -1,18 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 3 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 3 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Their htlcs: 1 3 - SIGNED -REMOTE COMMIT: - Commit 2: - Their htlcs: 1 3 - SIGNED diff --git a/test/commits/10-offers-crossover.script b/test/commits/10-offers-crossover.script deleted file mode 100644 index 1ee12f10f..000000000 --- a/test/commits/10-offers-crossover.script +++ /dev/null @@ -1,22 +0,0 @@ -# Offers which cross over still get resolved. -A:offer 1 -A:commit -B:offer 2 -B:recvoffer -B:recvcommit -B:commit - -A:recvoffer -A:recvrevoke -A:recvcommit -B:recvrevoke - -A:commit -B:recvcommit -A:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/10-offers-crossover.script.expected b/test/commits/10-offers-crossover.script.expected deleted file mode 100644 index 751ebc204..000000000 --- a/test/commits/10-offers-crossover.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 1: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 1: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/11-commits-crossover.script b/test/commits/11-commits-crossover.script deleted file mode 100644 index 478f3117d..000000000 --- a/test/commits/11-commits-crossover.script +++ /dev/null @@ -1,27 +0,0 @@ -# Commits which cross over still get resolved. -A:offer 1 -B:offer 2 -A:commit -B:commit - -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit - -A:recvrevoke -B:recvrevoke - -# They've got to come into sync eventually! -A:commit -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/11-commits-crossover.script.expected b/test/commits/11-commits-crossover.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/11-commits-crossover.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/13-fee.script b/test/commits/13-fee.script deleted file mode 100644 index e040104fa..000000000 --- a/test/commits/13-fee.script +++ /dev/null @@ -1,13 +0,0 @@ -# Simple test that we can change fee level -A:feechange -B:recvfeechange -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/13-fee.script.expected b/test/commits/13-fee.script.expected deleted file mode 100644 index f96ef363b..000000000 --- a/test/commits/13-fee.script.expected +++ /dev/null @@ -1,16 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 1: - Fee level 1 - SIGNED -REMOTE COMMIT: - Commit 1: - SIGNED -***B*** -LOCAL COMMIT: - Commit 1: - SIGNED -REMOTE COMMIT: - Commit 1: - Fee level 1 - SIGNED diff --git a/test/commits/14-fee-twice.script b/test/commits/14-fee-twice.script deleted file mode 100644 index 738edf44a..000000000 --- a/test/commits/14-fee-twice.script +++ /dev/null @@ -1,15 +0,0 @@ -# We can change fee level twice. -A:feechange -A:feechange -A:commit -B:recvfeechange -B:recvfeechange -B:recvcommit -B:commit -A:recvrevoke -A:recvcommit -B:recvrevoke -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/14-fee-twice.script.expected b/test/commits/14-fee-twice.script.expected deleted file mode 100644 index 084b88253..000000000 --- a/test/commits/14-fee-twice.script.expected +++ /dev/null @@ -1,16 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 1: - Fee level 2 - SIGNED -REMOTE COMMIT: - Commit 1: - SIGNED -***B*** -LOCAL COMMIT: - Commit 1: - SIGNED -REMOTE COMMIT: - Commit 1: - Fee level 2 - SIGNED diff --git a/test/commits/20-restore-02.script b/test/commits/20-restore-02.script deleted file mode 100644 index 833af6d41..000000000 --- a/test/commits/20-restore-02.script +++ /dev/null @@ -1,24 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -restart -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-02.script.expected b/test/commits/20-restore-02.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-02.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-03.script b/test/commits/20-restore-03.script deleted file mode 100644 index c19630e4c..000000000 --- a/test/commits/20-restore-03.script +++ /dev/null @@ -1,25 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -restart -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-03.script.expected b/test/commits/20-restore-03.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-03.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-04.script b/test/commits/20-restore-04.script deleted file mode 100644 index 6af9c2b58..000000000 --- a/test/commits/20-restore-04.script +++ /dev/null @@ -1,24 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -restart -B:recvoffer -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-04.script.expected b/test/commits/20-restore-04.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-04.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-05.script b/test/commits/20-restore-05.script deleted file mode 100644 index fb8c08c59..000000000 --- a/test/commits/20-restore-05.script +++ /dev/null @@ -1,23 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -restart -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-05.script.expected b/test/commits/20-restore-05.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-05.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-06.script b/test/commits/20-restore-06.script deleted file mode 100644 index 3db9a5295..000000000 --- a/test/commits/20-restore-06.script +++ /dev/null @@ -1,23 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -restart -B:commit -A:recvcommit -B:recvrevoke -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-06.script.expected b/test/commits/20-restore-06.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-06.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-07.script b/test/commits/20-restore-07.script deleted file mode 100644 index 947a5d1bf..000000000 --- a/test/commits/20-restore-07.script +++ /dev/null @@ -1,23 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -restart -A:recvcommit -B:recvrevoke -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-07.script.expected b/test/commits/20-restore-07.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-07.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-08.script b/test/commits/20-restore-08.script deleted file mode 100644 index e6e78d266..000000000 --- a/test/commits/20-restore-08.script +++ /dev/null @@ -1,23 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -restart -B:recvrevoke -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-08.script.expected b/test/commits/20-restore-08.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-08.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-09.script b/test/commits/20-restore-09.script deleted file mode 100644 index a0fe539d9..000000000 --- a/test/commits/20-restore-09.script +++ /dev/null @@ -1,23 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -restart -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-09.script.expected b/test/commits/20-restore-09.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-09.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-10.script b/test/commits/20-restore-10.script deleted file mode 100644 index 23d2293af..000000000 --- a/test/commits/20-restore-10.script +++ /dev/null @@ -1,24 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -B:remove 1 -restart -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-10.script.expected b/test/commits/20-restore-10.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-10.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-11.script b/test/commits/20-restore-11.script deleted file mode 100644 index 225aaac74..000000000 --- a/test/commits/20-restore-11.script +++ /dev/null @@ -1,23 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -B:remove 1 -B:commit -restart -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-11.script.expected b/test/commits/20-restore-11.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-11.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-12.script b/test/commits/20-restore-12.script deleted file mode 100644 index a788a2953..000000000 --- a/test/commits/20-restore-12.script +++ /dev/null @@ -1,24 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -B:remove 1 -B:commit -A:recvremove -restart -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-12.script.expected b/test/commits/20-restore-12.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-12.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-13.script b/test/commits/20-restore-13.script deleted file mode 100644 index 518370033..000000000 --- a/test/commits/20-restore-13.script +++ /dev/null @@ -1,23 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -B:remove 1 -B:commit -A:recvremove -A:recvcommit -restart -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-13.script.expected b/test/commits/20-restore-13.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-13.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-14.script b/test/commits/20-restore-14.script deleted file mode 100644 index 9f4ce908e..000000000 --- a/test/commits/20-restore-14.script +++ /dev/null @@ -1,23 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -restart -A:commit -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-14.script.expected b/test/commits/20-restore-14.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-14.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-15.script b/test/commits/20-restore-15.script deleted file mode 100644 index e402526de..000000000 --- a/test/commits/20-restore-15.script +++ /dev/null @@ -1,23 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -restart -B:recvcommit -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-15.script.expected b/test/commits/20-restore-15.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-15.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-16.script b/test/commits/20-restore-16.script deleted file mode 100644 index 13f116d46..000000000 --- a/test/commits/20-restore-16.script +++ /dev/null @@ -1,23 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -restart -A:recvrevoke -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-16.script.expected b/test/commits/20-restore-16.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-16.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/20-restore-17.script b/test/commits/20-restore-17.script deleted file mode 100644 index 98cc99d4b..000000000 --- a/test/commits/20-restore-17.script +++ /dev/null @@ -1,23 +0,0 @@ -# Variety of tests for save/restore. -A:offer 1 -B:recvoffer -A:commit -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke -B:remove 1 -B:commit -A:recvremove -A:recvcommit -B:recvrevoke -A:commit -B:recvcommit -A:recvrevoke -restart -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/20-restore-17.script.expected b/test/commits/20-restore-17.script.expected deleted file mode 100644 index 79acdd358..000000000 --- a/test/commits/20-restore-17.script.expected +++ /dev/null @@ -1,14 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - SIGNED -REMOTE COMMIT: - Commit 2: - SIGNED diff --git a/test/commits/21-restore-crossover-02.script b/test/commits/21-restore-crossover-02.script deleted file mode 100644 index 5ee637d31..000000000 --- a/test/commits/21-restore-crossover-02.script +++ /dev/null @@ -1,25 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -restart -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -A:commit -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-02.script.expected b/test/commits/21-restore-crossover-02.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-02.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-03.script b/test/commits/21-restore-crossover-03.script deleted file mode 100644 index 15da68994..000000000 --- a/test/commits/21-restore-crossover-03.script +++ /dev/null @@ -1,26 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -restart -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -A:commit -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-03.script.expected b/test/commits/21-restore-crossover-03.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-03.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-04.script b/test/commits/21-restore-crossover-04.script deleted file mode 100644 index ea5fb3084..000000000 --- a/test/commits/21-restore-crossover-04.script +++ /dev/null @@ -1,25 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -restart -B:offer 2 -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -A:commit -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-04.script.expected b/test/commits/21-restore-crossover-04.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-04.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-05.script b/test/commits/21-restore-crossover-05.script deleted file mode 100644 index 730363cbd..000000000 --- a/test/commits/21-restore-crossover-05.script +++ /dev/null @@ -1,24 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -B:commit -restart -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -A:commit -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-05.script.expected b/test/commits/21-restore-crossover-05.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-05.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-06.script b/test/commits/21-restore-crossover-06.script deleted file mode 100644 index d8c7b6cf8..000000000 --- a/test/commits/21-restore-crossover-06.script +++ /dev/null @@ -1,25 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -restart -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -A:commit -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-06.script.expected b/test/commits/21-restore-crossover-06.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-06.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-07.script b/test/commits/21-restore-crossover-07.script deleted file mode 100644 index 99e554c4f..000000000 --- a/test/commits/21-restore-crossover-07.script +++ /dev/null @@ -1,26 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -B:recvoffer -restart -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -A:commit -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-07.script.expected b/test/commits/21-restore-crossover-07.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-07.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-08.script b/test/commits/21-restore-crossover-08.script deleted file mode 100644 index c7d8f51c9..000000000 --- a/test/commits/21-restore-crossover-08.script +++ /dev/null @@ -1,25 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -restart -B:recvoffer -B:recvcommit -A:recvrevoke -B:recvrevoke -A:commit -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-08.script.expected b/test/commits/21-restore-crossover-08.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-08.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-08a.script b/test/commits/21-restore-crossover-08a.script deleted file mode 100644 index 979b28e11..000000000 --- a/test/commits/21-restore-crossover-08a.script +++ /dev/null @@ -1,23 +0,0 @@ -# Restart during commits which cross over still. -# In this variant, A sends revocation *before* sending commit. -A:offer 1 -B:offer 2 -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -A:commit -restart -B:recvrevoke -B:recvoffer -B:recvcommit -A:recvrevoke -B:commit -A:recvcommit -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-08a.script.expected b/test/commits/21-restore-crossover-08a.script.expected deleted file mode 100644 index f4ca6477a..000000000 --- a/test/commits/21-restore-crossover-08a.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 1: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 1: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-09.script b/test/commits/21-restore-crossover-09.script deleted file mode 100644 index 65d66f255..000000000 --- a/test/commits/21-restore-crossover-09.script +++ /dev/null @@ -1,24 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -restart -A:recvrevoke -B:recvrevoke -A:commit -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-09.script.expected b/test/commits/21-restore-crossover-09.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-09.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-10.script b/test/commits/21-restore-crossover-10.script deleted file mode 100644 index 92b47ec07..000000000 --- a/test/commits/21-restore-crossover-10.script +++ /dev/null @@ -1,24 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -restart -B:recvrevoke -A:commit -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-10.script.expected b/test/commits/21-restore-crossover-10.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-10.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-11.script b/test/commits/21-restore-crossover-11.script deleted file mode 100644 index f73726bf8..000000000 --- a/test/commits/21-restore-crossover-11.script +++ /dev/null @@ -1,24 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -restart -A:commit -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-11.script.expected b/test/commits/21-restore-crossover-11.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-11.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-12.script b/test/commits/21-restore-crossover-12.script deleted file mode 100644 index 178e58730..000000000 --- a/test/commits/21-restore-crossover-12.script +++ /dev/null @@ -1,24 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -A:commit -restart -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-12.script.expected b/test/commits/21-restore-crossover-12.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-12.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-13.script b/test/commits/21-restore-crossover-13.script deleted file mode 100644 index b81532ddd..000000000 --- a/test/commits/21-restore-crossover-13.script +++ /dev/null @@ -1,24 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -A:commit -B:commit -restart -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-13.script.expected b/test/commits/21-restore-crossover-13.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-13.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-14.script b/test/commits/21-restore-crossover-14.script deleted file mode 100644 index b6d7b05d0..000000000 --- a/test/commits/21-restore-crossover-14.script +++ /dev/null @@ -1,24 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -A:commit -B:commit -A:recvcommit -restart -B:recvcommit -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-14.script.expected b/test/commits/21-restore-crossover-14.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-14.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-15.script b/test/commits/21-restore-crossover-15.script deleted file mode 100644 index 13131790b..000000000 --- a/test/commits/21-restore-crossover-15.script +++ /dev/null @@ -1,24 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -A:commit -B:commit -A:recvcommit -B:recvcommit -restart -A:recvrevoke -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-15.script.expected b/test/commits/21-restore-crossover-15.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-15.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-16.script b/test/commits/21-restore-crossover-16.script deleted file mode 100644 index 5445dc2f6..000000000 --- a/test/commits/21-restore-crossover-16.script +++ /dev/null @@ -1,24 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -A:commit -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -restart -B:recvrevoke - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-16.script.expected b/test/commits/21-restore-crossover-16.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-16.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/commits/21-restore-crossover-17.script b/test/commits/21-restore-crossover-17.script deleted file mode 100644 index 85b234cb8..000000000 --- a/test/commits/21-restore-crossover-17.script +++ /dev/null @@ -1,24 +0,0 @@ -# Restart during commits which cross over still. -A:offer 1 -B:offer 2 -A:commit -B:commit -A:recvoffer -B:recvoffer -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -A:commit -B:commit -A:recvcommit -B:recvcommit -A:recvrevoke -B:recvrevoke -restart - -checksync -echo ***A*** -A:dump -echo ***B*** -B:dump diff --git a/test/commits/21-restore-crossover-17.script.expected b/test/commits/21-restore-crossover-17.script.expected deleted file mode 100644 index 56fb201da..000000000 --- a/test/commits/21-restore-crossover-17.script.expected +++ /dev/null @@ -1,22 +0,0 @@ -***A*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 1 - Their htlcs: 2 - SIGNED -***B*** -LOCAL COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED -REMOTE COMMIT: - Commit 2: - Our htlcs: 2 - Their htlcs: 1 - SIGNED diff --git a/test/test_protocol.c b/test/test_protocol.c deleted file mode 100644 index 5e3e02f81..000000000 --- a/test/test_protocol.c +++ /dev/null @@ -1,1426 +0,0 @@ -/* Simple simulator for protocol. */ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define A_LINEX 100 -#define B_LINEX 245 -#define A_TEXTX 95 -#define B_TEXTX 250 - -#define LINE_HEIGHT 5 -#define TEXT_HEIGHT 4 -#define STEP_HEIGHT 10 -#define LETTER_WIDTH 3 - -#define TEXT_STYLE "style=\"font-size:4;\"" - -static bool verbose = false; - -struct commit_tx { - /* inhtlcs = htlcs they offered, outhtlcs = htlcs we offered */ - u32 inhtlcs, outhtlcs; - /* This is a simple counter, reflecting fee updates. */ - u32 fee; -}; - -/* We keep one for them, one for us. */ -struct commit_info { - struct commit_info *prev; - /* How deep we are */ - unsigned int number; - /* Have sent/received revocation secret. */ - bool revoked; - /* Have their signature, ie. can be broadcast */ - bool counterparty_signed; - u16 pad; - /* num_commit_or_revoke when we sent/received this. */ - size_t order; -}; - -/* A "signature" is a copy of the commit tx state, for easy diagnosis. */ -struct signature { - struct commit_tx f; -}; - -/* What are we doing: adding or removing? */ -#define ADDING 0x1000 -#define REMOVING 0x2000 - -#define PENDING 0x001 /* Change is pending. */ -#define COMMITTED 0x002 /* HTLC is in commit_tx */ -#define REVOKED 0x004 /* Old pre-change tx revoked */ -#define OWNER 0x020 /* This side owns it */ - -#define OURS LOCAL(OWNER) -#define THEIRS REMOTE(OWNER) - -#define LOCAL_ 0 -#define REMOTE_ 6 -#define SIDE(flag,local_or_remote) ((flag) << local_or_remote) -#define OTHER_SIDE(flag,local_or_remote) ((flag) << (6 - local_or_remote)) -#define LOCAL(flag) SIDE(flag, LOCAL_) -#define REMOTE(flag) SIDE(flag, REMOTE_) - -enum htlc_state { - NONEXISTENT = 0, - - /* When we add a new htlc, it goes in this order. */ - SENT_ADD_HTLC = ADDING + OURS + REMOTE(PENDING), - SENT_ADD_COMMIT = SENT_ADD_HTLC - REMOTE(PENDING) + REMOTE(COMMITTED), - RECV_ADD_REVOCATION = SENT_ADD_COMMIT + REMOTE(REVOKED), - RECV_ADD_ACK_COMMIT = RECV_ADD_REVOCATION + LOCAL(COMMITTED), - SENT_ADD_ACK_REVOCATION = RECV_ADD_ACK_COMMIT + LOCAL(REVOKED) - ADDING, - - /* When they remove an HTLC, it goes from SENT_ADD_ACK_REVOCATION: */ - RECV_REMOVE_HTLC = REMOVING + OURS + LOCAL(PENDING) - + LOCAL(COMMITTED) + REMOTE(COMMITTED), - RECV_REMOVE_COMMIT = RECV_REMOVE_HTLC - LOCAL(PENDING) - LOCAL(COMMITTED), - SENT_REMOVE_REVOCATION = RECV_REMOVE_COMMIT + LOCAL(REVOKED), - SENT_REMOVE_ACK_COMMIT = SENT_REMOVE_REVOCATION - REMOTE(COMMITTED), - RECV_REMOVE_ACK_REVOCATION = SENT_REMOVE_ACK_COMMIT - REMOVING + REMOTE(REVOKED), - - /* When they add a new htlc, it goes in this order. */ - RECV_ADD_HTLC = ADDING + THEIRS + LOCAL(PENDING), - RECV_ADD_COMMIT = RECV_ADD_HTLC - LOCAL(PENDING) + LOCAL(COMMITTED), - SENT_ADD_REVOCATION = RECV_ADD_COMMIT + LOCAL(REVOKED), - SENT_ADD_ACK_COMMIT = SENT_ADD_REVOCATION + REMOTE(COMMITTED), - RECV_ADD_ACK_REVOCATION = SENT_ADD_ACK_COMMIT + REMOTE(REVOKED), - - /* When we remove an HTLC, it goes from RECV_ADD_ACK_REVOCATION: */ - SENT_REMOVE_HTLC = REMOVING + THEIRS + REMOTE(PENDING) - + LOCAL(COMMITTED) + REMOTE(COMMITTED), - SENT_REMOVE_COMMIT = SENT_REMOVE_HTLC - REMOTE(PENDING) - REMOTE(COMMITTED), - RECV_REMOVE_REVOCATION = SENT_REMOVE_COMMIT + REMOTE(REVOKED), - RECV_REMOVE_ACK_COMMIT = RECV_REMOVE_REVOCATION - LOCAL(COMMITTED), - SENT_REMOVE_ACK_REVOCATION = RECV_REMOVE_ACK_COMMIT + LOCAL(REVOKED) - REMOVING -}; - -static const char *htlc_statename(enum htlc_state state) -{ - switch (state) { - case NONEXISTENT: return "NONEXISTENT"; - case SENT_ADD_HTLC: return "SENT_ADD_HTLC"; - case SENT_ADD_COMMIT: return "SENT_ADD_COMMIT"; - case RECV_ADD_REVOCATION: return "RECV_ADD_REVOCATION"; - case RECV_ADD_ACK_COMMIT: return "RECV_ADD_ACK_COMMIT"; - case SENT_ADD_ACK_REVOCATION: return "SENT_ADD_ACK_REVOCATION"; - case RECV_REMOVE_HTLC: return "RECV_REMOVE_HTLC"; - case RECV_REMOVE_COMMIT: return "RECV_REMOVE_COMMIT"; - case SENT_REMOVE_REVOCATION: return "SENT_REMOVE_REVOCATION"; - case SENT_REMOVE_ACK_COMMIT: return "SENT_REMOVE_ACK_COMMIT"; - case RECV_REMOVE_ACK_REVOCATION: return "RECV_REMOVE_ACK_REVOCATION"; - case RECV_ADD_HTLC: return "RECV_ADD_HTLC"; - case RECV_ADD_COMMIT: return "RECV_ADD_COMMIT"; - case SENT_ADD_REVOCATION: return "SENT_ADD_REVOCATION"; - case SENT_ADD_ACK_COMMIT: return "SENT_ADD_ACK_COMMIT"; - case RECV_ADD_ACK_REVOCATION: return "RECV_ADD_ACK_REVOCATION"; - case SENT_REMOVE_HTLC: return "SENT_REMOVE_HTLC"; - case SENT_REMOVE_COMMIT: return "SENT_REMOVE_COMMIT"; - case RECV_REMOVE_REVOCATION: return "RECV_REMOVE_REVOCATION"; - case RECV_REMOVE_ACK_COMMIT: return "RECV_REMOVE_ACK_COMMIT"; - case SENT_REMOVE_ACK_REVOCATION: return "SENT_REMOVE_ACK_REVOCATION"; - } - return tal_fmt(NULL, "UNKNOWN STATE %i", state); -} - -static const char *htlc_stateflags(const tal_t *ctx, enum htlc_state state) -{ - char *flags = tal_strdup(ctx, ""); -#define ADD_STATE(flags, flag) \ - if (state & flag) \ - tal_append_fmt(&flags, #flag ","); - - ADD_STATE(flags, ADDING); - ADD_STATE(flags, REMOVING); - ADD_STATE(flags, OURS); - ADD_STATE(flags, THEIRS); - - ADD_STATE(flags, LOCAL(PENDING)); - ADD_STATE(flags, LOCAL(COMMITTED)); - ADD_STATE(flags, LOCAL(REVOKED)); - - ADD_STATE(flags, REMOTE(PENDING)); - ADD_STATE(flags, REMOTE(COMMITTED)); - ADD_STATE(flags, REMOTE(REVOKED)); - - if (strends(flags, ",")) - flags[strlen(flags)-1] = '\0'; - - return flags; -} - -struct htlc { - enum htlc_state state; - /* 0 means this is actually a new fee, not an HTLC. */ - unsigned int id; -}; - -static u32 htlc_mask(unsigned int htlc) -{ - if (htlc > 32) - errx(1, "HTLC number %u too large", htlc); - if (!htlc) - errx(1, "HTLC number can't be zero"); - return (1U << (htlc-1)); -} - -/* Make commit tx for local/remote */ -static struct commit_tx make_commit_tx(struct htlc **htlcs, int local_or_remote) -{ - size_t i, n = tal_count(htlcs); - int committed_flag = SIDE(COMMITTED, local_or_remote); - struct commit_tx tx = { 0, 0, 0 }; - - for (i = 0; i < n; i++) { - if (!(htlcs[i]->state & committed_flag)) - continue; - - if (!(htlcs[i]->state & SIDE(OWNER, local_or_remote))) { - /* We don't apply fee changes to each other. */ - if (htlcs[i]->id) - tx.outhtlcs |= htlc_mask(htlcs[i]->id); - } else { - if (!htlcs[i]->id) - tx.fee++; - else - tx.inhtlcs |= htlc_mask(htlcs[i]->id); - } - } - - return tx; -} - -struct database { - /* This keeps *all* our HTLCs, including expired ones. */ - size_t num_htlcs; - struct htlc htlcs[100]; - - /* This counts the number of received commit and revocation pkts. */ - size_t last_recv; - size_t last_sent; - - /* We keep remote_prev because it might not be revoked, and this - * makes our receive_revoke logic simpler. */ - struct commit_info local, remote, remote_prev; -}; - -struct peer { - const char *name; - - int infd, outfd, cmdfd, cmddonefd; - - /* For drawing svg */ - char *info; - - /* What we save on disk. */ - struct database db; - - /* All htlcs. */ - struct htlc **htlcs; - - /* Last one is the one we're changing. */ - struct commit_info *local, *remote; -}; - -static void db_update_htlc(struct database *db, const struct htlc *htlc) -{ - size_t i; - - for (i = 0; i < db->num_htlcs; i++) { - if ((db->htlcs[i].state & (OURS|THEIRS)) - != (htlc->state & (OURS|THEIRS))) - continue; - /* FIXME: This isn't quite right for multiple fee changes. */ - if (db->htlcs[i].id == htlc->id) - break; - } - if (i == db->num_htlcs) { - db->num_htlcs++; - if (db->num_htlcs > ARRAY_SIZE(db->htlcs)) - errx(1, "Too many htlcs"); - } - db->htlcs[i] = *htlc; -} - -static void db_recv_local_commit(struct database *db, - const struct commit_info *ci) -{ - db->last_recv++; - db->local = *ci; -} - -static void db_send_remote_commit(struct database *db, - const struct commit_info *ci) -{ - if (ci->prev) - db->remote_prev = *ci->prev; - db->remote = *ci; - db->remote.order = ++db->last_sent; -} - -static void db_send_local_revoke(struct database *db) -{ - db->last_sent++; -} - -static void db_recv_remote_revoke(struct database *db, - const struct commit_info *ci) -{ - assert(ci->revoked); - - db->last_recv++; - db->remote_prev.revoked = true; - - /* A real db would save the previous revocation hash here too */ -} - -static struct htlc *find_htlc(struct peer *peer, unsigned int htlc_id, int side) -{ - size_t i, n = tal_count(peer->htlcs); - - for (i = 0; i < n; i++) { - if ((peer->htlcs[i]->state & side) - && peer->htlcs[i]->id == htlc_id) - return peer->htlcs[i]; - } - return NULL; -} - -static struct htlc *new_htlc(struct peer *peer, unsigned int htlc_id, int side) -{ - size_t n = tal_count(peer->htlcs); - - /* Fee changes don't have to be unique. */ - if (htlc_id && find_htlc(peer, htlc_id, side)) - errx(1, "%s: %s duplicate new htlc %u", peer->name, - side == OURS ? "Our" : "Their", htlc_id); - tal_resize(&peer->htlcs, n+1); - peer->htlcs[n] = tal(peer, struct htlc); - peer->htlcs[n]->state = NONEXISTENT; - peer->htlcs[n]->id = htlc_id; - - return peer->htlcs[n]; -} - -static void htlc_changestate(struct peer *peer, - struct htlc *htlc, - bool commit, - enum htlc_state old, - enum htlc_state new) -{ - if (htlc->state != old) - errx(1, "%s: htlc was in state %s not %s", peer->name, - htlc_statename(htlc->state), htlc_statename(old)); - if (htlc->id) { - if (verbose) - printf("%s: HTLC %u -> %s\n", - peer->name, htlc->id, htlc_statename(new)); - tal_append_fmt(&peer->info, "%u:%s\n", - htlc->id, htlc_statename(new)); - } else { - if (verbose) - printf("%s: FEE -> %s\n", - peer->name, htlc_statename(new)); - tal_append_fmt(&peer->info, "FEE:%s\n", - htlc_statename(new)); - } - htlc->state = new; - if (commit) - db_update_htlc(&peer->db, htlc); -} - -struct state_table { - enum htlc_state from, to; -}; - -static bool change_htlcs_(struct peer *peer, bool commit, - const struct state_table *table, - size_t n_table) -{ - size_t i, n = tal_count(peer->htlcs); - bool changed = false; - - for (i = 0; i < n; i++) { - size_t t; - for (t = 0; t < n_table; t++) { - if (peer->htlcs[i]->state == table[t].from) { - htlc_changestate(peer, peer->htlcs[i], commit, - table[t].from, table[t].to); - changed = true; - break; - } - } - } - return changed; -} - -#define change_htlcs(peer, table, commit) \ - change_htlcs_((peer), (commit), (table), ARRAY_SIZE(table)) - -static struct commit_info *new_commit_info(const struct peer *peer, - struct commit_info *prev) -{ - struct commit_info *ci = tal(peer, struct commit_info); - - ci->prev = prev; - ci->revoked = false; - ci->counterparty_signed = false; - ci->pad = 0; - ci->order = 0; - if (prev) - ci->number = prev->number + 1; - else - ci->number = 0; - return ci; -} - -static struct signature commit_sig(const struct commit_tx *commit_tx) -{ - struct signature sig; - sig.f = *commit_tx; - return sig; -} - -static void write_out(int fd, const void *p, size_t len) -{ - if (!write_all(fd, p, len)) - err(1, "Writing to peer"); -} - -static void dump_htlcs(struct htlc **htlcs, - const char *prefix, - bool verbose, - int flags_inc, int flags_exc) -{ - size_t i, n = tal_count(htlcs); - const tal_t *ctx = tal_tmpctx(htlcs); - bool printed = false; - - for (i = 0; i < n; i++) { - if ((htlcs[i]->state & flags_inc) != flags_inc) - continue; - if (htlcs[i]->state & flags_exc) - continue; - if (!htlcs[i]->id && !verbose) - continue; - if (!printed) { - printf("%s", prefix); - printed = true; - } - if (!htlcs[i]->id) - printf(" FEE"); - else - printf(" %u", htlcs[i]->id); - if (verbose) { - printf(" (%s - %s)", - htlc_statename(htlcs[i]->state), - htlc_stateflags(ctx, htlcs[i]->state)); - } - } - if (printed) - printf("\n"); - tal_free(ctx); -} - -static void dump_commit_info(const struct peer *peer, - const struct commit_info *ci, - int local_or_remote) -{ - struct commit_tx tx; - int committed_flag = SIDE(COMMITTED, local_or_remote); - - tx = make_commit_tx(peer->htlcs, local_or_remote); - - printf(" Commit %u:\n", ci->number); - dump_htlcs(peer->htlcs, " Our htlcs:", false, - OURS|committed_flag, 0); - dump_htlcs(peer->htlcs, " Their htlcs:", false, - THEIRS|committed_flag, 0); - - /* Don't clutter output if fee level untouched. */ - if (tx.fee) - printf(" Fee level %u\n", tx.fee); - - dump_htlcs(peer->htlcs, "Pending unacked:", true, - SIDE(PENDING, local_or_remote), committed_flag); - - dump_htlcs(peer->htlcs, "Pending acked:", true, - OTHER_SIDE(COMMITTED, local_or_remote), committed_flag); - - if (ci->counterparty_signed) - printf(" SIGNED\n"); - if (ci->revoked) - printf(" REVOKED\n"); - fflush(stdout); -} - -static void dump_peer(const struct peer *peer, bool all) -{ - printf("LOCAL COMMIT:\n"); - dump_commit_info(peer, peer->local, LOCAL_); - - printf("REMOTE COMMIT:\n"); - dump_commit_info(peer, peer->remote, REMOTE_); - - if (all) - dump_htlcs(peer->htlcs, "OLD HTLCs:", true, - 0, LOCAL(COMMITTED)|REMOTE(COMMITTED)); -} - -static void read_in(int fd, void *p, size_t len) -{ - alarm(5); - if (!read_all(fd, p, len)) - err(1, "Reading from peer"); - alarm(0); -} - -static void read_peer(struct peer *peer, const char *str, const char *cmd) -{ - char *p = tal_arr(peer, char, strlen(str)+1); - read_in(peer->infd, p, strlen(str)); - p[strlen(str)] = '\0'; - if (!streq(p, str)) - errx(1, "%s: %s: Expected %s from peer, got %s", - peer->name, cmd, str, p); - tal_free(p); -} - -static void PRINTF_FMT(2,3) record_send(struct peer *peer, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - tal_append_fmt(&peer->info, ">"); - tal_append_vfmt(&peer->info, fmt, ap); - tal_append_fmt(&peer->info, "\n"); - va_end(ap); - - if (verbose) { - va_start(ap, fmt); - printf("%s: SEND ", peer->name); - vprintf(fmt, ap); - printf("\n"); - va_end(ap); - } -} - -static void PRINTF_FMT(2,3) record_recv(struct peer *peer, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - tal_append_fmt(&peer->info, "<"); - tal_append_vfmt(&peer->info, fmt, ap); - tal_append_fmt(&peer->info, "\n"); - va_end(ap); - - if (verbose) { - va_start(ap, fmt); - printf("%s: RECEIVE ", peer->name); - vprintf(fmt, ap); - printf("\n"); - va_end(ap); - } -} - -static void xmit_add_htlc(struct peer *peer, const struct htlc *h) -{ - record_send(peer, "add_htlc %u", h->id); - write_out(peer->outfd, "+", 1); - write_out(peer->outfd, &h->id, sizeof(h->id)); -} - -static void xmit_remove_htlc(struct peer *peer, const struct htlc *h) -{ - record_send(peer, "fulfill_htlc %u", h->id); - write_out(peer->outfd, "-", 1); - write_out(peer->outfd, &h->id, sizeof(h->id)); -} - -static void xmit_feechange(struct peer *peer) -{ - record_send(peer, "update_fee"); - write_out(peer->outfd, "F", 1); -} - -static void xmit_commit(struct peer *peer, struct signature sig) -{ - record_send(peer, "update_commit"); - write_out(peer->outfd, "C", 1); - write_out(peer->outfd, &sig, sizeof(sig)); -} - -static void xmit_revoke(struct peer *peer, unsigned int number) -{ - record_send(peer, "update_revocation"); - write_out(peer->outfd, "R", 1); - write_out(peer->outfd, &number, sizeof(number)); -} - -static void send_offer(struct peer *peer, unsigned int htlc) -{ - struct htlc *h = new_htlc(peer, htlc, OURS); - - htlc_changestate(peer, h, false, NONEXISTENT, SENT_ADD_HTLC); - xmit_add_htlc(peer, h); -} - -static void send_remove(struct peer *peer, unsigned int htlc) -{ - struct htlc *h = find_htlc(peer, htlc, THEIRS); - - if (!h) - errx(1, "%s: send_remove: htlc %u does not exist", - peer->name, htlc); - - htlc_changestate(peer, h, false, RECV_ADD_ACK_REVOCATION, SENT_REMOVE_HTLC); - xmit_remove_htlc(peer, h); -} - -static void send_feechange(struct peer *peer) -{ - struct htlc *fee = new_htlc(peer, 0, OURS); - - htlc_changestate(peer, fee, false, NONEXISTENT, SENT_ADD_HTLC); - xmit_feechange(peer); -} - -/* - * We don't enforce the rule that commits have to wait for revoke response - * before the next one. - */ -static struct commit_info *last_unrevoked(struct commit_info *ci) -{ - struct commit_info *next = NULL; - - /* If this is already revoked, all are. */ - if (ci->revoked) - return NULL; - - /* Find revoked commit; one we hit before that was last unrevoked. */ - for (; ci; next = ci, ci = ci->prev) { - if (ci->revoked) - break; - } - return next; -} - -static void send_commit(struct peer *peer) -{ - struct commit_tx tx; - struct signature sig; - - static const struct state_table changes[] = { - { SENT_ADD_HTLC, SENT_ADD_COMMIT }, - { SENT_REMOVE_REVOCATION, SENT_REMOVE_ACK_COMMIT }, - { SENT_ADD_REVOCATION, SENT_ADD_ACK_COMMIT}, - { SENT_REMOVE_HTLC, SENT_REMOVE_COMMIT} - }; - - /* FIXME-OLD #2: - * - * An implementation MAY choose not to send an `update_commit` - * until it receives the `update_revocation` response to the - * previous `update_commit`, so there is only ever one - * unrevoked local commitment. */ - if (peer->remote->prev && !peer->remote->prev->revoked) - errx(1, "%s: commit: must wait for previous commit", peer->name); - - /* FIXME-OLD #2: - * - * ...a sending node MUST apply all remote acked and unacked - * changes except unacked fee changes to the remote commitment - * before generating `sig`. - */ - if (!change_htlcs(peer, changes, true)) { - /* FIXME-OLD #2: - * - * A node MUST NOT send an `update_commit` message which does - * not include any updates. - */ - errx(1, "%s: commit: no changes to commit", peer->name); - } - tx = make_commit_tx(peer->htlcs, REMOTE_); - sig = commit_sig(&tx); - - peer->remote = new_commit_info(peer, peer->remote); - peer->remote->counterparty_signed = true; - db_send_remote_commit(&peer->db, peer->remote); - - /* Tell other side about commit and result (it should agree!) */ - xmit_commit(peer, sig); -} - -static void receive_revoke(struct peer *peer, u32 number) -{ - static const struct state_table changes[] = { - { SENT_ADD_COMMIT, RECV_ADD_REVOCATION }, - { SENT_REMOVE_ACK_COMMIT, RECV_REMOVE_ACK_REVOCATION }, - { SENT_ADD_ACK_COMMIT, RECV_ADD_ACK_REVOCATION }, - { SENT_REMOVE_COMMIT, RECV_REMOVE_REVOCATION } - }; - struct commit_info *ci = last_unrevoked(peer->remote); - - if (!ci) - errx(1, "%s: receive_revoke: no commit to revoke", peer->name); - if (ci->number != number) - errx(1, "%s: receive_revoke: revoked %u but %u is next", - peer->name, number, ci->number); - - /* This shouldn't happen if we don't allow multiple commits. */ - if (ci != peer->remote->prev) - errx(1, "%s: receive_revoke: always revoke previous?", - peer->name); - - if (ci->revoked) - errx(1, "%s: receive_revoke: already revoked?", peer->name); - - record_recv(peer, "update_revocation"); - ci->revoked = true; - if (!ci->counterparty_signed) - errx(1, "%s: receive_revoke: revoked unsigned commit?", - peer->name); - - if (!change_htlcs(peer, changes, true)) - errx(1, "%s: receive_revoke: no changes?", peer->name); - - db_recv_remote_revoke(&peer->db, ci); -} - -/* FIXME-OLD #2: - * - * the receiving node MUST add the HTLC addition to the unacked - * changeset for its local commitment. - */ -static void receive_offer(struct peer *peer, unsigned int htlc) -{ - struct htlc *h = new_htlc(peer, htlc, THEIRS); - - htlc_changestate(peer, h, false, NONEXISTENT, RECV_ADD_HTLC); - record_recv(peer, "add_htlc %u", h->id); -} - -/* FIXME-OLD #2: - * - * the receiving node MUST add the HTLC fulfill/fail to the unacked - * changeset for its local commitment. - */ -static void receive_remove(struct peer *peer, unsigned int htlc) -{ - struct htlc *h = find_htlc(peer, htlc, OURS); - - if (!h) - errx(1, "%s: recv_remove: htlc %u does not exist", - peer->name, htlc); - - htlc_changestate(peer, h, false, SENT_ADD_ACK_REVOCATION, RECV_REMOVE_HTLC); - record_recv(peer, "fulfill_htlc %u", h->id); -} - -/* FIXME-OLD #2: - * - * the receiving node MUST add the fee change to the unacked changeset - * for its local commitment. - */ -static void receive_feechange(struct peer *peer) -{ - struct htlc *fee = new_htlc(peer, 0, THEIRS); - - htlc_changestate(peer, fee, false, NONEXISTENT, RECV_ADD_HTLC); - record_recv(peer, "update_fee"); -} - -/* Send revoke. - * - Queue changes to them. - */ -static void send_revoke(struct peer *peer, struct commit_info *ci) -{ - static const struct state_table changes[] = { - { RECV_ADD_ACK_COMMIT, SENT_ADD_ACK_REVOCATION }, - { RECV_REMOVE_COMMIT, SENT_REMOVE_REVOCATION }, - { RECV_ADD_COMMIT, SENT_ADD_REVOCATION }, - { RECV_REMOVE_ACK_COMMIT, SENT_REMOVE_ACK_REVOCATION } - }; - - /* We always revoke in order. */ - assert(!ci->prev || ci->prev->revoked); - assert(ci->counterparty_signed); - assert(!ci->revoked); - ci->revoked = true; - - if (!change_htlcs(peer, changes, true)) - errx(1, "%s: update_revocation: no changes?", peer->name); - - db_send_local_revoke(&peer->db); - xmit_revoke(peer, ci->number); -} - -/* Receive commit: - * - Apply changes to us. - */ -static void receive_commit(struct peer *peer, const struct signature *sig) -{ - struct commit_tx commit_tx; - struct signature oursig; - static const struct state_table changes[] = { - { RECV_ADD_REVOCATION, RECV_ADD_ACK_COMMIT }, - { RECV_REMOVE_HTLC, RECV_REMOVE_COMMIT }, - { RECV_ADD_HTLC, RECV_ADD_COMMIT }, - { RECV_REMOVE_REVOCATION, RECV_REMOVE_ACK_COMMIT } - }; - - record_recv(peer, "update_commit"); - - /* FIXME-OLD #2: - * - * A node MUST NOT send an `update_commit` message which does - * not include any updates. - */ - if (!change_htlcs(peer, changes, true)) - errx(1, "%s: receive_commit: no changes to commit", peer->name); - - commit_tx = make_commit_tx(peer->htlcs, LOCAL_); - oursig = commit_sig(&commit_tx); - if (!structeq(sig, &oursig)) - errx(1, "%s: Commit state %#x/%#x/%u, they gave %#x/%#x/%u", - peer->name, - sig->f.inhtlcs, sig->f.outhtlcs, sig->f.fee, - oursig.f.inhtlcs, oursig.f.outhtlcs, oursig.f.fee); - - peer->local = new_commit_info(peer, peer->local); - peer->local->counterparty_signed = true; - - db_recv_local_commit(&peer->db, peer->local); - - send_revoke(peer, peer->local->prev); -} - -static void resend_updates(struct peer *peer) -{ - size_t i; - - /* Re-transmit our add, removes and fee changes. */ - for (i = 0; i < tal_count(peer->htlcs); i++) { - switch (peer->htlcs[i]->state) { - case SENT_ADD_COMMIT: - if (peer->htlcs[i]->id) - xmit_add_htlc(peer, peer->htlcs[i]); - else - xmit_feechange(peer); - break; - case SENT_REMOVE_COMMIT: - xmit_remove_htlc(peer, peer->htlcs[i]); - break; - default: - break; - } - } -} - -static void restore_state(struct peer *peer) -{ - size_t i, sent, num_revokes, revoke_idx; - - peer->htlcs = tal_arr(peer, struct htlc *, peer->db.num_htlcs); - for (i = 0; i < peer->db.num_htlcs; i++) { - peer->htlcs[i] = tal_dup(peer->htlcs, struct htlc, - &peer->db.htlcs[i]); - if (verbose) - printf("%s: HTLC %u %s\n", - peer->name, peer->htlcs[i]->id, - htlc_statename(peer->htlcs[i]->state)); - } - - *peer->local = peer->db.local; - peer->local->prev = NULL; - - *peer->remote = peer->db.remote; - if (peer->remote->number != 0) { - peer->remote->prev = tal(peer, struct commit_info); - *peer->remote->prev = peer->db.remote_prev; - peer->remote->prev->prev = NULL; - } else - peer->remote->prev = NULL; - - /* Tell peer where we've received. */ - write_out(peer->outfd, "!", 1); - write_out(peer->outfd, &peer->db.last_recv, sizeof(peer->db.last_recv)); - - /* Find out where peer is up to. */ - read_peer(peer, "!", "restore"); - read_in(peer->infd, &sent, sizeof(sent)); - - if (verbose) - printf("%s: peer is up to %zu/%zu: last commit at %zu\n", - peer->name, sent, peer->db.last_sent,peer->remote->order); - - if (sent > peer->db.last_sent) - errx(1, "%s: peer said up to %zu, but we only sent %zu", - peer->name, sent, peer->db.last_sent); - - /* All up to date? Nothing to do. */ - if (sent == peer->db.last_sent) - return; - - /* Since we wait for revocation replies, only one of the missing - * could be our update; the rest must be revocations. */ - num_revokes = peer->db.last_sent - sent - (sent < peer->remote->order); - - if (num_revokes > peer->local->number) - errx(1, "%s: can't rexmit %zu revoke txs at %u", - peer->name, num_revokes, peer->local->number); - - revoke_idx = peer->local->number - num_revokes; - - /* If we sent a revocation before the commit. */ - if (sent + 1 < peer->remote->order) { - xmit_revoke(peer, revoke_idx++); - num_revokes--; - sent++; - } - - /* If they didn't get the last commit, re-send all. */ - if (sent + 1 == peer->remote->order) { - struct commit_tx tx; - struct signature sig; - - resend_updates(peer); - tx = make_commit_tx(peer->htlcs, REMOTE_); - sig = commit_sig(&tx); - xmit_commit(peer, sig); - sent++; - } - - /* Now send any revocations after the commit. */ - if (sent + 1 == peer->db.last_sent) { - num_revokes--; - xmit_revoke(peer, revoke_idx++); - sent++; - } - - if (sent != peer->db.last_sent) - errx(1, "%s: could not catch up %zu to %zu", - peer->name, sent, peer->db.last_sent); - - assert(num_revokes == 0); -} - -static void do_cmd(struct peer *peer) -{ - char cmd[80]; - int i; - unsigned int htlc; - struct commit_info *ci; - - i = read(peer->cmdfd, cmd, sizeof(cmd)-1); - if (i <= 0) - err(1, "%s: reading command", peer->name); - if (cmd[i-1] != '\0') - errx(1, "%s: Unterminated command", peer->name); - - if (i == 1) { - fflush(stdout); - exit(0); - } - - peer->info = tal_strdup(peer, ""); - - if (sscanf(cmd, "offer %u", &htlc) == 1) - send_offer(peer, htlc); - else if (sscanf(cmd, "remove %u", &htlc) == 1) - send_remove(peer, htlc); - else if (streq(cmd, "feechange")) - send_feechange(peer); - else if (streq(cmd, "commit")) - send_commit(peer); - else if (streq(cmd, "recvrevoke")) { - u32 number; - read_peer(peer, "R", cmd); - read_in(peer->infd, &number, sizeof(number)); - receive_revoke(peer, number); - } else if (streq(cmd, "recvoffer")) { - read_peer(peer, "+", cmd); - read_in(peer->infd, &htlc, sizeof(htlc)); - receive_offer(peer, htlc); - } else if (streq(cmd, "recvremove")) { - read_peer(peer, "-", cmd); - read_in(peer->infd, &htlc, sizeof(htlc)); - receive_remove(peer, htlc); - } else if (streq(cmd, "recvfeechange")) { - read_peer(peer, "F", cmd); - receive_feechange(peer); - } else if (streq(cmd, "recvcommit")) { - struct signature sig; - read_peer(peer, "C", cmd); - read_in(peer->infd, &sig, sizeof(sig)); - receive_commit(peer, &sig); - } else if (streq(cmd, "save")) { - write_all(peer->cmddonefd, &peer->db, sizeof(peer->db)); - return; - } else if (streq(cmd, "restore")) { - write_all(peer->cmddonefd, "", 1); - /* Ack, then read in blob */ - if (!read_all(peer->cmdfd, &peer->db, sizeof(peer->db))) { - errx(1, "Read failed for command \"restore\""); - } - restore_state(peer); - } else if (streq(cmd, "checksync")) { - struct commit_tx ours, theirs; - - ours = make_commit_tx(peer->htlcs, LOCAL_); - theirs = make_commit_tx(peer->htlcs, REMOTE_); - write_all(peer->cmddonefd, &ours, sizeof(ours)); - write_all(peer->cmddonefd, &theirs, sizeof(theirs)); - return; - } else if (streq(cmd, "dump")) { - dump_peer(peer, false); - } else if (streq(cmd, "dumpall")) { - dump_peer(peer, true); - } else - errx(1, "%s: Unknown command %s", peer->name, cmd); - - if (write(peer->cmddonefd, peer->info, strlen(peer->info)+1) - != strlen(peer->info)+1) - abort(); - - /* We must always have (at least one) signed, unrevoked commit. */ - for (ci = peer->local; ci; ci = ci->prev) { - if (ci->counterparty_signed && !ci->revoked) { - return; - } - } - errx(1, "%s: No signed, unrevoked commit!", peer->name); -} - -static void new_peer(const char *name, - int infdpair[2], int outfdpair[2], int cmdfdpair[2], - int cmddonefdpair[2]) -{ - struct peer *peer; - - switch (fork()) { - case 0: - break; - case -1: - err(1, "Forking"); - default: - return; - } - - close(infdpair[1]); - close(outfdpair[0]); - close(cmdfdpair[1]); - close(cmddonefdpair[0]); - - peer = tal(NULL, struct peer); - peer->name = name; - peer->htlcs = tal_arr(peer, struct htlc *, 0); - - memset(&peer->db, 0, sizeof(peer->db)); - - /* Create first, signed commit info. */ - peer->local = new_commit_info(peer, NULL); - peer->local->counterparty_signed = true; - - peer->remote = new_commit_info(peer, NULL); - peer->remote->counterparty_signed = true; - - peer->db.local = *peer->local; - peer->db.remote = *peer->remote; - - peer->infd = infdpair[0]; - peer->outfd = outfdpair[1]; - peer->cmdfd = cmdfdpair[0]; - peer->cmddonefd = cmddonefdpair[1]; - - while (1) - do_cmd(peer); -} - -struct sent { - int y; - const char *desc; -}; - -static void add_sent(struct sent **sent, int y, const char *msg) -{ - size_t n = tal_count(*sent); - tal_resize(sent, n+1); - (*sent)[n].y = y; - (*sent)[n].desc = tal_strdup(*sent, msg); -} - -static void draw_restart(char **str, const char *name, - int *y) -{ - *y += STEP_HEIGHT / 2; - tal_append_fmt(str, "\n", - A_TEXTX - 50, *y, B_TEXTX + 50, *y); - tal_append_fmt(str, "%s\n", - (A_TEXTX + B_TEXTX) / 2, *y - TEXT_HEIGHT/2, name); - *y += STEP_HEIGHT / 2; -} - -static void draw_line(char **str, - int old_x, struct sent **sent, const char *what, - int new_x, int new_y) -{ - size_t n = tal_count(*sent); - if (n == 0) - errx(1, "Receive without send?"); - - if (!streq((*sent)->desc, what)) - errx(1, "Received %s but sent %s?", what, (*sent)->desc); - - if (*str) { - tal_append_fmt(str, "\n", - old_x, (*sent)[0].y - LINE_HEIGHT/2, - new_x, new_y - LINE_HEIGHT/2); - tal_append_fmt(str, "%s\n", - (old_x + new_x) / 2, - ((*sent)[0].y + new_y) / 2, - (*sent)[0].desc); - } - - memmove(*sent, (*sent)+1, sizeof(**sent) * (n-1)); - tal_resize(sent, n-1); -} - -static void reset_sends(char **svg, bool is_a, struct sent **sent, int *y) -{ - /* These sends were lost. */ - while (tal_count(*sent)) { - if (is_a) - draw_line(svg, A_LINEX, sent, (*sent)->desc, - (B_LINEX + A_LINEX)/2, *y - STEP_HEIGHT/2); - else - draw_line(svg, B_LINEX, sent, (*sent)->desc, - (B_LINEX + A_LINEX)/2, *y - STEP_HEIGHT/2); - } -} - -static bool append_text(char **svg, bool is_a, int *y, const char *text, - size_t *max_chars) -{ - char **texts = tal_strsplit(NULL, text, "\n", STR_NO_EMPTY); - size_t i; - - if (tal_count(texts) == 1) - return false; - - for (i = 0; i < tal_count(texts) - 1; i++) { - tal_append_fmt(svg, - "%s", - is_a ? A_TEXTX : B_TEXTX, *y, - is_a ? "end" : "start", - texts[i]); - *y += TEXT_HEIGHT; - if (strlen(texts[i]) > *max_chars) - *max_chars = strlen(texts[i]); - } - return true; -} - -static bool process_output(char **svg, bool is_a, const char *output, - struct sent **a_sent, struct sent **b_sent, - int *y, size_t *max_chars) -{ - /* We can recv and send for recvcommit */ - char **outputs = tal_strsplit(NULL, output, "\n", STR_NO_EMPTY); - size_t i; - - if (tal_count(outputs) == 1) - return false; - - for (i = 0; i < tal_count(outputs)-1; i++) { - if (strstarts(outputs[i], "<")) { - if (is_a) - draw_line(svg, B_LINEX, b_sent, outputs[i]+1, - A_LINEX, *y); - else - draw_line(svg, A_LINEX, a_sent, outputs[i]+1, - B_LINEX, *y); - *y += STEP_HEIGHT; - } else if (strstarts(outputs[i], ">")) { - if (is_a) - add_sent(a_sent, *y, outputs[i]+1); - else - add_sent(b_sent, *y, outputs[i]+1); - *y += STEP_HEIGHT; - } else { - append_text(svg, is_a, y, outputs[i], max_chars); - } - } - return true; -} - -static void get_output(int donefd, char **svg, bool is_a, - struct sent **a_sent, struct sent **b_sent, - int *y, size_t *max_chars) -{ - char output[200]; - int r; - - alarm(5); - /* FIXME: Assumes large pipebuf, atomic read */ - r = read(donefd, output, sizeof(output)-1); - if (r <= 0) - err(1, "Reading from %s", is_a ? "A" : "B"); - output[r] = '\0'; - alarm(0); - - if (*svg) - process_output(svg, is_a, output, a_sent, b_sent, y, max_chars); -} - -static void start_clients(int a_to_b[2], - int b_to_a[2], - int acmd[2], - int bcmd[2], - int adonefd[2], - int bdonefd[2]) -{ - if (pipe(a_to_b) || pipe(b_to_a) || pipe(adonefd) || pipe(acmd)) - err(1, "Creating pipes"); - - new_peer("A", a_to_b, b_to_a, acmd, adonefd); - - if (pipe(bdonefd) || pipe(bcmd)) - err(1, "Creating pipes"); - - new_peer("B", b_to_a, a_to_b, bcmd, bdonefd); - - close(acmd[0]); - close(bcmd[0]); - close(adonefd[1]); - close(bdonefd[1]); - close(b_to_a[0]); - close(b_to_a[1]); - close(a_to_b[0]); - close(a_to_b[1]); -} - -static void do_nothing(int sig UNUSED) -{ -} - -static void read_from_client(const char *desc, int fd, void *dst, size_t len) -{ - alarm(5); - while (len) { - int r = read(fd, dst, len); - if (r < 0) - err(1, "Reading from %s", desc); - if (r == 0) - errx(1, "%s closed", desc); - len -= r; - dst += r; - } - alarm(0); -} - -static void write_to_client(const char *desc, int fd, const void *dst, size_t len) -{ - if (!write_all(fd, dst, len)) - err(1, "Writing to %s", desc); -} - - -static void stop_clients(int acmd[2], - int bcmd[2], - int adonefd[2], - int bdonefd[2]) -{ - char unused; - - write_to_client("A", acmd[1], "", 1); - write_to_client("B", bcmd[1], "", 1); - - /* Make sure they've finished */ - alarm(5); - if (read(adonefd[0], &unused, 1) || read(bdonefd[0], &unused, 1)) - errx(1, "Response after sending exit command"); - alarm(0); - - close(acmd[1]); - close(bcmd[1]); - close(adonefd[0]); - close(bdonefd[0]); -} - -int main(int argc, char *argv[]) -{ - char cmd[80], *svg; - int a_to_b[2], b_to_a[2], acmd[2], bcmd[2], adonefd[2], bdonefd[2]; - int y = STEP_HEIGHT + LINE_HEIGHT; - struct sent *a_sent = tal_arr(NULL, struct sent, 0), - *b_sent = tal_arr(NULL, struct sent, 0); - size_t max_chars = 0; - bool do_svg = false; - - err_set_progname(argv[0]); - opt_register_noarg("--help|-h", opt_usage_and_exit, - "\n" - "Lightning protocol tester.", - "Print this message."); - opt_register_noarg("--svg", opt_set_bool, &do_svg, "Output SVG diagram"); - opt_register_noarg("--verbose", opt_set_bool, &verbose, - "Extra output"); - opt_parse(&argc, argv, opt_log_stderr_exit); - if (argc != 1) - errx(1, "no arguments accepted"); - - if (do_svg) - svg = tal_strdup(NULL, ""); - else - svg = NULL; - -#if 1 - { - struct sigaction alarmed, old; - - memset(&alarmed, 0, sizeof(alarmed)); - alarmed.sa_flags = SA_RESETHAND; - alarmed.sa_handler = do_nothing; - - if (sigaction(SIGALRM, &alarmed, &old) != 0) - err(1, "Setting alarm handler"); - } -#else - signal(SIGALRM, do_nothing); -#endif - - start_clients(a_to_b, b_to_a, acmd, bcmd, adonefd, bdonefd); - - while (fgets(cmd, sizeof(cmd), stdin)) { - int cmdfd, donefd; - - if (!strends(cmd, "\n")) - errx(1, "Truncated command"); - cmd[strlen(cmd)-1] = '\0'; - - if (verbose) - printf("%s\n", cmd); - - if (strstarts(cmd, "A:")) { - cmdfd = acmd[1]; - donefd = adonefd[0]; - } else if (strstarts(cmd, "B:")) { - cmdfd = bcmd[1]; - donefd = bdonefd[0]; - } else if (strstarts(cmd, "echo ")) { - if (!svg) { - printf("%s\n", cmd + 5); - fflush(stdout); - } - continue; - } else if (streq(cmd, "checksync")) { - struct commit_tx fa_us, fa_them, fb_us, fb_them; - write_to_client("A", acmd[1], cmd, strlen(cmd)+1); - write_to_client("B", bcmd[1], cmd, strlen(cmd)+1); - read_from_client("A", adonefd[0], &fa_us, sizeof(fa_us)); - read_from_client("B", bdonefd[0], &fb_us, sizeof(fb_us)); - read_from_client("A", adonefd[0], - &fa_them, sizeof(fa_them)); - read_from_client("A", bdonefd[0], - &fb_them, sizeof(fb_them)); - if (!structeq(&fa_us, &fb_them) - || !structeq(&fa_them, &fb_us)) - errx(1, "checksync: not equal"); - continue; - } else if (streq(cmd, "restart")) { - struct database a_db, b_db; - char ack; - - if (svg) - draw_restart(&svg, "RESTART", - &y); - - write_to_client("A", acmd[1], "save", strlen("save")+1); - write_to_client("B", bcmd[1], "save", strlen("save")+1); - - read_from_client("A", adonefd[0], &a_db, sizeof(a_db)); - read_from_client("B", bdonefd[0], &b_db, sizeof(b_db)); - - stop_clients(acmd, bcmd, adonefd, bdonefd); - - /* Forget everything they sent */ - reset_sends(&svg, true, &a_sent, &y); - reset_sends(&svg, false, &b_sent, &y); - - start_clients(a_to_b, b_to_a, acmd, bcmd, - adonefd, bdonefd); - - /* Send restore command, wait for ack, send blob */ - write_to_client("A", acmd[1], "restore", strlen("restore")+1); - write_to_client("B", bcmd[1], "restore", strlen("restore")+1); - - read_from_client("A", adonefd[0], &ack, 1); - read_from_client("B", bdonefd[0], &ack, 1); - - write_to_client("A", acmd[1], &a_db, sizeof(a_db)); - write_to_client("B", bcmd[1], &b_db, sizeof(b_db)); - - get_output(adonefd[0], &svg, true, - &a_sent, &b_sent, &y, &max_chars); - get_output(bdonefd[0], &svg, false, - &a_sent, &b_sent, &y, &max_chars); - - if (svg) - draw_restart(&svg, "RESTART END", - &y); - continue; - } else if (strstarts(cmd, "#") || streq(cmd, "")) - continue; - else - errx(1, "Unknown command %s", cmd); - - /* Don't dump if outputting svg. */ - if (svg && strstarts(cmd+2, "dump")) - continue; - - write_to_client(cmd, cmdfd, cmd+2, strlen(cmd)-1); - - get_output(donefd, &svg, strstarts(cmd, "A:"), - &a_sent, &b_sent, &y, &max_chars); - } - - stop_clients(acmd, bcmd, adonefd, bdonefd); - - if (svg) - printf("\n" - "" - "" - "" - "Node A\n" - "Node B\n" - "%s\n" - "\n", - B_TEXTX + max_chars*LETTER_WIDTH, y + LINE_HEIGHT, - A_LINEX, STEP_HEIGHT, B_LINEX, STEP_HEIGHT, - svg); - - return 0; -} diff --git a/test/test_state_coverage.c b/test/test_state_coverage.c deleted file mode 100644 index 29955ba3d..000000000 --- a/test/test_state_coverage.c +++ /dev/null @@ -1,2475 +0,0 @@ -/* Test for state machine. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -static bool record_input_mapping(int b); -#define MAPPING_INPUTS(b) \ - do { if (record_input_mapping(b)) return false; } while(0) - -#include "state.h" -#include "names.c" - -static bool quick = false; -static bool dot_simplify = false; -static bool dot_enable = false; -static bool dot_include_abnormal = false; -static bool dot_include_errors = false; -static bool include_nops = false; -static enum state_input *mapping_inputs; - -enum failure { - FAIL_NONE, - FAIL_DECLINE_HTLC, - FAIL_STEAL, - FAIL_ACCEPT_OPEN, - FAIL_ACCEPT_ANCHOR, - FAIL_ACCEPT_OPEN_COMMIT_SIG, - FAIL_ACCEPT_OPEN_COMPLETE, - FAIL_ACCEPT_HTLC_ADD, - FAIL_ACCEPT_HTLC_FAIL, - FAIL_ACCEPT_HTLC_FULFILL, - FAIL_ACCEPT_UPDATE_ACCEPT, - FAIL_ACCEPT_UPDATE_COMPLETE, - FAIL_ACCEPT_UPDATE_SIGNATURE, - FAIL_ACCEPT_CLOSE, - FAIL_ACCEPT_CLOSE_COMPLETE, - FAIL_ACCEPT_CLOSE_ACK, - FAIL_ACCEPT_SIMULTANEOUS_CLOSE -}; - -struct htlc { - bool to_them; - unsigned int id; -}; - -struct htlc_progress { - struct htlc htlc; /* id == -1 if none in progress. */ - bool adding; /* otherwise, removing. */ -}; - -struct htlc_spend_watch { - unsigned int id; - enum state_input done; -}; - -/* Beyond this we consider cases equal for traverse loop detection. */ -#define CAP_HTLCS 1 - -/* How many HTLCs to negotiate. */ -#define MAX_HTLCS 2 - -/* But we can have many different malleated commit txs. */ -#define HTLC_ARRSIZE 20 - -/* - * Worst case: - * Low priority: PKT_UPDATE_ADD_HTLC - * Receive update, which we decline: PKT_UPDATE_DECLINE_HTLC - * Send new update: PKT_UPDATE_ADD_HTLC - * Start close: PKT_CLOSE - * Some error: PKT_ERROR - */ -#define MAX_OUTQ 5 - -/* No padding, for fast compare and hashing. */ -struct core_state { - /* What bitcoin/timeout notifications are we subscribed to? */ - uint64_t event_notifies; - - enum state_input current_command; - - enum state_input outputs[MAX_OUTQ]; - - uint8_t num_outputs; - /* Here down need to be generated from other fields */ - uint8_t state; - uint8_t peercond; - bool has_current_htlc; - - uint8_t capped_htlcs_to_them; - uint8_t capped_htlcs_to_us; - uint8_t capped_htlc_spends_to_them; - uint8_t capped_htlc_spends_to_us; - - uint8_t capped_live_htlcs_to_them; - uint8_t capped_live_htlcs_to_us; - bool valid; - bool pad[5]; -}; - -struct peer { - struct core_state core; - - enum state state; - enum state_peercond cond; - - /* To store HTLC numbers. */ - unsigned int pkt_data[MAX_OUTQ]; - - /* id == -1 if none currently. */ - struct htlc_progress current_htlc; - - /* Transitory: True if we just declined an HTLC. */ - bool htlc_declined; - - /* Have we created an anchor tx? */ - bool anchor; - /* Have we broadcast anchor? */ - bool anchor_broadcast; - /* Have we spent anchor (or seen them do it?) */ - bool anchor_spent; - - unsigned int num_htlcs_to_them, num_htlcs_to_us; - struct htlc htlcs_to_them[MAX_HTLCS], htlcs_to_us[MAX_HTLCS]; - - unsigned int num_live_htlcs_to_them, num_live_htlcs_to_us; - struct htlc live_htlcs_to_them[HTLC_ARRSIZE], live_htlcs_to_us[HTLC_ARRSIZE]; - - unsigned int num_htlc_spends_to_them, num_htlc_spends_to_us; - struct htlc htlc_spends_to_us[HTLC_ARRSIZE], - htlc_spends_to_them[HTLC_ARRSIZE]; - - unsigned int num_rvals_known; - unsigned int rvals_known[HTLC_ARRSIZE]; - - /* Where we came from. */ - const struct trail *trail; - - /* Current input and idata (for fail()) */ - enum state_input current_input; - const union input *current_idata; - - const char *error; - - /* ID. */ - const char *name; - /* The other peer's data. */ - struct peer *other; -}; - -/* To recontruct errors. */ -struct trail { - const struct trail *prev; - const char *name; - enum state_input input; - const struct peer *before, *after; - int htlc_id; - unsigned int num_peer_outputs; - unsigned int depth; - const char *pkt_sent; -}; - -struct situation { - union { - struct core_state s; - uint32_t u32[sizeof(struct core_state)/sizeof(uint32_t)]; - } a, b; -}; - -static const struct situation *situation_keyof(const struct situation *situation) -{ - return situation; -} - -/* After 2, we stop looping. */ -static unsigned int cap(unsigned int val) -{ - return val > CAP_HTLCS ? CAP_HTLCS : val; -} - -static size_t situation_hash(const struct situation *situation) -{ - BUILD_ASSERT(sizeof(situation->a.u32) == sizeof(situation->a.s)); - return hash(situation->a.u32, ARRAY_SIZE(situation->a.u32), 0); -} - -static bool situation_eq(const struct situation *a, const struct situation *b) -{ - /* No padding */ - BUILD_ASSERT(sizeof(a->a.s) - == (sizeof(a->a.s.event_notifies) - + sizeof(a->a.s.state) - + sizeof(a->a.s.current_command) - + sizeof(a->a.s.outputs) - + sizeof(a->a.s.num_outputs) - + sizeof(a->a.s.peercond) - + sizeof(a->a.s.has_current_htlc) - + sizeof(a->a.s.capped_htlcs_to_us) - + sizeof(a->a.s.capped_htlcs_to_them) - + sizeof(a->a.s.capped_htlc_spends_to_us) - + sizeof(a->a.s.capped_htlc_spends_to_them) - + sizeof(a->a.s.capped_live_htlcs_to_us) - + sizeof(a->a.s.capped_live_htlcs_to_them) - + sizeof(a->a.s.valid) - + sizeof(a->a.s.pad))); - return structeq(&a->a.s, &b->a.s) && structeq(&a->b.s, &b->b.s); -} - -struct dot_edge { - const char *oldstate, *newstate; - enum state_input i; - const char *pkt; -}; - -static const struct dot_edge *dot_edge_keyof(const struct dot_edge *dot_edge) -{ - return dot_edge; -} - -static size_t dot_edge_hash(const struct dot_edge *d) -{ - uint32_t pkthash; - - if (d->pkt) - pkthash = hash(d->pkt, strlen(d->pkt), d->i); - else - pkthash = d->i; - return hash_pointer(d->oldstate, hash_pointer(d->newstate, pkthash)); -} - -static bool dot_edge_eq(const struct dot_edge *a, const struct dot_edge *b) -{ - return a->oldstate == b->oldstate - && a->newstate == b->newstate - && a->i == b->i - && ((a->pkt == NULL && b->pkt == NULL) - || streq(a->pkt, b->pkt)); -} - -HTABLE_DEFINE_TYPE(struct dot_edge, - dot_edge_keyof, dot_edge_hash, dot_edge_eq, - edge_hash); - -HTABLE_DEFINE_TYPE(struct situation, - situation_keyof, situation_hash, situation_eq, - sithash); - -struct hist { - /* All the different state combinations. */ - struct sithash sithash; - - /* The different inputs. */ - enum state_input **inputs_per_state; - - /* The different outputs. */ - enum state_input *outputs; - - /* Edges for the dot graph, if any. */ - struct edge_hash edges; - - /* For dumping states. */ - struct state_dump { - enum state_input input; - enum state next; - enum state_input pkt; - } **state_dump; -}; - -struct fail_details { - /* The universe state at the time. */ - struct peer us, other; - enum state_input input; - union input idata; - /* Previous history. */ - const struct trail *prev_trail; -}; - -struct failpoint { - /* Hash key (with which_fail) */ - struct situation sit; - /* Which failure */ - enum failure which_fail; - - /* If we haven't tried failing yet, this is set */ - struct fail_details *details; -}; - -static const struct failpoint * -failpoint_keyof(const struct failpoint *f) -{ - return f; -} - -static size_t failpoint_hash(const struct failpoint *f) -{ - return situation_hash(&f->sit) + f->which_fail; -} - -static bool failpoint_eq(const struct failpoint *a, - const struct failpoint *b) -{ - return a->which_fail == b->which_fail - && situation_eq(&a->sit, &b->sit); -} - -HTABLE_DEFINE_TYPE(struct failpoint, - failpoint_keyof, failpoint_hash, failpoint_eq, - failhash); - -static struct failhash failhash; - -static void update_core(struct core_state *core, const struct peer *peer) -{ - size_t i; - - for (i = core->num_outputs; i < ARRAY_SIZE(core->outputs); i++) - assert(core->outputs[i] == 0); - - core->has_current_htlc = peer->current_htlc.htlc.id != -1; - core->state = peer->state; - BUILD_ASSERT(STATE_MAX < 256); - core->peercond = peer->cond; - core->capped_htlcs_to_us = cap(peer->num_htlcs_to_us); - core->capped_htlcs_to_them = cap(peer->num_htlcs_to_them); - core->capped_live_htlcs_to_us = cap(peer->num_live_htlcs_to_us); - core->capped_live_htlcs_to_them = cap(peer->num_live_htlcs_to_them); - core->capped_htlc_spends_to_us = cap(peer->num_htlc_spends_to_us); - core->capped_htlc_spends_to_them = cap(peer->num_htlc_spends_to_them); - core->valid = true; -} - -static void situation_init(struct situation *sit, - const struct peer *peer) -{ - if (streq(peer->name, "A")) { - sit->a.s = peer->core; - update_core(&sit->a.s, peer); - /* If we're still talking to peer, their state matters. */ - if (peer->cond != PEER_CLOSED - || peer->other->cond != PEER_CLOSED) { - sit->b.s = peer->other->core; - update_core(&sit->b.s, peer->other); - } else - memset(&sit->b.s, 0, sizeof(sit->b.s)); - } else { - sit->b.s = peer->core; - update_core(&sit->b.s, peer); - /* If we're still talking to peer, their state matters. */ - if (peer->cond != PEER_CLOSED - || peer->other->cond != PEER_CLOSED) { - sit->a.s = peer->other->core; - update_core(&sit->a.s, peer->other); - } else - memset(&sit->a.s, 0, sizeof(sit->a.s)); - } -} - - -/* Returns false if we've been here before. */ -static bool sithash_update(struct sithash *sithash, - const struct peer *peer) -{ - struct situation sit; - - situation_init(&sit, peer); - - if (sithash_get(sithash, &sit)) - return false; - - sithash_add(sithash, tal_dup(NULL, struct situation, &sit)); - return true; -} - -static void copy_peers(struct peer *dst, struct peer *other, - const struct peer *src) -{ - *dst = *src; - *other = *src->other; - dst->other = other; - other->other = dst; -} - -static const struct trail *clone_trail(const tal_t *ctx, - const struct trail *trail) -{ - struct trail *t; - - if (!trail) - return NULL; - - t = tal_dup(ctx, struct trail, trail); - t->before = tal_dup(t, struct peer, trail->before); - t->after = trail->after ? tal_dup(t, struct peer, trail->after) - : NULL; - t->pkt_sent = trail->pkt_sent ? tal_strdup(t, trail->pkt_sent) : NULL; - t->prev = clone_trail(t, trail->prev); - return t; -} - -static const union input dup_idata(const tal_t *ctx, - enum state_input input, - const union input *idata) -{ - union input i; - - if (input_is_pkt(input)) - i.pkt = (Pkt *)tal_strdup(ctx, (const char *)idata->pkt); - else if (input == CMD_SEND_HTLC_ADD - || input == CMD_SEND_HTLC_FULFILL - || input == CMD_SEND_HTLC_FAIL) { - i.htlc_prog = tal_dup(ctx, struct htlc_progress, - idata->htlc_prog); - } else { - if (idata->htlc) - i.htlc = tal_dup(ctx, struct htlc, idata->htlc); - else - i.htlc = NULL; - } - return i; -} - -static bool fail(const struct peer *peer, enum failure which_fail) -{ - struct failpoint *f = tal(NULL, struct failpoint), *old; - - situation_init(&f->sit, peer); - f->which_fail = which_fail; - - /* If we've been here before... */ - old = failhash_get(&failhash, f); - if (old) { - tal_free(f); - /* If we haven't tried failing, try that now. */ - if (old->details) { - old->details = tal_free(old->details); - return true; - } - return false; - } - - /* First time here, save details, don't fail yet. */ - f->details = tal(f, struct fail_details); - /* Copy old peer, in case it has been changed since. */ - copy_peers(&f->details->us, &f->details->other, peer->trail->before); - f->details->us.trail = clone_trail(f->details, peer->trail); - f->details->input = peer->current_input; - f->details->idata = dup_idata(f->details, - f->details->input, peer->current_idata); - - failhash_add(&failhash, f); - return false; -} - -static enum state_input input_by_name(const char *name) -{ - size_t i; - - for (i = 0; enum_state_input_names[i].name; i++) { - if (!strstarts(name, enum_state_input_names[i].name)) - continue; - if (name[strlen(enum_state_input_names[i].name)] == '\0' - || name[strlen(enum_state_input_names[i].name)] == ':') - return enum_state_input_names[i].v; - } - abort(); -} - -static Pkt *new_pkt(const tal_t *ctx, enum state_input i) -{ - return (Pkt *)input_name(i); -} - -static unsigned int htlc_id_from_pkt(const Pkt *pkt) -{ - const char *s = strstr((const char *)pkt, ": HTLC #"); - return s ? atoi(s + strlen(": HTLC #")) : -1U; -} - -static Pkt *htlc_pkt(const tal_t *ctx, const char *prefix, unsigned int id) -{ - assert(id != -1); - assert(prefix != NULL); - return (Pkt *)tal_fmt(ctx, "%s: HTLC #%u", prefix, id); -} - -static unsigned int htlc_id_from_tx(const struct bitcoin_tx *tx) -{ - const char *s = strstr((const char *)tx, "HTLC #"); - return atoi(s + strlen("HTLC #")); -} - -static struct bitcoin_tx *htlc_tx(const tal_t *ctx, - const char *prefix, unsigned int id) -{ - assert(prefix != NULL); - return (struct bitcoin_tx *)tal_fmt(ctx, "%s HTLC #%u", prefix, id); -} - -static struct htlc *find_any_htlc(const struct htlc *htlcs, size_t num, - unsigned id) -{ - unsigned int i; - - for (i = 0; i < num; i++) - if (htlcs[i].id == id) - return (struct htlc *)htlcs + i; - return NULL; -} - -static struct htlc *find_htlc(const struct peer *peer, unsigned id) -{ - const struct htlc *h; - - h = find_any_htlc(peer->htlcs_to_us, peer->num_htlcs_to_us, id); - if (!h) - h = find_any_htlc(peer->htlcs_to_them, - peer->num_htlcs_to_them, id); - return (struct htlc *)h; -} - -static struct htlc *find_live_htlc(const struct peer *peer, - unsigned id) -{ - const struct htlc *h; - - h = find_any_htlc(peer->live_htlcs_to_us, peer->num_live_htlcs_to_us, - id); - if (!h) - h = find_any_htlc(peer->live_htlcs_to_them, - peer->num_live_htlcs_to_them, id); - return (struct htlc *)h; -} - -static struct htlc *find_htlc_spend(const struct peer *peer, - unsigned id) -{ - const struct htlc *h; - - h = find_any_htlc(peer->htlc_spends_to_us, - peer->num_htlc_spends_to_us, - id); - if (!h) - h = find_any_htlc(peer->htlc_spends_to_them, - peer->num_htlc_spends_to_them, id); - return (struct htlc *)h; -} - -/* FIXME: order functions correctly. */ -static void report_trail(const struct trail *t, const char *problem); - -static void set_current_htlc(struct peer *peer, - unsigned int id, - bool to_them, bool adding) -{ - if (peer->current_htlc.htlc.id != -1) - report_trail(peer->trail, "Already have current htlc"); - - assert(id != -1); - peer->current_htlc.htlc.id = id; - peer->current_htlc.htlc.to_them = to_them; - peer->current_htlc.adding = adding; -} - -static void clear_current_htlc(struct peer *peer) -{ - if (peer->current_htlc.htlc.id == -1) - report_trail(peer->trail, "No current htlc"); - - peer->current_htlc.htlc.id = -1; -} - -static bool rval_known(const struct peer *peer, unsigned int id) -{ - unsigned int i; - - for (i = 0; i < peer->num_rvals_known; i++) - if (peer->rvals_known[i] == id) - return true; - return false; -} - -static void add_rval(struct peer *peer, unsigned int id) -{ - if (!rval_known(peer, id)) { - assert(peer->num_rvals_known < ARRAY_SIZE(peer->rvals_known)); - peer->rvals_known[peer->num_rvals_known++] = id; - } -} - -Pkt *pkt_open(const tal_t *ctx, const struct peer *peer, - OpenChannel__AnchorOffer anchor) -{ - return new_pkt(ctx, PKT_OPEN); -} - -Pkt *pkt_anchor(const tal_t *ctx, const struct peer *peer) -{ - return new_pkt(ctx, PKT_OPEN_ANCHOR); -} - -Pkt *pkt_open_commit_sig(const tal_t *ctx, const struct peer *peer) -{ - return new_pkt(ctx, PKT_OPEN_COMMIT_SIG); -} - -Pkt *pkt_open_complete(const tal_t *ctx, const struct peer *peer) -{ - return new_pkt(ctx, PKT_OPEN_COMPLETE); -} - -Pkt *pkt_htlc_add(const tal_t *ctx, const struct peer *peer, - const struct htlc_progress *htlc_prog) -{ - return htlc_pkt(ctx, "PKT_UPDATE_ADD_HTLC", htlc_prog->htlc.id); -} - -Pkt *pkt_htlc_fulfill(const tal_t *ctx, const struct peer *peer, - const struct htlc_progress *htlc_prog) -{ - return htlc_pkt(ctx, "PKT_UPDATE_FULFILL_HTLC", htlc_prog->htlc.id); -} - -Pkt *pkt_htlc_fail(const tal_t *ctx, const struct peer *peer, - const struct htlc_progress *htlc_prog) -{ - return htlc_pkt(ctx, "PKT_UPDATE_FAIL_HTLC", htlc_prog->htlc.id); -} - -Pkt *pkt_update_accept(const tal_t *ctx, const struct peer *peer) -{ - return htlc_pkt(ctx, "PKT_UPDATE_ACCEPT", peer->current_htlc.htlc.id); -} - -Pkt *pkt_update_signature(const tal_t *ctx, const struct peer *peer) -{ - return htlc_pkt(ctx, "PKT_UPDATE_SIGNATURE", - peer->current_htlc.htlc.id); -} - -Pkt *pkt_update_complete(const tal_t *ctx, const struct peer *peer) -{ - return htlc_pkt(ctx, "PKT_UPDATE_COMPLETE", - peer->current_htlc.htlc.id); -} - -Pkt *pkt_err(const tal_t *ctx, const char *fmt, ...) -{ - char *str; - va_list ap; - - str = tal_strdup(ctx, "PKT_ERROR: "); - va_start(ap, fmt); - tal_append_vfmt(&str, fmt, ap); - va_end(ap); - - return (Pkt *)str; -} - -Pkt *pkt_close(const tal_t *ctx, const struct peer *peer) -{ - return new_pkt(ctx, PKT_CLOSE); -} - -Pkt *pkt_close_complete(const tal_t *ctx, const struct peer *peer) -{ - return new_pkt(ctx, PKT_CLOSE_COMPLETE); -} - -Pkt *pkt_close_ack(const tal_t *ctx, const struct peer *peer) -{ - return new_pkt(ctx, PKT_CLOSE_ACK); -} - -Pkt *pkt_err_unexpected(const tal_t *ctx, const Pkt *pkt) -{ - return pkt_err("Unexpected pkt %s", (const char *)pkt); -} - -Pkt *accept_pkt_open(const tal_t *ctx, - struct peer *peer, - const Pkt *pkt) -{ - if (fail(peer, FAIL_ACCEPT_OPEN)) - return pkt_err(ctx, "Error inject"); - return NULL; -} - -Pkt *accept_pkt_anchor(const tal_t *ctx, struct peer *peer, const Pkt *pkt) -{ - if (fail(peer, FAIL_ACCEPT_ANCHOR)) - return pkt_err(ctx, "Error inject"); - return NULL; -} - -Pkt *accept_pkt_open_commit_sig(const tal_t *ctx, - struct peer *peer, - const Pkt *pkt) -{ - if (fail(peer, FAIL_ACCEPT_OPEN_COMMIT_SIG)) - return pkt_err(ctx, "Error inject"); - return NULL; -} - -Pkt *accept_pkt_open_complete(const tal_t *ctx, - struct peer *peer, - const Pkt *pkt) -{ - if (fail(peer, FAIL_ACCEPT_OPEN_COMPLETE)) - return pkt_err(ctx, "Error inject"); - return NULL; -} - -Pkt *accept_pkt_htlc_add(const tal_t *ctx, - struct peer *peer, const Pkt *pkt, - Pkt **decline) -{ - if (fail(peer, FAIL_ACCEPT_HTLC_ADD)) - return pkt_err(ctx, "Error inject"); - - /* This is the current htlc: If they propose it, it's to us. */ - set_current_htlc(peer, htlc_id_from_pkt(pkt), false, true); - - if (fail(peer, FAIL_DECLINE_HTLC)) - *decline = new_pkt(ctx, PKT_UPDATE_DECLINE_HTLC); - else - *decline = NULL; - - return NULL; -} - -Pkt *accept_pkt_htlc_fail(const tal_t *ctx, - struct peer *peer, const Pkt *pkt) -{ - unsigned int id = htlc_id_from_pkt(pkt); - const struct htlc *h = find_htlc(peer, id); - - if (fail(peer, FAIL_ACCEPT_HTLC_FAIL)) - return pkt_err(ctx, "Error inject"); - - /* The shouldn't fail unless it's to them */ - assert(h->to_them); - - /* This is the current htlc */ - set_current_htlc(peer, h->id, h->to_them, false); - return NULL; -} - -Pkt *accept_pkt_htlc_fulfill(const tal_t *ctx, - struct peer *peer, const Pkt *pkt) -{ - unsigned int id = htlc_id_from_pkt(pkt); - const struct htlc *h = find_htlc(peer, id); - - if (fail(peer, FAIL_ACCEPT_HTLC_FULFILL)) - return pkt_err(ctx, "Error inject"); - - /* The shouldn't complete unless it's to them */ - assert(h->to_them); - - /* This gives us the r value. */ - add_rval(peer, htlc_id_from_pkt(pkt)); - - /* This is the current htlc */ - set_current_htlc(peer, h->id, h->to_them, false); - return NULL; -} - -Pkt *accept_pkt_update_accept(const tal_t *ctx, - struct peer *peer, const Pkt *pkt) -{ - unsigned int id = htlc_id_from_pkt(pkt); - - assert(id == peer->current_htlc.htlc.id); - - if (fail(peer, FAIL_ACCEPT_UPDATE_ACCEPT)) - return pkt_err(ctx, "Error inject"); - - return NULL; -} - -Pkt *accept_pkt_update_complete(const tal_t *ctx, - struct peer *peer, const Pkt *pkt) -{ - unsigned int id = htlc_id_from_pkt(pkt); - - assert(id == peer->current_htlc.htlc.id); - - if (fail(peer, FAIL_ACCEPT_UPDATE_COMPLETE)) - return pkt_err(ctx, "Error inject"); - - return NULL; -} - -Pkt *accept_pkt_update_signature(const tal_t *ctx, - struct peer *peer, const Pkt *pkt) -{ - unsigned int id = htlc_id_from_pkt(pkt); - - assert(id == peer->current_htlc.htlc.id); - - if (fail(peer, FAIL_ACCEPT_UPDATE_SIGNATURE)) - return pkt_err(ctx, "Error inject"); - - return NULL; -} - -Pkt *accept_pkt_close(const tal_t *ctx, struct peer *peer, const Pkt *pkt) -{ - if (fail(peer, FAIL_ACCEPT_CLOSE)) - return pkt_err(ctx, "Error inject"); - return NULL; -} - -Pkt *accept_pkt_close_complete(const tal_t *ctx, - struct peer *peer, const Pkt *pkt) -{ - if (fail(peer, FAIL_ACCEPT_CLOSE_COMPLETE)) - return pkt_err(ctx, "Error inject"); - return NULL; -} - -Pkt *accept_pkt_simultaneous_close(const tal_t *ctx, - struct peer *peer, - const Pkt *pkt) -{ - if (fail(peer, FAIL_ACCEPT_SIMULTANEOUS_CLOSE)) - return pkt_err(ctx, "Error inject"); - return NULL; -} - -Pkt *accept_pkt_close_ack(const tal_t *ctx, - struct peer *peer, const Pkt *pkt) -{ - if (fail(peer, FAIL_ACCEPT_CLOSE_ACK)) - return pkt_err(ctx, "Error inject"); - return NULL; -} - -static struct bitcoin_tx *bitcoin_tx(const char *str) -{ - return (struct bitcoin_tx *)str; -} - -static bool bitcoin_tx_is(const struct bitcoin_tx *btx, const char *str) -{ - return streq((const char *)btx, str); -} - -const struct bitcoin_tx *bitcoin_anchor(const tal_t *ctx, struct peer *peer) -{ - if (!peer->anchor) - report_trail(peer->trail, "Can't create anchor tx: no anchor!"); - peer->anchor = false; - peer->anchor_broadcast = true; - return bitcoin_tx("anchor"); -} - -const struct bitcoin_tx *bitcoin_close(const tal_t *ctx, - struct peer *peer) -{ - peer->anchor_spent = true; - return bitcoin_tx("close"); -} - -const struct bitcoin_tx *bitcoin_spend_ours(const tal_t *ctx, - const struct peer *peer) -{ - return bitcoin_tx("spend our commit"); -} - -const struct bitcoin_tx *bitcoin_spend_theirs(const tal_t *ctx, - const struct peer *peer, - const struct bitcoin_event *btc) -{ - return bitcoin_tx("spend their commit"); -} - -const struct bitcoin_tx *bitcoin_steal(const tal_t *ctx, - const struct peer *peer, - struct bitcoin_event *btc) -{ - if (fail(peer, FAIL_STEAL)) - return NULL; - return bitcoin_tx("steal"); -} - -const struct bitcoin_tx *bitcoin_commit(const tal_t *ctx, struct peer *peer) -{ - peer->anchor_spent = true; - return bitcoin_tx("our commit"); -} - -/* Create an HTLC refund collection */ -const struct bitcoin_tx *bitcoin_htlc_timeout(const tal_t *ctx, - const struct peer *peer, - const struct htlc *htlc) -{ - return htlc_tx(ctx, "htlc timeout", htlc->id); -} - -/* Create an HTLC collection */ -const struct bitcoin_tx *bitcoin_htlc_spend(const tal_t *ctx, - const struct peer *peer, - const struct htlc *htlc) -{ - return htlc_tx(ctx, "htlc fulfill", htlc->id); -} - -bool committed_to_htlcs(const struct peer *peer) -{ - return peer->num_htlcs_to_them != 0 || peer->num_htlcs_to_us != 0; -} - -#define TEST_STATE_COVERAGE 1 -#include "state.c" -#include -#include - -static void peer_init(struct peer *peer, - struct peer *other, - const char *name) -{ - peer->cond = PEER_CMD_OK; - peer->state = STATE_INIT; - peer->core.num_outputs = 0; - peer->current_htlc.htlc.id = -1; - peer->num_htlcs_to_us = 0; - peer->num_htlcs_to_them = 0; - peer->num_live_htlcs_to_us = 0; - peer->num_live_htlcs_to_them = 0; - peer->num_htlc_spends_to_us = 0; - peer->num_htlc_spends_to_them = 0; - peer->num_rvals_known = 0; - peer->error = NULL; - peer->htlc_declined = false; - peer->anchor = false; - peer->anchor_broadcast = false; - peer->anchor_spent = false; - memset(peer->core.outputs, 0, sizeof(peer->core.outputs)); - peer->pkt_data[0] = -1; - peer->core.current_command = INPUT_NONE; - peer->core.event_notifies = 0; - peer->name = name; - peer->other = other; - peer->trail = NULL; - memset(peer->core.pad, 0, sizeof(peer->core.pad)); -} - -/* Recursion! */ -static void run_peer(const struct peer *peer, - bool normalpath, bool errorpath, - const struct trail *prev_trail, - struct hist *hist); - -static void init_trail(struct trail *t, - enum state_input input, - const union input *idata, - const struct peer *before, - const struct trail *prev) -{ - t->name = before->name; - t->prev = prev; - t->depth = prev ? prev->depth + 1 : 0; - t->input = input; - t->before = before; - t->after = NULL; - t->num_peer_outputs = -1; - t->pkt_sent = NULL; - if (input == CMD_SEND_HTLC_FULFILL - || input == INPUT_RVALUE - || input == BITCOIN_HTLC_TOTHEM_TIMEOUT - || input == BITCOIN_HTLC_TOTHEM_SPENT - || input == BITCOIN_HTLC_TOUS_TIMEOUT - || input == BITCOIN_HTLC_FULFILL_SPEND_DONE - || input == BITCOIN_HTLC_RETURN_SPEND_DONE) - t->htlc_id = idata->htlc->id; - else if (input == PKT_UPDATE_ADD_HTLC) - t->htlc_id = htlc_id_from_pkt(idata->pkt); - else - t->htlc_id = -1; -} - -static void update_trail(struct trail *t, - const struct peer *after, - const Pkt *output) -{ - t->after = after; - t->num_peer_outputs = after->other->core.num_outputs; - t->pkt_sent = (const char *)output; -} - -static void report_trail_rev(const struct trail *t) -{ - size_t i; - - if (t->prev) - report_trail_rev(t->prev); - - fprintf(stderr, "%s: %s(%i) %s -> %s", - t->name, - input_name(t->input), t->htlc_id, - state_name(t->before->state), - t->after ? state_name(t->after->state) : ""); - if (t->after) { - for (i = 0; i < t->after->core.num_outputs; i++) - fprintf(stderr, " >%s", - input_name(t->after->core.outputs[i])); - } - fprintf(stderr, " +%u in\n", - t->num_peer_outputs); - if (!t->after) - goto pkt_sent; - - if (t->after->state >= STATE_CLOSED) { - if (t->after->num_live_htlcs_to_us - || t->after->num_live_htlcs_to_them) { - fprintf(stderr, " Live HTLCs:"); - for (i = 0; i < t->after->num_live_htlcs_to_us; i++) - fprintf(stderr, " <%u", - t->after->live_htlcs_to_us[i].id); - for (i = 0; i < t->after->num_live_htlcs_to_them; i++) - fprintf(stderr, " >%u", - t->after->live_htlcs_to_them[i].id); - fprintf(stderr, "\n"); - } - if (t->after->num_htlc_spends_to_us - || t->after->num_htlc_spends_to_them) { - fprintf(stderr, " HTLC spends:"); - for (i = 0; i < t->after->num_htlc_spends_to_us; i++) - fprintf(stderr, " <%u", - t->after->htlc_spends_to_us[i].id); - for (i = 0; i < t->after->num_htlc_spends_to_them; i++) - fprintf(stderr, " <%u", - t->after->htlc_spends_to_them[i].id); - fprintf(stderr, "\n"); - } - } else { - if (t->after->num_htlcs_to_us - || t->after->num_htlcs_to_them) { - fprintf(stderr, " HTLCs:"); - for (i = 0; i < t->after->num_htlcs_to_us; i++) - fprintf(stderr, " <%u", - t->after->htlcs_to_us[i].id); - for (i = 0; i < t->after->num_htlcs_to_them; i++) - fprintf(stderr, " >%u", - t->after->htlcs_to_them[i].id); - fprintf(stderr, "\n"); - } - } -pkt_sent: - if (t->pkt_sent) - fprintf(stderr, " => %s\n", t->pkt_sent); -} - -static void report_trail(const struct trail *t, const char *problem) -{ - fprintf(stderr, "Error: %s\n", problem); - report_trail_rev(t); - exit(1); -} - -static void add_htlc(struct htlc *to_us, unsigned int *num_to_us, - struct htlc *to_them, unsigned int *num_to_them, - size_t arrsize, - const struct htlc *h) -{ - struct htlc *arr; - unsigned int *n; - - if (h->to_them) { - arr = to_them; - n = num_to_them; - } else { - arr = to_us; - n = num_to_us; - } - assert(*n < arrsize); - arr[(*n)++] = *h; -} - -static void remove_htlc(struct htlc *to_us, unsigned int *num_to_us, - struct htlc *to_them, unsigned int *num_to_them, - size_t arrsize, - const struct htlc *h) -{ - size_t off; - struct htlc *arr; - unsigned int *n; - - if (h->to_them) { - arr = to_them; - n = num_to_them; - } else { - arr = to_us; - n = num_to_us; - } - assert(*n <= arrsize); - assert(h >= arr && h < arr + *n); - - off = h - arr; - memmove(arr + off, arr + off + 1, (char *)(arr + *n) - (char *)(h + 1)); - (*n)--; -} - -static void remove_htlc_id(struct peer *peer, unsigned int id) -{ - const struct htlc *h = find_htlc(peer, id); - - if (!h) - report_trail(peer->trail, "Removing nonexistent HTLC?"); - if (h->to_them != peer->current_htlc.htlc.to_them) - report_trail(peer->trail, - "Removing disagreed about to_them"); - remove_htlc(peer->htlcs_to_us, &peer->num_htlcs_to_us, - peer->htlcs_to_them, &peer->num_htlcs_to_them, - ARRAY_SIZE(peer->htlcs_to_us), h); -} - - -static bool outstanding_htlc_watches(const struct peer *peer) -{ - return peer->num_live_htlcs_to_us - || peer->num_live_htlcs_to_them - || peer->num_htlc_spends_to_us - || peer->num_htlc_spends_to_them; -} - -static bool have_event(uint64_t events, enum state_input input) -{ - return events & (1ULL << input); -} - -static bool add_event_(struct peer *peer, enum state_input input) -{ - /* This is how they say "no event please" */ - if (input == INPUT_NONE) - return true; - - assert(input < 64); - if (have_event(peer->core.event_notifies, input)) - return false; - peer->core.event_notifies |= (1ULL << input); - return true; -} - -static bool remove_event_(uint64_t *events, enum state_input input) -{ - /* This is how they say "no event please" */ - if (input == INPUT_NONE) - return true; - - assert(input < 64); - if (!have_event(*events, input)) - return false; - *events &= ~(1ULL << input); - return true; -} - -static void remove_event(struct peer *peer, enum state_input input) -{ - if (!remove_event_(&peer->core.event_notifies, input)) - report_trail(peer->trail, "Removing event we don't have?"); -} - -static void add_event(struct peer *peer, enum state_input input) -{ - if (!add_event_(peer, input)) - report_trail(peer->trail, "Adding event we already have?"); -} - -void peer_watch_anchor(struct peer *peer, - enum state_input depthok, - enum state_input timeout, - enum state_input unspent, - enum state_input theyspent, - enum state_input otherspent) -{ - /* We assume these values in activate_event. */ - assert(timeout == BITCOIN_ANCHOR_TIMEOUT - || timeout == INPUT_NONE); - assert(depthok == BITCOIN_ANCHOR_DEPTHOK); - - add_event(peer, depthok); - add_event(peer, timeout); - add_event(peer, unspent); - add_event(peer, theyspent); - add_event(peer, otherspent); -} - -void bitcoin_create_anchor(struct peer *peer, enum state_input done) -{ - /* We assume this below */ - assert(done == BITCOIN_ANCHOR_CREATED); - if (peer->anchor) - report_trail(peer->trail, "Anchor already created?"); - - peer->anchor = true; - add_event(peer, done); -} - -void bitcoin_release_anchor(struct peer *peer, enum state_input done) -{ - if (!peer->anchor) - report_trail(peer->trail, "Anchor not created?"); - - peer->anchor = false; - remove_event(peer, done); -} - -void peer_unwatch_anchor_depth(struct peer *peer, - enum state_input depthok, - enum state_input timeout) -{ - /* We assume these values in activate_event. */ - assert(timeout == BITCOIN_ANCHOR_TIMEOUT - || timeout == INPUT_NONE); - assert(depthok == BITCOIN_ANCHOR_DEPTHOK); - - remove_event(peer, depthok); - remove_event(peer, timeout); -} - -/* Wait for our commit to be spendable. */ -void peer_watch_delayed(struct peer *peer, - const struct bitcoin_tx *tx, enum state_input canspend) -{ - assert(bitcoin_tx_is(tx, "our commit")); - add_event(peer, canspend); -} - -/* Wait for commit to be very deeply buried (so we no longer need to - * even watch) */ -void peer_watch_tx(struct peer *peer, - const struct bitcoin_tx *tx, - enum state_input done) -{ - /* We can have multiple steals or spendtheirs in flight, so - * allow repeats for - * BITCOIN_STEAL_DONE/BITCOIN_SPEND_THEIRS_DONE */ - if (done == BITCOIN_STEAL_DONE) { - assert(bitcoin_tx_is(tx, "steal")); - add_event_(peer, done); - } else if (done == BITCOIN_SPEND_THEIRS_DONE) { - assert(bitcoin_tx_is(tx, "spend their commit")); - add_event_(peer, done); - } else if (done == BITCOIN_SPEND_OURS_DONE) { - assert(bitcoin_tx_is(tx, "spend our commit")); - add_event(peer, done); - } else - report_trail(peer->trail, "Unknown watch effect"); -} - -/* Other side should drop close tx; watch for it. */ -void peer_watch_close(struct peer *peer, - enum state_input done, enum state_input timedout) -{ - add_event(peer, done); - - /* We assume this. */ - assert(timedout == INPUT_CLOSE_COMPLETE_TIMEOUT || timedout == INPUT_NONE); - add_event(peer, timedout); -} - -void peer_unwatch_close_timeout(struct peer *peer, enum state_input timedout) -{ - assert(timedout == INPUT_CLOSE_COMPLETE_TIMEOUT); - if (!mapping_inputs) - remove_event(peer, timedout); -} - -bool peer_watch_our_htlc_outputs(struct peer *peer, - const struct bitcoin_tx *tx, - enum state_input tous_timeout, - enum state_input tothem_spent, - enum state_input tothem_timeout) -{ - /* FIXME: We assume these. */ - assert(tous_timeout == BITCOIN_HTLC_TOUS_TIMEOUT); - assert(tothem_spent == BITCOIN_HTLC_TOTHEM_SPENT); - assert(tothem_timeout == BITCOIN_HTLC_TOTHEM_TIMEOUT); - - if (!peer->num_htlcs_to_us && !peer->num_htlcs_to_them) - return false; - - assert(peer->num_live_htlcs_to_us + peer->num_htlcs_to_us - <= ARRAY_SIZE(peer->live_htlcs_to_us)); - assert(peer->num_live_htlcs_to_them + peer->num_htlcs_to_them - <= ARRAY_SIZE(peer->live_htlcs_to_them)); - memcpy(peer->live_htlcs_to_us + peer->num_live_htlcs_to_us, - peer->htlcs_to_us, - peer->num_htlcs_to_us * sizeof(peer->htlcs_to_us[0])); - memcpy(peer->live_htlcs_to_them + peer->num_live_htlcs_to_them, - peer->htlcs_to_them, - peer->num_htlcs_to_them * sizeof(peer->htlcs_to_them[0])); - peer->num_live_htlcs_to_us += peer->num_htlcs_to_us; - peer->num_live_htlcs_to_them += peer->num_htlcs_to_them; - /* Can happen if we were finished, then new commit tx */ - remove_event_(&peer->core.event_notifies, INPUT_NO_MORE_HTLCS); - - return true; -} - -bool peer_watch_their_htlc_outputs(struct peer *peer, - const struct bitcoin_event *tx, - enum state_input tous_timeout, - enum state_input tothem_spent, - enum state_input tothem_timeout) -{ - size_t i; - struct htlc *htlcs; - - /* We assume these. */ - assert(tous_timeout == BITCOIN_HTLC_TOUS_TIMEOUT); - assert(tothem_spent == BITCOIN_HTLC_TOTHEM_SPENT); - assert(tothem_timeout == BITCOIN_HTLC_TOTHEM_TIMEOUT); - - /* It's what our peer thinks is current... */ - if (!peer->other->num_htlcs_to_them && !peer->other->num_htlcs_to_us) - return false; - - assert(peer->num_live_htlcs_to_us + peer->other->num_htlcs_to_them - <= ARRAY_SIZE(peer->live_htlcs_to_us)); - assert(peer->num_live_htlcs_to_them + peer->other->num_htlcs_to_us - <= ARRAY_SIZE(peer->live_htlcs_to_them)); - - /* Copy from other peer, but reverse perspective */ - htlcs = peer->live_htlcs_to_us + peer->num_live_htlcs_to_us; - memcpy(htlcs, peer->other->htlcs_to_them, - peer->other->num_htlcs_to_them * sizeof(peer->htlcs_to_us[0])); - for (i = 0; i < peer->other->num_htlcs_to_them; i++) { - assert(htlcs[i].to_them); - htlcs[i].to_them = false; - } - - htlcs = peer->live_htlcs_to_them + peer->num_live_htlcs_to_them; - memcpy(htlcs, - peer->other->htlcs_to_us, - peer->other->num_htlcs_to_us * sizeof(peer->htlcs_to_them[0])); - for (i = 0; i < peer->other->num_htlcs_to_us; i++) { - assert(!htlcs[i].to_them); - htlcs[i].to_them = true; - } - - peer->num_live_htlcs_to_us += peer->other->num_htlcs_to_them; - peer->num_live_htlcs_to_them += peer->other->num_htlcs_to_us; - /* Can happen if we were finished, then new commit tx */ - remove_event_(&peer->core.event_notifies, INPUT_NO_MORE_HTLCS); - - return true; -} - -void peer_unwatch_htlc_output(struct peer *peer, - const struct htlc *htlc, - enum state_input all_done) -{ - const struct htlc *h; - - /* We assume this. */ - assert(all_done == INPUT_NO_MORE_HTLCS); - - h = find_live_htlc(peer, htlc->id); - - /* That can fail, when we see them spend (and thus stop - * watching) after we've timed out, then our return tx wins - * and gets buried. */ - if (h) { - remove_htlc(peer->live_htlcs_to_us, - &peer->num_live_htlcs_to_us, - peer->live_htlcs_to_them, - &peer->num_live_htlcs_to_them, - ARRAY_SIZE(peer->live_htlcs_to_us), - h); - - /* If that was last, fire INPUT_NO_MORE_HTLCS */ - if (!outstanding_htlc_watches(peer)) - add_event(peer, all_done); - } -} - -void peer_unwatch_all_htlc_outputs(struct peer *peer) -{ - /* This can happen if we get in front of INPUT_NO_MORE_HTLCS */ - if (!outstanding_htlc_watches(peer) - && !have_event(peer->core.event_notifies, INPUT_NO_MORE_HTLCS)) - report_trail(peer->trail, "unwatching all with no htlcs?"); - - peer->num_htlc_spends_to_us = 0; - peer->num_htlc_spends_to_them = 0; - peer->num_live_htlcs_to_us = 0; - peer->num_live_htlcs_to_them = 0; -} - -void peer_watch_htlc_spend(struct peer *peer, - const struct bitcoin_tx *tx, - const struct htlc *htlc, - enum state_input done) -{ - struct htlc *h = find_live_htlc(peer, htlc_id_from_tx(tx)); - - add_htlc(peer->htlc_spends_to_us, &peer->num_htlc_spends_to_us, - peer->htlc_spends_to_them, - &peer->num_htlc_spends_to_them, - ARRAY_SIZE(peer->htlc_spends_to_us), - h); - - /* We assume this */ - if (h->to_them) - assert(done == BITCOIN_HTLC_RETURN_SPEND_DONE); - else - assert(done == BITCOIN_HTLC_FULFILL_SPEND_DONE); -} - -void peer_unwatch_htlc_spend(struct peer *peer, - const struct htlc *htlc, - enum state_input all_done) -{ - struct htlc *h = find_htlc_spend(peer, htlc->id); - - assert(all_done == INPUT_NO_MORE_HTLCS); - remove_htlc(peer->htlc_spends_to_us, - &peer->num_htlc_spends_to_us, - peer->htlc_spends_to_them, - &peer->num_htlc_spends_to_them, - ARRAY_SIZE(peer->htlc_spends_to_us), - h); - - if (!outstanding_htlc_watches(peer)) - add_event(peer, all_done); -} - -void peer_unexpected_pkt(struct peer *peer, const Pkt *pkt) -{ - const char *str = (const char *)pkt; - - /* We can get errors. */ - if (strstarts(str, "PKT_ERROR:")) - return; - - /* Shouldn't get any other unexpected packets. */ - report_trail(peer->trail, "Unexpected packet"); -} - -/* Called when their update overrides our update cmd. */ -void peer_htlc_ours_deferred(struct peer *peer) -{ - /* Only happens for HTLC commands of low priority. */ - if (high_priority(peer->state)) - report_trail(peer->trail, "Defer while high priority"); - - if (peer->current_htlc.htlc.id == -1) - report_trail(peer->trail, "Deferred with no current HTLC"); - if (!input_is(peer->core.current_command, CMD_SEND_UPDATE_ANY)) - report_trail(peer->trail, "Deferred their HTLC?"); - - /* FIXME: Expect CMD_REQUEUE */ - clear_current_htlc(peer); -} - -/* Successfully added/fulfilled/timedout/fail an HTLC. */ -void peer_htlc_done(struct peer *peer) -{ - if (peer->current_htlc.htlc.id == -1) - report_trail(peer->trail, "Adding with no current HTLC"); - - if (peer->current_htlc.adding) { - add_htlc(peer->htlcs_to_us, &peer->num_htlcs_to_us, - peer->htlcs_to_them, &peer->num_htlcs_to_them, - ARRAY_SIZE(peer->htlcs_to_us), - &peer->current_htlc.htlc); - } else { - remove_htlc_id(peer, peer->current_htlc.htlc.id); - } - clear_current_htlc(peer); -} - -/* Someone aborted an existing HTLC update. */ -void peer_htlc_aborted(struct peer *peer) -{ - if (peer->current_htlc.htlc.id == -1) - report_trail(peer->trail, "Abort with no current HTLC"); - clear_current_htlc(peer); -} - -void peer_htlc_declined(struct peer *peer, const Pkt *pkt) -{ - if (peer->current_htlc.htlc.id == -1) - report_trail(peer->trail, "Decline with no current HTLC"); - if (!peer->current_htlc.adding) - report_trail(peer->trail, "Decline but HTLC not marked for add"); - clear_current_htlc(peer); - peer->htlc_declined = true; -} - -const struct htlc *peer_tx_revealed_r_value(struct peer *peer, - const struct bitcoin_event *btc) -{ - const struct htlc *htlc = (struct htlc *)btc; - add_rval(peer, htlc->id); - return htlc; -} - -static const char *check_changes(const struct peer *old, struct peer *new, - enum state_input input) -{ - if (new->cond != old->cond) { - /* Only BUSY -> CMD_OK can go backwards. */ - if (!(old->cond == PEER_BUSY && new->cond == PEER_CMD_OK)) - if (new->cond < old->cond) - return tal_fmt(NULL, "cond from %u to %u", - old->cond, new->cond); - } - if (new->cond == PEER_CLOSING - || new->cond == PEER_CLOSED) { - if (new->core.current_command != INPUT_NONE) - return tal_fmt(NULL, - "cond CLOSE with pending command %s", - input_name(new->core.current_command)); - if (new->current_htlc.htlc.id != -1) - return tal_fmt(NULL, - "cond CLOSE with pending htlc"); - if (new->anchor) - return tal_fmt(NULL, - "cond CLOSE with anchor"); - } - if (new->cond == PEER_CLOSED) { - /* Should not have pending close timeout. */ - if (have_event(new->core.event_notifies, - INPUT_CLOSE_COMPLETE_TIMEOUT)) - return tal_fmt(NULL, "CLOSED with pending close timeout"); - /* We must not leave anchor dangling, if we broadcast it. */ - if (new->anchor_broadcast && !new->anchor_spent) - return tal_fmt(NULL, "CLOSED with unspent anchor?"); - } - - if (input == PKT_ERROR) { - /* We should stop talking to them after error recvd. */ - if (new->cond != PEER_CLOSING - && new->cond != PEER_CLOSED) - return "packets still open after error pkt"; - } - - return NULL; -} - -static const char *check_all_effects(const struct peer *old, - enum command_status cstatus, - enum state_input input, - struct peer *peer, - Pkt *output) -{ - if (cstatus != CMD_NONE) { - assert(peer->core.current_command != INPUT_NONE); - /* We should only requeue HTLCs if we're lowprio */ - if (cstatus == CMD_REQUEUE) { - if (high_priority(old->state)) - return "CMD_REQUEUE despite high prio state"; - else if (!input_is(peer->core.current_command, - CMD_SEND_UPDATE_ANY)) - return tal_fmt(NULL, "CMD_REQUEUE on cmd %s", - input_name(peer->core.current_command)); - /* We expect to be replaced by their HTLC - * (unless we inject an error!). */ - if (peer->current_htlc.htlc.id == -1 - && peer->cond != PEER_CLOSED - && !peer->htlc_declined) - return tal_fmt(NULL, "CMD_REQUEUE but no new htlc?"); - } else { - /* Expect no HTLCs in other cases. */ - if (peer->current_htlc.htlc.id != -1) - return tal_fmt(NULL, "%s but still have htlc?", - cstatus_name(cstatus)); - } - peer->core.current_command = INPUT_NONE; - } - - if (output) { - const char *pkt = (const char *)output; - /* Check for errors. */ - if (strstarts(pkt, "PKT_ERROR: ")) { - /* Some are expected. */ - if (!streq(pkt, "PKT_ERROR: Commit tx noticed") - && !streq(pkt, "PKT_ERROR: Otherspend noticed") - && !streq(pkt, "PKT_ERROR: Error inject") - && !streq(pkt, "PKT_ERROR: Anchor timed out") - && !streq(pkt, "PKT_ERROR: Close timed out") - && !streq(pkt, "PKT_ERROR: Close forced due to HTLCs")) { - return pkt; - } - } - if (peer->core.num_outputs >= ARRAY_SIZE(peer->core.outputs)) - return "Too many outputs"; - peer->core.outputs[peer->core.num_outputs] - = input_by_name(pkt); - peer->pkt_data[peer->core.num_outputs++] - = htlc_id_from_pkt(output); - } - - if (peer->state >= STATE_CLOSE_WAIT_STEAL - && peer->state <= STATE_CLOSE_WAIT_STEAL_SPENDTHEM_CLOSE_SPENDOURS_WITH_HTLCS) { - if (STATE_TO_BITS(peer->state) & STATE_CLOSE_HTLCS_BIT) { - if (!outstanding_htlc_watches(peer) - && !have_event(peer->core.event_notifies, INPUT_NO_MORE_HTLCS)) - return "CLOSE_HTLCS with no outstanding watches?"; - } - } - - return check_changes(old, peer, input); -} - -static void eliminate_input(enum state_input **inputs, enum state_input in) -{ - size_t i, n = tal_count(*inputs); - - for (i = 0; i < n; i++) { - if ((*inputs)[i] != in) - continue; - - if (i != n-1) - (*inputs)[i] = (*inputs)[n-1]; - tal_resize(inputs, n - 1); - break; - } -} - -static bool find_output(const enum state_input *outputs, enum state_input out) -{ - size_t n, i; - - n = tal_count(outputs); - for (i = 0; i < n; i++) - if (outputs[i] == out) - return true; - return false; -} - -static void record_output(enum state_input **outputs, enum state_input out) -{ - size_t n; - - if (find_output(*outputs, out)) - return; - - n = tal_count(*outputs); - tal_resize(outputs, n+1); - (*outputs)[n] = out; -} - -static void record_state(struct state_dump **sd, - enum state_input input, - enum state newstate, - const char *pktstr) -{ - size_t i, n = tal_count(*sd); - enum state_input pkt; - - if (!pktstr) - pkt = INPUT_NONE; - else - pkt = input_by_name(pktstr); - - for (i = 0; i < n; i++) { - if ((*sd)[i].input != input) - continue; - if ((*sd)[i].next != newstate) - continue; - if ((*sd)[i].pkt != pkt) - continue; - /* Duplicate. */ - return; - } - tal_resize(sd, n+1); - (*sd)[n].input = input; - (*sd)[n].next = newstate; - (*sd)[n].pkt = pkt; -} - -static bool error_path(enum state_input i, enum state src, enum state dst) -{ - return state_is_error(dst) || i == PKT_ERROR; -} - -static bool normal_path(enum state_input i, enum state src, enum state dst) -{ - if (error_path(i, src, dst)) - return false; - - /* Weird inputs. */ - if (i == BITCOIN_ANCHOR_TIMEOUT - || i == BITCOIN_ANCHOR_UNSPENT - || i == BITCOIN_ANCHOR_THEIRSPEND - || i == BITCOIN_ANCHOR_OTHERSPEND - || i == BITCOIN_STEAL_DONE - || i == PKT_UPDATE_DECLINE_HTLC - || i == PKT_UPDATE_FAIL_HTLC - || i == INPUT_CLOSE_COMPLETE_TIMEOUT) - return false; - - return true; -} - -/* These clutter the graph, so only handle from normal state. */ -static bool too_cluttered(enum state_input i, enum state src) -{ - if (i == CMD_CLOSE || i == PKT_CLOSE || i == PKT_UPDATE_ADD_HTLC || i == PKT_UPDATE_FULFILL_HTLC) - return src != STATE_NORMAL_LOWPRIO - && src != STATE_NORMAL_HIGHPRIO; - return false; -} - -static void add_dot(struct edge_hash *hash, - const char *oldstate, - const char *newstate, - enum state_input i, - const Pkt *pkt) -{ - struct dot_edge *d = tal(NULL, struct dot_edge); - d->oldstate = oldstate; - d->newstate = newstate; - d->i = i; - if (pkt) - d->pkt = tal_strdup(d, (const char *)pkt); - else - d->pkt = NULL; - - if (edge_hash_get(hash, d)) - tal_free(d); - else - edge_hash_add(hash, d); -} - -static const char *simplify_state(enum state s) -{ - /* Turn all high prio into low prio, and merge some open states */ - switch (s) { - case STATE_OPEN_WAITING_OURANCHOR: - case STATE_OPEN_WAITING_THEIRANCHOR: - return "STATE_OPEN_WAITING"; - - case STATE_OPEN_WAIT_FOR_COMPLETE_OURANCHOR: - case STATE_OPEN_WAIT_FOR_COMPLETE_THEIRANCHOR: - return "STATE_OPEN_WAIT_FOR_COMPLETE"; - - case STATE_NORMAL_LOWPRIO: - case STATE_NORMAL_HIGHPRIO: - return "STATE_NORMAL"; - - case STATE_WAIT_FOR_HTLC_ACCEPT_LOWPRIO: - case STATE_WAIT_FOR_HTLC_ACCEPT_HIGHPRIO: - return "STATE_WAIT_FOR_HTLC_ACCEPT"; - - case STATE_WAIT_FOR_UPDATE_COMPLETE_LOWPRIO: - case STATE_WAIT_FOR_UPDATE_COMPLETE_HIGHPRIO: - return "STATE_WAIT_FOR_UPDATE_COMPLETE"; - - case STATE_WAIT_FOR_UPDATE_SIG_LOWPRIO: - case STATE_WAIT_FOR_UPDATE_SIG_HIGHPRIO: - return "STATE_WAIT_FOR_UPDATE_SIG"; - - default: - return state_name(s); - } -} - -static bool waiting_statepair(enum state a, enum state b) -{ - /* We don't need inputs if we're waiting for anchors. */ - if (a == STATE_OPEN_WAITING_OURANCHOR - || a == STATE_OPEN_WAITING_OURANCHOR_THEYCOMPLETED - || a == STATE_OPEN_WAITING_THEIRANCHOR - || a == STATE_OPEN_WAITING_THEIRANCHOR_THEYCOMPLETED - || a == STATE_OPEN_WAIT_FOR_ANCHOR_CREATE) - return true; - - if (b == STATE_OPEN_WAITING_OURANCHOR - || b == STATE_OPEN_WAITING_OURANCHOR_THEYCOMPLETED - || b == STATE_OPEN_WAITING_THEIRANCHOR - || b == STATE_OPEN_WAITING_THEIRANCHOR_THEYCOMPLETED - || b == STATE_OPEN_WAIT_FOR_ANCHOR_CREATE) - return true; - - /* We don't need inputs at start of main loop. */ - if (a == STATE_NORMAL_LOWPRIO - && b == STATE_NORMAL_HIGHPRIO) - return true; - - if (a == STATE_NORMAL_HIGHPRIO - && b == STATE_NORMAL_LOWPRIO) - return true; - - return false; -} - -static bool has_packets(const struct peer *peer) -{ - return peer->core.num_outputs != 0; -} - -static void try_input(const struct peer *peer, - enum state_input i, - const union input *idata, - bool normalpath, bool errorpath, - const struct trail *prev_trail, - struct hist *hist) -{ - struct peer copy, other; - struct trail t; - const char *problem; - Pkt *output; - const struct bitcoin_tx *broadcast; - const tal_t *ctx = tal_tmpctx(NULL); - enum command_status cstatus; - - copy_peers(©, &other, peer); - - copy.current_input = i; - copy.current_idata = idata; - init_trail(&t, i, idata, peer, prev_trail); - copy.trail = &t; - - /* The anchor is resolved in some way by these. */ - if (i == BITCOIN_ANCHOR_UNSPENT - || i == BITCOIN_ANCHOR_TIMEOUT - || i == BITCOIN_ANCHOR_THEIRSPEND - || i == BITCOIN_ANCHOR_OTHERSPEND - || i == BITCOIN_CLOSE_DONE) - copy.anchor_spent = true; - - eliminate_input(&hist->inputs_per_state[copy.state], i); - cstatus = state(ctx, ©, i, idata, &output, &broadcast); - - normalpath &= normal_path(i, peer->state, copy.state); - errorpath |= error_path(i, peer->state, copy.state); - - if (dot_enable - && (dot_include_abnormal || normalpath) - && (dot_include_errors || !errorpath) - && (dot_include_abnormal || !too_cluttered(i, peer->state))) { - const char *oldstr, *newstr; - - /* Simplify folds high and low prio, skip "STATE_" */ - if (dot_simplify) { - oldstr = simplify_state(peer->state) + 6; - newstr = simplify_state(copy.state) + 6; - } else { - oldstr = state_name(peer->state) + 6; - newstr = state_name(copy.state) + 6; - } - if (newstr != oldstr || include_nops) - add_dot(&hist->edges, oldstr, newstr, i, output); - } - - problem = check_all_effects(peer, cstatus, i, ©, output); - update_trail(&t, ©, output); - if (problem) - report_trail(&t, problem); - - if (copy.state == STATE_ERR_INTERNAL) - report_trail(&t, "Internal error"); - if (strstarts(state_name(copy.state), "STATE_UNUSED")) - report_trail(&t, "Unused state"); - - /* Re-set htlc_declined */ - copy.htlc_declined = false; - - /* Record any output. */ - if (output) { - record_output(&hist->outputs, - input_by_name((const char *)output)); - } - - if (hist->state_dump) { - record_state(&hist->state_dump[peer->state], i, copy.state, - (const char *)output); - } - - /* Have we been in this overall situation before? */ - if (!sithash_update(&hist->sithash, ©)) { - /* - * We expect to loop if: - * 1) We deferred, OR - * 2) We get repeated BITCOIN_ANCHOR_OTHERSPEND/THEIRSPEND, OR - * 3) We pass through NORMAL state. - * - * And if we're being quick, always stop. - */ - if (quick - || cstatus == CMD_REQUEUE - || copy.state == STATE_NORMAL_LOWPRIO - || copy.state == STATE_NORMAL_HIGHPRIO - || i == BITCOIN_ANCHOR_OTHERSPEND - || i == BITCOIN_ANCHOR_THEIRSPEND - || quick) { - tal_free(ctx); - return; - } - if (t.depth > STATE_MAX * 10) - report_trail(&t, "Loop"); - } - - /* Don't continue if we reached a different error state. */ - if (state_is_error(copy.state)) { - tal_free(ctx); - return; - } - - /* - * If we're listening, someone should be talking (usually). - */ - if (copy.cond != PEER_CLOSED - && !has_packets(©) && !has_packets(&other) - && !waiting_statepair(copy.state, other.state)) { - report_trail(&t, "Deadlock"); - } - - /* Finished? */ - if (copy.state == STATE_CLOSED) { - if (copy.cond != PEER_CLOSED) - report_trail(&t, "CLOSED but cond not CLOSED"); - - if (copy.core.current_command != INPUT_NONE) - report_trail(&t, input_name(copy.core.current_command)); - - if (copy.current_htlc.htlc.id != -1) - report_trail(&t, "CLOSED with htlc in progress?"); - - if (outstanding_htlc_watches(©)) - report_trail(&t, "CLOSED but watching HTLCs?"); - tal_free(ctx); - return; - } - - /* Try inputs from here down. */ - run_peer(©, normalpath, errorpath, &t, hist); - - /* Don't bother running other peer we can't communicate. */ - if (copy.cond != PEER_CLOSED - || other.cond != PEER_CLOSED) - run_peer(&other, normalpath, errorpath, &t, hist); - tal_free(ctx); -} - -static void sanity_check(const struct peer *peer) -{ - if (peer->state == STATE_NORMAL_LOWPRIO - || peer->state == STATE_NORMAL_HIGHPRIO) { - /* Home state: expect commands to be finished. */ - if (peer->core.current_command != INPUT_NONE) - errx(1, "Unexpected command %u in state %u", - peer->core.current_command, peer->state); - } -} - -static void activate_event(struct peer *peer, enum state_input i) -{ - /* Events are not independent. */ - switch (i) { - case BITCOIN_ANCHOR_DEPTHOK: - /* Can't sent TIMEOUT (may not be set) */ - remove_event_(&peer->core.event_notifies, BITCOIN_ANCHOR_TIMEOUT); - break; - case BITCOIN_ANCHOR_TIMEOUT: - /* Can't sent DEPTHOK */ - remove_event(peer, BITCOIN_ANCHOR_DEPTHOK); - break; - /* And of the "done" cases means we won't give the others. */ - case BITCOIN_SPEND_THEIRS_DONE: - case BITCOIN_SPEND_OURS_DONE: - case BITCOIN_STEAL_DONE: - case BITCOIN_CLOSE_DONE: - remove_event_(&peer->core.event_notifies, - BITCOIN_SPEND_OURS_DONE); - remove_event_(&peer->core.event_notifies, - BITCOIN_SPEND_THEIRS_DONE); - remove_event_(&peer->core.event_notifies, BITCOIN_STEAL_DONE); - remove_event_(&peer->core.event_notifies, BITCOIN_CLOSE_DONE); - remove_event_(&peer->core.event_notifies, - BITCOIN_ANCHOR_OURCOMMIT_DELAYPASSED); - remove_event_(&peer->core.event_notifies, - BITCOIN_ANCHOR_THEIRSPEND); - remove_event_(&peer->core.event_notifies, - BITCOIN_ANCHOR_OTHERSPEND); - remove_event_(&peer->core.event_notifies, - BITCOIN_ANCHOR_UNSPENT); - break; - default: - ; - } -} - -static bool can_refire(enum state_input i) -{ - /* They could have lots of old HTLCS */ - if (i == BITCOIN_ANCHOR_OTHERSPEND) - return true; - /* Signature malleability means any number of these */ - if (i == BITCOIN_ANCHOR_THEIRSPEND) - return true; - - /* They could have lots of htlcs. */ - if (i == BITCOIN_HTLC_TOTHEM_SPENT || i == BITCOIN_HTLC_TOTHEM_TIMEOUT - || i == BITCOIN_HTLC_TOUS_TIMEOUT) - return true; - - /* We manually remove these if they're not watching any more spends */ - if (i == BITCOIN_HTLC_RETURN_SPEND_DONE - || i == BITCOIN_HTLC_FULFILL_SPEND_DONE) - return true; - - return false; -} - -static unsigned int next_htlc_id(void) -{ - static unsigned int num; - - return ++num; -} - -static void run_peer(const struct peer *peer, - bool normalpath, bool errorpath, - const struct trail *prev_trail, - struct hist *hist) -{ - struct peer copy, other; - size_t i; - uint64_t old_notifies; - union input *idata = talz(NULL, union input); - - sanity_check(peer); - - /* We want to frob some things... */ - copy_peers(©, &other, peer); - - /* If in init state, we can only send start command. */ - if (peer->state == STATE_INIT) { - if (streq(peer->name, "A")) - copy.core.current_command = CMD_OPEN_WITH_ANCHOR; - else - copy.core.current_command = CMD_OPEN_WITHOUT_ANCHOR; - try_input(©, copy.core.current_command, idata, - normalpath, errorpath, - prev_trail, hist); - return; - } - - /* Try the event notifiers */ - old_notifies = copy.core.event_notifies; - for (i = 0; i < 64; i++) { - if (!have_event(copy.core.event_notifies, i)) - continue; - - /* Don't re-fire most events */ - if (!can_refire(i)) - remove_event(©, i); - activate_event(©, i); - try_input(©, i, idata, normalpath, errorpath, - prev_trail, hist); - copy.core.event_notifies = old_notifies; - } - - /* We can send a close command even if already sending a - * (different) command. */ - if (peer->state != STATE_INIT - && (peer->cond == PEER_CMD_OK - || peer->cond == PEER_BUSY)) { - try_input(©, CMD_CLOSE, idata, - normalpath, errorpath, prev_trail, hist); - } - - /* Try sending commands if allowed. */ - if (peer->cond == PEER_CMD_OK) { - unsigned int i; - - /* Shouldn't be currently doing an HTLC. */ - assert(copy.current_htlc.htlc.id == -1); - - /* Add a new HTLC if not at max. */ - if (copy.num_htlcs_to_them < MAX_HTLCS) { - copy.core.current_command = CMD_SEND_HTLC_ADD; - idata->htlc_prog = tal(idata, struct htlc_progress); - idata->htlc_prog->adding = true; - idata->htlc_prog->htlc.to_them = true; - idata->htlc_prog->htlc.id = next_htlc_id(); - - set_current_htlc(©, - idata->htlc_prog->htlc.id, - idata->htlc_prog->htlc.to_them, - idata->htlc_prog->adding); - try_input(©, copy.core.current_command, idata, - normalpath, errorpath, - prev_trail, hist); - idata->htlc_prog = tal_free(idata->htlc_prog); - /* If it was requeued, may already be reset. */ - copy.current_htlc.htlc.id = -1; - } - - /* We can complete or fail an HTLC they offered */ - for (i = 0; i < peer->num_htlcs_to_us; i++) { - idata->htlc_prog = tal(idata, struct htlc_progress); - idata->htlc_prog->htlc = peer->htlcs_to_us[i]; - idata->htlc_prog->adding = false; - - set_current_htlc(©, - idata->htlc_prog->htlc.id, - idata->htlc_prog->htlc.to_them, - idata->htlc_prog->adding); - - /* Only send this once. */ - if (!rval_known(peer, idata->htlc_prog->htlc.id)) { - copy.core.current_command - = CMD_SEND_HTLC_FULFILL; - try_input(©, copy.core.current_command, - idata, normalpath, errorpath, - prev_trail, hist); - } - copy.core.current_command = CMD_SEND_HTLC_FAIL; - try_input(©, copy.core.current_command, - idata, normalpath, errorpath, - prev_trail, hist); - /* If it was requeued, may already be reset. */ - copy.current_htlc.htlc.id = -1; - } - - /* Restore current_command */ - copy.core.current_command = INPUT_NONE; - } - - /* If they're watching HTLCs, we can send events. */ - for (i = 0; i < peer->num_live_htlcs_to_us; i++) { - idata->htlc = (struct htlc *)©.live_htlcs_to_us[i]; - /* Only send this once. */ - if (!rval_known(peer, idata->htlc->id)) { - try_input(©, INPUT_RVALUE, - idata, normalpath, errorpath, - prev_trail, hist); - } - try_input(©, BITCOIN_HTLC_TOUS_TIMEOUT, - idata, normalpath, errorpath, - prev_trail, hist); - } - - for (i = 0; i < peer->num_live_htlcs_to_them; i++) { - idata->btc = (struct bitcoin_event *)©.live_htlcs_to_them[i]; - try_input(©, BITCOIN_HTLC_TOTHEM_SPENT, - idata, normalpath, errorpath, - prev_trail, hist); - idata->htlc = (struct htlc *)©.live_htlcs_to_them[i]; - try_input(©, BITCOIN_HTLC_TOTHEM_TIMEOUT, - idata, normalpath, errorpath, - prev_trail, hist); - } - - /* If they're watching HTLC spends, we can send events. */ - for (i = 0; i < peer->num_htlc_spends_to_us; i++) { - idata->htlc = (struct htlc *)©.htlc_spends_to_us[i]; - try_input(©, BITCOIN_HTLC_FULFILL_SPEND_DONE, - idata, normalpath, errorpath, - prev_trail, hist); - } - for (i = 0; i < peer->num_htlc_spends_to_them; i++) { - idata->htlc = (struct htlc *)©.htlc_spends_to_them[i]; - try_input(©, BITCOIN_HTLC_RETURN_SPEND_DONE, - idata, normalpath, errorpath, - prev_trail, hist); - } - - /* Allowed to send packets? */ - if (copy.cond != PEER_CLOSED) { - enum state_input i; - - if (other.core.num_outputs) { - i = other.core.outputs[0]; - if (i == PKT_ERROR) - idata->pkt = pkt_err(idata, ""); - else if (other.pkt_data[0] == -1U) - idata->pkt = (Pkt *)talz(idata, char); - else - idata->pkt = htlc_pkt(idata, input_name(i), - other.pkt_data[0]); - - /* Do the first, recursion does the rest. */ - memmove(other.core.outputs, other.core.outputs + 1, - sizeof(other.core.outputs) - - sizeof(other.core.outputs[0])); - memmove(other.pkt_data, other.pkt_data + 1, - sizeof(other.pkt_data)-sizeof(other.pkt_data[0])); - other.core.num_outputs--; - /* Reset so that hashing doesn't get confused. */ - other.core.outputs[other.core.num_outputs] = 0; - try_input(©, i, idata, normalpath, errorpath, - prev_trail, hist); - } - } - tal_free(idata); -} - -static bool record_input_mapping(int b) -{ - size_t n; - - if (!mapping_inputs) - return false; - - /* Accumulating tested inputs? */ - n = tal_count(mapping_inputs); - tal_resize(&mapping_inputs, n+1); - mapping_inputs[n] = b; - return true; -} - -static enum state_input **map_inputs(void) -{ - enum state_input **inps = tal_arr(NULL, enum state_input *, STATE_MAX); - unsigned int i; - const tal_t *ctx = tal_tmpctx(NULL); - - for (i = 0; i < STATE_MAX; i++) { - /* This is a global */ - mapping_inputs = tal_arr(inps, enum state_input, 0); - - /* This adds to mapping_inputs every input_is() call */ - if (!state_is_error(i)) { - struct peer dummy; - const struct bitcoin_tx *dummy_tx; - Pkt *dummy_pkt; - memset(&dummy, 0, sizeof(dummy)); - dummy.state = i; - state(ctx, &dummy, INPUT_NONE, NULL, &dummy_pkt, - &dummy_tx); - } - inps[i] = mapping_inputs; - } - - /* Reset global */ - mapping_inputs = NULL; - tal_free(ctx); - return inps; -} - -static bool visited_state(const struct sithash *sithash, - enum state state, bool b) -{ - struct situation *h; - struct sithash_iter i; - unsigned int num = 0; - - for (h = sithash_first(sithash, &i); h; h = sithash_next(sithash, &i)) { - num++; - if (b) { - if (h->a.s.valid && h->b.s.state == state) - return true; - } else { - if (h->a.s.valid && h->a.s.state == state) - return true; - } - } - return false; -} - -static int state_dump_cmp(const struct state_dump *a, - const struct state_dump *b, - void *unused) -{ - if (a->input != b->input) - return a->input - b->input; - if (a->next != b->next) - return a->next - b->next; - return 0; -} - -int main(int argc, char *argv[]) -{ - struct peer a, b; - unsigned int i; - struct hist hist; - bool dump_states = false; - bool more_failpoints; - - err_set_progname(argv[0]); - - opt_register_noarg("--help|-h", opt_usage_and_exit, - "" - "Test lightning state machine", - "Print this message."); - opt_register_noarg("--dot", - opt_set_bool, &dot_enable, - "Output dot format for normal paths"); - opt_register_noarg("--dot-all", - opt_set_bool, &dot_include_abnormal, - "Output dot format for all non-error paths"); - opt_register_noarg("--dot-include-errors", - opt_set_bool, &dot_include_errors, - "Output dot format for error paths"); - opt_register_noarg("--include-nops", - opt_set_bool, &include_nops, - "Output even for inputs which don't change state"); - opt_register_noarg("--dot-simplify", - opt_set_bool, &dot_simplify, - "Merge high and low priority states"); - opt_register_noarg("--dump-states", - opt_set_bool, &dump_states, - "Summarize all state transitions"); - opt_register_version(); - - opt_parse(&argc, argv, opt_log_stderr_exit); - if (dot_include_abnormal) - dot_enable = true; - if (dot_simplify && !dot_enable) - opt_usage_exit_fail("--dot-simplify needs --dot/--dot-all"); - if (dot_include_errors && !dot_enable) - opt_usage_exit_fail("--dot-include-errors needs --dot/--dot-all"); - if (include_nops && !dot_enable && !dump_states) - opt_usage_exit_fail("--include-nops needs --dot/--dot-all/--dump-states"); - - /* Map the inputs tested in each state. */ - hist.inputs_per_state = map_inputs(); - sithash_init(&hist.sithash); - hist.outputs = tal_arr(NULL, enum state_input, 0); - edge_hash_init(&hist.edges); - if (dump_states) { - hist.state_dump = tal_arr(NULL, struct state_dump *, STATE_MAX); - for (i = 0; i < STATE_MAX; i++) - hist.state_dump[i] = tal_arr(hist.state_dump, - struct state_dump, 0); - } else - hist.state_dump = NULL; - -#if 0 - quick = dot_enable || dump_states; -#else - quick = true; -#endif - - /* Initialize universe. */ - peer_init(&a, &b, "A"); - peer_init(&b, &a, "B"); - if (!sithash_update(&hist.sithash, &a)) - abort(); - failhash_init(&failhash); - - /* Now, try each input in each state. */ - run_peer(&a, true, false, NULL, &hist); - - /* Now probe all the failure points */ - do { - struct failpoint *f; - struct failhash_iter i; - more_failpoints = false; - - for (f = failhash_first(&failhash, &i); - f; - f = failhash_next(&failhash, &i)) { - if (f->details) { - const struct trail *t; - - /* Trail will vanish when f->details freed */ - t = tal_steal(f, f->details->us.trail); - try_input(&f->details->us, - f->details->input, - &f->details->idata, - false, true, - t, - &hist); - /* Note: it can go down an earlier path and - * fail differently, so f->details may - * still be set. */ - if (!f->details) - tal_free(t); - more_failpoints = true; - } - } - } while (!more_failpoints); - - for (i = 0; i < STATE_MAX; i++) { - bool a_expect = true, b_expect = true; - - /* Ignore unused states. */ - if (strstarts(state_name(i), "STATE_UNUSED")) - continue; - - /* A supplied anchor, so doesn't enter NOANCHOR states. */ - if (i == STATE_OPEN_WAIT_FOR_OPEN_NOANCHOR - || i == STATE_OPEN_WAIT_FOR_ANCHOR - || i == STATE_OPEN_WAITING_THEIRANCHOR - || i == STATE_OPEN_WAITING_THEIRANCHOR_THEYCOMPLETED - || i == STATE_OPEN_WAIT_FOR_COMPLETE_THEIRANCHOR - || i == STATE_ERR_ANCHOR_TIMEOUT) - a_expect = false; - if (i == STATE_OPEN_WAIT_FOR_OPEN_WITHANCHOR - || i == STATE_OPEN_WAIT_FOR_ANCHOR_CREATE - || i == STATE_OPEN_WAIT_FOR_COMMIT_SIG - || i == STATE_OPEN_WAIT_FOR_COMPLETE_OURANCHOR - || i == STATE_OPEN_WAITING_OURANCHOR - || i == STATE_OPEN_WAITING_OURANCHOR_THEYCOMPLETED) - b_expect = false; - if (i == STATE_ERR_INTERNAL) - a_expect = b_expect = false; - if (visited_state(&hist.sithash, i, 0) != a_expect) - warnx("Peer A %s state %s", - a_expect ? "didn't visit" : "visited", - state_name(i)); - if (visited_state(&hist.sithash, i, 1) != b_expect) - warnx("Peer B %s state %s", - b_expect ? "didn't visit" : "visited", - state_name(i)); - if (!state_is_error(i) && tal_count(hist.inputs_per_state[i])) - warnx("Never sent %s input %s", state_name(i), - input_name(*hist.inputs_per_state[i])); - } - - for (i = 0; i < INPUT_MAX; i++) { - /* Not all input values are valid. */ - if (streq(input_name(i), "unknown")) - continue; - /* We only expect packets to be output. */ - if (!input_is_pkt(i)) - continue; - if (!find_output(hist.outputs, i)) - warnx("Never sent output %s", input_name(i)); - } - - if (dot_enable) { - struct dot_edge *d; - struct edge_hash_iter i; - - printf("digraph lightning {\n"); - for (d = edge_hash_first(&hist.edges, &i); - d; - d = edge_hash_next(&hist.edges, &i)) { - printf("%s -> %s ", d->oldstate, d->newstate); - if (!d->pkt) - printf("[label=\"<%s\"];\n", input_name(d->i)); - else { - printf("[label=\"<%s\\n>%s\"];\n", - input_name(d->i), d->pkt); - } - } - printf("}\n"); - } - - if (dump_states) { - for (i = 0; i < STATE_MAX; i++) { - size_t j; - size_t n = tal_count(hist.state_dump[i]); - if (!n) - continue; - printf("%s:\n", state_name(i) + 6); - asort(hist.state_dump[i], n, state_dump_cmp, NULL); - for (j = 0; j < n; j++) { - if (!include_nops - && hist.state_dump[i][j].next == i) - continue; - printf("\t%s -> %s", - input_name(hist.state_dump[i][j].input), - state_name(hist.state_dump[i][j].next)+6); - if (hist.state_dump[i][j].pkt != INPUT_NONE) - printf(" (%s)", - input_name(hist.state_dump[i][j].pkt)); - printf("\n"); - } - } - } - - return 0; -}