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) if (p->scid)
json_add_short_channel_id(response, "channel", p->scid); json_add_short_channel_id(response, "channel", p->scid);
if (p->balance) { if (p->balance) {
json_add_u64(response, "msatoshi_to_us", json_add_u64(response, "msatoshi_to_us", *p->balance);
p->balance[LOCAL]); json_add_u64(response, "msatoshi_total",
json_add_u64(response, "msatoshi_to_them", p->funding_satoshi * 1000);
p->balance[REMOTE]);
} }
if (leveltok) { if (leveltok) {
info.response = response; info.response = response;
json_array_start(response, "log"); 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"); log_debug(peer->log, "Waiting for HSM file descriptor");
/* Now we can consider balance set. */ /* Now we can consider balance set. */
peer->balance = tal_arr(peer, u64, NUM_SIDES); peer->balance = tal(peer, u64);
peer->balance[peer->funder] = peer->funding_satoshi * 1000 - peer->push_msat; if (peer->funder == LOCAL)
peer->balance[!peer->funder] = peer->push_msat; *peer->balance = peer->funding_satoshi * 1000 - peer->push_msat;
else
*peer->balance = peer->push_msat;
peer_set_condition(peer, oldstate, GETTING_HSMFD); peer_set_condition(peer, oldstate, GETTING_HSMFD);

View File

@ -69,7 +69,7 @@ struct peer {
u16 funding_outnum; u16 funding_outnum;
u64 funding_satoshi, push_msat; 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; u64 *balance;
/* Keys for channel. */ /* Keys for channel. */

View File

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

View File

@ -204,6 +204,18 @@ class LightningDTests(BaseLightningDTests):
assert p1['owner'] == 'lightningd_gossip' assert p1['owner'] == 'lightningd_gossip'
assert p2['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): def test_sendpay(self):
l1,l2 = self.connect() l1,l2 = self.connect()
@ -246,10 +258,27 @@ class LightningDTests(BaseLightningDTests):
self.assertRaises(ValueError, l1.rpc.sendpay, to_json([rs]), rhash) self.assertRaises(ValueError, l1.rpc.sendpay, to_json([rs]), rhash)
assert l2.rpc.listinvoice('testpayment2')[0]['complete'] == False 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. # This works.
l1.rpc.sendpay(to_json([routestep]), rhash) l1.rpc.sendpay(to_json([routestep]), rhash)
assert l2.rpc.listinvoice('testpayment2')[0]['complete'] == True 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) # Repeat will "succeed", but won't actually send anything (duplicate)
assert not l1.daemon.is_in_log('... succeeded') assert not l1.daemon.is_in_log('... succeeded')
l1.rpc.sendpay(to_json([routestep]), rhash) l1.rpc.sendpay(to_json([routestep]), rhash)
@ -263,7 +292,6 @@ class LightningDTests(BaseLightningDTests):
l1.rpc.sendpay(to_json([routestep]), rhash) l1.rpc.sendpay(to_json([routestep]), rhash)
assert l2.rpc.listinvoice('testpayment3')[0]['complete'] == True assert l2.rpc.listinvoice('testpayment3')[0]['complete'] == True
# FIXME: test paying via another node, should fail to pay twice.
def test_gossip_jsonrpc(self): def test_gossip_jsonrpc(self):
l1,l2 = self.connect() l1,l2 = self.connect()