mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-19 05:44:12 +01:00
bkpr: for zerconfs, we still wanna know you're opening a channel
We need a record of the channel account before you start sending payments through it. Normally we don't start allowing payments to be sent until after the channel has locked in but zeroconf does away with this assumption. Instead we push out a "channel_proposed" event, which should only show up for zeroconfs.
This commit is contained in:
parent
1b5dc4409a
commit
30aa1d79fb
@ -40,6 +40,7 @@ static const char *mvt_tags[] = {
|
|||||||
"lease_fee",
|
"lease_fee",
|
||||||
"leased",
|
"leased",
|
||||||
"stealable",
|
"stealable",
|
||||||
|
"channel_proposed",
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *mvt_tag_str(enum mvt_tag tag)
|
const char *mvt_tag_str(enum mvt_tag tag)
|
||||||
@ -196,6 +197,33 @@ struct chain_coin_mvt *new_coin_channel_close(const tal_t *ctx,
|
|||||||
output_count);
|
output_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct chain_coin_mvt *new_coin_channel_open_proposed(const tal_t *ctx,
|
||||||
|
const struct channel_id *chan_id,
|
||||||
|
const struct bitcoin_outpoint *out,
|
||||||
|
const struct node_id *peer_id,
|
||||||
|
const struct amount_msat amount,
|
||||||
|
const struct amount_sat output_val,
|
||||||
|
bool is_opener,
|
||||||
|
bool is_leased)
|
||||||
|
{
|
||||||
|
struct chain_coin_mvt *mvt;
|
||||||
|
|
||||||
|
mvt = new_chain_coin_mvt(ctx, NULL, NULL, out, NULL, 0,
|
||||||
|
take(new_tag_arr(NULL, CHANNEL_PROPOSED)),
|
||||||
|
amount, true, output_val, 0);
|
||||||
|
mvt->account_name = type_to_string(mvt, struct channel_id, chan_id);
|
||||||
|
mvt->peer_id = tal_dup(mvt, struct node_id, peer_id);
|
||||||
|
|
||||||
|
/* If we're the opener, add to the tag list */
|
||||||
|
if (is_opener)
|
||||||
|
tal_arr_expand(&mvt->tags, OPENER);
|
||||||
|
|
||||||
|
if (is_leased)
|
||||||
|
tal_arr_expand(&mvt->tags, LEASED);
|
||||||
|
|
||||||
|
return mvt;
|
||||||
|
}
|
||||||
|
|
||||||
struct chain_coin_mvt *new_coin_channel_open(const tal_t *ctx,
|
struct chain_coin_mvt *new_coin_channel_open(const tal_t *ctx,
|
||||||
const struct channel_id *chan_id,
|
const struct channel_id *chan_id,
|
||||||
const struct bitcoin_outpoint *out,
|
const struct bitcoin_outpoint *out,
|
||||||
|
@ -14,7 +14,7 @@ enum mvt_type {
|
|||||||
CHANNEL_MVT = 1,
|
CHANNEL_MVT = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_MVT_TAGS (STEALABLE + 1)
|
#define NUM_MVT_TAGS (CHANNEL_PROPOSED + 1)
|
||||||
enum mvt_tag {
|
enum mvt_tag {
|
||||||
DEPOSIT = 0,
|
DEPOSIT = 0,
|
||||||
WITHDRAWAL = 1,
|
WITHDRAWAL = 1,
|
||||||
@ -39,6 +39,7 @@ enum mvt_tag {
|
|||||||
LEASE_FEE = 20,
|
LEASE_FEE = 20,
|
||||||
LEASED = 21,
|
LEASED = 21,
|
||||||
STEALABLE = 22,
|
STEALABLE = 22,
|
||||||
|
CHANNEL_PROPOSED = 23,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct channel_coin_mvt {
|
struct channel_coin_mvt {
|
||||||
@ -188,6 +189,16 @@ struct chain_coin_mvt *new_coin_channel_close(const tal_t *ctx,
|
|||||||
u32 output_count)
|
u32 output_count)
|
||||||
NON_NULL_ARGS(2, 3);
|
NON_NULL_ARGS(2, 3);
|
||||||
|
|
||||||
|
struct chain_coin_mvt *new_coin_channel_open_proposed(const tal_t *ctx,
|
||||||
|
const struct channel_id *chan_id,
|
||||||
|
const struct bitcoin_outpoint *out,
|
||||||
|
const struct node_id *peer_id,
|
||||||
|
const struct amount_msat amount,
|
||||||
|
const struct amount_sat output_val,
|
||||||
|
bool is_opener,
|
||||||
|
bool is_leased)
|
||||||
|
NON_NULL_ARGS(2, 3);
|
||||||
|
|
||||||
struct chain_coin_mvt *new_coin_channel_open(const tal_t *ctx,
|
struct chain_coin_mvt *new_coin_channel_open(const tal_t *ctx,
|
||||||
const struct channel_id *chan_id,
|
const struct channel_id *chan_id,
|
||||||
const struct bitcoin_outpoint *out,
|
const struct bitcoin_outpoint *out,
|
||||||
|
@ -127,7 +127,7 @@ void notify_feerate_change(struct lightningd *ld)
|
|||||||
* peer. We *could* do so, however. */
|
* peer. We *could* do so, however. */
|
||||||
}
|
}
|
||||||
|
|
||||||
void channel_record_open(struct channel *channel, u32 blockheight)
|
void channel_record_open(struct channel *channel, u32 blockheight, bool record_push)
|
||||||
{
|
{
|
||||||
struct chain_coin_mvt *mvt;
|
struct chain_coin_mvt *mvt;
|
||||||
struct amount_msat start_balance;
|
struct amount_msat start_balance;
|
||||||
@ -153,20 +153,31 @@ void channel_record_open(struct channel *channel, u32 blockheight)
|
|||||||
&channel->push));
|
&channel->push));
|
||||||
}
|
}
|
||||||
|
|
||||||
mvt = new_coin_channel_open(tmpctx,
|
/* If it's not in a block yet, send a proposal */
|
||||||
&channel->cid,
|
if (blockheight > 0)
|
||||||
&channel->funding,
|
mvt = new_coin_channel_open(tmpctx,
|
||||||
&channel->peer->id,
|
&channel->cid,
|
||||||
blockheight,
|
&channel->funding,
|
||||||
start_balance,
|
&channel->peer->id,
|
||||||
channel->funding_sats,
|
blockheight,
|
||||||
channel->opener == LOCAL,
|
start_balance,
|
||||||
is_leased);
|
channel->funding_sats,
|
||||||
|
channel->opener == LOCAL,
|
||||||
|
is_leased);
|
||||||
|
else
|
||||||
|
mvt = new_coin_channel_open_proposed(tmpctx,
|
||||||
|
&channel->cid,
|
||||||
|
&channel->funding,
|
||||||
|
&channel->peer->id,
|
||||||
|
start_balance,
|
||||||
|
channel->funding_sats,
|
||||||
|
channel->opener == LOCAL,
|
||||||
|
is_leased);
|
||||||
|
|
||||||
notify_chain_mvt(channel->peer->ld, mvt);
|
notify_chain_mvt(channel->peer->ld, mvt);
|
||||||
|
|
||||||
/* If we pushed sats, *now* record them */
|
/* If we pushed sats, *now* record them */
|
||||||
if (is_pushed)
|
if (is_pushed && record_push)
|
||||||
notify_channel_mvt(channel->peer->ld,
|
notify_channel_mvt(channel->peer->ld,
|
||||||
new_coin_channel_push(tmpctx, &channel->cid,
|
new_coin_channel_push(tmpctx, &channel->cid,
|
||||||
channel->push,
|
channel->push,
|
||||||
@ -206,10 +217,12 @@ static void lockin_complete(struct channel *channel)
|
|||||||
try_update_blockheight(channel->peer->ld, channel,
|
try_update_blockheight(channel->peer->ld, channel,
|
||||||
get_block_height(channel->peer->ld->topology));
|
get_block_height(channel->peer->ld->topology));
|
||||||
|
|
||||||
/* Only record this once we get a real confirmation. */
|
/* Emit an event for the channel open (or channel proposal if blockheight
|
||||||
if (channel->scid)
|
* is zero) */
|
||||||
channel_record_open(channel,
|
channel_record_open(channel,
|
||||||
short_channel_id_blocknum(channel->scid));
|
channel->scid ?
|
||||||
|
short_channel_id_blocknum(channel->scid) : 0,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool channel_on_funding_locked(struct channel *channel,
|
bool channel_on_funding_locked(struct channel *channel,
|
||||||
@ -867,9 +880,10 @@ bool channel_tell_depth(struct lightningd *ld,
|
|||||||
channel->peer->ld, channel,
|
channel->peer->ld, channel,
|
||||||
get_block_height(channel->peer->ld->topology));
|
get_block_height(channel->peer->ld->topology));
|
||||||
|
|
||||||
/* Only record this once we get a real confirmation. */
|
/* Emit channel_open event */
|
||||||
channel_record_open(channel,
|
channel_record_open(channel,
|
||||||
short_channel_id_blocknum(channel->scid));
|
short_channel_id_blocknum(channel->scid),
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ bool channel_on_funding_locked(struct channel *channel,
|
|||||||
struct pubkey *next_per_commitment_point);
|
struct pubkey *next_per_commitment_point);
|
||||||
|
|
||||||
/* Record channel open (coin movement notifications) */
|
/* Record channel open (coin movement notifications) */
|
||||||
void channel_record_open(struct channel *channel, u32 blockheight);
|
void channel_record_open(struct channel *channel, u32 blockheight, bool record_push);
|
||||||
|
|
||||||
/* A channel has unrecoverably fallen behind */
|
/* A channel has unrecoverably fallen behind */
|
||||||
void channel_fallen_behind(struct channel *channel, const u8 *msg);
|
void channel_fallen_behind(struct channel *channel, const u8 *msg);
|
||||||
|
@ -1750,7 +1750,8 @@ static void handle_channel_locked(struct subd *dualopend,
|
|||||||
REASON_UNKNOWN,
|
REASON_UNKNOWN,
|
||||||
"Lockin complete");
|
"Lockin complete");
|
||||||
channel_record_open(channel,
|
channel_record_open(channel,
|
||||||
short_channel_id_blocknum(channel->scid));
|
short_channel_id_blocknum(channel->scid),
|
||||||
|
true);
|
||||||
|
|
||||||
/* Empty out the inflights */
|
/* Empty out the inflights */
|
||||||
wallet_channel_clear_inflights(dualopend->ld->wallet, channel);
|
wallet_channel_clear_inflights(dualopend->ld->wallet, channel);
|
||||||
|
@ -627,11 +627,10 @@ enum watch_result onchaind_funding_spent(struct channel *channel,
|
|||||||
/* If we haven't posted the open event yet, post an open */
|
/* If we haven't posted the open event yet, post an open */
|
||||||
if (!channel->scid || !channel->remote_funding_locked) {
|
if (!channel->scid || !channel->remote_funding_locked) {
|
||||||
u32 blkh;
|
u32 blkh;
|
||||||
/* Note that blockheight will be zero if it's not in chain
|
/* Blockheight will be zero if it's not in chain */
|
||||||
* yet */
|
|
||||||
blkh = wallet_transaction_height(channel->peer->ld->wallet,
|
blkh = wallet_transaction_height(channel->peer->ld->wallet,
|
||||||
&channel->funding.txid);
|
&channel->funding.txid);
|
||||||
channel_record_open(channel, blkh);
|
channel_record_open(channel, blkh, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1219,6 +1219,7 @@ void maybe_update_account(struct db *db,
|
|||||||
|
|
||||||
for (size_t i = 0; i < tal_count(tags); i++) {
|
for (size_t i = 0; i < tal_count(tags); i++) {
|
||||||
switch (tags[i]) {
|
switch (tags[i]) {
|
||||||
|
case CHANNEL_PROPOSED:
|
||||||
case CHANNEL_OPEN:
|
case CHANNEL_OPEN:
|
||||||
updated = true;
|
updated = true;
|
||||||
acct->open_event_db_id = tal(acct, u64);
|
acct->open_event_db_id = tal(acct, u64);
|
||||||
|
@ -2,7 +2,7 @@ from fixtures import * # noqa: F401,F403
|
|||||||
from fixtures import TEST_NETWORK
|
from fixtures import TEST_NETWORK
|
||||||
from pyln.client import RpcError, Millisatoshi
|
from pyln.client import RpcError, Millisatoshi
|
||||||
from utils import (
|
from utils import (
|
||||||
only_one, wait_for, sync_blockheight, first_channel_id, calc_lease_fee
|
only_one, wait_for, sync_blockheight, first_channel_id, calc_lease_fee, check_coin_moves
|
||||||
)
|
)
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -1312,7 +1312,7 @@ def test_zeroconf_open(bitcoind, node_factory):
|
|||||||
l2.rpc.pay(inv)
|
l2.rpc.pay(inv)
|
||||||
|
|
||||||
|
|
||||||
def test_zeroconf_public(bitcoind, node_factory):
|
def test_zeroconf_public(bitcoind, node_factory, chainparams):
|
||||||
"""Test that we transition correctly from zeroconf to public
|
"""Test that we transition correctly from zeroconf to public
|
||||||
|
|
||||||
The differences being that a public channel MUST use the public
|
The differences being that a public channel MUST use the public
|
||||||
@ -1321,9 +1321,10 @@ def test_zeroconf_public(bitcoind, node_factory):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
plugin_path = Path(__file__).parent / "plugins" / "zeroconf-selective.py"
|
plugin_path = Path(__file__).parent / "plugins" / "zeroconf-selective.py"
|
||||||
|
coin_mvt_plugin = Path(__file__).parent / "plugins" / "coin_movements.py"
|
||||||
|
|
||||||
l1, l2, l3 = node_factory.get_nodes(3, opts=[
|
l1, l2, l3 = node_factory.get_nodes(3, opts=[
|
||||||
{},
|
{'plugin': str(coin_mvt_plugin)},
|
||||||
{
|
{
|
||||||
'plugin': str(plugin_path),
|
'plugin': str(plugin_path),
|
||||||
'zeroconf-allow': '0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518'
|
'zeroconf-allow': '0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518'
|
||||||
@ -1346,6 +1347,13 @@ def test_zeroconf_public(bitcoind, node_factory):
|
|||||||
assert('short_channel_id' not in l1chan)
|
assert('short_channel_id' not in l1chan)
|
||||||
assert('short_channel_id' not in l2chan)
|
assert('short_channel_id' not in l2chan)
|
||||||
|
|
||||||
|
# Channel is "proposed"
|
||||||
|
chan_val = 993198000 if chainparams['elements'] else 995673000
|
||||||
|
l1_mvts = [
|
||||||
|
{'type': 'chain_mvt', 'credit_msat': chan_val, 'debit_msat': 0, 'tags': ['channel_proposed', 'opener']},
|
||||||
|
]
|
||||||
|
check_coin_moves(l1, l1chan['channel_id'], l1_mvts, chainparams)
|
||||||
|
|
||||||
# Now add 1 confirmation, we should get a `short_channel_id`
|
# Now add 1 confirmation, we should get a `short_channel_id`
|
||||||
bitcoind.generate_block(1)
|
bitcoind.generate_block(1)
|
||||||
l1.daemon.wait_for_log(r'Funding tx [a-f0-9]{64} depth 1 of 0')
|
l1.daemon.wait_for_log(r'Funding tx [a-f0-9]{64} depth 1 of 0')
|
||||||
@ -1356,6 +1364,12 @@ def test_zeroconf_public(bitcoind, node_factory):
|
|||||||
assert('short_channel_id' in l1chan)
|
assert('short_channel_id' in l1chan)
|
||||||
assert('short_channel_id' in l2chan)
|
assert('short_channel_id' in l2chan)
|
||||||
|
|
||||||
|
# We also now have an 'open' event
|
||||||
|
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)
|
||||||
|
|
||||||
# Now make it public, we should be switching over to the real
|
# Now make it public, we should be switching over to the real
|
||||||
# scid.
|
# scid.
|
||||||
bitcoind.generate_block(5)
|
bitcoind.generate_block(5)
|
||||||
|
Loading…
Reference in New Issue
Block a user