lightningd: track balance in way which matches channeld.

Currently it's fairly ad-hoc, but we need to tell it to channeld when
it restarts, so we define it as the non-HTLC balance.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-06-20 15:29:03 +09:30
parent f918c3a0e7
commit a55b58d0d5
4 changed files with 63 additions and 20 deletions

View File

@ -587,11 +587,11 @@ static void json_getpeers(struct command *cmd,
if (p->scid)
json_add_short_channel_id(response, "channel", p->scid);
if (p->balance) {
json_add_u64(response, "msatoshi_to_us",
p->balance[LOCAL]);
json_add_u64(response, "msatoshi_to_them",
p->balance[REMOTE]);
json_add_u64(response, "msatoshi_to_us", *p->balance);
json_add_u64(response, "msatoshi_total",
p->funding_satoshi * 1000);
}
if (leveltok) {
info.response = response;
json_array_start(response, "log");
@ -982,9 +982,11 @@ static void peer_start_channeld(struct peer *peer, enum peer_state oldstate,
log_debug(peer->log, "Waiting for HSM file descriptor");
/* Now we can consider balance set. */
peer->balance = tal_arr(peer, u64, NUM_SIDES);
peer->balance[peer->funder] = peer->funding_satoshi * 1000 - peer->push_msat;
peer->balance[!peer->funder] = peer->push_msat;
peer->balance = tal(peer, u64);
if (peer->funder == LOCAL)
*peer->balance = peer->funding_satoshi * 1000 - peer->push_msat;
else
*peer->balance = peer->push_msat;
peer_set_condition(peer, oldstate, GETTING_HSMFD);

View File

@ -69,7 +69,7 @@ struct peer {
u16 funding_outnum;
u64 funding_satoshi, push_msat;
/* Channel balance (LOCAL and REMOTE); if we have one. */
/* Amount going to us, not counting unfinished HTLCs; if we have one. */
u64 *balance;
/* Keys for channel. */

View File

@ -175,8 +175,8 @@ static void fulfill_htlc(struct htlc_in *hin, const struct preimage *preimage)
{
u8 *msg;
hin->key.peer->balance[LOCAL] += hin->msatoshi;
hin->key.peer->balance[REMOTE] -= hin->msatoshi;
hin->preimage = tal_dup(hin, struct preimage, preimage);
htlc_in_check(hin, __func__);
/* FIXME: fail the peer if it doesn't tell us that htlc fulfill is
* committed before deadline.
@ -628,10 +628,6 @@ static bool peer_fulfilled_our_htlc(struct peer *peer,
/* FIXME: Save to db */
/* They fulfilled our HTLC. Credit them, forward immediately. */
peer->balance[REMOTE] += hout->msatoshi;
peer->balance[LOCAL] -= hout->msatoshi;
if (hout->in)
fulfill_htlc(hout->in, &fulfilled->payment_preimage);
else
@ -665,16 +661,30 @@ static bool peer_failed_our_htlc(struct peer *peer,
static void remove_htlc_in(struct peer *peer, struct htlc_in *hin)
{
htlc_in_check(hin, __func__);
log_debug(peer->log, "Removing in HTLC %"PRIu64" state %s",
hin->key.id, htlc_state_name(hin->hstate));
assert(hin->failuremsg || hin->preimage);
log_debug(peer->log, "Removing in HTLC %"PRIu64" state %s %s",
hin->key.id, htlc_state_name(hin->hstate),
hin->failuremsg ? "FAILED" : "FULFILLED");
/* If we fulfilled their HTLC, credit us. */
if (hin->preimage) {
log_debug(peer->log, "Balance %"PRIu64" -> %"PRIu64,
*peer->balance,
*peer->balance + hin->msatoshi);
*peer->balance += hin->msatoshi;
}
tal_free(hin);
}
static void remove_htlc_out(struct peer *peer, struct htlc_out *hout)
{
htlc_out_check(hout, __func__);
log_debug(peer->log, "Removing out HTLC %"PRIu64" state %s",
hout->key.id, htlc_state_name(hout->hstate));
assert(hout->failuremsg || hout->preimage);
log_debug(peer->log, "Removing out HTLC %"PRIu64" state %s %s",
hout->key.id, htlc_state_name(hout->hstate),
hout->failuremsg ? "FAILED" : "FULFILLED");
/* If it's failed, now we can forward since it's completely locked-in */
if (hout->failuremsg) {
@ -687,6 +697,9 @@ static void remove_htlc_out(struct peer *peer, struct htlc_out *hout)
} else {
payment_failed(peer->ld, hout);
}
} else {
/* We paid for this HTLC, so deduct balance. */
*peer->balance -= hout->msatoshi;
}
tal_free(hout);

View File

@ -204,6 +204,18 @@ class LightningDTests(BaseLightningDTests):
assert p1['owner'] == 'lightningd_gossip'
assert p2['owner'] == 'lightningd_gossip'
def test_balance(self):
l1,l2 = self.connect()
self.fund_channel(l1, l2, 10**6)
p1 = l1.rpc.getpeer(l2.info['id'], 'info')
p2 = l2.rpc.getpeer(l1.info['id'], 'info')
assert p1['msatoshi_to_us'] == 10**6 * 1000
assert p1['msatoshi_total'] == 10**6 * 1000
assert p2['msatoshi_to_us'] == 0
assert p2['msatoshi_total'] == 10**6 * 1000
def test_sendpay(self):
l1,l2 = self.connect()
@ -246,10 +258,27 @@ class LightningDTests(BaseLightningDTests):
self.assertRaises(ValueError, l1.rpc.sendpay, to_json([rs]), rhash)
assert l2.rpc.listinvoice('testpayment2')[0]['complete'] == False
# FIXME: test paying via another node, should fail to pay twice.
p1 = l1.rpc.getpeer(l2.info['id'], 'info')
p2 = l2.rpc.getpeer(l1.info['id'], 'info')
assert p1['msatoshi_to_us'] == 10**6 * 1000
assert p1['msatoshi_total'] == 10**6 * 1000
assert p2['msatoshi_to_us'] == 0
assert p2['msatoshi_total'] == 10**6 * 1000
# This works.
l1.rpc.sendpay(to_json([routestep]), rhash)
assert l2.rpc.listinvoice('testpayment2')[0]['complete'] == True
# Balances should reflect it.
time.sleep(1)
p1 = l1.rpc.getpeer(l2.info['id'], 'info')
p2 = l2.rpc.getpeer(l1.info['id'], 'info')
assert p1['msatoshi_to_us'] == 10**6 * 1000 - amt
assert p1['msatoshi_total'] == 10**6 * 1000
assert p2['msatoshi_to_us'] == amt
assert p2['msatoshi_total'] == 10**6 * 1000
# Repeat will "succeed", but won't actually send anything (duplicate)
assert not l1.daemon.is_in_log('... succeeded')
l1.rpc.sendpay(to_json([routestep]), rhash)
@ -263,7 +292,6 @@ class LightningDTests(BaseLightningDTests):
l1.rpc.sendpay(to_json([routestep]), rhash)
assert l2.rpc.listinvoice('testpayment3')[0]['complete'] == True
# FIXME: test paying via another node, should fail to pay twice.
def test_gossip_jsonrpc(self):
l1,l2 = self.connect()