forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dualopend.c
4541 lines (3960 loc) · 135 KB
/
dualopend.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*~ Welcome to the ~nifty~ dual-opening daemon: the other gateway to channels!
*
* This daemon handles a single peer. It's happy to trade gossip with the
* peer until either lightningd asks it to fund a channel, or the peer itself
* asks to fund a channel. Then it goes through with the channel opening
* negotiations. It's important to note that until this negotiation is complete,
* there's nothing permanent about the channel: lightningd will only have to
* commit to the database once dualopend succeeds.
*
* Much like the original opening daemon, openingd, dualopend implements the
* new and improved, two-party opening protocol, which allows bother peers to
* contribute inputs to the transaction
*/
#include "config.h"
#include <bitcoin/script.h>
#include <ccan/array_size/array_size.h>
#include <ccan/cast/cast.h>
#include <ccan/mem/mem.h>
#include <ccan/tal/str/str.h>
#include <common/billboard.h>
#include <common/blockheight_states.h>
#include <common/channel_type.h>
#include <common/gossip_store.h>
#include <common/initial_channel.h>
#include <common/lease_rates.h>
#include <common/memleak.h>
#include <common/peer_billboard.h>
#include <common/peer_failed.h>
#include <common/peer_io.h>
#include <common/peer_status_wiregen.h>
#include <common/per_peer_state.h>
#include <common/psbt_internal.h>
#include <common/psbt_open.h>
#include <common/read_peer_msg.h>
#include <common/setup.h>
#include <common/status.h>
#include <common/subdaemon.h>
#include <common/wire_error.h>
#include <errno.h>
#include <hsmd/hsmd_wiregen.h>
#include <openingd/common.h>
#include <openingd/dualopend_wiregen.h>
#include <unistd.h>
#include <wire/wire_sync.h>
/* stdin == lightningd, 3 == peer, 4 = hsmd */
#define REQ_FD STDIN_FILENO
#define HSM_FD 4
/* tx_add_input, tx_add_output, tx_rm_input, tx_rm_output */
#define NUM_TX_MSGS (TX_RM_OUTPUT + 1)
enum tx_msgs {
TX_ADD_INPUT,
TX_ADD_OUTPUT,
TX_RM_INPUT,
TX_RM_OUTPUT,
};
/*
* BOLT #2:
* The maximum inputs and outputs are capped at 252. This effectively fixes
* the byte size of the input and output counts on the transaction to one (1).
*/
#define MAX_TX_MSG_RCVD (1 << 12)
/*
* BOLT #2:
* The receiving node: ...
* - MUST fail the negotiation if: ...
* - there are more than 252 inputs
* - there are more than 252 outputs
*/
#define MAX_FUNDING_INPUTS 252
#define MAX_FUNDING_OUTPUTS 252
/* State for a 'new' funding transaction. There should be one
* for every new funding transaction attempt */
struct tx_state {
/* Funding and feerate: set by opening peer. */
struct amount_sat opener_funding;
struct amount_sat accepter_funding;
u32 tx_locktime;
u32 feerate_per_kw_funding;
struct bitcoin_outpoint funding;
/* This is a cluster of fields in open_channel and accept_channel which
* indicate the restrictions each side places on the channel. */
struct channel_config localconf, remoteconf;
/* PSBT of the funding tx */
struct wally_psbt *psbt;
/* Set of pending changes to send to peer */
struct psbt_changeset *changeset;
/* The serial_id of the funding output */
u64 funding_serial;
/* Track how many of each tx collab msg we receive */
u16 tx_msg_count[NUM_TX_MSGS];
/* Have we gotten the peer's tx-sigs yet? */
bool remote_funding_sigs_rcvd;
/* Have we gotten the peer's commitments yet? */
bool has_commitments;
/* Rates that we're using for this open... */
struct lease_rates *rates;
/* Lease blockheight start */
u32 blockheight;
/* If delay til the channel funds lease expires */
u32 lease_expiry;
/* Total fee for lease */
struct amount_sat lease_fee;
/* Lease's commit sig */
secp256k1_ecdsa_signature *lease_commit_sig;
/* Lease's commited chan max msat */
u32 lease_chan_max_msat;
/* Lease's commited chan max ppt */
u16 lease_chan_max_ppt;
};
static struct tx_state *new_tx_state(const tal_t *ctx)
{
struct tx_state *tx_state = tal(ctx, struct tx_state);
tx_state->psbt = NULL;
tx_state->remote_funding_sigs_rcvd = false;
tx_state->has_commitments = false;
tx_state->lease_expiry = 0;
tx_state->lease_fee = AMOUNT_SAT(0);
tx_state->blockheight = 0;
tx_state->lease_commit_sig = NULL;
tx_state->lease_chan_max_msat = 0;
tx_state->lease_chan_max_ppt = 0;
/* no max_htlc_dust_exposure on remoteconf, we exclusively use the local's */
tx_state->remoteconf.max_dust_htlc_exposure_msat = AMOUNT_MSAT(0);
for (size_t i = 0; i < NUM_TX_MSGS; i++)
tx_state->tx_msg_count[i] = 0;
return tx_state;
}
/* Global state structure. This is only for the one specific peer and channel */
struct state {
struct per_peer_state *pps;
/* --developer? */
bool developer;
/* Features they offered */
u8 *their_features;
/* Constraints on a channel they open. */
u32 minimum_depth;
struct amount_msat min_effective_htlc_capacity;
/* Limits on what remote config we accept. */
u32 max_to_self_delay;
/* These are the points lightningd told us to use when accepting or
* opening a channel. */
struct basepoints our_points;
struct pubkey our_funding_pubkey;
struct pubkey their_funding_pubkey;
/* Information we need between funding_start and funding_complete */
struct basepoints their_points;
/* hsmd gives us our first+second per-commitment points, and peer tells us
* theirs */
struct pubkey first_per_commitment_point[NUM_SIDES];
struct pubkey second_per_commitment_point[NUM_SIDES];
struct channel_id channel_id;
u8 channel_flags;
enum tx_role our_role;
u32 feerate_per_kw_commitment;
/* If non-NULL, this is the scriptpubkey we/they *must* close with */
u8 *upfront_shutdown_script[NUM_SIDES];
/* If non-NULL, the wallet index for the LOCAL script */
u32 *local_upfront_shutdown_wallet_index;
/* The channel structure, as defined in common/initial_channel.h. While
* the structure has room for HTLCs, those routines are
* channeld-specific as initial channels never have HTLCs. */
struct channel *channel;
/* Channel type we agreed on (even before channel populated) */
struct channel_type *channel_type;
struct feature_set *our_features;
/* Tally of which sides are locked, or not */
bool channel_ready[NUM_SIDES];
/* Are we shutting down? */
bool shutdown_sent[NUM_SIDES];
/* Were we reconnected at start ? */
bool reconnected;
/* Did we send tx-abort? */
const char *aborted_err;
/* State of inflight funding transaction attempt */
struct tx_state *tx_state;
/* Amount of leased sats requested, persisted across
* RBF attempts, so we know when we've messed up lol */
struct amount_sat *requested_lease;
/* Does this negotation require confirmed inputs? */
bool require_confirmed_inputs[NUM_SIDES];
/* Our alias */
struct short_channel_id local_alias;
bool dev_accept_any_channel_type;
};
/* psbt_changeset_get_next - Get next message to send
*
* This generates the next message to send from a changeset for the
* interactive transaction protocol.
*
* @ctx - allocation context of returned msg
* @cid - channel_id for the message
* @set - changeset to get next update from
*
* Returns a wire message or NULL if no changes.
*/
static u8 *psbt_changeset_get_next(const tal_t *ctx,
struct channel_id *cid,
struct psbt_changeset *set)
{
u64 serial_id;
u8 *msg;
if (tal_count(set->added_ins) != 0) {
const struct input_set *in = &set->added_ins[0];
if (!psbt_get_serial_id(&in->input.unknowns, &serial_id))
abort();
const u8 *prevtx = linearize_wtx(ctx,
in->input.utxo);
msg = towire_tx_add_input(ctx, cid, serial_id,
prevtx, in->input.index,
in->input.sequence,
NULL);
tal_arr_remove(&set->added_ins, 0);
return msg;
}
if (tal_count(set->rm_ins) != 0) {
if (!psbt_get_serial_id(&set->rm_ins[0].input.unknowns,
&serial_id))
abort();
msg = towire_tx_remove_input(ctx, cid, serial_id);
tal_arr_remove(&set->rm_ins, 0);
return msg;
}
if (tal_count(set->added_outs) != 0) {
struct amount_sat sats;
struct amount_asset asset_amt;
const struct output_set *out = &set->added_outs[0];
if (!psbt_get_serial_id(&out->output.unknowns, &serial_id))
abort();
asset_amt = wally_psbt_output_get_amount(&out->output);
sats = amount_asset_to_sat(&asset_amt);
const u8 *script = wally_psbt_output_get_script(ctx,
&out->output);
msg = towire_tx_add_output(ctx, cid, serial_id,
sats.satoshis, /* Raw: wire interface */
script);
tal_arr_remove(&set->added_outs, 0);
return msg;
}
if (tal_count(set->rm_outs) != 0) {
if (!psbt_get_serial_id(&set->rm_outs[0].output.unknowns,
&serial_id))
abort();
msg = towire_tx_remove_output(ctx, cid, serial_id);
/* Is this a kosher way to move the list forward? */
tal_arr_remove(&set->rm_outs, 0);
return msg;
}
return NULL;
}
static void dualopen_shutdown(struct state *state)
{
u8 *msg = towire_dualopend_shutdown_complete(state);
wire_sync_write(REQ_FD, msg);
per_peer_state_fdpass_send(REQ_FD, state->pps);
status_debug("Sent %s with fds",
dualopend_wire_name(fromwire_peektype(msg)));
/* Give master a chance to pass the fd along */
sleep(1);
/* This frees the entire tal tree. */
tal_free(state);
daemon_shutdown();
exit(0);
}
static bool shutdown_complete(const struct state *state)
{
return state->shutdown_sent[LOCAL]
&& state->shutdown_sent[REMOTE];
}
/* They failed the open with us */
static void negotiation_aborted(struct state *state, const char *why, bool aborted)
{
status_debug("aborted opening negotiation: %s", why);
/* Tell master that funding failed (don't disconnect if we aborted) */
peer_failed_received_errmsg(state->pps, !aborted, why);
}
/* Softer version of 'warning' (we don't disconnect)
* Only valid iff *we* haven't sent tx-sigs for a in-progress
* negotiation */
static void open_abort(struct state *state,
const char *fmt, ...)
{
va_list ap;
const char *errmsg;
u8 *msg;
va_start(ap, fmt);
errmsg = tal_vfmt(NULL, fmt, ap);
va_end(ap);
status_debug("aborted open negotiation, tx-abort: %s", errmsg);
/*~ The "billboard" (exposed as "status" in the JSON listpeers RPC
* call) is a transient per-channel area which indicates important
* information about what is happening. It has a "permanent" area for
* each state, which can be used to indicate what went wrong in that
* state (such as here), and a single transient area for current
* status. */
peer_billboard(true, errmsg);
msg = towire_tx_abort(NULL, &state->channel_id,
(u8 *)tal_dup_arr(tmpctx, char, errmsg,
strlen(errmsg), 0));
peer_write(state->pps, take(msg));
/* We're now in aborted mode, all
* subsequent msgs will be dropped */
if (!state->aborted_err)
state->aborted_err = tal_steal(state, errmsg);
else
tal_free(errmsg);
}
static void open_err_warn(struct state *state,
const char *fmt, ...)
{
va_list ap;
const char *errmsg;
va_start(ap, fmt);
errmsg = tal_vfmt(tmpctx, fmt, ap);
va_end(ap);
status_debug("aborted open negotiation, warn: %s", errmsg);
peer_failed_warn(state->pps, &state->channel_id, "%s", errmsg);
}
static void open_err_fatal(struct state *state,
const char *fmt, ...)
{
va_list ap;
const char *errmsg;
va_start(ap, fmt);
errmsg = tal_vfmt(tmpctx, fmt, ap);
va_end(ap);
status_debug("aborted open negotiation, fatal: %s", errmsg);
peer_failed_err(state->pps, &state->channel_id, "%s", errmsg);
}
/*~ For negotiation failures: we tell them the parameter we didn't like. */
static void negotiation_failed(struct state *state,
const char *fmt, ...)
{
va_list ap;
const char *errmsg;
va_start(ap, fmt);
errmsg = tal_vfmt(tmpctx, fmt, ap);
va_end(ap);
open_abort(state, "You gave bad parameters: %s", errmsg);
}
static void billboard_update(struct state *state)
{
const char *update = billboard_message(tmpctx, state->channel_ready,
NULL,
state->shutdown_sent,
0, /* Always zero? */
0);
peer_billboard(false, update);
}
static void lock_signer_outpoint(const struct bitcoin_outpoint *outpoint)
{
const u8 *msg;
bool is_buried = false;
/* FIXME(vincenzopalazzo): Sleeping in a deamon of cln should be never fine
* howerver the core deamon of cln will never trigger the sleep.
*
* I think that the correct solution for this is a timer base solution, but this
* required to implement all the timers in the deamon. */
do {
/* Make sure the hsmd agrees that this outpoint is
* sufficiently buried. */
msg = towire_hsmd_check_outpoint(NULL, &outpoint->txid, outpoint->n);
wire_sync_write(HSM_FD, take(msg));
msg = wire_sync_read(tmpctx, HSM_FD);
if (!fromwire_hsmd_check_outpoint_reply(msg, &is_buried))
status_failed(STATUS_FAIL_HSM_IO,
"Bad hsmd_check_outpoint_reply: %s",
tal_hex(tmpctx, msg));
/* the signer should have a shorter buried height requirement so
* it almost always will be ready ahead of us.*/
if (!is_buried)
sleep(10);
} while (!is_buried);
/* tell the signer that we are now locked */
msg = towire_hsmd_lock_outpoint(NULL, &outpoint->txid, outpoint->n);
wire_sync_write(HSM_FD, take(msg));
msg = wire_sync_read(tmpctx, HSM_FD);
if (!fromwire_hsmd_lock_outpoint_reply(msg))
status_failed(STATUS_FAIL_HSM_IO,
"Bad hsmd_lock_outpoint_reply: %s",
tal_hex(tmpctx, msg));
}
/* Call this method when channel_ready status are changed. */
static void check_mutual_channel_ready(const struct state *state)
{
if (state->channel_ready[LOCAL] && state->channel_ready[REMOTE])
lock_signer_outpoint(&state->channel->funding);
}
static void send_shutdown(struct state *state, const u8 *final_scriptpubkey)
{
u8 *msg;
/* FIXME: send wrong_funding */
msg = towire_shutdown(NULL, &state->channel_id,
final_scriptpubkey, NULL);
peer_write(state->pps, take(msg));
state->shutdown_sent[LOCAL] = true;
}
static void handle_peer_shutdown(struct state *state, u8 *msg)
{
u8 *scriptpubkey;
struct channel_id cid;
struct tlv_shutdown_tlvs *tlvs;
if (!fromwire_shutdown(tmpctx, msg, &cid, &scriptpubkey, &tlvs))
open_err_fatal(state, "Bad shutdown %s", tal_hex(msg, msg));
if (tal_count(state->upfront_shutdown_script[REMOTE])
&& !tal_arr_eq(scriptpubkey, state->upfront_shutdown_script[REMOTE]))
open_err_fatal(state,
"scriptpubkey %s is not as agreed upfront (%s)",
tal_hex(state, scriptpubkey),
tal_hex(state,
state->upfront_shutdown_script[REMOTE]));
/* @niftynei points out that negotiated this together, so this
* hack is not required (or safe!). */
if (tlvs->wrong_funding)
open_err_fatal(state,
"wrong_funding shutdown"
" invalid for dual-funding");
wire_sync_write(REQ_FD,
take(towire_dualopend_got_shutdown(NULL,
scriptpubkey)));
msg = wire_sync_read(tmpctx, REQ_FD);
if (!fromwire_dualopend_send_shutdown(tmpctx, msg, &scriptpubkey))
master_badmsg(fromwire_peektype(msg), msg);
state->shutdown_sent[REMOTE] = true;
if (!state->shutdown_sent[LOCAL])
send_shutdown(state, scriptpubkey);
billboard_update(state);
}
static void handle_our_shutdown(struct state *state, u8 *msg)
{
u8 *scriptpubkey;
if (!fromwire_dualopend_send_shutdown(tmpctx, msg, &scriptpubkey))
master_badmsg(fromwire_peektype(msg), msg);
if (!state->shutdown_sent[LOCAL])
send_shutdown(state, scriptpubkey);
billboard_update(state);
}
static void handle_failure_fatal(struct state *state, u8 *msg)
{
char *err;
if (!fromwire_dualopend_fail(msg, msg, &err))
master_badmsg(fromwire_peektype(msg), msg);
/* We're gonna fail here */
open_err_fatal(state, "%s", err);
}
static void check_channel_id(struct state *state,
struct channel_id *id_in,
struct channel_id *orig_id)
{
if (!channel_id_eq(id_in, orig_id))
open_err_fatal(state, "channel ids don't match."
" expected %s, got %s",
fmt_channel_id(tmpctx,
orig_id),
fmt_channel_id(tmpctx,
id_in));
}
/* BOLT #2:
* The receiving node:
*...
* - MUST fail the negotiation if:
*...
* - the `sats` amount is less than the `dust_limit`
*/
static bool is_dust(struct tx_state *tx_state,
struct amount_sat amount)
{
return amount_sat_less(amount, tx_state->localconf.dust_limit)
|| amount_sat_less(amount, tx_state->remoteconf.dust_limit);
}
static char *validate_inputs(struct state *state,
struct tx_state *tx_state,
enum tx_role role_to_validate)
{
/* BOLT #2:
* Upon receipt of consecutive `tx_complete`s, the receiving node:
* ...
* - if it has sent `require_confirmed_inputs` in `open_channel2`,
* `accept_channel2`, `tx_init_rbf` or `tx_ack_rbf`:
* - MUST fail the negotiation if:
* - one of the inputs added by the other peer is unconfirmed
*/
u8 *msg;
char *err_reason;
msg = towire_dualopend_validate_inputs(NULL, tx_state->psbt,
role_to_validate);
wire_sync_write(REQ_FD, take(msg));
msg = wire_sync_read(tmpctx, REQ_FD);
if (!fromwire_dualopend_validate_inputs_reply(msg)) {
if (!fromwire_dualopend_fail(tmpctx, msg, &err_reason))
master_badmsg(fromwire_peektype(msg), msg);
return err_reason;
}
return NULL;
}
static void set_reserve(struct tx_state *tx_state,
struct amount_sat funding_total,
enum tx_role our_role)
{
struct amount_sat reserve, dust_limit;
/* BOLT #2:
*
* Instead, the channel reserve is fixed at 1% of the total
* channel balance (`open_channel2`.`funding_satoshis` +
* `accept_channel2`.`funding_satoshis`) rounded down to the
* nearest whole satoshi or the `dust_limit_satoshis`, whichever is
* greater.
*/
reserve = amount_sat_div(funding_total, 100);
dust_limit = our_role == TX_INITIATOR ?
tx_state->localconf.dust_limit :
tx_state->remoteconf.dust_limit;
if (amount_sat_greater(dust_limit, reserve)) {
tx_state->remoteconf.channel_reserve = dust_limit;
tx_state->localconf.channel_reserve = dust_limit;
} else {
tx_state->remoteconf.channel_reserve = reserve;
tx_state->localconf.channel_reserve = reserve;
}
}
static bool is_openers(const struct wally_map *unknowns)
{
/* BOLT #2:
* The sending node: ...
* - if is the *initiator*:
* - MUST send even `serial_id`s
* - if is the *non-initiator*:
* - MUST send odd `serial_id`s
*/
u64 serial_id;
if (!psbt_get_serial_id(unknowns, &serial_id))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"PSBTs must have serial_ids set");
return serial_id % 2 == TX_INITIATOR;
}
static bool find_txout(struct wally_psbt *psbt, const u8 *wscript, u32 *funding_txout)
{
for (size_t i = 0; i < psbt->num_outputs; i++) {
if (memeq(wscript, tal_bytelen(wscript), psbt->outputs[i].script,
psbt->outputs[i].script_len)) {
*funding_txout = i;
return true;
}
}
return false;
}
static char *insufficient_err_msg(const tal_t *ctx,
char *error,
struct wally_psbt *psbt)
{
return tal_fmt(tmpctx, "Insufficiently funded funding tx, %s. %s",
error, fmt_wally_psbt(tmpctx, psbt));
}
static char *check_balances(const tal_t *ctx,
struct state *state,
struct tx_state *tx_state,
struct wally_psbt *psbt,
u32 feerate_per_kw_funding)
{
struct amount_sat initiator_inputs, initiator_outs,
accepter_inputs, accepter_outs,
tot_input_amt, tot_output_amt,
initiator_fee, accepter_fee,
initiator_diff, accepter_diff;
bool ok;
u32 funding_outnum = psbt->num_outputs;
size_t accepter_weight = 0;
/* BOLT #2:
*
* The *initiator* is responsible for paying the fees for the
* following fields, to be referred to as the `common fields`.
* - version
* - segwit marker + flag
* - input count
* - output count
* - locktime
*/
size_t initiator_weight =
bitcoin_tx_core_weight(psbt->num_inputs,
psbt->num_outputs);
u8 *funding_wscript =
bitcoin_redeem_2of2(tmpctx,
&state->our_funding_pubkey,
&state->their_funding_pubkey);
/*
* BOLT #2:
* The receiving node: ...
* - MUST fail the negotiation if: ...
* - there are more than 252 inputs
*/
if (tx_state->psbt->num_inputs > MAX_FUNDING_INPUTS)
return tal_fmt(ctx,
"Too many inputs. Have %zu,"
" Max allowed %u",
tx_state->psbt->num_inputs,
MAX_FUNDING_INPUTS);
/*
* BOLT #2:
* The receiving node: ...
* - MUST fail the negotiation if: ...
* - there are more than 252 outputs
*/
if (tx_state->psbt->num_outputs > MAX_FUNDING_OUTPUTS)
return tal_fmt(ctx, "Too many inputs. Have %zu,"
" Max allowed %u",
tx_state->psbt->num_outputs,
MAX_FUNDING_OUTPUTS);
/* Find funding output, check balance */
if (find_txout(psbt,
scriptpubkey_p2wsh(tmpctx, funding_wscript),
&funding_outnum)) {
struct amount_sat output_val, total_funding;
output_val = psbt_output_get_amount(psbt,
funding_outnum);
if (!amount_sat_add(&total_funding,
tx_state->accepter_funding,
tx_state->opener_funding)) {
return insufficient_err_msg(ctx,
"overflow adding desired funding",
tx_state->psbt);
}
/* BOLT #2:
*
* Upon receipt of consecutive `tx_complete`s, the receiving
* node:
* - if is the *accepter*:
* - MUST fail the negotiation if: ...
* - the value of the funding output is not equal to the
* sum of `open_channel2`.`funding_satoshis`
* and `accept_channel2`. `funding_satoshis`
*/
if (!amount_sat_eq(total_funding, output_val))
return insufficient_err_msg(ctx,
tal_fmt(tmpctx, "total desired funding %s != "
"funding output %s",
fmt_amount_sat(tmpctx,
total_funding),
fmt_amount_sat(tmpctx,
output_val)),
tx_state->psbt);
/* BOLT #2:
*
* Upon receipt of consecutive `tx_complete`s, the receiving
* node:
* - if is the *accepter*:
* - MUST fail the negotiation if: ...
* - the value of the funding output is
* less than the `dust_limit`
*/
if (is_dust(tx_state, output_val))
return insufficient_err_msg(ctx, "funding output is dust",
tx_state->psbt);
} else {
/* BOLT #2:
*
* Upon receipt of consecutive `tx_complete`s, the receiving
* node:
* - if is the *accepter*:
* - MUST fail the negotiation if:
* - no funding output was received
*/
return insufficient_err_msg(ctx, "funding output not present",
tx_state->psbt);
}
/* Find the total input and output sums */
tot_input_amt = AMOUNT_SAT(0);
initiator_inputs = AMOUNT_SAT(0);
accepter_inputs = AMOUNT_SAT(0);
for (size_t i = 0; i < psbt->num_inputs; i++) {
struct amount_sat amt =
psbt_input_get_amount(psbt, i);
/* Add to total balance check */
if (!amount_sat_add(&tot_input_amt,
tot_input_amt, amt)) {
return insufficient_err_msg(ctx,
"overflow adding input total",
tx_state->psbt);
}
if (is_openers(&psbt->inputs[i].unknowns)) {
/* If the above additon passed,
* this should also */
ok = amount_sat_add(&initiator_inputs,
initiator_inputs, amt);
assert(ok);
initiator_weight +=
psbt_input_get_weight(psbt, i);
} else {
ok = amount_sat_add(&accepter_inputs,
accepter_inputs, amt);
assert(ok);
accepter_weight +=
psbt_input_get_weight(psbt, i);
}
}
tot_output_amt = AMOUNT_SAT(0);
initiator_outs = tx_state->opener_funding;
accepter_outs = tx_state->accepter_funding;
/* The lease_fee has been added to the accepter_funding,
* but the opener_funding is responsible for covering it,
* so we do a little switcheroo here */
if (!amount_sat_add(&initiator_outs, initiator_outs,
tx_state->lease_fee))
return insufficient_err_msg(ctx, "overflow adding lease_fee"
" to initiator's funding",
tx_state->psbt);
if (!amount_sat_sub(&accepter_outs, accepter_outs,
tx_state->lease_fee))
return insufficient_err_msg(ctx, "unable to subtract lease_fee"
" from accepter's funding",
tx_state->psbt);
for (size_t i = 0; i < psbt->num_outputs; i++) {
struct amount_sat amt =
psbt_output_get_amount(psbt, i);
/* Add to total balance check */
if (!amount_sat_add(&tot_output_amt,
tot_output_amt, amt)) {
return insufficient_err_msg(ctx,
"overflow adding output total",
tx_state->psbt);
}
/* BOLT #2:
* The receiving node:
* ...
* - MUST fail the negotiation if:
* ...
* - the `sats` amount is less than the `dust_limit`
*/
if (is_dust(tx_state, amt))
return insufficient_err_msg(ctx, "output is dust",
tx_state->psbt);
if (is_openers(&psbt->outputs[i].unknowns)) {
/* Don't add the funding output to
* the amount */
if (i != funding_outnum) {
/* If the above additon passed,
* this should also */
ok = amount_sat_add(&initiator_outs,
initiator_outs,
amt);
assert(ok);
}
initiator_weight +=
psbt_output_get_weight(psbt, i);
} else {
ok = amount_sat_add(&accepter_outs,
accepter_outs, amt);
assert(ok);
accepter_weight +=
psbt_output_get_weight(psbt, i);
}
}
/* BOLT #2:
* The receiving node:
* ...
* - MUST fail the negotiation if:
* ...
* - the peer's total input satoshis is less than their outputs
*/
/* We check both, why not? */
if (!amount_sat_greater_eq(initiator_inputs, initiator_outs)) {
return insufficient_err_msg(ctx,
tal_fmt(tmpctx, "initiator inputs"
" less than outputs (%s < %s)"
" (lease fee %s)",
fmt_amount_sat(tmpctx,
initiator_inputs),
fmt_amount_sat(tmpctx,
initiator_outs),
fmt_amount_sat(tmpctx,
tx_state->lease_fee)),
tx_state->psbt);
}
/* BOLT #2:
* The receiving node: ...
* - MUST fail the negotiation if:
* ...
* - the peer's paid feerate does not meet or exceed the
* agreed `feerate` (based on the `minimum fee`).
* - if is the *non-initiator*:
* - the *initiator*'s fees do not cover the `common` fields
*/
if (!amount_sat_sub(&accepter_diff, accepter_inputs,
accepter_outs)) {
return insufficient_err_msg(ctx,
tal_fmt(tmpctx, "accepter inputs"
" %s less than outputs %s"
" (lease fee %s)",
fmt_amount_sat(tmpctx,
accepter_inputs),
fmt_amount_sat(tmpctx,
accepter_outs),
fmt_amount_sat(tmpctx,
tx_state->lease_fee)),
tx_state->psbt);
}
if (!amount_sat_sub(&initiator_diff, initiator_inputs,
initiator_outs)) {
return insufficient_err_msg(ctx,
"initiator inputs less than outputs",
tx_state->psbt);
}
/* BOLT #2:
* The receiving node: ...
* - MUST fail the negotiation if:
* ...
* - the peer's paid feerate does not meet or exceed the
* agreed `feerate` (based on the `minimum fee`).
*/
accepter_fee = amount_tx_fee(feerate_per_kw_funding,
accepter_weight);
initiator_fee = amount_tx_fee(feerate_per_kw_funding,
initiator_weight);
if (!amount_sat_greater_eq(accepter_diff, accepter_fee))
return insufficient_err_msg(ctx,
tal_fmt(ctx, "accepter fee not covered"
" (need %s > have %s)",
fmt_amount_sat(ctx,
accepter_fee),
fmt_amount_sat(ctx,
accepter_diff)),
tx_state->psbt);
if (!amount_sat_greater_eq(initiator_diff, initiator_fee))
return insufficient_err_msg(ctx,
tal_fmt(ctx, "initiator fee %s"
" (%zux%d) not covered %s",
fmt_amount_sat(ctx,
initiator_fee),
initiator_weight,
feerate_per_kw_funding,
fmt_amount_sat(ctx,
initiator_diff)),
tx_state->psbt);
return NULL;
}
/*
* BOLT #2:
* The receiving node: ...
* - MUST fail the negotiation if: ...
* - the `scriptPubKey` of the `prevtx_vout` output
* of `prevtx` is not exactly a 1-byte push opcode
* (for the numeric values `0` to `16`) followed
* by a data push between 2 and 40 bytes
*/
static bool is_segwit_output(const struct wally_tx_output *output)
{
const u8 *script = output->script;