Browse Source

test_protocol: restart support.

We keep a "database" for each side's persistent state.  Upon restart,
each side tells the other where it was up to, in terms of the number
of commit and revocation messages it receives.

Because only one update can be in flight at a time, we can tell w

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 8 years ago
parent
commit
de7fb4a83f
  1. 24
      test/commits/20-restore-02.script
  2. 14
      test/commits/20-restore-02.script.expected
  3. 25
      test/commits/20-restore-03.script
  4. 14
      test/commits/20-restore-03.script.expected
  5. 24
      test/commits/20-restore-04.script
  6. 14
      test/commits/20-restore-04.script.expected
  7. 23
      test/commits/20-restore-05.script
  8. 14
      test/commits/20-restore-05.script.expected
  9. 23
      test/commits/20-restore-06.script
  10. 14
      test/commits/20-restore-06.script.expected
  11. 23
      test/commits/20-restore-07.script
  12. 14
      test/commits/20-restore-07.script.expected
  13. 23
      test/commits/20-restore-08.script
  14. 14
      test/commits/20-restore-08.script.expected
  15. 23
      test/commits/20-restore-09.script
  16. 14
      test/commits/20-restore-09.script.expected
  17. 24
      test/commits/20-restore-10.script
  18. 14
      test/commits/20-restore-10.script.expected
  19. 23
      test/commits/20-restore-11.script
  20. 14
      test/commits/20-restore-11.script.expected
  21. 24
      test/commits/20-restore-12.script
  22. 14
      test/commits/20-restore-12.script.expected
  23. 23
      test/commits/20-restore-13.script
  24. 14
      test/commits/20-restore-13.script.expected
  25. 23
      test/commits/20-restore-14.script
  26. 14
      test/commits/20-restore-14.script.expected
  27. 23
      test/commits/20-restore-15.script
  28. 14
      test/commits/20-restore-15.script.expected
  29. 23
      test/commits/20-restore-16.script
  30. 14
      test/commits/20-restore-16.script.expected
  31. 23
      test/commits/20-restore-17.script
  32. 14
      test/commits/20-restore-17.script.expected
  33. 25
      test/commits/21-restore-crossover-02.script
  34. 22
      test/commits/21-restore-crossover-02.script.expected
  35. 26
      test/commits/21-restore-crossover-03.script
  36. 22
      test/commits/21-restore-crossover-03.script.expected
  37. 25
      test/commits/21-restore-crossover-04.script
  38. 22
      test/commits/21-restore-crossover-04.script.expected
  39. 24
      test/commits/21-restore-crossover-05.script
  40. 22
      test/commits/21-restore-crossover-05.script.expected
  41. 25
      test/commits/21-restore-crossover-06.script
  42. 22
      test/commits/21-restore-crossover-06.script.expected
  43. 26
      test/commits/21-restore-crossover-07.script
  44. 22
      test/commits/21-restore-crossover-07.script.expected
  45. 25
      test/commits/21-restore-crossover-08.script
  46. 22
      test/commits/21-restore-crossover-08.script.expected
  47. 23
      test/commits/21-restore-crossover-08a.script
  48. 22
      test/commits/21-restore-crossover-08a.script.expected
  49. 24
      test/commits/21-restore-crossover-09.script
  50. 22
      test/commits/21-restore-crossover-09.script.expected
  51. 24
      test/commits/21-restore-crossover-10.script
  52. 22
      test/commits/21-restore-crossover-10.script.expected
  53. 24
      test/commits/21-restore-crossover-11.script
  54. 22
      test/commits/21-restore-crossover-11.script.expected
  55. 24
      test/commits/21-restore-crossover-12.script
  56. 22
      test/commits/21-restore-crossover-12.script.expected
  57. 24
      test/commits/21-restore-crossover-13.script
  58. 22
      test/commits/21-restore-crossover-13.script.expected
  59. 24
      test/commits/21-restore-crossover-14.script
  60. 22
      test/commits/21-restore-crossover-14.script.expected
  61. 24
      test/commits/21-restore-crossover-15.script
  62. 22
      test/commits/21-restore-crossover-15.script.expected
  63. 24
      test/commits/21-restore-crossover-16.script
  64. 22
      test/commits/21-restore-crossover-16.script.expected
  65. 24
      test/commits/21-restore-crossover-17.script
  66. 22
      test/commits/21-restore-crossover-17.script.expected
  67. 581
      test/test_protocol.c

24
test/commits/20-restore-02.script

@ -0,0 +1,24 @@
# 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

14
test/commits/20-restore-02.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

