Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions channeld/channeld.c
Original file line number Diff line number Diff line change
Expand Up @@ -4347,6 +4347,16 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg)
peer_failed_warn(peer->pps, &peer->channel_id,
"Splice internal error: mismatched channelid");

/* The spec requires us to fail if they splice out more than their current channel balance */
if (!amount_msat_can_add_sat_s64(peer->channel->view->owed[REMOTE],
peer->splicing->opener_relative))
peer_failed_warn(peer->pps, &peer->channel_id,
"Splice contribution %"PRId64"sat exceeds"
" peer balance %s",
peer->splicing->opener_relative,
fmt_amount_msat(tmpctx,
peer->channel->view->owed[REMOTE]));

if (!pubkey_eq(&peer->splicing->remote_funding_pubkey,
&peer->channel->funding_pubkey[REMOTE]))
status_info("Splice peer is rotating funding pubkey");
Expand Down Expand Up @@ -4552,6 +4562,16 @@ static void splice_initiator(struct peer *peer, const u8 *inmsg)
peer_failed_warn(peer->pps, &peer->channel_id,
"Splice[ACK] internal error: mismatched channelid");

/* The spec requires us to fail if they splice out more than their current channel balance */
if (!amount_msat_can_add_sat_s64(peer->channel->view->owed[REMOTE],
peer->splicing->accepter_relative))
peer_failed_warn(peer->pps, &peer->channel_id,
"Splice[ACK] contribution %"PRId64"sat exceeds"
" peer balance %s",
peer->splicing->accepter_relative,
fmt_amount_msat(tmpctx,
peer->channel->view->owed[REMOTE]));

if (!pubkey_eq(&peer->splicing->remote_funding_pubkey,
&peer->channel->funding_pubkey[REMOTE]))
status_info("Splice[ACK] peer is rotating funding pubkey");
Expand Down
4 changes: 2 additions & 2 deletions common/amount.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ WARN_UNUSED_RESULT bool amount_msat_add_sat_s64(struct amount_msat *val,
s64 b)
{
if (b < 0)
return amount_msat_sub_sat(val, a, amount_sat(-b));
return amount_msat_sub_sat(val, a, amount_sat(-(u64)b));
else
return amount_msat_add_sat(val, a, amount_sat(b));
}
Expand All @@ -413,7 +413,7 @@ WARN_UNUSED_RESULT bool amount_sat_add_sat_s64(struct amount_sat *val,
s64 b)
{
if (b < 0)
return amount_sat_sub(val, a, amount_sat(-b));
return amount_sat_sub(val, a, amount_sat(-(u64)b));
else
return amount_sat_add(val, a, amount_sat(b));
}
Expand Down
23 changes: 23 additions & 0 deletions common/test/run-amount.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,28 @@ static void test_case_amount_div_ceil(u64 input, u64 div, u64 expected)
assert(amount_msat_eq(result_msat, expected_msat));
}

static void test_amount_add_sat_s64(void)
{
struct amount_msat msat;
struct amount_sat sat;

assert(amount_msat_add_sat_s64(&msat, AMOUNT_MSAT(5000), -5));
assert(amount_msat_eq(msat, AMOUNT_MSAT(0)));
assert(!amount_msat_add_sat_s64(&msat, AMOUNT_MSAT(5000), -6));
assert(amount_msat_add_sat_s64(&msat, AMOUNT_MSAT(5000), 5));
assert(amount_msat_eq(msat, AMOUNT_MSAT(10000)));

assert(amount_sat_add_sat_s64(&sat, AMOUNT_SAT(5), -5));
assert(amount_sat_eq(sat, AMOUNT_SAT(0)));
assert(!amount_sat_add_sat_s64(&sat, AMOUNT_SAT(5), -6));

/* Negating INT64_MIN must not overflow */
assert(!amount_msat_can_add_sat_s64(AMOUNT_MSAT(UINT64_MAX), INT64_MIN));
assert(!amount_sat_add_sat_s64(&sat, AMOUNT_SAT(0), INT64_MIN));
assert(amount_sat_add_sat_s64(&sat, AMOUNT_SAT((u64)1 << 63), INT64_MIN));
assert(amount_sat_eq(sat, AMOUNT_SAT(0)));
}

static void test_amount_div(void)
{
test_case_amount_div(1, 1, 1);
Expand Down Expand Up @@ -455,5 +477,6 @@ int main(int argc, char *argv[])

test_amount_with_fee();
test_amount_div();
test_amount_add_sat_s64();
common_shutdown();
}
24 changes: 24 additions & 0 deletions tests/test_splicing.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,30 @@ def _splice():
l2.daemon.wait_for_log(r'Splice feerate_perkw 200000 is above our maximum 150000')


@pytest.mark.openchannel('v1')
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
def test_splice_out_exceeds_balance(node_factory, bitcoind):
l1, l2 = node_factory.line_graph(2, fundamount=1000000,
wait_for_announce=True,
opts={'allow_warning': True,
'may_reconnect': True})
chan_id = l1.get_channel_id(l2)

funds_result = l1.rpc.addpsbtoutput(100000)

# l2 refuses on receipt of splice_init, so the splice_ack l1 is waiting
# for never arrives - run it in a daemon thread so the test can proceed
def _splice():
try:
l1.rpc.splice_init(chan_id, -1000001, funds_result['psbt'])
except Exception:
pass

threading.Thread(target=_splice, daemon=True).start()

l2.daemon.wait_for_log(r'Splice contribution -1000001sat exceeds peer balance')


@pytest.mark.openchannel('v1')
@pytest.mark.openchannel('v2')
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
Expand Down
Loading