Skip to content

Commit e8e96e6

Browse files
committed
commit_tx: make interface side-agnostic.
It's currently written to produce "local" commit-txs, but of course we need to produce remote ones too, for signing. Thus instead of using "remote" and "local" we use "other" and "self", and indicate with a single "side" flag which we're generating (because that changes how HTLCs are interpreted). This also adds to the tests: generate the remote view of the commit_tx and make sure it matches! Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent 068cdc8 commit e8e96e6

File tree

3 files changed

+177
-41
lines changed

3 files changed

+177
-41
lines changed

lightningd/commit_tx.c

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ u64 commit_number_obscurer(const struct pubkey *opener_payment_basepoint,
3333
return be64_to_cpu(obscurer);
3434
}
3535

36-
static void subtract_fee(enum side funder,
37-
u64 base_fee_msat, u64 *local_msat, u64 *remote_msat)
36+
static void subtract_fee(enum side funder, enum side side,
37+
u64 base_fee_msat, u64 *self_msat, u64 *other_msat)
3838
{
3939
u64 *funder_msat;
4040

41-
if (funder == LOCAL)
42-
funder_msat = local_msat;
41+
if (funder == side)
42+
funder_msat = self_msat;
4343
else
44-
funder_msat = remote_msat;
44+
funder_msat = other_msat;
4545

4646
if (*funder_msat >= base_fee_msat)
4747
*funder_msat -= base_fee_msat;
@@ -97,7 +97,7 @@ static const struct htlc **untrimmed(const tal_t *ctx,
9797
*/
9898
arr = tal_arr(ctx, const struct htlc *, tal_count(htlcs));
9999
for (i = n = 0; i < tal_count(htlcs); i++) {
100-
if (htlc_owner(htlcs[i]) != side)
100+
if (htlc_owner(htlcs[i]) != side)
101101
continue;
102102
if (htlcs[i]->msatoshi / 1000 < dust_limit_satoshis + htlc_fee)
103103
continue;
@@ -146,34 +146,35 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx,
146146
enum side funder,
147147
u16 to_self_delay,
148148
const struct pubkey *revocation_pubkey,
149-
const struct pubkey *local_delayedkey,
150-
const struct pubkey *localkey,
151-
const struct pubkey *remotekey,
149+
const struct pubkey *self_delayedkey,
150+
const struct pubkey *selfkey,
151+
const struct pubkey *otherkey,
152152
u64 feerate_per_kw,
153153
u64 dust_limit_satoshis,
154-
u64 local_pay_msat,
155-
u64 remote_pay_msat,
154+
u64 self_pay_msat,
155+
u64 other_pay_msat,
156156
const struct htlc **htlcs,
157157
const struct htlc ***htlcmap,
158-
u64 obscured_commitment_number)
158+
u64 obscured_commitment_number,
159+
enum side side)
159160
{
160161
const tal_t *tmpctx = tal_tmpctx(ctx);
161162
const struct htlc **offered, **received;
162163
u64 base_fee_msat;
163164
struct bitcoin_tx *tx;
164165
size_t i, n;
165166

166-
assert(local_pay_msat + remote_pay_msat <= funding_satoshis * 1000);
167+
assert(self_pay_msat + other_pay_msat <= funding_satoshis * 1000);
167168

168169
/* BOLT #3:
169170
*
170171
* 1. Calculate which committed HTLCs need to be trimmed (see
171172
* [Trimmed Outputs](#trimmed-outputs)).
172173
*/
173-
offered = untrimmed(tmpctx, htlcs, LOCAL,
174+
offered = untrimmed(tmpctx, htlcs, side,
174175
htlc_timeout_fee(feerate_per_kw),
175176
dust_limit_satoshis);
176-
received = untrimmed(tmpctx, htlcs, REMOTE,
177+
received = untrimmed(tmpctx, htlcs, !side,
177178
htlc_success_fee(feerate_per_kw),
178179
dust_limit_satoshis);
179180

@@ -195,7 +196,8 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx,
195196
* 3. Subtract this base fee from the funder (either `to-local` or
196197
* `to-remote`), with a floor of zero (see [Fee Payment](#fee-payment)).
197198
*/
198-
subtract_fee(funder, base_fee_msat, &local_pay_msat, &remote_pay_msat);
199+
subtract_fee(funder, side, base_fee_msat,
200+
&self_pay_msat, &other_pay_msat);
199201

200202
/* Worst-case sizing: both to-local and to-remote outputs. */
201203
tx = bitcoin_tx(ctx, 1, tal_count(offered) + tal_count(received) + 2);
@@ -211,7 +213,7 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx,
211213
n = 0;
212214
for (i = 0; i < tal_count(offered); i++, n++) {
213215
u8 *wscript = bitcoin_wscript_htlc_offer(tmpctx,
214-
localkey, remotekey,
216+
selfkey, otherkey,
215217
&offered[i]->rhash);
216218
tx->output[n].amount = offered[i]->msatoshi / 1000;
217219
tx->output[n].script = scriptpubkey_p2wsh(tx, wscript);
@@ -229,7 +231,7 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx,
229231
for (i = 0; i < tal_count(received); i++, n++) {
230232
u8 *wscript = bitcoin_wscript_htlc_receive(tmpctx,
231233
&received[i]->expiry,
232-
localkey, remotekey,
234+
selfkey, otherkey,
233235
&received[i]->rhash);
234236
tx->output[n].amount = received[i]->msatoshi / 1000;
235237
tx->output[n].script = scriptpubkey_p2wsh(tx, wscript);
@@ -245,12 +247,12 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx,
245247
* `dust-limit-satoshis`, add a [To-Local
246248
* Output](#to-local-output).
247249
*/
248-
if (local_pay_msat / 1000 >= dust_limit_satoshis) {
250+
if (self_pay_msat / 1000 >= dust_limit_satoshis) {
249251
u8 *wscript = bitcoin_wscript_to_local(tmpctx,
250252
to_self_delay,
251253
revocation_pubkey,
252-
local_delayedkey);
253-
tx->output[n].amount = local_pay_msat / 1000;
254+
self_delayedkey);
255+
tx->output[n].amount = self_pay_msat / 1000;
254256
tx->output[n].script = scriptpubkey_p2wsh(tx, wscript);
255257
(*htlcmap)[n] = NULL;
256258
SUPERVERBOSE("# to-local amount %"PRIu64" wscript %s\n",
@@ -265,20 +267,20 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx,
265267
* `dust-limit-satoshis`, add a [To-Remote
266268
* Output](#to-remote-output).
267269
*/
268-
if (remote_pay_msat / 1000 >= dust_limit_satoshis) {
270+
if (other_pay_msat / 1000 >= dust_limit_satoshis) {
269271
/* BOLT #3:
270272
*
271273
* #### To-Remote Output
272274
*
273275
* This output sends funds to the other peer, thus is a simple
274276
* P2WPKH to `remotekey`.
275277
*/
276-
tx->output[n].amount = remote_pay_msat / 1000;
277-
tx->output[n].script = scriptpubkey_p2wpkh(tx, remotekey);
278+
tx->output[n].amount = other_pay_msat / 1000;
279+
tx->output[n].script = scriptpubkey_p2wpkh(tx, otherkey);
278280
(*htlcmap)[n] = NULL;
279281
SUPERVERBOSE("# to-remote amount %"PRIu64" P2WPKH(%s)\n",
280282
tx->output[n].amount,
281-
type_to_string(tmpctx, struct pubkey, remotekey));
283+
type_to_string(tmpctx, struct pubkey, otherkey));
282284
n++;
283285
}
284286

lightningd/commit_tx.h

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,44 @@ u64 commit_number_obscurer(const struct pubkey *opener_payment_basepoint,
2020
u64 htlc_success_fee(u64 feerate_per_kw);
2121
u64 htlc_timeout_fee(u64 feerate_per_kw);
2222

23-
/* Create commitment tx to spend the funding tx output; doesn't fill in
24-
* input scriptsig. */
23+
/**
24+
* commit_tx: create (unsigned) commitment tx to spend the funding tx output
25+
* @ctx: context to allocate transaction and @htlc_map from.
26+
* @funding_txid, @funding_out, @funding_satoshis: funding outpoint.
27+
* @funder: is the LOCAL or REMOTE paying the fee?
28+
* @revocation_pubkey: revocation pubkey for this @side
29+
* @self_delayedey: pubkey for delayed payments to this @side
30+
* @selfkey: pubkey for HTLC payments to this @side
31+
* @otherkey: pubkey for direct and HTLC payments to other side @side
32+
* @feerate_per_kw: feerate to use
33+
* @dust_limit_satoshis: dust limit below which to trim outputs.
34+
* @self_pay_msat: amount to pay directly to self
35+
* @other_pay_msat: amount to pay directly to the other side
36+
* @htlcs: tal_arr of htlcs committed by transaction (some may be trimmed)
37+
* @htlc_map: outputed map of outnum->HTLC (NULL for direct outputs).
38+
* @obscured_commitment_number: number to encode in commitment transaction
39+
* @side: side to generate commitment transaction for.
40+
*
41+
* We need to be able to generate the remote side's tx to create signatures,
42+
* but the BOLT is expressed in terms of generating our local commitment
43+
* transaction, so we carefully use the terms "self" and "other" here.
44+
*/
2545
struct bitcoin_tx *commit_tx(const tal_t *ctx,
2646
const struct sha256_double *funding_txid,
2747
unsigned int funding_txout,
2848
u64 funding_satoshis,
2949
enum side funder,
3050
u16 to_self_delay,
3151
const struct pubkey *revocation_pubkey,
32-
const struct pubkey *local_delayedkey,
33-
const struct pubkey *localkey,
34-
const struct pubkey *remotekey,
52+
const struct pubkey *self_delayedkey,
53+
const struct pubkey *selfkey,
54+
const struct pubkey *otherkey,
3555
u64 feerate_per_kw,
3656
u64 dust_limit_satoshis,
37-
u64 local_pay_msat,
38-
u64 remote_pay_msat,
57+
u64 self_pay_msat,
58+
u64 other_pay_msat,
3959
const struct htlc **htlcs,
4060
const struct htlc ***htlcmap,
41-
u64 commit_number_obscurer);
61+
u64 obscured_commitment_number,
62+
enum side side);
4263
#endif /* LIGHTNING_LIGHTNINGD_COMMIT_TX_H */

lightningd/test/run-commit_tx.c

Lines changed: 121 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ static bool print_superverbose;
1111
#include <bitcoin/privkey.h>
1212
#include <bitcoin/pubkey.h>
1313
#include <ccan/array_size/array_size.h>
14+
#include <ccan/err/err.h>
1415
#include <ccan/str/hex/hex.h>
1516
#include <type_to_string.h>
1617

@@ -56,6 +57,45 @@ static struct privkey privkey_from_hex(const char *hex)
5657
return pk;
5758
}
5859

60+
static void tx_must_be_eq(const struct bitcoin_tx *a,
61+
const struct bitcoin_tx *b)
62+
{
63+
tal_t *tmpctx = tal_tmpctx(NULL);
64+
u8 *lina, *linb;
65+
size_t i, len;
66+
67+
lina = linearize_tx(tmpctx, a);
68+
linb = linearize_tx(tmpctx, b);
69+
70+
len = tal_len(lina);
71+
if (tal_len(linb) < len)
72+
len = tal_len(linb);
73+
74+
for (i = 0; i < tal_len(lina); i++) {
75+
if (i >= tal_len(linb))
76+
errx(1, "Second tx is truncated:\n"
77+
"%s\n"
78+
"%s",
79+
tal_hex(tmpctx, lina),
80+
tal_hex(tmpctx, linb));
81+
if (lina[i] != linb[i])
82+
errx(1, "tx differ at offset %zu:\n"
83+
"%s\n"
84+
"%s",
85+
i,
86+
tal_hex(tmpctx, lina),
87+
tal_hex(tmpctx, linb));
88+
}
89+
if (i != tal_len(linb))
90+
errx(1, "First tx is truncated:\n"
91+
"%s\n"
92+
"%s",
93+
tal_hex(tmpctx, lina),
94+
tal_hex(tmpctx, linb));
95+
96+
tal_free(tmpctx);
97+
}
98+
5999
/* BOLT #3:
60100
*
61101
* htlc 0 direction: remote->local
@@ -329,6 +369,25 @@ static u64 increase(u64 feerate_per_kw)
329369
}
330370
#endif
331371

372+
/* HTLCs as seen from other side. */
373+
static const struct htlc **invert_htlcs(const struct htlc **htlcs)
374+
{
375+
size_t i, n = tal_count(htlcs);
376+
const struct htlc **inv = tal_arr(htlcs, const struct htlc *, n);
377+
378+
for (i = 0; i < n; i++) {
379+
struct htlc *htlc;
380+
inv[i] = htlc = tal_dup(inv, struct htlc, htlcs[i]);
381+
if (inv[i]->state == RCVD_ADD_ACK_REVOCATION)
382+
htlc->state = SENT_ADD_ACK_REVOCATION;
383+
else {
384+
assert(inv[i]->state == SENT_ADD_ACK_REVOCATION);
385+
htlc->state = RCVD_ADD_ACK_REVOCATION;
386+
}
387+
}
388+
return inv;
389+
}
390+
332391
int main(void)
333392
{
334393
tal_t *tmpctx = tal_tmpctx(NULL);
@@ -351,11 +410,12 @@ int main(void)
351410
struct pubkey localkey, remotekey, tmpkey;
352411
struct pubkey local_delayedkey;
353412
struct pubkey local_revocation_key;
354-
struct bitcoin_tx *tx;
413+
struct bitcoin_tx *tx, *tx2;
355414
u8 *wscript;
356415
unsigned int funding_output_index;
357416
u64 commitment_number, cn_obscurer, to_local_msat, to_remote_msat;
358-
const struct htlc **htlcs = setup_htlcs(tmpctx), **htlc_map;
417+
const struct htlc **htlcs = setup_htlcs(tmpctx), **htlc_map, **htlc_map2,
418+
**inv_htlcs = invert_htlcs(htlcs);
359419

360420
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
361421
| SECP256K1_CONTEXT_SIGN);
@@ -593,7 +653,23 @@ int main(void)
593653
dust_limit_satoshi,
594654
to_local_msat,
595655
to_remote_msat,
596-
NULL, &htlc_map, commitment_number ^ cn_obscurer);
656+
NULL, &htlc_map, commitment_number ^ cn_obscurer,
657+
LOCAL);
658+
print_superverbose = false;
659+
tx2 = commit_tx(tmpctx, &funding_txid, funding_output_index,
660+
funding_amount_satoshi,
661+
REMOTE, to_self_delay,
662+
&local_revocation_key,
663+
&local_delayedkey,
664+
&localkey,
665+
&remotekey,
666+
feerate_per_kw,
667+
dust_limit_satoshi,
668+
to_local_msat,
669+
to_remote_msat,
670+
NULL, &htlc_map2, commitment_number ^ cn_obscurer,
671+
REMOTE);
672+
tx_must_be_eq(tx, tx2);
597673
report(tx, wscript, &x_remote_funding_privkey, &remote_funding_pubkey,
598674
&local_funding_privkey, &local_funding_pubkey,
599675
to_self_delay,
@@ -635,7 +711,24 @@ int main(void)
635711
dust_limit_satoshi,
636712
to_local_msat,
637713
to_remote_msat,
638-
htlcs, &htlc_map, commitment_number ^ cn_obscurer);
714+
htlcs, &htlc_map, commitment_number ^ cn_obscurer,
715+
LOCAL);
716+
print_superverbose = false;
717+
tx2 = commit_tx(tmpctx, &funding_txid, funding_output_index,
718+
funding_amount_satoshi,
719+
REMOTE, to_self_delay,
720+
&local_revocation_key,
721+
&local_delayedkey,
722+
&localkey,
723+
&remotekey,
724+
feerate_per_kw,
725+
dust_limit_satoshi,
726+
to_local_msat,
727+
to_remote_msat,
728+
inv_htlcs, &htlc_map2,
729+
commitment_number ^ cn_obscurer,
730+
REMOTE);
731+
tx_must_be_eq(tx, tx2);
639732
report(tx, wscript, &x_remote_funding_privkey, &remote_funding_pubkey,
640733
&local_funding_privkey, &local_funding_pubkey,
641734
to_self_delay,
@@ -665,7 +758,24 @@ int main(void)
665758
to_local_msat,
666759
to_remote_msat,
667760
htlcs, &htlc_map,
668-
commitment_number ^ cn_obscurer);
761+
commitment_number ^ cn_obscurer,
762+
LOCAL);
763+
/* This is what it would look like for peer generating it! */
764+
tx2 = commit_tx(tmpctx, &funding_txid, funding_output_index,
765+
funding_amount_satoshi,
766+
REMOTE, to_self_delay,
767+
&local_revocation_key,
768+
&local_delayedkey,
769+
&localkey,
770+
&remotekey,
771+
feerate_per_kw,
772+
dust_limit_satoshi,
773+
to_local_msat,
774+
to_remote_msat,
775+
inv_htlcs, &htlc_map2,
776+
commitment_number ^ cn_obscurer,
777+
REMOTE);
778+
tx_must_be_eq(newtx, tx2);
669779
#ifdef DEBUG
670780
if (feerate_per_kw % 100000 == 0)
671781
printf("feerate_per_kw = %"PRIu64", fees = %"PRIu64"\n",
@@ -697,7 +807,8 @@ int main(void)
697807
to_local_msat,
698808
to_remote_msat,
699809
htlcs, &htlc_map,
700-
commitment_number ^ cn_obscurer);
810+
commitment_number ^ cn_obscurer,
811+
LOCAL);
701812
report(tx, wscript,
702813
&x_remote_funding_privkey, &remote_funding_pubkey,
703814
&local_funding_privkey, &local_funding_pubkey,
@@ -733,7 +844,8 @@ int main(void)
733844
to_local_msat,
734845
to_remote_msat,
735846
htlcs, &htlc_map,
736-
commitment_number ^ cn_obscurer);
847+
commitment_number ^ cn_obscurer,
848+
LOCAL);
737849
report(newtx, wscript,
738850
&x_remote_funding_privkey, &remote_funding_pubkey,
739851
&local_funding_privkey, &local_funding_pubkey,
@@ -782,7 +894,8 @@ int main(void)
782894
to_local_msat,
783895
to_remote_msat,
784896
htlcs, &htlc_map,
785-
commitment_number ^ cn_obscurer);
897+
commitment_number ^ cn_obscurer,
898+
LOCAL);
786899
report(tx, wscript,
787900
&x_remote_funding_privkey, &remote_funding_pubkey,
788901
&local_funding_privkey, &local_funding_pubkey,

0 commit comments

Comments
 (0)