mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-23 00:54:20 +01:00
bkpr: create accounts for zero sat channels
we weren't making records for 'missed' accounts that had a zero balance at snapshot time (if peer opens channel and is unused) Fixes: #5502 Reported-By: https://github.com/niftynei/cln-logmaid
This commit is contained in:
@@ -136,7 +136,7 @@ def test_bookkeeping_external_withdraws(node_factory, bitcoind):
|
||||
|
||||
assert withdrawal[0]['amount'] == Decimal('0.00555555')
|
||||
incomes = l1.rpc.bkpr_listincome()['income_events']
|
||||
# There should only be two income events: deposits to wallet
|
||||
# There are two income events: deposits to wallet
|
||||
# for {amount}
|
||||
assert len(incomes) == 2
|
||||
for inc in incomes:
|
||||
@@ -145,7 +145,7 @@ def test_bookkeeping_external_withdraws(node_factory, bitcoind):
|
||||
assert inc['credit_msat'] == amount_msat
|
||||
# The event should show up in the 'bkpr_listaccountevents' however
|
||||
events = l1.rpc.bkpr_listaccountevents()['events']
|
||||
assert len(events) == 3
|
||||
assert len(events) == 4
|
||||
external = [e for e in events if e['account'] == 'external'][0]
|
||||
assert external['credit_msat'] == Millisatoshi(amount // 2 * 1000)
|
||||
|
||||
@@ -162,8 +162,8 @@ def test_bookkeeping_external_withdraws(node_factory, bitcoind):
|
||||
assert len(find_tags(incomes, 'journal_entry')) == 0
|
||||
assert len(incomes) == 2
|
||||
events = l1.rpc.bkpr_listaccountevents()['events']
|
||||
assert len(events) == 3
|
||||
assert len(find_tags(events, 'journal_entry')) == 0
|
||||
assert len(events) == 4
|
||||
assert len(find_tags(events, 'journal_entry')) == 1
|
||||
|
||||
# the wallet balance should be unchanged
|
||||
btc_balance = only_one(only_one(l1.rpc.bkpr_listbalances()['accounts'])['balances'])
|
||||
@@ -214,17 +214,17 @@ def test_bookkeeping_external_withdraw_missing(node_factory, bitcoind):
|
||||
# Ok, now we send some funds to an external address
|
||||
l1.rpc.withdraw(waddr, amount // 2)
|
||||
|
||||
# There should only be two income events: deposits to wallet
|
||||
# Only two income events: deposits
|
||||
assert len(l1.rpc.bkpr_listincome()['income_events']) == 2
|
||||
# There are three account events: 2 wallet deposits, 1 external deposit
|
||||
assert len(l1.rpc.bkpr_listaccountevents()['events']) == 3
|
||||
# 4 account events: empty wallet start, 2 wallet deposits, 1 external deposit
|
||||
assert len(l1.rpc.bkpr_listaccountevents()['events']) == 4
|
||||
|
||||
# Stop node and remove the accounts data
|
||||
l1.stop()
|
||||
os.remove(os.path.join(basedir, TEST_NETWORK, 'accounts.sqlite3'))
|
||||
l1.start()
|
||||
|
||||
# the number of income events should be unchanged
|
||||
# Number of income events should be unchanged
|
||||
assert len(l1.rpc.bkpr_listincome()['income_events']) == 2
|
||||
# we're now missing the external deposit
|
||||
events = l1.rpc.bkpr_listaccountevents()['events']
|
||||
@@ -270,7 +270,7 @@ def test_bookkeeping_rbf_withdraw(node_factory, bitcoind):
|
||||
bitcoind.rpc.sendtoaddress(addr, amount / 10**8)
|
||||
bitcoind.generate_block(1)
|
||||
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 1)
|
||||
assert len(l1.rpc.bkpr_listaccountevents()['events']) == 1
|
||||
assert len(l1.rpc.bkpr_listaccountevents()['events']) == 2
|
||||
assert len(l1.rpc.bkpr_listincome()['income_events']) == 1
|
||||
|
||||
# Ok, now we send some funds to an external address
|
||||
@@ -281,7 +281,7 @@ def test_bookkeeping_rbf_withdraw(node_factory, bitcoind):
|
||||
assert out1['txid'] in list(mempool.keys())
|
||||
|
||||
# another account event, still one income event
|
||||
assert len(l1.rpc.bkpr_listaccountevents()['events']) == 2
|
||||
assert len(l1.rpc.bkpr_listaccountevents()['events']) == 3
|
||||
assert len(l1.rpc.bkpr_listincome()['income_events']) == 1
|
||||
|
||||
# unreserve the existing output
|
||||
@@ -294,7 +294,7 @@ def test_bookkeeping_rbf_withdraw(node_factory, bitcoind):
|
||||
assert out2['txid'] in list(mempool.keys())
|
||||
|
||||
# another account event, still one income event
|
||||
assert len(l1.rpc.bkpr_listaccountevents()['events']) == 3
|
||||
assert len(l1.rpc.bkpr_listaccountevents()['events']) == 4
|
||||
assert len(l1.rpc.bkpr_listincome()['income_events']) == 1
|
||||
|
||||
# ok now we mine a block
|
||||
@@ -463,6 +463,76 @@ def test_bookkeeping_missed_chans_pushed(node_factory, bitcoind):
|
||||
_check_events(l2, channel_id, exp_events)
|
||||
|
||||
|
||||
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "turns off bookkeeper at start")
|
||||
@unittest.skipIf(TEST_NETWORK != 'regtest', "network fees hardcoded")
|
||||
@pytest.mark.openchannel('v1', 'Uses push-msat')
|
||||
def test_bookkeeping_missed_chans_pay_after(node_factory, bitcoind):
|
||||
"""
|
||||
Route a payment through a channel that we didn't have open when the bookkeeper
|
||||
was around
|
||||
"""
|
||||
coin_mvt_plugin = Path(__file__).parent / "plugins" / "coin_movements.py"
|
||||
l1, l2 = node_factory.get_nodes(2, opts={'disable-plugin': 'bookkeeper',
|
||||
'plugin': str(coin_mvt_plugin)})
|
||||
|
||||
# Double check there's no bookkeeper plugin on
|
||||
assert l1.daemon.opts['disable-plugin'] == 'bookkeeper'
|
||||
assert l2.daemon.opts['disable-plugin'] == 'bookkeeper'
|
||||
|
||||
open_amt = 10**7
|
||||
invoice_msat = 11000000
|
||||
|
||||
l1.fundwallet(200000000)
|
||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||
txid = l1.rpc.fundchannel(l2.info['id'], open_amt)['txid']
|
||||
bitcoind.generate_block(1, wait_for_mempool=[txid])
|
||||
wait_for(lambda: l1.channel_state(l2) == 'CHANNELD_NORMAL')
|
||||
scid = l1.get_channel_scid(l2)
|
||||
l1.wait_channel_active(scid)
|
||||
channel_id = first_channel_id(l1, l2)
|
||||
|
||||
# Now turn the bookkeeper on and restart
|
||||
l1.stop()
|
||||
l2.stop()
|
||||
del l1.daemon.opts['disable-plugin']
|
||||
del l2.daemon.opts['disable-plugin']
|
||||
l1.start()
|
||||
l2.start()
|
||||
|
||||
# Wait for the balance snapshot to fire/finish
|
||||
l1.daemon.wait_for_log('Snapshot balances updated')
|
||||
l2.daemon.wait_for_log('Snapshot balances updated')
|
||||
|
||||
# Should have channel in both, with balances
|
||||
for n in [l1, l2]:
|
||||
accts = [ba['account'] for ba in n.rpc.bkpr_listbalances()['accounts']]
|
||||
assert channel_id in accts
|
||||
|
||||
# Send a payment, should be ok.
|
||||
l1.wait_channel_active(scid)
|
||||
l1.pay(l2, invoice_msat)
|
||||
l1.daemon.wait_for_log(r'coin movement:.*\'invoice\'')
|
||||
|
||||
def _check_events(node, channel_id, exp_events):
|
||||
chan_events = [ev for ev in node.rpc.bkpr_listaccountevents()['events'] if ev['account'] == channel_id]
|
||||
assert len(chan_events) == len(exp_events)
|
||||
for ev, exp in zip(chan_events, exp_events):
|
||||
assert ev['tag'] == exp[0]
|
||||
assert ev['credit_msat'] == Millisatoshi(exp[1])
|
||||
assert ev['debit_msat'] == Millisatoshi(exp[2])
|
||||
|
||||
# l1 events
|
||||
exp_events = [('channel_open', open_amt * 1000, 0),
|
||||
('onchain_fee', 5257000, 0),
|
||||
('invoice', 0, invoice_msat)]
|
||||
_check_events(l1, channel_id, exp_events)
|
||||
|
||||
# l2 events
|
||||
exp_events = [('channel_open', 0, 0),
|
||||
('invoice', invoice_msat, 0)]
|
||||
_check_events(l2, channel_id, exp_events)
|
||||
|
||||
|
||||
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "turns off bookkeeper at start")
|
||||
def test_bookkeeping_onchaind_txs(node_factory, bitcoind):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user