From 388dfc355ec23f2073633eab913de0baea3c5fcb Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 17 May 2016 13:49:32 +0930 Subject: [PATCH] test/test_protocol: add fee support. We simply record how many fee changes there are, rather than supporting a particular level. Fees are tricky: it's a noop to apply them when incoming, but we apply them when they've been acked. Unlike HTLC modifications, which are symmetric, fee updates only apply when returning to the originating node. Signed-off-by: Rusty Russell --- test/commits/13-fee.script | 13 ++++ test/commits/13-fee.script.expected | 24 ++++++ test/commits/14-fee-twice.script | 15 ++++ test/commits/14-fee-twice.script.expected | 24 ++++++ test/commits/15-fee-twice-back-to-back.script | 25 +++++++ .../15-fee-twice-back-to-back.script.expected | 69 ++++++++++++++++++ test/test_protocol.c | 73 +++++++++++++++---- 7 files changed, 229 insertions(+), 14 deletions(-) create mode 100644 test/commits/13-fee.script create mode 100644 test/commits/13-fee.script.expected create mode 100644 test/commits/14-fee-twice.script create mode 100644 test/commits/14-fee-twice.script.expected create mode 100644 test/commits/15-fee-twice-back-to-back.script create mode 100644 test/commits/15-fee-twice-back-to-back.script.expected diff --git a/test/commits/13-fee.script b/test/commits/13-fee.script new file mode 100644 index 000000000..e040104fa --- /dev/null +++ b/test/commits/13-fee.script @@ -0,0 +1,13 @@ +# 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 new file mode 100644 index 000000000..fae6d983b --- /dev/null +++ b/test/commits/13-fee.script.expected @@ -0,0 +1,24 @@ +***A*** +OUR COMMITS: + Commit 1: + Offered htlcs: + Received htlcs: + Fee level 1 + SIGNED +THEIR COMMITS: + Commit 1: + Offered htlcs: + Received htlcs: + SIGNED +***B*** +OUR COMMITS: + Commit 1: + Offered htlcs: + Received htlcs: + SIGNED +THEIR COMMITS: + Commit 1: + Offered htlcs: + Received htlcs: + Fee level 1 + SIGNED diff --git a/test/commits/14-fee-twice.script b/test/commits/14-fee-twice.script new file mode 100644 index 000000000..738edf44a --- /dev/null +++ b/test/commits/14-fee-twice.script @@ -0,0 +1,15 @@ +# 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 new file mode 100644 index 000000000..c94cc5e0a --- /dev/null +++ b/test/commits/14-fee-twice.script.expected @@ -0,0 +1,24 @@ +***A*** +OUR COMMITS: + Commit 1: + Offered htlcs: + Received htlcs: + Fee level 2 + SIGNED +THEIR COMMITS: + Commit 1: + Offered htlcs: + Received htlcs: + SIGNED +***B*** +OUR COMMITS: + Commit 1: + Offered htlcs: + Received htlcs: + SIGNED +THEIR COMMITS: + Commit 1: + Offered htlcs: + Received htlcs: + Fee level 2 + SIGNED diff --git a/test/commits/15-fee-twice-back-to-back.script b/test/commits/15-fee-twice-back-to-back.script new file mode 100644 index 000000000..db67a8e1e --- /dev/null +++ b/test/commits/15-fee-twice-back-to-back.script @@ -0,0 +1,25 @@ +# Test committing fees before receiving previous revocation. +A:feechange +A:commit +A:feechange +A:commit +echo ***A after two commits with fee changes*** +A:dump +B:recvfeechange +echo ***B after receiving fee change*** +B:dump +B:recvcommit +echo ***B after receiving first commit*** +B:dump +B:recvfeechange +B:recvcommit +echo ***B after receiving second commit*** +B:dump +A:recvrevoke +A:recvrevoke +B:commit +A:recvcommit +B:recvrevoke +echo ***B after committing*** +B:dump +checksync diff --git a/test/commits/15-fee-twice-back-to-back.script.expected b/test/commits/15-fee-twice-back-to-back.script.expected new file mode 100644 index 000000000..9288957be --- /dev/null +++ b/test/commits/15-fee-twice-back-to-back.script.expected @@ -0,0 +1,69 @@ +***A after two commits with fee changes*** +OUR COMMITS: + Commit 0: + Offered htlcs: + Received htlcs: + SIGNED +THEIR COMMITS: + Commit 0: + Offered htlcs: + Received htlcs: + Pending incoming: FEE + SIGNED + Commit 1: + Offered htlcs: + Received htlcs: + Pending incoming: FEE + SIGNED + Commit 2: + Offered htlcs: + Received htlcs: + SIGNED +***B after receiving fee change*** +OUR COMMITS: + Commit 0: + Offered htlcs: + Received htlcs: + Pending incoming: FEE + SIGNED +THEIR COMMITS: + Commit 0: + Offered htlcs: + Received htlcs: + SIGNED +***B after receiving first commit*** +OUR COMMITS: + Commit 1: + Offered htlcs: + Received htlcs: + SIGNED +THEIR COMMITS: + Commit 0: + Offered htlcs: + Received htlcs: + Pending outgoing: FEE + SIGNED +***B after receiving second commit*** +OUR COMMITS: + Commit 2: + Offered htlcs: + Received htlcs: + SIGNED +THEIR COMMITS: + Commit 0: + Offered htlcs: + Received htlcs: + Pending outgoing: FEE FEE + SIGNED +***B after committing*** +OUR COMMITS: + Commit 2: + Offered htlcs: + Received htlcs: + SIGNED +THEIR COMMITS: + Commit 1: + Offered htlcs: + Received htlcs: + Fee level 2 + SIGNED diff --git a/test/test_protocol.c b/test/test_protocol.c index 210a43928..959f9444c 100644 --- a/test/test_protocol.c +++ b/test/test_protocol.c @@ -16,6 +16,8 @@ struct funding { /* 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. */ @@ -64,9 +66,10 @@ static bool add_change_internal(struct commit_info *ci, int **changes, int c) { size_t i, n = tal_count(*changes); - - if (!c) - errx(1, "INTERNAL: Adding zero change?"); + + /* You can have as many fee changes as you like */ + if (c == 0) + goto add; /* Can't add/remove it already there/absent. */ if (c > 0 && have_htlc(*add, c)) @@ -79,6 +82,7 @@ static bool add_change_internal(struct commit_info *ci, int **changes, if ((*changes)[i] == c) return false; +add: tal_resize(changes, n+1); (*changes)[n] = c; return true; @@ -127,15 +131,18 @@ static struct commit_info *new_commit_info(const tal_t *ctx, } /* Each side can add their own incoming HTLC, or close your outgoing HTLC. */ -static void do_change(u32 *add, u32 *remove, int htlc) +static void do_change(u32 *add, u32 *remove, u32 *fees, int htlc) { - if (htlc < 0) { + /* We ignore fee changes from them: they only count when reflected + * back to us via revocation. */ + if (htlc == 0) { + if (fees) + (*fees)++; + } else if (htlc < 0) { if (!have_htlc(*remove, -htlc)) errx(1, "Already removed htlc %u", -htlc); *remove &= ~htlc_mask(-htlc); } else { - if (htlc == 0) - errx(1, "zero change?"); if (have_htlc(*add, htlc)) errx(1, "Already added htlc %u", htlc); *add |= htlc_mask(htlc); @@ -154,6 +161,7 @@ static struct commit_info *apply_changes(const tal_t *ctx, for (i = 0; i < n; i++) do_change(&ci->funding.inhtlcs, &ci->funding.outhtlcs, + NULL, old->changes_incoming[i]); /* Changes we offered. */ @@ -161,6 +169,7 @@ static struct commit_info *apply_changes(const tal_t *ctx, for (i = 0; i < n; i++) do_change(&ci->funding.outhtlcs, &ci->funding.inhtlcs, + &ci->funding.fee, old->changes_outgoing[i]); return ci; @@ -198,18 +207,30 @@ static void dump_commit_info(const struct commit_info *ci) printf("\n Received htlcs:"); dump_htlcs(ci->funding.inhtlcs); + /* Don't clutter output if fee level untouched. */ + if (ci->funding.fee) + printf("\n Fee level %u", ci->funding.fee); + n = tal_count(ci->changes_incoming); if (n > 0) { printf("\n Pending incoming:"); - for (i = 0; i < n; i++) - printf(" %+i", ci->changes_incoming[i]); + for (i = 0; i < n; i++) { + if (ci->changes_incoming[i] == 0) + printf(" FEE"); + else + printf(" %+i", ci->changes_incoming[i]); + } } n = tal_count(ci->changes_outgoing); if (n > 0) { printf("\n Pending outgoing:"); - for (i = 0; i < n; i++) - printf(" %+i", ci->changes_outgoing[i]); + for (i = 0; i < n; i++) { + if (ci->changes_outgoing[i] == 0) + printf(" FEE"); + else + printf(" %+i", ci->changes_outgoing[i]); + } } if (ci->counterparty_signed) @@ -279,6 +300,16 @@ static void send_remove(struct peer *peer, unsigned int htlc) write_out(peer->outfd, &htlc, sizeof(htlc)); } +/* Fee change: + * - Record the change to them (but don't ever apply it!). + */ +static void send_feechange(struct peer *peer) +{ + if (!add_incoming_change(peer->them, 0)) + errx(1, "INTERNAL: failed to change fee"); + write_out(peer->outfd, "F", 1); +} + /* FIXME: * We don't enforce the rule that commits have to wait for revoke response * before the next one. It might be simpler if we did? @@ -363,6 +394,15 @@ static void receive_remove(struct peer *peer, unsigned int htlc) errx(1, "receive_remove: already removed %u", htlc); } +/* Receives fee change: + * - Record the change to us (but never apply it). + */ +static void receive_feechange(struct peer *peer) +{ + if (!add_incoming_change(peer->us, 0)) + errx(1, "INTERNAL: failed to change fee"); +} + /* Send revoke. * - Queue changes to them. */ @@ -401,9 +441,9 @@ static void receive_commit(struct peer *peer, const struct signature *sig) peer->us = apply_changes(peer, peer->us); oursig = commit_sig(peer->us); if (!structeq(sig, &oursig)) - errx(1, "Commit state %#x/%#x, they gave %#x/%#x", - sig->f.inhtlcs, sig->f.outhtlcs, - oursig.f.inhtlcs, oursig.f.outhtlcs); + errx(1, "Commit state %#x/%#x/%u, they gave %#x/%#x/%u", + sig->f.inhtlcs, sig->f.outhtlcs, sig->f.fee, + oursig.f.inhtlcs, oursig.f.outhtlcs, oursig.f.fee); peer->us->counterparty_signed = true; send_revoke(peer, peer->us->prev); } @@ -429,6 +469,8 @@ static void do_cmd(struct peer *peer) 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")) { @@ -444,6 +486,9 @@ static void do_cmd(struct peer *peer) 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);