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 <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2016-05-17 13:49:32 +09:30
parent 056c219bc1
commit 388dfc355e
7 changed files with 229 additions and 14 deletions

View File

@@ -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);