Skip to content

Commit bcf603c

Browse files
committed
WIP Commit
Work is still in progress!
1 parent a8b6647 commit bcf603c

8 files changed

Lines changed: 351 additions & 18 deletions

File tree

channeld/channeld.c

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,10 @@ static struct bitcoin_signature *calc_commitsigs(const tal_t *ctx,
955955
const u8 *msg;
956956
struct bitcoin_signature *htlc_sigs;
957957

958+
status_debug("calc_commitsigs(%p, %p, %p, %p, %p, %d, %p, %p)",
959+
ctx, peer, txs, funding_wscript, htlc_map,
960+
(int)commit_index, remote_per_commit, commit_sig);
961+
958962
htlcs = collect_htlcs(tmpctx, htlc_map);
959963
msg = towire_hsmd_sign_remote_commitment_tx(NULL, txs[0],
960964
&remote_funding_pubkey,
@@ -3308,7 +3312,7 @@ static struct amount_sat calc_balance(struct peer *peer)
33083312
}
33093313

33103314
/* Returns the total channel funding output amount if all checks pass.
3311-
* Otherwise, exits via peer_failed_warn. DTODO: Change to `tx_abort`. */
3315+
* Otherwise, exits via peer_failed_warn. */
33123316
static struct amount_sat check_balances(struct peer *peer,
33133317
enum tx_role our_role,
33143318
const struct wally_psbt *psbt,
@@ -3349,6 +3353,32 @@ static struct amount_sat check_balances(struct peer *peer,
33493353
"Unable to add HTLC balance");
33503354
}
33513355

3356+
status_debug("in[TX_INITIATOR] %s; in[TX_ACCEPTER] %s",
3357+
fmt_amount_m_as_sat(tmpctx, in[TX_INITIATOR]),
3358+
fmt_amount_m_as_sat(tmpctx, in[TX_ACCEPTER]));
3359+
3360+
/* Here in[*] only contains the amounts from this channel.
3361+
* This is a great opportunity to check their splice out amount does
3362+
* not exceed their channel funds as this is never allowed even if
3363+
* additional funds are otherwise contributed. */
3364+
if (!amount_msat_can_add_sat_s64(in[TX_INITIATOR],
3365+
peer->splicing->opener_relative)) {
3366+
splice_abort(peer, "Intiator is attempting to splice out"
3367+
" %"PRId64"sat funds out of channel while only "
3368+
"having %s funds attributable to them.",
3369+
peer->splicing->opener_relative,
3370+
fmt_amount_m_as_sat(tmpctx, in[TX_INITIATOR]));
3371+
}
3372+
if (!amount_msat_can_add_sat_s64(in[TX_ACCEPTER],
3373+
peer->splicing->accepter_relative)) {
3374+
splice_abort(peer, "Accepter is attempting to splice out"
3375+
" %"PRId64"sat funds out of channel while only "
3376+
"having %s funds attributable to them.",
3377+
peer->splicing->accepter_relative,
3378+
fmt_amount_m_as_sat(tmpctx, in[TX_ACCEPTER]));
3379+
}
3380+
3381+
/* Now add values from the other outputs */
33523382
for (size_t i = 0; i < psbt->num_inputs; i++)
33533383
if (i != chan_input_index)
33543384
add_amount_to_side(peer, in,
@@ -3402,6 +3432,11 @@ static struct amount_sat check_balances(struct peer *peer,
34023432
" %"PRIu64,
34033433
fmt_amount_msat(tmpctx, funding_amount),
34043434
peer->splicing->opener_relative);
3435+
3436+
status_debug("out[TX_INITIATOR] %s + %"PRId64,
3437+
fmt_amount_m_as_sat(tmpctx, out[TX_INITIATOR]),
3438+
peer->splicing->opener_relative);
3439+
34053440
if (!amount_msat_add_sat_s64(&out[TX_INITIATOR], out[TX_INITIATOR],
34063441
peer->splicing->opener_relative))
34073442
peer_failed_warn(peer->pps, &peer->channel_id,
@@ -3416,6 +3451,10 @@ static struct amount_sat check_balances(struct peer *peer,
34163451
peer_failed_warn(peer->pps, &peer->channel_id,
34173452
"Unable to add accepter funding to out amnt.");
34183453

3454+
status_debug("is in[TX_INITIATOR] %s less than out[TX_INITIATOR] %s?",
3455+
fmt_amount_m_as_sat(tmpctx, in[TX_INITIATOR]),
3456+
fmt_amount_m_as_sat(tmpctx, out[TX_INITIATOR]));
3457+
34193458
if (amount_msat_less(in[TX_INITIATOR], out[TX_INITIATOR])) {
34203459
msg = towire_channeld_splice_funding_error(NULL,
34213460
in[TX_INITIATOR],

channeld/full_channel.c

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,10 @@ struct bitcoin_tx **channel_txs(const tal_t *ctx,
324324
&channel->basepoints[side],
325325
&channel->basepoints[!side],
326326
channel_has(channel, OPT_STATIC_REMOTEKEY),
327-
&keyset))
327+
&keyset)) {
328+
status_broken("channel_txs fails to derive keyset");
328329
return NULL;
330+
}
329331

330332
/* Figure out what @side will already be committed to. */
331333
gather_htlcs(ctx, channel, side, &committed, NULL, NULL);
@@ -339,16 +341,54 @@ struct bitcoin_tx **channel_txs(const tal_t *ctx,
339341
side_pay = channel->view[side].owed[side];
340342
other_side_pay = channel->view[side].owed[!side];
341343

344+
status_debug("channel->view[REMOTE].owed[REMOTE] %s;"
345+
" channel->view[REMOTE].owed[LOCAL] %s;"
346+
" channel->view[LOCAL].owed[REMOTE] %s;"
347+
" channel->view[LOCAL].owed[LOCAL] %s;",
348+
fmt_amount_m_as_sat(tmpctx,
349+
channel->view[REMOTE].owed[REMOTE]),
350+
fmt_amount_m_as_sat(tmpctx,
351+
channel->view[REMOTE].owed[LOCAL]),
352+
fmt_amount_m_as_sat(tmpctx,
353+
channel->view[LOCAL].owed[REMOTE]),
354+
fmt_amount_m_as_sat(tmpctx,
355+
channel->view[LOCAL].owed[LOCAL]));
356+
342357
if (side == LOCAL) {
343-
if (!amount_msat_add_sat_s64(&side_pay, side_pay, splice_amnt))
358+
if (!amount_msat_add_sat_s64(&side_pay, side_pay, splice_amnt)) {
359+
status_broken("channel_txs fails to"
360+
" amount_msat_add_sat_s64 %s + %"PRId64
361+
" LOCAL (side_pay + splice_amnt)",
362+
fmt_amount_m_as_sat(tmpctx, side_pay),
363+
splice_amnt);
344364
return NULL;
345-
if (!amount_msat_add_sat_s64(&other_side_pay, other_side_pay, remote_splice_amnt))
365+
}
366+
if (!amount_msat_add_sat_s64(&other_side_pay, other_side_pay, remote_splice_amnt)) {
367+
status_broken("channel_txs fails to"
368+
" amount_msat_add_sat_s64 %s + %"PRId64
369+
" LOCAL (other_side_pay + remote_splice_amnt)",
370+
fmt_amount_m_as_sat(tmpctx, other_side_pay),
371+
remote_splice_amnt);
346372
return NULL;
373+
}
347374
} else if (side == REMOTE) {
348-
if (!amount_msat_add_sat_s64(&side_pay, side_pay, remote_splice_amnt))
375+
// channel_txs fails to amount_msat_add_sat_s64 0sat + -100000 REMOTE (side_pay + remote_splice_amnt)
376+
if (!amount_msat_add_sat_s64(&side_pay, side_pay, remote_splice_amnt)) {
377+
status_broken("channel_txs fails to"
378+
" amount_msat_add_sat_s64 %s + %"PRId64
379+
" REMOTE (side_pay + remote_splice_amnt)",
380+
fmt_amount_m_as_sat(tmpctx, side_pay),
381+
remote_splice_amnt);
349382
return NULL;
350-
if (!amount_msat_add_sat_s64(&other_side_pay, other_side_pay, splice_amnt))
383+
}
384+
if (!amount_msat_add_sat_s64(&other_side_pay, other_side_pay, splice_amnt)){
385+
status_broken("channel_txs fails to"
386+
" amount_msat_add_sat_s64 %s + %"PRId64
387+
" REMOTE (other_side_pay + splice_amnt)",
388+
fmt_amount_m_as_sat(tmpctx, other_side_pay),
389+
splice_amnt);
351390
return NULL;
391+
}
352392
}
353393

354394
txs = tal_arr(ctx, struct bitcoin_tx *, 1);

common/amount.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,13 @@ WARN_UNUSED_RESULT bool amount_sat_add_sat_s64(struct amount_sat *val,
400400
return amount_sat_add(val, a, amount_sat(b));
401401
}
402402

403+
bool amount_msat_can_add_sat_s64(struct amount_msat a, s64 b)
404+
{
405+
struct amount_msat val;
406+
/* This fails if the result goes below 0 */
407+
return amount_msat_add_sat_s64(&val, a, b);
408+
}
409+
403410
bool amount_sat_eq(struct amount_sat a, struct amount_sat b)
404411
{
405412
return a.satoshis == b.satoshis;

common/amount.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ WARN_UNUSED_RESULT bool amount_sat_add_sat_s64(struct amount_sat *val,
100100
struct amount_sat a,
101101
s64 b);
102102

103+
WARN_UNUSED_RESULT bool amount_msat_can_add_sat_s64(struct amount_msat a,
104+
s64 b);
105+
103106
/* a += b */
104107
WARN_UNUSED_RESULT bool amount_msat_accumulate(struct amount_msat *a,
105108
struct amount_msat b);

common/splice_script.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,19 @@ static struct splice_script_error *new_error(const tal_t *ctx,
282282
return new_error_offset(ctx, type, token, phase, 0);
283283
}
284284

285+
static struct splice_script_error *new_error_msg(const tal_t *ctx,
286+
enum splice_script_error_type type,
287+
struct token *token,
288+
const char *phase,
289+
char *msg)
290+
{
291+
struct splice_script_error *error = new_error(ctx, type, token, phase);
292+
293+
tal_append_fmt(&error->message, "%s", msg);
294+
295+
return error;
296+
}
297+
285298
static char *context_snippet(const tal_t *ctx,
286299
const char *script,
287300
struct splice_script_error *error)
@@ -2345,10 +2358,15 @@ static struct splice_script_error *calculate_amounts(const tal_t *ctx,
23452358
/* Do we know precisely how much we're getting? */
23462359
if (!right_wilds && !right_used_ppm) {
23472360
/* Then we can give sat amount errors */
2348-
if (amount_sat_greater(left_total, right_total))
2349-
return new_error(ctx, INSUFFICENT_FUNDS,
2350-
left_wildcard_token ?: input[0],
2351-
"calculate_amounts");
2361+
if (amount_sat_greater(left_total, right_total)) {
2362+
return new_error_msg(ctx, INSUFFICENT_FUNDS,
2363+
left_wildcard_token ?: input[0],
2364+
"calculate_amounts",
2365+
tal_fmt(tmpctx, "required: %s,"
2366+
" provided: %s",
2367+
fmt_amount_sat(tmpctx, left_total),
2368+
fmt_amount_sat(tmpctx, right_total)));
2369+
}
23522370
if (left_used_ppm && amount_sat_eq(left_total, right_total))
23532371
return new_error(ctx, PERCENT_IS_ZERO,
23542372
left_percent_token ?: input[0],

plugins/spender/splice.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,6 @@ static struct command_result *onchain_wallet_fund(struct command *cmd,
394394
if (addinginputs) {
395395
command = "addpsbtinput";
396396
splice_cmd->wallet_inputs_to_signed++;
397-
/* DTODO track which specific inputs are added and only sign
398-
* those */
399397
}
400398

401399
req = jsonrpc_request_start(cmd, command,

tests/test_splice.py

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,152 @@ def test_script_two_chan_splice_in(node_factory, bitcoind):
227227

228228
inv = l3.rpc.invoice(10**2, '2', 'no_2')
229229
l2.rpc.pay(inv['bolt11'])
230+
231+
232+
@pytest.mark.openchannel('v1')
233+
@pytest.mark.openchannel('v2')
234+
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
235+
def test_script_two_chan_splice_out(node_factory, bitcoind):
236+
l1, l2, l3 = node_factory.line_graph(3, fundamount=1000000, wait_for_announce=True, opts={'experimental-splicing': None})
237+
238+
# We need to get funds into l1 -> l2 channel so we can splice it out
239+
inv = l2.rpc.invoice(100000000, '1', 'no_1')
240+
l1.rpc.pay(inv['bolt11'])
241+
242+
chan_id1 = l2.get_channel_id(l1)
243+
chan_id2 = l2.get_channel_id(l3)
244+
245+
# l2 will splice funds ouit of the channels with l1 and l3 at the same time
246+
result = l2.rpc.splice(f"{chan_id1} -> 100000; {chan_id2} -> 100000")
247+
248+
l3.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE')
249+
l2.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE')
250+
l1.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE')
251+
252+
wait_for(lambda: len(list(bitcoind.rpc.getrawmempool(True).keys())) == 1)
253+
assert result['txid'] in list(bitcoind.rpc.getrawmempool(True).keys())
254+
255+
bitcoind.generate_block(6, wait_for_mempool=1)
256+
257+
l3.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')
258+
l2.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')
259+
l1.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')
260+
261+
inv = l2.rpc.invoice(10**2, '2', 'no_2')
262+
l1.rpc.pay(inv['bolt11'])
263+
264+
inv = l3.rpc.invoice(10**2, '3', 'no_3')
265+
l2.rpc.pay(inv['bolt11'])
266+
267+
268+
@pytest.mark.openchannel('v1')
269+
@pytest.mark.openchannel('v2')
270+
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
271+
def test_script_two_chan_splice_inout(node_factory, bitcoind):
272+
l1, l2, l3 = node_factory.line_graph(3, fundamount=1000000, wait_for_announce=True, opts={'experimental-splicing': None})
273+
274+
chan_id1 = l2.get_channel_id(l1)
275+
chan_id2 = l2.get_channel_id(l3)
276+
277+
# move sats from chan 2 into chan 1
278+
result = l2.rpc.splice(f"wallet -> 10000; 100000 -> {chan_id1}; {chan_id2} -> 100000")
279+
280+
l3.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE')
281+
l2.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE')
282+
l1.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE')
283+
284+
wait_for(lambda: len(list(bitcoind.rpc.getrawmempool(True).keys())) == 1)
285+
assert result['txid'] in list(bitcoind.rpc.getrawmempool(True).keys())
286+
287+
bitcoind.generate_block(6, wait_for_mempool=1)
288+
289+
l3.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')
290+
l2.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')
291+
l1.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')
292+
293+
inv = l2.rpc.invoice(10**2, '2', 'no_2')
294+
l1.rpc.pay(inv['bolt11'])
295+
296+
inv = l3.rpc.invoice(10**2, '3', 'no_3')
297+
l2.rpc.pay(inv['bolt11'])
298+
299+
300+
# Makes channels going from node 1 -> 2, 2 -> 3, etc up to 'qty' number channels.
301+
# If balanced is True, than each channel will be balanced -- otherwise the lower
302+
# index channel will have funds in the channel to the higher indexed one.
303+
# The second node is a *special case* -- it will get a channel to every other node.
304+
# Returns an array of all nodes, and an array of all the *second node's* channels
305+
def make_chans(node_factory, qty=2, fundamount=1000000, balanced=True):
306+
nodes = node_factory.line_graph(qty+1, fundamount=fundamount, opts={'experimental-splicing': None})
307+
chanids = []
308+
309+
if qty > 2:
310+
for i in range(len(nodes) - 1, 2, -1):
311+
chanid, _ = nodes[2].fundchannel(nodes[i].info["id"], fundamount)
312+
chanids.append(chanid)
313+
314+
assert(qty > 1);
315+
chanids.insert(0, nodes[1],get_channel_id(nodes[0]))
316+
chanids.insert(0, nodes[1],get_channel_id(nodes[0]))
317+
318+
for i in range(len(nodes) - 1):
319+
if i == 1:
320+
continue;
321+
322+
TODO: balane the cahnenls for node[1]!!!
323+
chanids.append(nodes[i].get_channel_id(nodes[i + 1]))
324+
if balanced:
325+
inv = nodes[i + 1].rpc.invoice(int(1000 * fundamount / 2), str(i) + "bal", str(i) + "bal")
326+
nodes[i].rpc.pay(inv['bolt11'])
327+
328+
return [nodes, chanids]
329+
330+
331+
def test_chans(nodes, txid, bitcoind, payment_check_style = 1, payamount=1000000):
332+
for node in nodes:
333+
node.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE')
334+
335+
wait_for(lambda: len(list(bitcoind.rpc.getrawmempool(True).keys())) == 1)
336+
assert txid in list(bitcoind.rpc.getrawmempool(True).keys())
337+
338+
bitcoind.generate_block(6, wait_for_mempool=1)
339+
340+
for node in nodes:
341+
node.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')
342+
343+
if payment_check_style == 1:
344+
for i in range(len(nodes) - 1):
345+
inv = nodes[i + 1].rpc.invoice(payamount, str(i) + "test", str(i) + "test")
346+
nodes[i].rpc.pay(inv['bolt11'])
347+
348+
349+
@pytest.mark.openchannel('v1')
350+
@pytest.mark.openchannel('v2')
351+
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
352+
def test_script_two_chan_splice_crazy(node_factory, bitcoind):
353+
scripts = [
354+
"wallet -> 10000; {} -> 100000; {} -> 100000",
355+
"wallet -> 10000; 100000 -> {}; {} -> 100000",
356+
"wallet -> 200000; 100000 -> {}; 100000 -> {}",
357+
"{} -> 100000; {} -> 100000",
358+
"{} -> 200000; 100000 -> {}", # '* -> wallet' is implied here
359+
"{} -> 200000; 100000 -> {}; * -> wallet", # but we test it here explicitly
360+
# "wallet -> 200000+fee; 100000 -> {}; 100000 -> {}", # Don't support wallet funding being used for fee
361+
# "wallet -> *; 100000 -> {}; 100000 -> {}", # Don't support dynamic wallet funding amounts for now
362+
# "100000 -> {}; {} -> 100000+fee", # Internal error; should not get here with non-channels with state NONE
363+
# "100000-fee -> {}; {} -> 100000", # Internal error; should not get here with non-channels with state NONE
364+
]
365+
366+
for script in scripts:
367+
nodes, chanids = make_chans(node_factory, script.count("{}"))
368+
result = nodes[1].rpc.splice(script.format(*chanids))
369+
test_chans(nodes, result['txid'], bitcoind)
370+
371+
372+
373+
374+
375+
376+
377+
378+

0 commit comments

Comments
 (0)