Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix onchain fees lookup query #6939

Merged
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
4 changes: 2 additions & 2 deletions plugins/bkpr/recorder.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,8 @@ struct fee_sum **find_account_onchain_fees(const tal_t *ctx,
", CAST(SUM(debit) AS BIGINT) as debit"
" FROM onchain_fees"
" WHERE account_id = ?"
" GROUP BY txid, update_count"
" ORDER BY txid, update_count"));
" GROUP BY txid"
" ORDER BY txid"));

db_bind_u64(stmt, acct->db_id);
db_query_prepared(stmt);
Expand Down
129 changes: 129 additions & 0 deletions tests/test_bookkeeper.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,135 @@ def _check_events(node, channel_id, exp_events):
_check_events(l2, channel_id, exp_events)


@unittest.skipIf(TEST_NETWORK != 'regtest', "network fees hardcoded")
@pytest.mark.openchannel('v1')
def test_bookkeeping_inspect_multifundchannel(node_factory, bitcoind):
"""
Test that bookkeeper splits multifundchannel fees correctly for single funded channels.
For single funded channels, l1 pays the entirety of the fee associated with multifundchannel, and the fee is
split into each channel and is viewed from the opener's perspective.
"""
l1, l2, l3, l4 = node_factory.get_nodes(4)

l1.fundwallet(200000000)
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
l1.rpc.connect(l3.info['id'], 'localhost', l3.port)
l1.rpc.connect(l4.info['id'], 'localhost', l4.port)

destinations = [{"id": '{}@localhost:{}'.format(l2.info['id'], l2.port),
"amount": 25000},
{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port),
"amount": 25000},
{"id": '{}@localhost:{}'.format(l4.info['id'], l4.port),
"amount": 25000}]

multifundchannel_return = l1.rpc.multifundchannel(destinations)

multifundchannel_txid = multifundchannel_return['txid']

channel_ids = multifundchannel_return['channel_ids']

channel_12_channel_id = channel_ids[0]['channel_id']
channel_13_channel_id = channel_ids[1]['channel_id']
channel_14_channel_id = channel_ids[2]['channel_id']

bitcoind.generate_block(1, wait_for_mempool=[multifundchannel_txid])
wait_for(lambda: l1.channel_state(l2) == 'CHANNELD_NORMAL')
wait_for(lambda: l1.channel_state(l3) == 'CHANNELD_NORMAL')
wait_for(lambda: l1.channel_state(l4) == 'CHANNELD_NORMAL')

# now use getblock to get the tx fee from bitcoin-cli's perspective
multifundchannel_rawtx = l1.bitcoin.rpc.getrawtransaction(multifundchannel_txid, True)
blockhash = multifundchannel_rawtx['blockhash']
getblock_tx = l1.bitcoin.rpc.getblock(blockhash, 2)['tx']
getblock_fee_btc = 0
for tx in getblock_tx:
if tx['txid'] == multifundchannel_txid:
getblock_fee_btc = tx['fee']

# now sum bookkeeper fees for each channel to get the total fees for this tx
channel_12_multifundchannel_fee_msat = l1.rpc.bkpr_inspect(channel_12_channel_id)['txs'][0]['fees_paid_msat']
channel_13_multifundchannel_fee_msat = l1.rpc.bkpr_inspect(channel_13_channel_id)['txs'][0]['fees_paid_msat']
channel_14_multifundchannel_fee_msat = l1.rpc.bkpr_inspect(channel_14_channel_id)['txs'][0]['fees_paid_msat']

bkpr_total_fee_msat = (channel_12_multifundchannel_fee_msat
+ channel_13_multifundchannel_fee_msat
+ channel_14_multifundchannel_fee_msat)

assert bkpr_total_fee_msat == int(getblock_fee_btc * 100000000000)


