mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 09:54:16 +01:00
bkpr-zeroconf: Zeroconfs will emit 'channel_proposed' event
Keep the accounts as an 'append only' log, instead we move the marker for the 'channel_open' forward when a 'channel_open' comes out. We also neatly hide the 'channel_proposed' events in 'inspect' if there's a 'channel_open' for that same event. If you call inspect before the 'channel_open' is confirmed, you'll see the tag as 'channel_proposed', afterwards it shows up as 'channel_open'. However the event log rolls forward -- listaccountevents will show the correct history of the proposal then open confirming (plus any routing that happened before the channel confirmed).
This commit is contained in:
parent
30aa1d79fb
commit
e048292fdf
@ -225,7 +225,8 @@ static struct chain_event **find_txos_for_tx(const tal_t *ctx,
|
||||
" ORDER BY "
|
||||
" e.utxo_txid"
|
||||
", e.outnum"
|
||||
", e.spending_txid NULLS FIRST"));
|
||||
", e.spending_txid NULLS FIRST"
|
||||
", e.blockheight"));
|
||||
|
||||
db_bind_txid(stmt, 0, txid);
|
||||
return find_chain_events(ctx, take(stmt));
|
||||
@ -403,8 +404,14 @@ static struct txo_set *find_txo_set(const tal_t *ctx,
|
||||
} else {
|
||||
/* We might not have a spend event
|
||||
* for everything */
|
||||
if (pr)
|
||||
tal_arr_expand(&txos->pairs, pr);
|
||||
if (pr) {
|
||||
/* Disappear "channel_proposed" events */
|
||||
if (streq(pr->txo->tag,
|
||||
mvt_tag_str(CHANNEL_PROPOSED)))
|
||||
pr = tal_free(pr);
|
||||
else
|
||||
tal_arr_expand(&txos->pairs, pr);
|
||||
}
|
||||
pr = new_txo_pair(txos->pairs);
|
||||
pr->txo = tal_steal(pr, ev);
|
||||
}
|
||||
@ -671,7 +678,8 @@ static struct chain_event *find_chain_event(const tal_t *ctx,
|
||||
struct db *db,
|
||||
const struct account *acct,
|
||||
const struct bitcoin_outpoint *outpoint,
|
||||
const struct bitcoin_txid *spending_txid)
|
||||
const struct bitcoin_txid *spending_txid,
|
||||
const char *tag)
|
||||
|
||||
{
|
||||
struct db_stmt *stmt;
|
||||
@ -733,7 +741,10 @@ static struct chain_event *find_chain_event(const tal_t *ctx,
|
||||
" e.account_id = ?"
|
||||
" AND e.utxo_txid = ?"
|
||||
" AND e.outnum = ?"
|
||||
" AND e.spending_txid IS NULL"));
|
||||
" AND e.spending_txid IS NULL"
|
||||
" AND e.tag = ?"));
|
||||
|
||||
db_bind_text(stmt, 3, tag);
|
||||
}
|
||||
|
||||
db_bind_u64(stmt, 0, acct->db_id);
|
||||
@ -1850,7 +1861,8 @@ bool log_chain_event(struct db *db,
|
||||
|
||||
/* We're responsible for de-duping chain events! */
|
||||
if (find_chain_event(e, db, acct,
|
||||
&e->outpoint, e->spending_txid))
|
||||
&e->outpoint, e->spending_txid,
|
||||
e->tag))
|
||||
return false;
|
||||
|
||||
stmt = db_prepare_v2(db, SQL("INSERT INTO chain_events"
|
||||
|
@ -11,6 +11,7 @@ BOOKKEEPER_TEST_COMMON_OBJS := \
|
||||
common/base32.o \
|
||||
common/blockheight_states.o \
|
||||
common/channel_type.o \
|
||||
common/coin_mvt.o \
|
||||
common/features.o \
|
||||
common/json_stream.o \
|
||||
common/key_derive.o \
|
||||
|
@ -88,6 +88,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
/* Generated stub for fromwire_u8_array */
|
||||
void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_wirestring */
|
||||
char *fromwire_wirestring(const tal_t *ctx UNNEEDED, const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_wirestring called!\n"); abort(); }
|
||||
/* Generated stub for htlc_state_flags */
|
||||
int htlc_state_flags(enum htlc_state state UNNEEDED)
|
||||
{ fprintf(stderr, "htlc_state_flags called!\n"); abort(); }
|
||||
@ -177,9 +180,6 @@ enum htlc_state last_fee_state(enum side opener UNNEEDED)
|
||||
/* Generated stub for log_level_name */
|
||||
const char *log_level_name(enum log_level level UNNEEDED)
|
||||
{ fprintf(stderr, "log_level_name called!\n"); abort(); }
|
||||
/* Generated stub for mvt_tag_str */
|
||||
const char *mvt_tag_str(enum mvt_tag tag UNNEEDED)
|
||||
{ fprintf(stderr, "mvt_tag_str called!\n"); abort(); }
|
||||
/* Generated stub for new_channel_event */
|
||||
struct channel_event *new_channel_event(const tal_t *ctx UNNEEDED,
|
||||
const char *tag UNNEEDED,
|
||||
@ -225,6 +225,9 @@ void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED)
|
||||
/* Generated stub for towire_u8_array */
|
||||
void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u8_array called!\n"); abort(); }
|
||||
/* Generated stub for towire_wirestring */
|
||||
void towire_wirestring(u8 **pptr UNNEEDED, const char *str UNNEEDED)
|
||||
{ fprintf(stderr, "towire_wirestring called!\n"); abort(); }
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
|
||||
static char *tmp_dsn(const tal_t *ctx)
|
||||
|
@ -94,6 +94,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
/* Generated stub for fromwire_u8_array */
|
||||
void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_wirestring */
|
||||
char *fromwire_wirestring(const tal_t *ctx UNNEEDED, const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_wirestring called!\n"); abort(); }
|
||||
/* Generated stub for htlc_state_flags */
|
||||
int htlc_state_flags(enum htlc_state state UNNEEDED)
|
||||
{ fprintf(stderr, "htlc_state_flags called!\n"); abort(); }
|
||||
@ -183,9 +186,6 @@ enum htlc_state last_fee_state(enum side opener UNNEEDED)
|
||||
/* Generated stub for log_level_name */
|
||||
const char *log_level_name(enum log_level level UNNEEDED)
|
||||
{ fprintf(stderr, "log_level_name called!\n"); abort(); }
|
||||
/* Generated stub for mvt_tag_str */
|
||||
const char *mvt_tag_str(enum mvt_tag tag UNNEEDED)
|
||||
{ fprintf(stderr, "mvt_tag_str called!\n"); abort(); }
|
||||
/* Generated stub for new_channel_event */
|
||||
struct channel_event *new_channel_event(const tal_t *ctx UNNEEDED,
|
||||
const char *tag UNNEEDED,
|
||||
@ -231,6 +231,9 @@ void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED)
|
||||
/* Generated stub for towire_u8_array */
|
||||
void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u8_array called!\n"); abort(); }
|
||||
/* Generated stub for towire_wirestring */
|
||||
void towire_wirestring(u8 **pptr UNNEEDED, const char *str UNNEEDED)
|
||||
{ fprintf(stderr, "towire_wirestring called!\n"); abort(); }
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
|
||||
static char *tmp_dsn(const tal_t *ctx)
|
||||
|
@ -1331,9 +1331,11 @@ def test_zeroconf_public(bitcoind, node_factory, chainparams):
|
||||
},
|
||||
{}
|
||||
])
|
||||
# Advances blockheight to 102
|
||||
l1.fundwallet(10**6)
|
||||
push_msat = 20000 * 1000
|
||||
l1.connect(l2)
|
||||
l1.rpc.fundchannel(l2.info['id'], 'all', mindepth=0)
|
||||
l1.rpc.fundchannel(l2.info['id'], 'all', mindepth=0, push_msat=push_msat)
|
||||
|
||||
# Wait for the update to be signed (might not be the most reliable
|
||||
# signal)
|
||||
@ -1342,6 +1344,7 @@ def test_zeroconf_public(bitcoind, node_factory, chainparams):
|
||||
|
||||
l1chan = l1.rpc.listpeers()['peers'][0]['channels'][0]
|
||||
l2chan = l2.rpc.listpeers()['peers'][0]['channels'][0]
|
||||
channel_id = l1chan['channel_id']
|
||||
|
||||
# We have no confirmation yet, so no `short_channel_id`
|
||||
assert('short_channel_id' not in l1chan)
|
||||
@ -1351,10 +1354,22 @@ def test_zeroconf_public(bitcoind, node_factory, chainparams):
|
||||
chan_val = 993198000 if chainparams['elements'] else 995673000
|
||||
l1_mvts = [
|
||||
{'type': 'chain_mvt', 'credit_msat': chan_val, 'debit_msat': 0, 'tags': ['channel_proposed', 'opener']},
|
||||
{'type': 'channel_mvt', 'credit_msat': 0, 'debit_msat': 20000000, 'tags': ['pushed'], 'fees_msat': '0msat'},
|
||||
]
|
||||
check_coin_moves(l1, l1chan['channel_id'], l1_mvts, chainparams)
|
||||
|
||||
# Now add 1 confirmation, we should get a `short_channel_id`
|
||||
# Check that the channel_open event has blockheight of zero
|
||||
for n in [l1, l2]:
|
||||
evs = n.rpc.bkpr_listaccountevents(channel_id)['events']
|
||||
open_ev = only_one([e for e in evs if e['tag'] == 'channel_proposed'])
|
||||
assert open_ev['blockheight'] == 0
|
||||
|
||||
# Call inspect, should have pending event in it
|
||||
tx = only_one(n.rpc.bkpr_inspect(channel_id)['txs'])
|
||||
assert 'blockheight' not in tx
|
||||
assert only_one(tx['outputs'])['output_tag'] == 'channel_proposed'
|
||||
|
||||
# Now add 1 confirmation, we should get a `short_channel_id` (block 103)
|
||||
bitcoind.generate_block(1)
|
||||
l1.daemon.wait_for_log(r'Funding tx [a-f0-9]{64} depth 1 of 0')
|
||||
l2.daemon.wait_for_log(r'Funding tx [a-f0-9]{64} depth 1 of 0')
|
||||
@ -1364,11 +1379,24 @@ def test_zeroconf_public(bitcoind, node_factory, chainparams):
|
||||
assert('short_channel_id' in l1chan)
|
||||
assert('short_channel_id' in l2chan)
|
||||
|
||||
# We also now have an 'open' event
|
||||
# We also now have an 'open' event, the push event isn't re-recorded
|
||||
l1_mvts += [
|
||||
{'type': 'chain_mvt', 'credit_msat': chan_val, 'debit_msat': 0, 'tags': ['channel_open', 'opener']},
|
||||
]
|
||||
check_coin_moves(l1, l1chan['channel_id'], l1_mvts, chainparams)
|
||||
check_coin_moves(l1, channel_id, l1_mvts, chainparams)
|
||||
|
||||
# Check that there is a channel_open event w/ real blockheight
|
||||
for n in [l1, l2]:
|
||||
evs = n.rpc.bkpr_listaccountevents(channel_id)['events']
|
||||
# Still has the channel-proposed event
|
||||
only_one([e for e in evs if e['tag'] == 'channel_proposed'])
|
||||
open_ev = only_one([e for e in evs if e['tag'] == 'channel_open'])
|
||||
assert open_ev['blockheight'] == 103
|
||||
|
||||
# Call inspect, should have open event in it
|
||||
tx = only_one(n.rpc.bkpr_inspect(channel_id)['txs'])
|
||||
assert tx['blockheight'] == 103
|
||||
assert only_one(tx['outputs'])['output_tag'] == 'channel_open'
|
||||
|
||||
# Now make it public, we should be switching over to the real
|
||||
# scid.
|
||||
@ -1378,6 +1406,14 @@ def test_zeroconf_public(bitcoind, node_factory, chainparams):
|
||||
l3.connect(l1)
|
||||
wait_for(lambda: len(l3.rpc.listchannels()['channels']) == 2)
|
||||
|
||||
# Close the zerconf channel, check that we mark it as onchain_resolved ok
|
||||
l1.rpc.close(l2.info['id'])
|
||||
bitcoind.generate_block(1, wait_for_mempool=1)
|
||||
|
||||
# Channel should be marked resolved
|
||||
for n in [l1, l2]:
|
||||
wait_for(lambda: only_one([x for x in n.rpc.bkpr_listbalances()['accounts'] if x['account'] == channel_id])['account_resolved'])
|
||||
|
||||
|
||||
def test_zeroconf_forward(node_factory, bitcoind):
|
||||
"""Ensure that we can use zeroconf channels in forwards.
|
||||
|
Loading…
Reference in New Issue
Block a user