25
test/commits/20-restore-03.script

@ -0,0 +1,25 @@
# 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

14
test/commits/20-restore-03.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

24
test/commits/20-restore-04.script

@ -0,0 +1,24 @@
# 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

14
test/commits/20-restore-04.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

23
test/commits/20-restore-05.script

@ -0,0 +1,23 @@
# 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

14
test/commits/20-restore-05.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

23
test/commits/20-restore-06.script

@ -0,0 +1,23 @@
# 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

14
test/commits/20-restore-06.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

23
test/commits/20-restore-07.script

@ -0,0 +1,23 @@
# 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

14
test/commits/20-restore-07.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

23
test/commits/20-restore-08.script

@ -0,0 +1,23 @@
# 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

14
test/commits/20-restore-08.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

23
test/commits/20-restore-09.script

@ -0,0 +1,23 @@
# 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

14
test/commits/20-restore-09.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

24
test/commits/20-restore-10.script

@ -0,0 +1,24 @@
# 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

14
test/commits/20-restore-10.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

23
test/commits/20-restore-11.script

@ -0,0 +1,23 @@
# 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

14
test/commits/20-restore-11.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

24
test/commits/20-restore-12.script

@ -0,0 +1,24 @@
# 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

14
test/commits/20-restore-12.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

23
test/commits/20-restore-13.script

@ -0,0 +1,23 @@
# 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

14
test/commits/20-restore-13.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

23
test/commits/20-restore-14.script

@ -0,0 +1,23 @@
# 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

14
test/commits/20-restore-14.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

23
test/commits/20-restore-15.script

@ -0,0 +1,23 @@
# 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

14
test/commits/20-restore-15.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

23
test/commits/20-restore-16.script

@ -0,0 +1,23 @@
# 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

14
test/commits/20-restore-16.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

23
test/commits/20-restore-17.script

@ -0,0 +1,23 @@
# 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

14
test/commits/20-restore-17.script.expected

@ -0,0 +1,14 @@
***A***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED
***B***
LOCAL COMMIT:
Commit 2:
SIGNED
REMOTE COMMIT:
Commit 2:
SIGNED

25
test/commits/21-restore-crossover-02.script

@ -0,0 +1,25 @@
# 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

22
test/commits/21-restore-crossover-02.script.expected

@ -0,0 +1,22 @@
***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

26
test/commits/21-restore-crossover-03.script

@ -0,0 +1,26 @@
# 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

22
test/commits/21-restore-crossover-03.script.expected

@ -0,0 +1,22 @@
***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

25
test/commits/21-restore-crossover-04.script

@ -0,0 +1,25 @@
# 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

22
test/commits/21-restore-crossover-04.script.expected

@ -0,0 +1,22 @@
***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

24
test/commits/21-restore-crossover-05.script

@ -0,0 +1,24 @@
# 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

22
test/commits/21-restore-crossover-05.script.expected

@ -0,0 +1,22 @@
***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

25
test/commits/21-restore-crossover-06.script

@ -0,0 +1,25 @@
# 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

22
test/commits/21-restore-crossover-06.script.expected

@ -0,0 +1,22 @@
***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

26
test/commits/21-restore-crossover-07.script

@ -0,0 +1,26 @@
# 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

22
test/commits/21-restore-crossover-07.script.expected

@ -0,0 +1,22 @@
***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

25
test/commits/21-restore-crossover-08.script

@ -0,0 +1,25 @@
# 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

22
test/commits/21-restore-crossover-08.script.expected

@ -0,0 +1,22 @@
***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

23
test/commits/21-restore-crossover-08a.script

@ -0,0 +1,23 @@
# 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

22
test/commits/21-restore-crossover-08a.script.expected

@ -0,0 +1,22 @@
***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

24
test/commits/21-restore-crossover-09.script

@ -0,0 +1,24 @@
# 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

22
test/commits/21-restore-crossover-09.script.expected

@ -0,0 +1,22 @@
***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

24
test/commits/21-restore-crossover-10.script

@ -0,0 +1,24 @@
# 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

22
test/commits/21-restore-crossover-10.script.expected

@ -0,0 +1,22 @@
***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

24
test/commits/21-restore-crossover-11.script

@ -0,0 +1,24 @@
# 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

22
test/commits/21-restore-crossover-11.script.expected

@ -0,0 +1,22 @@
***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

24
test/commits/21-restore-crossover-12.script

@ -0,0 +1,24 @@
# 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

22
test/commits/21-restore-crossover-12.script.expected

