Skip to content

Commit cdbd201

Browse files
committed
channeld: reject splice contribution above peer balance on receipt
Changelog-Fixed: channeld: reject a splice contribution larger than the peers balance on receipt, as required by bolt2
1 parent 1112b47 commit cdbd201

4 files changed

Lines changed: 69 additions & 2 deletions

File tree

‎channeld/channeld.c‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4406,6 +4406,16 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg)
44064406
peer_failed_warn(peer->pps, &peer->channel_id,
44074407
"Splice internal error: mismatched channelid");
44084408

4409+
/* The spec requires us to fail if they splice out more than their current channel balance */
4410+
if (!amount_msat_can_add_sat_s64(peer->channel->view->owed[REMOTE],
4411+
peer->splicing->opener_relative))
4412+
peer_failed_warn(peer->pps, &peer->channel_id,
4413+
"Splice contribution %"PRId64"sat exceeds"
4414+
" peer balance %s",
4415+
peer->splicing->opener_relative,
4416+
fmt_amount_msat(tmpctx,
4417+
peer->channel->view->owed[REMOTE]));
4418+
44094419
if (!pubkey_eq(&peer->splicing->remote_funding_pubkey,
44104420
&peer->channel->funding_pubkey[REMOTE]))
44114421
status_info("Splice peer is rotating funding pubkey");
@@ -4614,6 +4624,16 @@ static void splice_initiator(struct peer *peer, const u8 *inmsg)
46144624
peer_failed_warn(peer->pps, &peer->channel_id,
46154625
"Splice[ACK] internal error: mismatched channelid");
46164626

4627+
/* The spec requires us to fail if they splice out more than their current channel balance */
4628+
if (!amount_msat_can_add_sat_s64(peer->channel->view->owed[REMOTE],
4629+
peer->splicing->accepter_relative))
4630+
peer_failed_warn(peer->pps, &peer->channel_id,
4631+
"Splice[ACK] contribution %"PRId64"sat exceeds"
4632+
" peer balance %s",
4633+
peer->splicing->accepter_relative,
4634+
fmt_amount_msat(tmpctx,
4635+
peer->channel->view->owed[REMOTE]));
4636+
46174637
if (!pubkey_eq(&peer->splicing->remote_funding_pubkey,
46184638
&peer->channel->funding_pubkey[REMOTE]))
46194639
status_info("Splice[ACK] peer is rotating funding pubkey");

‎common/amount.c‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ WARN_UNUSED_RESULT bool amount_msat_add_sat_s64(struct amount_msat *val,
402402
s64 b)
403403
{
404404
if (b < 0)
405-
return amount_msat_sub_sat(val, a, amount_sat(-b));
405+
return amount_msat_sub_sat(val, a, amount_sat(-(u64)b));
406406
else
407407
return amount_msat_add_sat(val, a, amount_sat(b));
408408
}
@@ -413,7 +413,7 @@ WARN_UNUSED_RESULT bool amount_sat_add_sat_s64(struct amount_sat *val,
413413
s64 b)
414414
{
415415
if (b < 0)
416-
return amount_sat_sub(val, a, amount_sat(-b));
416+
return amount_sat_sub(val, a, amount_sat(-(u64)b));
417417
else
418418
return amount_sat_add(val, a, amount_sat(b));
419419
}

‎common/test/run-amount.c‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,28 @@ static void test_case_amount_div_ceil(u64 input, u64 div, u64 expected)
183183
assert(amount_msat_eq(result_msat, expected_msat));
184184
}
185185

186+
static void test_amount_add_sat_s64(void)
187+
{
188+
struct amount_msat msat;
189+
struct amount_sat sat;
190+
191+
assert(amount_msat_add_sat_s64(&msat, AMOUNT_MSAT(5000), -5));
192+
assert(amount_msat_eq(msat, AMOUNT_MSAT(0)));
193+
assert(!amount_msat_add_sat_s64(&msat, AMOUNT_MSAT(5000), -6));
194+
assert(amount_msat_add_sat_s64(&msat, AMOUNT_MSAT(5000), 5));
195+
assert(amount_msat_eq(msat, AMOUNT_MSAT(10000)));
196+
197+
assert(amount_sat_add_sat_s64(&sat, AMOUNT_SAT(5), -5));
198+
assert(amount_sat_eq(sat, AMOUNT_SAT(0)));
199+
assert(!amount_sat_add_sat_s64(&sat, AMOUNT_SAT(5), -6));
200+
201+
/* Negating INT64_MIN must not overflow */
202+
assert(!amount_msat_can_add_sat_s64(AMOUNT_MSAT(UINT64_MAX), INT64_MIN));
203+
assert(!amount_sat_add_sat_s64(&sat, AMOUNT_SAT(0), INT64_MIN));
204+
assert(amount_sat_add_sat_s64(&sat, AMOUNT_SAT((u64)1 << 63), INT64_MIN));
205+
assert(amount_sat_eq(sat, AMOUNT_SAT(0)));
206+
}
207+
186208
static void test_amount_div(void)
187209
{
188210
test_case_amount_div(1, 1, 1);
@@ -455,5 +477,6 @@ int main(int argc, char *argv[])
455477

456478
test_amount_with_fee();
457479
test_amount_div();
480+
test_amount_add_sat_s64();
458481
common_shutdown();
459482
}

‎tests/test_splicing.py‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,30 @@ def _splice():
155155
l2.daemon.wait_for_log(r'Splice feerate_perkw 200000 is above our maximum 150000')
156156

157157

158+
@pytest.mark.openchannel('v1')
159+
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
160+
def test_splice_out_exceeds_balance(node_factory, bitcoind):
161+
l1, l2 = node_factory.line_graph(2, fundamount=1000000,
162+
wait_for_announce=True,
163+
opts={'allow_warning': True,
164+
'may_reconnect': True})
165+
chan_id = l1.get_channel_id(l2)
166+
167+
funds_result = l1.rpc.addpsbtoutput(100000)
168+
169+
# l2 refuses on receipt of splice_init, so the splice_ack l1 is waiting
170+
# for never arrives - run it in a daemon thread so the test can proceed
171+
def _splice():
172+
try:
173+
l1.rpc.splice_init(chan_id, -1000001, funds_result['psbt'])
174+
except Exception:
175+
pass
176+
177+
threading.Thread(target=_splice, daemon=True).start()
178+
179+
l2.daemon.wait_for_log(r'Splice contribution -1000001sat exceeds peer balance')
180+
181+
158182
@pytest.mark.openchannel('v1')
159183
@pytest.mark.openchannel('v2')
160184
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')

0 commit comments

Comments
 (0)