Browse Source
This is not connected yet; during the transition, there will be a 1:1 mapping from channel to peer, so we can use channel2peer and peer2channel to shim between them. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>ppa-0.6.1
Rusty Russell
7 years ago
committed by
Christian Decker
2 changed files with 288 additions and 0 deletions
@ -0,0 +1,95 @@ |
|||||
|
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h> |
||||
|
#include <ccan/tal/str/str.h> |
||||
|
#include <gossipd/gen_gossip_wire.h> |
||||
|
#include <inttypes.h> |
||||
|
#include <lightningd/channel.h> |
||||
|
#include <lightningd/jsonrpc.h> |
||||
|
#include <lightningd/lightningd.h> |
||||
|
#include <lightningd/log.h> |
||||
|
#include <lightningd/peer_control.h> |
||||
|
#include <lightningd/subd.h> |
||||
|
|
||||
|
static void destroy_channel(struct channel *channel) |
||||
|
{ |
||||
|
list_del_from(&channel->peer->channels, &channel->list); |
||||
|
} |
||||
|
|
||||
|
/* FIXME: We have no business knowing this! */ |
||||
|
/**
|
||||
|
* derive_channel_seed - Generate a unique secret for this peer's channel |
||||
|
* |
||||
|
* @ld: the lightning daemon to get global secret from |
||||
|
* @seed: where to store the generated secret |
||||
|
* @peer_id: the id node_id of the remote peer |
||||
|
* @dbid: channel DBID |
||||
|
* |
||||
|
* This method generates a unique secret from the given parameters. It |
||||
|
* is important that this secret be unique for each channel, but it |
||||
|
* must be reproducible for the same channel in case of |
||||
|
* reconnection. We use the DB channel ID to guarantee unique secrets |
||||
|
* per channel. |
||||
|
*/ |
||||
|
void derive_channel_seed(struct lightningd *ld, struct privkey *seed, |
||||
|
const struct pubkey *peer_id, |
||||
|
const u64 dbid) |
||||
|
{ |
||||
|
u8 input[PUBKEY_DER_LEN + sizeof(dbid)]; |
||||
|
char *info = "per-peer seed"; |
||||
|
pubkey_to_der(input, peer_id); |
||||
|
memcpy(input + PUBKEY_DER_LEN, &dbid, sizeof(dbid)); |
||||
|
|
||||
|
assert(dbid != 0); |
||||
|
hkdf_sha256(seed, sizeof(*seed), |
||||
|
input, sizeof(input), |
||||
|
&ld->peer_seed, sizeof(ld->peer_seed), |
||||
|
info, strlen(info)); |
||||
|
} |
||||
|
|
||||
|
struct channel *new_channel(struct peer *peer, u64 dbid, u32 first_blocknum) |
||||
|
{ |
||||
|
/* FIXME: We currently rely on it being all zero/NULL */ |
||||
|
struct channel *channel = talz(peer->ld, struct channel); |
||||
|
|
||||
|
channel->dbid = dbid; |
||||
|
channel->peer = peer; |
||||
|
channel->first_blocknum = first_blocknum; |
||||
|
channel->state = UNINITIALIZED; |
||||
|
channel->local_shutdown_idx = -1; |
||||
|
|
||||
|
/* FIXME: update log prefix when we get scid */ |
||||
|
channel->log = new_log(channel, peer->log_book, "%s chan #%"PRIu64":", |
||||
|
log_prefix(peer->log), dbid); |
||||
|
list_add_tail(&peer->channels, &channel->list); |
||||
|
tal_add_destructor(channel, destroy_channel); |
||||
|
if (channel->dbid != 0) |
||||
|
derive_channel_seed(peer->ld, &channel->seed, &peer->id, |
||||
|
channel->dbid); |
||||
|
|
||||
|
return channel; |
||||
|
} |
||||
|
|
||||
|
const char *channel_state_name(const struct channel *channel) |
||||
|
{ |
||||
|
return peer_state_name(channel->state); |
||||
|
} |
||||
|
|
||||
|
struct channel *peer_active_channel(struct peer *peer) |
||||
|
{ |
||||
|
struct channel *channel; |
||||
|
|
||||
|
list_for_each(&peer->channels, channel, list) { |
||||
|
if (channel_active(channel)) |
||||
|
return channel; |
||||
|
} |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
struct channel *peer2channel(const struct peer *peer) |
||||
|
{ |
||||
|
return list_top(&peer->channels, struct channel, list); |
||||
|
} |
||||
|
|
||||
|
struct peer *channel2peer(const struct channel *channel) |
||||
|
{ |
||||
|
return channel->peer; |
||||
|
} |
@ -0,0 +1,193 @@ |
|||||
|
#ifndef LIGHTNING_LIGHTNINGD_CHANNEL_H |
||||
|
#define LIGHTNING_LIGHTNINGD_CHANNEL_H |
||||
|
#include "config.h" |
||||
|
#include <ccan/list/list.h> |
||||
|
#include <lightningd/peer_state.h> |
||||
|
#include <wallet/wallet.h> |
||||
|
|
||||
|
struct channel { |
||||
|
/* Inside peer->channels. */ |
||||
|
struct list_node list; |
||||
|
|
||||
|
/* Peer context */ |
||||
|
struct peer *peer; |
||||
|
|
||||
|
/* Database ID: 0 == not in db yet */ |
||||
|
u64 dbid; |
||||
|
|
||||
|
/* Error message (iff in error state) */ |
||||
|
u8 *error; |
||||
|
|
||||
|
/* Their shachain. */ |
||||
|
struct wallet_shachain their_shachain; |
||||
|
|
||||
|
/* What's happening. */ |
||||
|
enum peer_state state; |
||||
|
|
||||
|
/* Which side offered channel? */ |
||||
|
enum side funder; |
||||
|
|
||||
|
/* Command which ordered us to open channel, if any. */ |
||||
|
struct command *opening_cmd; |
||||
|
|
||||
|
/* Is there a single subdaemon responsible for us? */ |
||||
|
struct subd *owner; |
||||
|
|
||||
|
/* History */ |
||||
|
struct log *log; |
||||
|
|
||||
|
/* Channel flags from opening message. */ |
||||
|
u8 channel_flags; |
||||
|
|
||||
|
/* Our channel config. */ |
||||
|
struct channel_config our_config; |
||||
|
|
||||
|
/* Minimum funding depth (specified by us if they fund). */ |
||||
|
u32 minimum_depth; |
||||
|
|
||||
|
/* Tracking commitment transaction numbers. */ |
||||
|
u64 next_index[NUM_SIDES]; |
||||
|
u64 next_htlc_id; |
||||
|
|
||||
|
/* Funding txid and amounts (once known) */ |
||||
|
struct bitcoin_txid *funding_txid; |
||||
|
u16 funding_outnum; |
||||
|
u64 funding_satoshi, push_msat; |
||||
|
bool remote_funding_locked; |
||||
|
/* Channel if locked locally. */ |
||||
|
struct short_channel_id *scid; |
||||
|
|
||||
|
/* Amount going to us, not counting unfinished HTLCs; if we have one. */ |
||||
|
u64 *our_msatoshi; |
||||
|
|
||||
|
/* Last tx they gave us (if any). */ |
||||
|
struct bitcoin_tx *last_tx; |
||||
|
secp256k1_ecdsa_signature *last_sig; |
||||
|
secp256k1_ecdsa_signature *last_htlc_sigs; |
||||
|
|
||||
|
/* Keys for channel. */ |
||||
|
struct channel_info *channel_info; |
||||
|
|
||||
|
/* Secret seed (FIXME: Move to hsm!) */ |
||||
|
struct privkey seed; |
||||
|
|
||||
|
/* Their scriptpubkey if they sent shutdown. */ |
||||
|
u8 *remote_shutdown_scriptpubkey; |
||||
|
/* Our key for shutdown (-1 if not chosen yet) */ |
||||
|
s64 local_shutdown_idx; |
||||
|
|
||||
|
/* Reestablishment stuff: last sent commit and revocation details. */ |
||||
|
bool last_was_revoke; |
||||
|
struct changed_htlc *last_sent_commit; |
||||
|
|
||||
|
/* Blockheight at creation, scans for funding confirmations
|
||||
|
* will start here */ |
||||
|
u64 first_blocknum; |
||||
|
}; |
||||
|
|
||||
|
struct channel *new_channel(struct peer *peer, u64 dbid, u32 first_blocknum); |
||||
|
|
||||
|
const char *channel_state_name(const struct channel *channel); |
||||
|
|
||||
|
void derive_channel_seed(struct lightningd *ld, struct privkey *seed, |
||||
|
const struct pubkey *peer_id, |
||||
|
const u64 dbid); |
||||
|
|
||||
|
/* FIXME: Temporary mapping from peer to channel, while we only have one. */ |
||||
|
struct channel *peer2channel(const struct peer *peer); |
||||
|
struct peer *channel2peer(const struct channel *channel); |
||||
|
|
||||
|
/* Find a channel which is not onchain, if any */ |
||||
|
struct channel *peer_active_channel(struct peer *peer); |
||||
|
|
||||
|
static inline bool channel_can_add_htlc(const struct channel *channel) |
||||
|
{ |
||||
|
return channel->state == CHANNELD_NORMAL; |
||||
|
} |
||||
|
|
||||
|
static inline bool channel_fees_can_change(const struct channel *channel) |
||||
|
{ |
||||
|
return channel->state == CHANNELD_NORMAL |
||||
|
|| channel->state == CHANNELD_SHUTTING_DOWN; |
||||
|
} |
||||
|
|
||||
|
static inline bool channel_can_remove_htlc(const struct channel *channel) |
||||
|
{ |
||||
|
return channel->state == CHANNELD_NORMAL |
||||
|
|| channel->state == CHANNELD_SHUTTING_DOWN |
||||
|
|| channel->state == ONCHAIND_THEIR_UNILATERAL |
||||
|
|| channel->state == ONCHAIND_OUR_UNILATERAL; |
||||
|
} |
||||
|
|
||||
|
static inline bool channel_state_on_chain(enum peer_state state) |
||||
|
{ |
||||
|
return state == ONCHAIND_CHEATED |
||||
|
|| state == ONCHAIND_THEIR_UNILATERAL |
||||
|
|| state == ONCHAIND_OUR_UNILATERAL |
||||
|
|| state == ONCHAIND_MUTUAL; |
||||
|
} |
||||
|
|
||||
|
static inline bool channel_on_chain(const struct channel *channel) |
||||
|
{ |
||||
|
return channel_state_on_chain(channel->state); |
||||
|
} |
||||
|
|
||||
|
static inline bool channel_active(const struct channel *channel) |
||||
|
{ |
||||
|
return channel->state != FUNDING_SPEND_SEEN |
||||
|
&& channel->state != CLOSINGD_COMPLETE |
||||
|
&& !channel_on_chain(channel); |
||||
|
} |
||||
|
|
||||
|
static inline bool channel_wants_reconnect(const struct channel *channel) |
||||
|
{ |
||||
|
return channel->state >= CHANNELD_AWAITING_LOCKIN |
||||
|
&& channel->state <= CLOSINGD_COMPLETE; |
||||
|
} |
||||
|
|
||||
|
/* BOLT #2:
|
||||
|
* |
||||
|
* On disconnection, the funder MUST remember the channel for |
||||
|
* reconnection if it has broadcast the funding transaction, otherwise it |
||||
|
* SHOULD NOT. |
||||
|
* |
||||
|
* On disconnection, the non-funding node MUST remember the channel for |
||||
|
* reconnection if it has sent the `funding_signed` message, otherwise |
||||
|
* it SHOULD NOT. |
||||
|
*/ |
||||
|
static inline bool channel_persists(const struct channel *channel) |
||||
|
{ |
||||
|
return channel->state >= CHANNELD_AWAITING_LOCKIN; |
||||
|
} |
||||
|
|
||||
|
/* FIXME: Obsolete */ |
||||
|
static inline bool peer_can_add_htlc(const struct peer *peer) |
||||
|
{ |
||||
|
return channel_can_add_htlc(peer2channel(peer)); |
||||
|
} |
||||
|
|
||||
|
static inline bool peer_fees_can_change(const struct peer *peer) |
||||
|
{ |
||||
|
return channel_fees_can_change(peer2channel(peer)); |
||||
|
} |
||||
|
|
||||
|
static inline bool peer_can_remove_htlc(const struct peer *peer) |
||||
|
{ |
||||
|
return channel_can_remove_htlc(peer2channel(peer)); |
||||
|
} |
||||
|
|
||||
|
static inline bool peer_on_chain(const struct peer *peer) |
||||
|
{ |
||||
|
return channel_state_on_chain(peer2channel(peer)->state); |
||||
|
} |
||||
|
|
||||
|
static inline bool peer_wants_reconnect(const struct peer *peer) |
||||
|
{ |
||||
|
return channel_wants_reconnect(peer2channel(peer)); |
||||
|
} |
||||
|
|
||||
|
static inline bool peer_persists(const struct peer *peer) |
||||
|
{ |
||||
|
return channel_persists(peer2channel(peer)); |
||||
|
} |
||||
|
#endif /* LIGHTNING_LIGHTNINGD_CHANNEL_H */ |
Loading…
Reference in new issue