@ -0,0 +1,22 @@
***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

24
test/commits/21-restore-crossover-13.script

@ -0,0 +1,24 @@
# 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

22
test/commits/21-restore-crossover-13.script.expected

@ -0,0 +1,22 @@
***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

24
test/commits/21-restore-crossover-14.script

@ -0,0 +1,24 @@
# 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

22
test/commits/21-restore-crossover-14.script.expected

@ -0,0 +1,22 @@
***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

24
test/commits/21-restore-crossover-15.script

@ -0,0 +1,24 @@
# 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

22
test/commits/21-restore-crossover-15.script.expected

@ -0,0 +1,22 @@
***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

24
test/commits/21-restore-crossover-16.script

@ -0,0 +1,24 @@
# 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

22
test/commits/21-restore-crossover-16.script.expected

@ -0,0 +1,22 @@
***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

24
test/commits/21-restore-crossover-17.script

@ -0,0 +1,24 @@
# 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

22
test/commits/21-restore-crossover-17.script.expected

@ -0,0 +1,22 @@
***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

581
test/test_protocol.c

@ -11,6 +11,7 @@
#include <ccan/tal/tal.h> #include <ccan/tal/tal.h>
#include <ccan/tal/str/str.h> #include <ccan/tal/str/str.h>
#include <inttypes.h> #include <inttypes.h>
#include <signal.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -47,6 +48,9 @@ struct commit_info {
bool revoked; bool revoked;
/* Have their signature, ie. can be broadcast */ /* Have their signature, ie. can be broadcast */
bool counterparty_signed; 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. */ /* A "signature" is a copy of the commit tx state, for easy diagnosis. */
@ -202,6 +206,20 @@ static struct commit_tx make_commit_tx(struct htlc **htlcs, int local_or_remote)
return tx; 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 { struct peer {
const char *name; const char *name;
@ -210,6 +228,9 @@ struct peer {
/* For drawing svg */ /* For drawing svg */
char *info; char *info;
/* What we save on disk. */
struct database db;
/* All htlcs. */ /* All htlcs. */
struct htlc **htlcs; struct htlc **htlcs;
@ -217,6 +238,61 @@ struct peer {
struct commit_info *local, *remote; 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 peer *peer,
struct database *db,
const struct commit_info *ci,
struct signature sig)
{
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,
const struct commit_info *ci)
{
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) static struct htlc *find_htlc(struct peer *peer, unsigned int htlc_id, int side)
{ {
size_t i, n = tal_count(peer->htlcs); size_t i, n = tal_count(peer->htlcs);
@ -247,6 +323,7 @@ static struct htlc *new_htlc(struct peer *peer, unsigned int htlc_id, int side)
static void htlc_changestate(struct peer *peer, static void htlc_changestate(struct peer *peer,
struct htlc *htlc, struct htlc *htlc,
bool commit,
enum htlc_state old, enum htlc_state old,
enum htlc_state new) enum htlc_state new)
{ {
@ -267,13 +344,15 @@ static void htlc_changestate(struct peer *peer,
htlc_statename(new)); htlc_statename(new));
} }
htlc->state = new; htlc->state = new;
if (commit)
db_update_htlc(&peer->db, htlc);
} }
struct state_table { struct state_table {
enum htlc_state from, to; enum htlc_state from, to;
}; };
static bool change_htlcs_(struct peer *peer, static bool change_htlcs_(struct peer *peer, bool commit,
const struct state_table *table, const struct state_table *table,
size_t n_table) size_t n_table)
{ {
@ -284,7 +363,7 @@ static bool change_htlcs_(struct peer *peer,
size_t t; size_t t;
for (t = 0; t < n_table; t++) { for (t = 0; t < n_table; t++) {
if (peer->htlcs[i]->state == table[t].from) { if (peer->htlcs[i]->state == table[t].from) {
htlc_changestate(peer, peer->htlcs[i], htlc_changestate(peer, peer->htlcs[i], commit,
table[t].from, table[t].to); table[t].from, table[t].to);
changed = true; changed = true;
break; break;
@ -294,8 +373,8 @@ static bool change_htlcs_(struct peer *peer,
return changed; return changed;
} }
#define change_htlcs(peer, table) \ #define change_htlcs(peer, table, commit) \
change_htlcs_((peer), (table), ARRAY_SIZE(table)) change_htlcs_((peer), (commit), (table), ARRAY_SIZE(table))
static struct commit_info *new_commit_info(const struct peer *peer, static struct commit_info *new_commit_info(const struct peer *peer,
struct commit_info *prev) struct commit_info *prev)
@ -305,6 +384,8 @@ static struct commit_info *new_commit_info(const struct peer *peer,
ci->prev = prev; ci->prev = prev;
ci->revoked = false; ci->revoked = false;
ci->counterparty_signed = false; ci->counterparty_signed = false;
ci->pad = 0;
ci->order = 0;
if (prev) if (prev)
ci->number = prev->number + 1; ci->number = prev->number + 1;
else else
@ -433,6 +514,14 @@ static void PRINTF_FMT(2,3) record_send(struct peer *peer, const char *fmt, ...)
tal_append_vfmt(&peer->info, fmt, ap); tal_append_vfmt(&peer->info, fmt, ap);
tal_append_fmt(&peer->info, "\n"); tal_append_fmt(&peer->info, "\n");
va_end(ap); 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, ...) static void PRINTF_FMT(2,3) record_recv(struct peer *peer, const char *fmt, ...)
@ -444,16 +533,56 @@ static void PRINTF_FMT(2,3) record_recv(struct peer *peer, const char *fmt, ...)
tal_append_vfmt(&peer->info, fmt, ap); tal_append_vfmt(&peer->info, fmt, ap);
tal_append_fmt(&peer->info, "\n"); tal_append_fmt(&peer->info, "\n");
va_end(ap); 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) static void send_offer(struct peer *peer, unsigned int htlc)
{ {
struct htlc *h = new_htlc(peer, htlc, OURS); struct htlc *h = new_htlc(peer, htlc, OURS);
htlc_changestate(peer, h, NONEXISTENT, SENT_ADD_HTLC); htlc_changestate(peer, h, false, NONEXISTENT, SENT_ADD_HTLC);
record_send(peer, "add_htlc %u", htlc); xmit_add_htlc(peer, h);
write_out(peer->outfd, "+", 1);
write_out(peer->outfd, &htlc, sizeof(htlc));
} }
static void send_remove(struct peer *peer, unsigned int htlc) static void send_remove(struct peer *peer, unsigned int htlc)
@ -461,22 +590,19 @@ static void send_remove(struct peer *peer, unsigned int htlc)
struct htlc *h = find_htlc(peer, htlc, THEIRS); struct htlc *h = find_htlc(peer, htlc, THEIRS);
if (!h) if (!h)
errx(1, "send_remove: htlc %u does not exist", htlc); errx(1, "%s: send_remove: htlc %u does not exist",
peer->name, htlc);
htlc_changestate(peer, h, RECV_ADD_ACK_REVOCATION, SENT_REMOVE_HTLC);
record_send(peer, "fulfill_htlc %u", htlc); htlc_changestate(peer, h, false, RECV_ADD_ACK_REVOCATION, SENT_REMOVE_HTLC);
write_out(peer->outfd, "-", 1); xmit_remove_htlc(peer, h);
write_out(peer->outfd, &htlc, sizeof(htlc));
} }
static void send_feechange(struct peer *peer) static void send_feechange(struct peer *peer)
{ {
struct htlc *fee = new_htlc(peer, 0, OURS); struct htlc *fee = new_htlc(peer, 0, OURS);
htlc_changestate(peer, fee, NONEXISTENT, SENT_ADD_HTLC); htlc_changestate(peer, fee, false, NONEXISTENT, SENT_ADD_HTLC);
record_send(peer, "update_fee"); xmit_feechange(peer);
write_out(peer->outfd, "F", 1);
} }
/* /*
@ -501,8 +627,9 @@ static struct commit_info *last_unrevoked(struct commit_info *ci)
static void send_commit(struct peer *peer) static void send_commit(struct peer *peer)
{ {
struct commit_tx tx;
struct signature sig; struct signature sig;
struct commit_tx commit_tx;
static const struct state_table changes[] = { static const struct state_table changes[] = {
{ SENT_ADD_HTLC, SENT_ADD_COMMIT }, { SENT_ADD_HTLC, SENT_ADD_COMMIT },
{ SENT_REMOVE_REVOCATION, SENT_REMOVE_ACK_COMMIT }, { SENT_REMOVE_REVOCATION, SENT_REMOVE_ACK_COMMIT },
@ -517,17 +644,7 @@ static void send_commit(struct peer *peer)
* previous `update_commit`, so there is only ever one * previous `update_commit`, so there is only ever one
* unrevoked local commitment. */ * unrevoked local commitment. */
if (peer->remote->prev && !peer->remote->prev->revoked) if (peer->remote->prev && !peer->remote->prev->revoked)
errx(1, "commit: must wait for previous commit"); errx(1, "%s: commit: must wait for previous commit", peer->name);
record_send(peer, "update_commit");
/* BOLT #2:
*
* A node MUST NOT send an `update_commit` message which does
* not include any updates.
*/
if (!change_htlcs(peer, changes))
errx(1, "commit: no changes to commit");
/* BOLT #2: /* BOLT #2:
* *
@ -535,15 +652,23 @@ static void send_commit(struct peer *peer)
* changes except unacked fee changes to the remote commitment * changes except unacked fee changes to the remote commitment
* before generating `sig`. * before generating `sig`.
*/ */
commit_tx = make_commit_tx(peer->htlcs, REMOTE_); if (!change_htlcs(peer, changes, true)) {
/* BOLT #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 = new_commit_info(peer, peer->remote);
peer->remote->counterparty_signed = true; peer->remote->counterparty_signed = true;
sig = commit_sig(&commit_tx); db_send_remote_commit(peer, &peer->db, peer->remote, sig);
/* Tell other side about commit and result (it should agree!) */ /* Tell other side about commit and result (it should agree!) */
write_out(peer->outfd, "C", 1); xmit_commit(peer, sig);
write_out(peer->outfd, &sig, sizeof(sig));
} }
static void receive_revoke(struct peer *peer, u32 number) static void receive_revoke(struct peer *peer, u32 number)
@ -557,22 +682,29 @@ static void receive_revoke(struct peer *peer, u32 number)
struct commit_info *ci = last_unrevoked(peer->remote); struct commit_info *ci = last_unrevoked(peer->remote);
if (!ci) if (!ci)
errx(1, "receive_revoke: no commit to revoke"); errx(1, "%s: receive_revoke: no commit to revoke", peer->name);
if (ci->number != number) if (ci->number != number)
errx(1, "receive_revoke: revoked %u but %u is next", errx(1, "%s: receive_revoke: revoked %u but %u is next",
number, ci->number); peer->name, number, ci->number);
/* This shouldn't happen if we don't allow multiple commits. */ /* This shouldn't happen if we don't allow multiple commits. */
if (ci != peer->remote->prev) if (ci != peer->remote->prev)
errx(1, "receive_revoke: always revoke previous?"); 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"); record_recv(peer, "update_revocation");
ci->revoked = true; ci->revoked = true;
if (!ci->counterparty_signed) if (!ci->counterparty_signed)
errx(1, "receive_revoke: revoked unsigned commit?"); 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);
if (!change_htlcs(peer, changes)) db_recv_remote_revoke(&peer->db, ci);
errx(1, "receive_revoke: no changes?");
} }
/* BOLT #2: /* BOLT #2:
@ -584,7 +716,7 @@ static void receive_offer(struct peer *peer, unsigned int htlc)
{ {
struct htlc *h = new_htlc(peer, htlc, THEIRS); struct htlc *h = new_htlc(peer, htlc, THEIRS);
htlc_changestate(peer, h, NONEXISTENT, RECV_ADD_HTLC); htlc_changestate(peer, h, false, NONEXISTENT, RECV_ADD_HTLC);
record_recv(peer, "add_htlc %u", h->id); record_recv(peer, "add_htlc %u", h->id);
} }
@ -598,9 +730,10 @@ static void receive_remove(struct peer *peer, unsigned int htlc)
struct htlc *h = find_htlc(peer, htlc, OURS); struct htlc *h = find_htlc(peer, htlc, OURS);
if (!h) if (!h)
errx(1, "recv_remove: htlc %u does not exist", htlc); errx(1, "%s: recv_remove: htlc %u does not exist",
peer->name, htlc);
htlc_changestate(peer, h, SENT_ADD_ACK_REVOCATION, RECV_REMOVE_HTLC); htlc_changestate(peer, h, false, SENT_ADD_ACK_REVOCATION, RECV_REMOVE_HTLC);
record_recv(peer, "fulfill_htlc %u", h->id); record_recv(peer, "fulfill_htlc %u", h->id);
} }
@ -613,7 +746,7 @@ static void receive_feechange(struct peer *peer)
{ {
struct htlc *fee = new_htlc(peer, 0, THEIRS); struct htlc *fee = new_htlc(peer, 0, THEIRS);
htlc_changestate(peer, fee, NONEXISTENT, RECV_ADD_HTLC); htlc_changestate(peer, fee, false, NONEXISTENT, RECV_ADD_HTLC);
record_recv(peer, "update_fee"); record_recv(peer, "update_fee");
} }
@ -628,7 +761,6 @@ static void send_revoke(struct peer *peer, struct commit_info *ci)
{ RECV_ADD_COMMIT, SENT_ADD_REVOCATION }, { RECV_ADD_COMMIT, SENT_ADD_REVOCATION },
{ RECV_REMOVE_ACK_COMMIT, SENT_REMOVE_ACK_REVOCATION } { RECV_REMOVE_ACK_COMMIT, SENT_REMOVE_ACK_REVOCATION }
}; };
record_send(peer, "update_revocation");
/* We always revoke in order. */ /* We always revoke in order. */
assert(!ci->prev || ci->prev->revoked); assert(!ci->prev || ci->prev->revoked);
@ -636,11 +768,11 @@ static void send_revoke(struct peer *peer, struct commit_info *ci)
assert(!ci->revoked); assert(!ci->revoked);
ci->revoked = true; ci->revoked = true;
if (!change_htlcs(peer, changes)) if (!change_htlcs(peer, changes, true))
errx(1, "update_revocation: no changes?"); errx(1, "%s: update_revocation: no changes?", peer->name);
write_out(peer->outfd, "R", 1); db_send_local_revoke(&peer->db, ci);
write_out(peer->outfd, &ci->number, sizeof(ci->number)); xmit_revoke(peer, ci->number);
} }
/* Receive commit: /* Receive commit:
@ -664,22 +796,135 @@ static void receive_commit(struct peer *peer, const struct signature *sig)
* A node MUST NOT send an `update_commit` message which does * A node MUST NOT send an `update_commit` message which does
* not include any updates. * not include any updates.
*/ */
if (!change_htlcs(peer, changes)) if (!change_htlcs(peer, changes, true))
errx(1, "receive_commit: no changes to commit"); errx(1, "%s: receive_commit: no changes to commit", peer->name);
commit_tx = make_commit_tx(peer->htlcs, LOCAL_); commit_tx = make_commit_tx(peer->htlcs, LOCAL_);
oursig = commit_sig(&commit_tx); oursig = commit_sig(&commit_tx);
if (!structeq(sig, &oursig)) if (!structeq(sig, &oursig))
errx(1, "Commit state %#x/%#x/%u, they gave %#x/%#x/%u", errx(1, "%s: Commit state %#x/%#x/%u, they gave %#x/%#x/%u",
peer->name,
sig->f.inhtlcs, sig->f.outhtlcs, sig->f.fee, sig->f.inhtlcs, sig->f.outhtlcs, sig->f.fee,
oursig.f.inhtlcs, oursig.f.outhtlcs, oursig.f.fee); oursig.f.inhtlcs, oursig.f.outhtlcs, oursig.f.fee);
peer->local = new_commit_info(peer, peer->local); peer->local = new_commit_info(peer, peer->local);
peer->local->counterparty_signed = true; peer->local->counterparty_signed = true;
db_recv_local_commit(&peer->db, peer->local);
send_revoke(peer, peer->local->prev); 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) static void do_cmd(struct peer *peer)
{ {
char cmd[80]; char cmd[80];
@ -729,6 +974,14 @@ static void do_cmd(struct peer *peer)
read_peer(peer, "C", cmd); read_peer(peer, "C", cmd);
read_in(peer->infd, &sig, sizeof(sig)); read_in(peer->infd, &sig, sizeof(sig));
receive_commit(peer, &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 */
read_all(peer->cmdfd, &peer->db, sizeof(peer->db));
restore_state(peer);
} else if (streq(cmd, "checksync")) { } else if (streq(cmd, "checksync")) {
struct commit_tx ours, theirs; struct commit_tx ours, theirs;
@ -779,6 +1032,8 @@ static void new_peer(const char *name,
peer->name = name; peer->name = name;
peer->htlcs = tal_arr(peer, struct htlc *, 0); peer->htlcs = tal_arr(peer, struct htlc *, 0);
memset(&peer->db, 0, sizeof(peer->db));
/* Create first, signed commit info. */ /* Create first, signed commit info. */
peer->local = new_commit_info(peer, NULL); peer->local = new_commit_info(peer, NULL);
peer->local->counterparty_signed = true; peer->local->counterparty_signed = true;
@ -786,6 +1041,9 @@ static void new_peer(const char *name,
peer->remote = new_commit_info(peer, NULL); peer->remote = new_commit_info(peer, NULL);
peer->remote->counterparty_signed = true; peer->remote->counterparty_signed = true;
peer->db.local = *peer->local;
peer->db.remote = *peer->remote;
peer->infd = infdpair[0]; peer->infd = infdpair[0];
peer->outfd = outfdpair[1]; peer->outfd = outfdpair[1];
peer->cmdfd = cmdfdpair[0]; peer->cmdfd = cmdfdpair[0];
@ -808,6 +1066,18 @@ static void add_sent(struct sent **sent, int y, const char *msg)
(*sent)[n].desc = tal_strdup(*sent, msg); (*sent)[n].desc = tal_strdup(*sent, msg);
} }
static void draw_restart(char **str, const char *name,
struct sent **a_sent, struct sent **b_sent,
int *y)
{
*y += STEP_HEIGHT / 2;
tal_append_fmt(str, "<line x1=\"%i\" y1=\"%i\" x2=\"%i\" y2=\"%i\" stroke=\"black\" stroke-width=\"1\"/>\n",
A_TEXTX - 50, *y, B_TEXTX + 50, *y);
tal_append_fmt(str, "<text text-anchor=\"middle\" "TEXT_STYLE" x=\"%i\" y=\"%i\">%s</text>\n",
(A_TEXTX + B_TEXTX) / 2, *y - TEXT_HEIGHT/2, name);
*y += STEP_HEIGHT / 2;
}
static void draw_line(char **str, static void draw_line(char **str,
int old_x, struct sent **sent, const char *what, int old_x, struct sent **sent, const char *what,
int new_x, int new_y) int new_x, int new_y)
@ -819,18 +1089,33 @@ static void draw_line(char **str,
if (!streq((*sent)->desc, what)) if (!streq((*sent)->desc, what))
errx(1, "Received %s but sent %s?", what, (*sent)->desc); errx(1, "Received %s but sent %s?", what, (*sent)->desc);
tal_append_fmt(str, "<line x1=\"%i\" y1=\"%i\" x2=\"%i\" y2=\"%i\" marker-end=\"url(#tri)\" stroke=\"black\" stroke-width=\"0.5\"/>\n", if (*str) {
old_x, (*sent)[0].y - LINE_HEIGHT/2, tal_append_fmt(str, "<line x1=\"%i\" y1=\"%i\" x2=\"%i\" y2=\"%i\" marker-end=\"url(#tri)\" stroke=\"black\" stroke-width=\"0.5\"/>\n",
new_x, new_y - LINE_HEIGHT/2); old_x, (*sent)[0].y - LINE_HEIGHT/2,
tal_append_fmt(str, "<text text-anchor=\"middle\" "TEXT_STYLE" x=\"%i\" y=\"%i\">%s</text>\n", new_x, new_y - LINE_HEIGHT/2);
(old_x + new_x) / 2, tal_append_fmt(str, "<text text-anchor=\"middle\" "TEXT_STYLE" x=\"%i\" y=\"%i\">%s</text>\n",
((*sent)[0].y + new_y) / 2, (old_x + new_x) / 2,
(*sent)[0].desc); ((*sent)[0].y + new_y) / 2,
(*sent)[0].desc);
}
memmove(*sent, (*sent)+1, sizeof(**sent) * (n-1)); memmove(*sent, (*sent)+1, sizeof(**sent) * (n-1));
tal_resize(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, static bool append_text(char **svg, bool is_a, int *y, const char *text,
size_t *max_chars) size_t *max_chars)
{ {
@ -872,16 +1157,17 @@ static bool process_output(char **svg, bool is_a, const char *output,
else else
draw_line(svg, A_LINEX, a_sent, outputs[i]+1, draw_line(svg, A_LINEX, a_sent, outputs[i]+1,
B_LINEX, *y); B_LINEX, *y);
*y += STEP_HEIGHT;
} else if (strstarts(outputs[i], ">")) { } else if (strstarts(outputs[i], ">")) {
if (is_a) if (is_a)
add_sent(a_sent, *y, outputs[i]+1); add_sent(a_sent, *y, outputs[i]+1);
else else
add_sent(b_sent, *y, outputs[i]+1); add_sent(b_sent, *y, outputs[i]+1);
*y += STEP_HEIGHT;
} else { } else {
append_text(svg, is_a, y, outputs[i], max_chars); append_text(svg, is_a, y, outputs[i], max_chars);
} }
} }
*y += STEP_HEIGHT;
return true; return true;
} }
@ -904,6 +1190,81 @@ static void get_output(int donefd, char **svg, bool is_a,
process_output(svg, is_a, output, a_sent, b_sent, y, max_chars); 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)
{
}
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[]) int main(int argc, char *argv[])
{ {
char cmd[80], *svg; char cmd[80], *svg;
@ -931,24 +1292,22 @@ int main(int argc, char *argv[])
else else
svg = NULL; svg = NULL;
if (pipe(a_to_b) || pipe(b_to_a) || pipe(adonefd) || pipe(acmd)) #if 1
err(1, "Creating pipes"); {
struct sigaction alarmed, old;
new_peer("A", a_to_b, b_to_a, acmd, adonefd);
if (pipe(bdonefd) || pipe(bcmd)) memset(&alarmed, 0, sizeof(alarmed));
err(1, "Creating pipes"); alarmed.sa_flags = SA_RESETHAND;
alarmed.sa_handler = do_nothing;
new_peer("B", b_to_a, a_to_b, bcmd, bdonefd); if (sigaction(SIGALRM, &alarmed, &old) != 0)
err(1, "Setting alarm handler");
}
#else
signal(SIGALRM, do_nothing);
#endif
close(acmd[0]); start_clients(a_to_b, b_to_a, acmd, bcmd, adonefd, bdonefd);
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]);
while (fgets(cmd, sizeof(cmd), stdin)) { while (fgets(cmd, sizeof(cmd), stdin)) {
int cmdfd, donefd; int cmdfd, donefd;
@ -974,19 +1333,60 @@ int main(int argc, char *argv[])
continue; continue;
} else if (streq(cmd, "checksync")) { } else if (streq(cmd, "checksync")) {
struct commit_tx fa_us, fa_them, fb_us, fb_them; struct commit_tx fa_us, fa_them, fb_us, fb_them;
if (!write_all(acmd[1], cmd, strlen(cmd)+1) write_to_client("A", acmd[1], cmd, strlen(cmd)+1);
|| !write_all(bcmd[1], cmd, strlen(cmd)+1)) write_to_client("B", bcmd[1], cmd, strlen(cmd)+1);
errx(1, "Failed writing command to peers"); read_from_client("A", adonefd[0], &fa_us, sizeof(fa_us));
alarm(5); read_from_client("B", bdonefd[0], &fb_us, sizeof(fb_us));
if (!read_all(adonefd[0], &fa_us, sizeof(fa_us)) read_from_client("A", adonefd[0],
|| !read_all(adonefd[0], &fa_them, sizeof(fa_them)) &fa_them, sizeof(fa_them));
|| !read_all(bdonefd[0], &fb_us, sizeof(fb_us)) read_from_client("A", bdonefd[0],
|| !read_all(bdonefd[0], &fb_them, sizeof(fb_them))) &fb_them, sizeof(fb_them));
errx(1, "Failed reading status from peers");
if (!structeq(&fa_us, &fb_them) if (!structeq(&fa_us, &fb_them)
|| !structeq(&fa_them, &fb_us)) || !structeq(&fa_them, &fb_us))
errx(1, "checksync: not equal"); errx(1, "checksync: not equal");
continue; continue;
} else if (streq(cmd, "restart")) {
struct database a_db, b_db;
char ack;
if (svg)
draw_restart(&svg, "RESTART",
&a_sent, &b_sent, &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",
&a_sent, &b_sent, &y);
continue;
} else if (strstarts(cmd, "#") || streq(cmd, "")) } else if (strstarts(cmd, "#") || streq(cmd, ""))
continue; continue;
else else
@ -996,22 +1396,13 @@ int main(int argc, char *argv[])
if (svg && strstarts(cmd+2, "dump")) if (svg && strstarts(cmd+2, "dump"))
continue; continue;
if (!write_all(cmdfd, cmd+2, strlen(cmd)-1)) write_to_client(cmd, cmdfd, cmd+2, strlen(cmd)-1);
errx(1, "Sending %s", cmd);
get_output(donefd, &svg, strstarts(cmd, "A:"), get_output(donefd, &svg, strstarts(cmd, "A:"),
&a_sent, &b_sent, &y, &max_chars); &a_sent, &b_sent, &y, &max_chars);
} }
write_all(acmd[1], "", 1); stop_clients(acmd, bcmd, adonefd, bdonefd);
write_all(bcmd[1], "", 1);
/* Make sure they've finished */
alarm(5);
if (read_all(adonefd[0], &y, 1)
|| read_all(bdonefd[0], &y, 1))
errx(1, "Response after sending exit command");
alarm(0);
if (svg) if (svg)
printf("<svg width=\"%zu\" height=\"%u\">\n" printf("<svg width=\"%zu\" height=\"%u\">\n"

Loading…
Cancel
Save