@unittest.skipIf(TEST_NETWORK != 'regtest', "network fees hardcoded")
@pytest.mark.openchannel('v2')
def test_bookkeeping_inspect_mfc_dual_funded(node_factory, bitcoind):
"""
Test that bookkeeper splits multifundchannel fees correctly for dual funded channels.
For dual funded channels, the other nodes also pay part of the fees associated with multifundchannel, since they
are also funding the channel. To calculate the total fees spent for the multifundchannel tx, the
other nodes' fees paid must be included.
"""
opts = {'experimental-dual-fund': None, 'funder-policy': 'match',
'funder-policy-mod': 100, 'funder-lease-requests-only': False}
l1, l2, l3, l4 = node_factory.get_nodes(4, opts=opts)

l1.fundwallet(2000000000)
l2.fundwallet(2000000000)
l3.fundwallet(2000000000)
l4.fundwallet(2000000000)
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
l1.rpc.connect(l3.info['id'], 'localhost', l3.port)
l1.rpc.connect(l4.info['id'], 'localhost', l4.port)

destinations = [{"id": '{}@localhost:{}'.format(l2.info['id'], l2.port),
"amount": 25000,
"announce": True},
{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port),
"amount": 25000,
"announce": True},
{"id": '{}@localhost:{}'.format(l4.info['id'], l4.port),
"amount": 25000,
"announce": True}]

multifundchannel_return = l1.rpc.multifundchannel(destinations)
multifundchannel_txid = multifundchannel_return['txid']
channel_ids = multifundchannel_return['channel_ids']

channel_12_channel_id = channel_ids[0]['channel_id']
channel_13_channel_id = channel_ids[1]['channel_id']
channel_14_channel_id = channel_ids[2]['channel_id']

bitcoind.generate_block(5, wait_for_mempool=[multifundchannel_txid])
wait_for(lambda: l1.channel_state(l2) == 'CHANNELD_NORMAL')
wait_for(lambda: l1.channel_state(l3) == 'CHANNELD_NORMAL')
wait_for(lambda: l1.channel_state(l4) == 'CHANNELD_NORMAL')

# now use getblock to get the tx fee from bitcoin-cli's perspective
multifundchannel_rawtx = l1.bitcoin.rpc.getrawtransaction(multifundchannel_txid, True)
blockhash = multifundchannel_rawtx['blockhash']
getblock_tx = l1.bitcoin.rpc.getblock(blockhash, 2)['tx']
getblock_fee_btc = 0
for tx in getblock_tx:
if tx['txid'] == multifundchannel_txid:
getblock_fee_btc = tx['fee']

# now sum bookkeeper fees for each node to get the total fees for this tx
channel_12_multifundchannel_fee_msat = l1.rpc.bkpr_inspect(channel_12_channel_id)['txs'][0]['fees_paid_msat']
channel_21_multifundchannel_fee_msat = l2.rpc.bkpr_inspect(channel_12_channel_id)['txs'][0]['fees_paid_msat']
channel_13_multifundchannel_fee_msat = l1.rpc.bkpr_inspect(channel_13_channel_id)['txs'][0]['fees_paid_msat']
channel_31_multifundchannel_fee_msat = l3.rpc.bkpr_inspect(channel_13_channel_id)['txs'][0]['fees_paid_msat']
channel_14_multifundchannel_fee_msat = l1.rpc.bkpr_inspect(channel_14_channel_id)['txs'][0]['fees_paid_msat']
channel_41_multifundchannel_fee_msat = l4.rpc.bkpr_inspect(channel_14_channel_id)['txs'][0]['fees_paid_msat']

bkpr_total_fee_msat = (channel_12_multifundchannel_fee_msat
+ channel_21_multifundchannel_fee_msat
+ channel_13_multifundchannel_fee_msat
+ channel_31_multifundchannel_fee_msat
+ channel_14_multifundchannel_fee_msat
+ channel_41_multifundchannel_fee_msat)

assert bkpr_total_fee_msat == int(getblock_fee_btc * 100000000000)


@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')
Expand Down
Loading