mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-24 01:24:26 +01:00
packets.c: queue_pkt_* only creates and sends packets.
Move other logic into caller: it grew this way because we used to have a centralized "state" machine which knew nothing of these internal details. But now we want to re-queue packets on reconnect, we really want these routines to be idempotent. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
268
daemon/packets.c
268
daemon/packets.c
@@ -69,24 +69,10 @@ static void queue_pkt(struct peer *peer, Pkt__PktCase type, const void *msg)
|
||||
queue_raw_pkt(peer, make_pkt(peer, type, msg));
|
||||
}
|
||||
|
||||
static struct commit_info *new_commit_info(const tal_t *ctx)
|
||||
{
|
||||
struct commit_info *ci = talz(ctx, struct commit_info);
|
||||
ci->unacked_changes = tal_arr(ci, union htlc_staging, 0);
|
||||
ci->acked_changes = tal_arr(ci, union htlc_staging, 0);
|
||||
return ci;
|
||||
}
|
||||
|
||||
void queue_pkt_open(struct peer *peer, OpenChannel__AnchorOffer anchor)
|
||||
{
|
||||
OpenChannel *o = tal(peer, OpenChannel);
|
||||
|
||||
/* Set up out commit info now: rest gets done in setup_first_commit
|
||||
* once anchor is established. */
|
||||
peer->local.commit = new_commit_info(peer);
|
||||
peer->local.commit->revocation_hash = peer->local.next_revocation_hash;
|
||||
peer_get_revocation_hash(peer, 1, &peer->local.next_revocation_hash);
|
||||
|
||||
open_channel__init(o);
|
||||
o->revocation_hash = sha256_to_proto(o, &peer->local.commit->revocation_hash);
|
||||
o->next_revocation_hash = sha256_to_proto(o, &peer->local.next_revocation_hash);
|
||||
@@ -120,14 +106,6 @@ void queue_pkt_anchor(struct peer *peer)
|
||||
a->output_index = peer->anchor.index;
|
||||
a->amount = peer->anchor.satoshis;
|
||||
|
||||
/* This shouldn't happen! */
|
||||
if (!setup_first_commit(peer)) {
|
||||
queue_pkt_err(peer,
|
||||
pkt_err(peer,
|
||||
"Own anchor has insufficient funds"));
|
||||
return;
|
||||
}
|
||||
|
||||
queue_pkt(peer, PKT__PKT_OPEN_ANCHOR, a);
|
||||
}
|
||||
|
||||
@@ -137,16 +115,6 @@ void queue_pkt_open_commit_sig(struct peer *peer)
|
||||
|
||||
open_commit_sig__init(s);
|
||||
|
||||
log_debug_struct(peer->log, "Creating sig for %s",
|
||||
struct bitcoin_tx, peer->remote.commit->tx);
|
||||
log_add_struct(peer->log, " using key %s",
|
||||
struct pubkey, &peer->local.commitkey);
|
||||
|
||||
peer->remote.commit->sig = tal(peer->remote.commit,
|
||||
struct bitcoin_signature);
|
||||
peer->remote.commit->sig->stype = SIGHASH_ALL;
|
||||
peer_sign_theircommit(peer, peer->remote.commit->tx,
|
||||
&peer->remote.commit->sig->sig);
|
||||
s->sig = signature_to_proto(s, peer->dstate->secpctx,
|
||||
&peer->remote.commit->sig->sig);
|
||||
|
||||
@@ -164,7 +132,6 @@ void queue_pkt_open_complete(struct peer *peer)
|
||||
void queue_pkt_htlc_add(struct peer *peer, struct htlc *htlc)
|
||||
{
|
||||
UpdateAddHtlc *u = tal(peer, UpdateAddHtlc);
|
||||
union htlc_staging stage;
|
||||
|
||||
update_add_htlc__init(u);
|
||||
|
||||
@@ -180,49 +147,16 @@ void queue_pkt_htlc_add(struct peer *peer, struct htlc *htlc)
|
||||
0);
|
||||
u->route->info.len = tal_count(u->route->info.data);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The sending node MUST add the HTLC addition to the unacked
|
||||
* changeset for its remote commitment
|
||||
*/
|
||||
if (!cstate_add_htlc(peer->remote.staging_cstate, htlc, OURS))
|
||||
fatal("Could not add HTLC?");
|
||||
|
||||
stage.add.add = HTLC_ADD;
|
||||
stage.add.htlc = htlc;
|
||||
add_unacked(&peer->remote, &stage);
|
||||
|
||||
remote_changes_pending(peer);
|
||||
|
||||
queue_pkt(peer, PKT__PKT_UPDATE_ADD_HTLC, u);
|
||||
}
|
||||
|
||||
void queue_pkt_htlc_fulfill(struct peer *peer, struct htlc *htlc,
|
||||
const struct rval *r)
|
||||
void queue_pkt_htlc_fulfill(struct peer *peer, struct htlc *htlc)
|
||||
{
|
||||
UpdateFulfillHtlc *f = tal(peer, UpdateFulfillHtlc);
|
||||
union htlc_staging stage;
|
||||
|
||||
update_fulfill_htlc__init(f);
|
||||
f->id = htlc->id;
|
||||
f->r = rval_to_proto(f, r);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The sending node MUST add the HTLC fulfill/fail to the
|
||||
* unacked changeset for its remote commitment
|
||||
*/
|
||||
assert(cstate_htlc_by_id(peer->remote.staging_cstate, f->id, THEIRS)
|
||||
== htlc);
|
||||
cstate_fulfill_htlc(peer->remote.staging_cstate, htlc, THEIRS);
|
||||
|
||||
stage.fulfill.fulfill = HTLC_FULFILL;
|
||||
stage.fulfill.htlc = htlc;
|
||||
stage.fulfill.r = *r;
|
||||
add_unacked(&peer->remote, &stage);
|
||||
htlc_changestate(htlc, RCVD_ADD_ACK_REVOCATION, SENT_REMOVE_HTLC);
|
||||
|
||||
remote_changes_pending(peer);
|
||||
f->r = rval_to_proto(f, htlc->r);
|
||||
|
||||
queue_pkt(peer, PKT__PKT_UPDATE_FULFILL_HTLC, f);
|
||||
}
|
||||
@@ -230,7 +164,6 @@ void queue_pkt_htlc_fulfill(struct peer *peer, struct htlc *htlc,
|
||||
void queue_pkt_htlc_fail(struct peer *peer, struct htlc *htlc)
|
||||
{
|
||||
UpdateFailHtlc *f = tal(peer, UpdateFailHtlc);
|
||||
union htlc_staging stage;
|
||||
|
||||
update_fail_htlc__init(f);
|
||||
f->id = htlc->id;
|
||||
@@ -239,218 +172,39 @@ void queue_pkt_htlc_fail(struct peer *peer, struct htlc *htlc)
|
||||
f->reason = tal(f, FailReason);
|
||||
fail_reason__init(f->reason);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The sending node MUST add the HTLC fulfill/fail to the
|
||||
* unacked changeset for its remote commitment
|
||||
*/
|
||||
assert(cstate_htlc_by_id(peer->remote.staging_cstate, f->id, THEIRS)
|
||||
== htlc);
|
||||
cstate_fail_htlc(peer->remote.staging_cstate, htlc, THEIRS);
|
||||
|
||||
stage.fail.fail = HTLC_FAIL;
|
||||
stage.fail.htlc = htlc;
|
||||
add_unacked(&peer->remote, &stage);
|
||||
htlc_changestate(htlc, RCVD_ADD_ACK_REVOCATION, SENT_REMOVE_HTLC);
|
||||
|
||||
remote_changes_pending(peer);
|
||||
queue_pkt(peer, PKT__PKT_UPDATE_FAIL_HTLC, f);
|
||||
}
|
||||
|
||||
struct state_table {
|
||||
enum htlc_state from, to;
|
||||
};
|
||||
|
||||
static bool htlcs_changestate(struct peer *peer,
|
||||
const struct state_table *table,
|
||||
size_t n)
|
||||
{
|
||||
struct htlc_map_iter it;
|
||||
struct htlc *h;
|
||||
bool changed = false;
|
||||
|
||||
for (h = htlc_map_first(&peer->htlcs, &it);
|
||||
h;
|
||||
h = htlc_map_next(&peer->htlcs, &it)) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (h->state == table[i].from) {
|
||||
htlc_changestate(h, table[i].from, table[i].to);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
/* OK, we're sending a signature for their pending changes. */
|
||||
void queue_pkt_commit(struct peer *peer)
|
||||
{
|
||||
UpdateCommit *u = tal(peer, UpdateCommit);
|
||||
struct commit_info *ci = new_commit_info(peer);
|
||||
static const struct state_table changes[] = {
|
||||
{ SENT_ADD_HTLC, SENT_ADD_COMMIT },
|
||||
{ SENT_REMOVE_REVOCATION, SENT_REMOVE_ACK_COMMIT },
|
||||
{ SENT_ADD_REVOCATION, SENT_ADD_ACK_COMMIT},
|
||||
{ SENT_REMOVE_HTLC, SENT_REMOVE_COMMIT}
|
||||
};
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A node MUST NOT send an `update_commit` message which does
|
||||
* not include any updates.
|
||||
*/
|
||||
if (!htlcs_changestate(peer, changes, ARRAY_SIZE(changes)))
|
||||
fatal("sent commit with no changes");
|
||||
|
||||
/* Create new commit info for this commit tx. */
|
||||
ci->prev = peer->remote.commit;
|
||||
ci->commit_num = ci->prev->commit_num + 1;
|
||||
ci->revocation_hash = peer->remote.next_revocation_hash;
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A sending node MUST apply all remote acked and unacked
|
||||
* changes except unacked fee changes to the remote commitment
|
||||
* before generating `sig`. */
|
||||
ci->cstate = copy_cstate(ci, peer->remote.staging_cstate);
|
||||
ci->tx = create_commit_tx(ci, peer, &ci->revocation_hash,
|
||||
ci->cstate, REMOTE, &ci->map);
|
||||
bitcoin_txid(ci->tx, &ci->txid);
|
||||
|
||||
log_debug(peer->log, "Signing tx for %u/%u msatoshis, %zu/%zu htlcs",
|
||||
ci->cstate->side[OURS].pay_msat,
|
||||
ci->cstate->side[THEIRS].pay_msat,
|
||||
tal_count(ci->cstate->side[OURS].htlcs),
|
||||
tal_count(ci->cstate->side[THEIRS].htlcs));
|
||||
log_add_struct(peer->log, " (txid %s)", struct sha256_double, &ci->txid);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A node MUST NOT send an `update_commit` message which does
|
||||
* not include any updates.
|
||||
*/
|
||||
assert(ci->prev->cstate->changes != ci->cstate->changes);
|
||||
|
||||
ci->sig = tal(ci, struct bitcoin_signature);
|
||||
ci->sig->stype = SIGHASH_ALL;
|
||||
peer_sign_theircommit(peer, ci->tx, &ci->sig->sig);
|
||||
|
||||
/* Switch to the new commitment. */
|
||||
peer->remote.commit = ci;
|
||||
|
||||
/* Now send message */
|
||||
update_commit__init(u);
|
||||
u->sig = signature_to_proto(u, peer->dstate->secpctx, &ci->sig->sig);
|
||||
u->sig = signature_to_proto(u, peer->dstate->secpctx,
|
||||
&peer->remote.commit->sig->sig);
|
||||
|
||||
queue_pkt(peer, PKT__PKT_UPDATE_COMMIT, u);
|
||||
}
|
||||
|
||||
/* At revocation time, we apply the changeset to the other side. */
|
||||
static void apply_changeset(struct peer *peer,
|
||||
struct peer_visible_state *which,
|
||||
enum channel_side side,
|
||||
const union htlc_staging *changes,
|
||||
size_t num_changes)
|
||||
{
|
||||
size_t i;
|
||||
struct htlc *htlc;
|
||||
|
||||
for (i = 0; i < num_changes; i++) {
|
||||
switch (changes[i].type) {
|
||||
case HTLC_ADD:
|
||||
htlc = cstate_htlc_by_id(which->staging_cstate,
|
||||
changes[i].add.htlc->id, side);
|
||||
if (htlc)
|
||||
fatal("Can't add duplicate HTLC id %"PRIu64,
|
||||
changes[i].add.htlc->id);
|
||||
if (!cstate_add_htlc(which->staging_cstate,
|
||||
changes[i].add.htlc,
|
||||
side))
|
||||
fatal("Adding HTLC to %s failed",
|
||||
side == OURS ? "ours" : "theirs");
|
||||
continue;
|
||||
case HTLC_FAIL:
|
||||
htlc = cstate_htlc_by_id(which->staging_cstate,
|
||||
changes[i].fail.htlc->id,
|
||||
!side);
|
||||
if (!htlc)
|
||||
fatal("Can't fail non-exisent HTLC id %"PRIu64,
|
||||
changes[i].fail.htlc->id);
|
||||
cstate_fail_htlc(which->staging_cstate, htlc, !side);
|
||||
continue;
|
||||
case HTLC_FULFILL:
|
||||
htlc = cstate_htlc_by_id(which->staging_cstate,
|
||||
changes[i].fulfill.htlc->id,
|
||||
!side);
|
||||
if (!htlc)
|
||||
fatal("Can't fulfill non-exisent HTLC id %"PRIu64,
|
||||
changes[i].fulfill.htlc->id);
|
||||
cstate_fulfill_htlc(which->staging_cstate, htlc, !side);
|
||||
continue;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* Send a preimage for the old commit tx. The one we've just committed to is
|
||||
* in peer->local.commit. */
|
||||
void queue_pkt_revocation(struct peer *peer)
|
||||
void queue_pkt_revocation(struct peer *peer,
|
||||
const struct sha256 *preimage,
|
||||
const struct sha256 *next_hash)
|
||||
{
|
||||
UpdateRevocation *u = tal(peer, UpdateRevocation);
|
||||
struct commit_info *ci;
|
||||
static const struct state_table changes[] = {
|
||||
{ RCVD_ADD_ACK_COMMIT, SENT_ADD_ACK_REVOCATION },
|
||||
{ RCVD_REMOVE_COMMIT, SENT_REMOVE_REVOCATION },
|
||||
{ RCVD_ADD_COMMIT, SENT_ADD_REVOCATION },
|
||||
{ RCVD_REMOVE_ACK_COMMIT, SENT_REMOVE_ACK_REVOCATION }
|
||||
};
|
||||
|
||||
update_revocation__init(u);
|
||||
|
||||
assert(peer->local.commit);
|
||||
ci = peer->local.commit->prev;
|
||||
assert(ci);
|
||||
assert(!ci->revocation_preimage);
|
||||
|
||||
/* We have their signature on the current one, right? */
|
||||
assert(peer->local.commit->sig);
|
||||
|
||||
if (!htlcs_changestate(peer, changes, ARRAY_SIZE(changes)))
|
||||
fatal("sent revoke with no changes");
|
||||
|
||||
ci->revocation_preimage = tal(ci, struct sha256);
|
||||
peer_get_revocation_preimage(peer, ci->commit_num,
|
||||
ci->revocation_preimage);
|
||||
|
||||
u->revocation_preimage = sha256_to_proto(u, ci->revocation_preimage);
|
||||
|
||||
u->next_revocation_hash = sha256_to_proto(u,
|
||||
&peer->local.next_revocation_hash);
|
||||
u->revocation_preimage
|
||||
= sha256_to_proto(u, peer->local.commit->prev->revocation_preimage);
|
||||
|
||||
u->next_revocation_hash
|
||||
= sha256_to_proto(u, &peer->local.next_revocation_hash);
|
||||
queue_pkt(peer, PKT__PKT_UPDATE_REVOCATION, u);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The node sending `update_revocation` MUST add the local unacked
|
||||
* changes to the set of remote acked changes.
|
||||
*/
|
||||
/* Note: this means the unacked changes as of the commit we're
|
||||
* revoking */
|
||||
add_acked_changes(&peer->remote.commit->acked_changes, ci->unacked_changes);
|
||||
apply_changeset(peer, &peer->remote, THEIRS,
|
||||
ci->unacked_changes, tal_count(ci->unacked_changes));
|
||||
|
||||
if (tal_count(ci->unacked_changes))
|
||||
remote_changes_pending(peer);
|
||||
|
||||
/* We should never look at this again. */
|
||||
ci->unacked_changes = tal_free(ci->unacked_changes);
|
||||
|
||||
/* That revocation has committed us to changes in the current commitment.
|
||||
* Any acked changes come from their commitment, so those are now committed
|
||||
* by both of us.
|
||||
*/
|
||||
peer_both_committed_to(peer, ci->acked_changes, OURS);
|
||||
}
|
||||
|
||||
Pkt *pkt_err(struct peer *peer, const char *msg, ...)
|
||||
|
||||
250
daemon/peer.c
250
daemon/peer.c
@@ -205,6 +205,53 @@ static bool peer_received_unexpected_pkt(struct peer *peer, const Pkt *pkt)
|
||||
return peer_comms_err(peer, pkt_err_unexpected(peer, pkt));
|
||||
}
|
||||
|
||||
/* At revocation time, we apply the changeset to the other side. */
|
||||
void apply_changeset(struct peer *peer,
|
||||
struct peer_visible_state *which,
|
||||
enum channel_side side,
|
||||
const union htlc_staging *changes,
|
||||
size_t num_changes)
|
||||
{
|
||||
size_t i;
|
||||
struct htlc *htlc;
|
||||
|
||||
for (i = 0; i < num_changes; i++) {
|
||||
switch (changes[i].type) {
|
||||
case HTLC_ADD:
|
||||
htlc = cstate_htlc_by_id(which->staging_cstate,
|
||||
changes[i].add.htlc->id, side);
|
||||
if (htlc)
|
||||
fatal("Can't add duplicate HTLC id %"PRIu64,
|
||||
changes[i].add.htlc->id);
|
||||
if (!cstate_add_htlc(which->staging_cstate,
|
||||
changes[i].add.htlc,
|
||||
side))
|
||||
fatal("Adding HTLC to %s failed",
|
||||
side == OURS ? "ours" : "theirs");
|
||||
continue;
|
||||
case HTLC_FAIL:
|
||||
htlc = cstate_htlc_by_id(which->staging_cstate,
|
||||
changes[i].fail.htlc->id,
|
||||
!side);
|
||||
if (!htlc)
|
||||
fatal("Can't fail non-exisent HTLC id %"PRIu64,
|
||||
changes[i].fail.htlc->id);
|
||||
cstate_fail_htlc(which->staging_cstate, htlc, !side);
|
||||
continue;
|
||||
case HTLC_FULFILL:
|
||||
htlc = cstate_htlc_by_id(which->staging_cstate,
|
||||
changes[i].fulfill.htlc->id,
|
||||
!side);
|
||||
if (!htlc)
|
||||
fatal("Can't fulfill non-exisent HTLC id %"PRIu64,
|
||||
changes[i].fulfill.htlc->id);
|
||||
cstate_fulfill_htlc(which->staging_cstate, htlc, !side);
|
||||
continue;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* This is the io loop while we're negotiating closing tx. */
|
||||
static bool closing_pkt_in(struct peer *peer, const Pkt *pkt)
|
||||
{
|
||||
@@ -317,6 +364,65 @@ static bool closing_pkt_in(struct peer *peer, const Pkt *pkt)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We can get update_commit in both normal and clearing states. */
|
||||
static Pkt *handle_pkt_commit(struct peer *peer, const Pkt *pkt)
|
||||
{
|
||||
Pkt *err;
|
||||
struct commit_info *ci;
|
||||
static const struct state_table changes[] = {
|
||||
{ RCVD_ADD_ACK_COMMIT, SENT_ADD_ACK_REVOCATION },
|
||||
{ RCVD_REMOVE_COMMIT, SENT_REMOVE_REVOCATION },
|
||||
{ RCVD_ADD_COMMIT, SENT_ADD_REVOCATION },
|
||||
{ RCVD_REMOVE_ACK_COMMIT, SENT_REMOVE_ACK_REVOCATION }
|
||||
};
|
||||
|
||||
err = accept_pkt_commit(peer, pkt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
assert(peer->local.commit);
|
||||
ci = peer->local.commit->prev;
|
||||
assert(ci);
|
||||
assert(!ci->revocation_preimage);
|
||||
|
||||
/* We have their signature on the current one, right? */
|
||||
assert(peer->local.commit->sig);
|
||||
|
||||
if (!htlcs_changestate(peer, changes, ARRAY_SIZE(changes)))
|
||||
fatal("sent revoke with no changes");
|
||||
|
||||
ci->revocation_preimage = tal(ci, struct sha256);
|
||||
peer_get_revocation_preimage(peer, ci->commit_num,
|
||||
ci->revocation_preimage);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The node sending `update_revocation` MUST add the local unacked
|
||||
* changes to the set of remote acked changes.
|
||||
*/
|
||||
/* Note: this means the unacked changes as of the commit we're
|
||||
* revoking */
|
||||
add_acked_changes(&peer->remote.commit->acked_changes, ci->unacked_changes);
|
||||
apply_changeset(peer, &peer->remote, THEIRS,
|
||||
ci->unacked_changes, tal_count(ci->unacked_changes));
|
||||
|
||||
if (tal_count(ci->unacked_changes))
|
||||
remote_changes_pending(peer);
|
||||
|
||||
/* We should never look at this again. */
|
||||
ci->unacked_changes = tal_free(ci->unacked_changes);
|
||||
|
||||
/* That revocation has committed us to changes in the current commitment.
|
||||
* Any acked changes come from their commitment, so those are now committed
|
||||
* by both of us.
|
||||
*/
|
||||
peer_both_committed_to(peer, ci->acked_changes, OURS);
|
||||
|
||||
queue_pkt_revocation(peer, ci->revocation_preimage,
|
||||
&peer->local.next_revocation_hash);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This is the io loop while we're clearing. */
|
||||
static bool clearing_pkt_in(struct peer *peer, const Pkt *pkt)
|
||||
{
|
||||
@@ -366,9 +472,7 @@ static bool clearing_pkt_in(struct peer *peer, const Pkt *pkt)
|
||||
err = accept_pkt_htlc_fail(peer, pkt);
|
||||
break;
|
||||
case PKT__PKT_UPDATE_COMMIT:
|
||||
err = accept_pkt_commit(peer, pkt);
|
||||
if (!err)
|
||||
queue_pkt_revocation(peer);
|
||||
err = handle_pkt_commit(peer, pkt);
|
||||
break;
|
||||
case PKT__PKT_ERROR:
|
||||
peer_unexpected_pkt(peer, pkt);
|
||||
@@ -450,9 +554,7 @@ static bool normal_pkt_in(struct peer *peer, const Pkt *pkt)
|
||||
break;
|
||||
|
||||
case PKT_UPDATE_COMMIT:
|
||||
err = accept_pkt_commit(peer, pkt);
|
||||
if (!err)
|
||||
queue_pkt_revocation(peer);
|
||||
err = handle_pkt_commit(peer, pkt);
|
||||
break;
|
||||
|
||||
case PKT_CLOSE_CLEARING:
|
||||
@@ -631,10 +733,28 @@ static const struct bitcoin_tx *htlc_fulfill_tx(const struct peer *peer,
|
||||
/* FIXME: Reason! */
|
||||
static bool command_htlc_fail(struct peer *peer, struct htlc *htlc)
|
||||
{
|
||||
union htlc_staging stage;
|
||||
|
||||
/* If onchain, nothing we can do. */
|
||||
if (!state_can_remove_htlc(peer->state))
|
||||
return false;
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The sending node MUST add the HTLC fulfill/fail to the
|
||||
* unacked changeset for its remote commitment
|
||||
*/
|
||||
assert(cstate_htlc_by_id(peer->remote.staging_cstate, htlc->id, THEIRS)
|
||||
== htlc);
|
||||
cstate_fail_htlc(peer->remote.staging_cstate, htlc, THEIRS);
|
||||
|
||||
stage.fail.fail = HTLC_FAIL;
|
||||
stage.fail.htlc = htlc;
|
||||
add_unacked(&peer->remote, &stage);
|
||||
htlc_changestate(htlc, RCVD_ADD_ACK_REVOCATION, SENT_REMOVE_HTLC);
|
||||
|
||||
remote_changes_pending(peer);
|
||||
|
||||
queue_pkt_htlc_fail(peer, htlc);
|
||||
return true;
|
||||
}
|
||||
@@ -668,6 +788,8 @@ static bool command_htlc_fulfill(struct peer *peer,
|
||||
struct htlc *htlc,
|
||||
const struct rval *r)
|
||||
{
|
||||
union htlc_staging stage;
|
||||
|
||||
assert(!htlc->r);
|
||||
htlc->r = tal_dup(htlc, struct rval, r);
|
||||
|
||||
@@ -679,7 +801,24 @@ static bool command_htlc_fulfill(struct peer *peer,
|
||||
if (!state_can_remove_htlc(peer->state))
|
||||
return false;
|
||||
|
||||
queue_pkt_htlc_fulfill(peer, htlc, r);
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The sending node MUST add the HTLC fulfill/fail to the
|
||||
* unacked changeset for its remote commitment
|
||||
*/
|
||||
assert(cstate_htlc_by_id(peer->remote.staging_cstate, htlc->id, THEIRS)
|
||||
== htlc);
|
||||
cstate_fulfill_htlc(peer->remote.staging_cstate, htlc, THEIRS);
|
||||
|
||||
stage.fulfill.fulfill = HTLC_FULFILL;
|
||||
stage.fulfill.htlc = htlc;
|
||||
stage.fulfill.r = *r;
|
||||
add_unacked(&peer->remote, &stage);
|
||||
htlc_changestate(htlc, RCVD_ADD_ACK_REVOCATION, SENT_REMOVE_HTLC);
|
||||
|
||||
remote_changes_pending(peer);
|
||||
|
||||
queue_pkt_htlc_fulfill(peer, htlc);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -692,6 +831,7 @@ struct htlc *command_htlc_add(struct peer *peer, u64 msatoshis,
|
||||
struct channel_state *cstate;
|
||||
struct abs_locktime locktime;
|
||||
struct htlc *htlc;
|
||||
union htlc_staging stage;
|
||||
|
||||
if (!blocks_to_abs_locktime(expiry, &locktime)) {
|
||||
log_unusual(peer->log, "add_htlc: fail: bad expiry %u", expiry);
|
||||
@@ -755,6 +895,20 @@ struct htlc *command_htlc_add(struct peer *peer, u64 msatoshis,
|
||||
}
|
||||
tal_free(cstate);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The sending node MUST add the HTLC addition to the unacked
|
||||
* changeset for its remote commitment
|
||||
*/
|
||||
if (!cstate_add_htlc(peer->remote.staging_cstate, htlc, OURS))
|
||||
fatal("Could not add HTLC?");
|
||||
|
||||
stage.add.add = HTLC_ADD;
|
||||
stage.add.htlc = htlc;
|
||||
add_unacked(&peer->remote, &stage);
|
||||
|
||||
remote_changes_pending(peer);
|
||||
|
||||
queue_pkt_htlc_add(peer, htlc);
|
||||
|
||||
/* Make sure we never offer the same one twice. */
|
||||
@@ -861,8 +1015,37 @@ static void peer_disconnect(struct io_conn *conn, struct peer *peer)
|
||||
}
|
||||
}
|
||||
|
||||
bool htlcs_changestate(struct peer *peer,
|
||||
const struct state_table *table, size_t n)
|
||||
{
|
||||
struct htlc_map_iter it;
|
||||
struct htlc *h;
|
||||
bool changed = false;
|
||||
|
||||
for (h = htlc_map_first(&peer->htlcs, &it);
|
||||
h;
|
||||
h = htlc_map_next(&peer->htlcs, &it)) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (h->state == table[i].from) {
|
||||
htlc_changestate(h, table[i].from, table[i].to);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void do_commit(struct peer *peer, struct command *jsoncmd)
|
||||
{
|
||||
struct commit_info *ci;
|
||||
static const struct state_table changes[] = {
|
||||
{ SENT_ADD_HTLC, SENT_ADD_COMMIT },
|
||||
{ SENT_REMOVE_REVOCATION, SENT_REMOVE_ACK_COMMIT },
|
||||
{ SENT_ADD_REVOCATION, SENT_ADD_ACK_COMMIT},
|
||||
{ SENT_REMOVE_HTLC, SENT_REMOVE_COMMIT}
|
||||
};
|
||||
|
||||
/* We can have changes we suggested, or changes they suggested. */
|
||||
if (!peer_uncommitted_changes(peer)) {
|
||||
log_debug(peer->log, "do_commit: no changes to commit");
|
||||
@@ -877,6 +1060,51 @@ static void do_commit(struct peer *peer, struct command *jsoncmd)
|
||||
assert(!peer->commit_jsoncmd);
|
||||
|
||||
peer->commit_jsoncmd = jsoncmd;
|
||||
ci = new_commit_info(peer);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A node MUST NOT send an `update_commit` message which does
|
||||
* not include any updates.
|
||||
*/
|
||||
if (!htlcs_changestate(peer, changes, ARRAY_SIZE(changes)))
|
||||
fatal("sent commit with no changes");
|
||||
|
||||
/* Create new commit info for this commit tx. */
|
||||
ci->prev = peer->remote.commit;
|
||||
ci->commit_num = ci->prev->commit_num + 1;
|
||||
ci->revocation_hash = peer->remote.next_revocation_hash;
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A sending node MUST apply all remote acked and unacked
|
||||
* changes except unacked fee changes to the remote commitment
|
||||
* before generating `sig`. */
|
||||
ci->cstate = copy_cstate(ci, peer->remote.staging_cstate);
|
||||
ci->tx = create_commit_tx(ci, peer, &ci->revocation_hash,
|
||||
ci->cstate, REMOTE, &ci->map);
|
||||
bitcoin_txid(ci->tx, &ci->txid);
|
||||
|
||||
log_debug(peer->log, "Signing tx for %u/%u msatoshis, %zu/%zu htlcs",
|
||||
ci->cstate->side[OURS].pay_msat,
|
||||
ci->cstate->side[THEIRS].pay_msat,
|
||||
tal_count(ci->cstate->side[OURS].htlcs),
|
||||
tal_count(ci->cstate->side[THEIRS].htlcs));
|
||||
log_add_struct(peer->log, " (txid %s)", struct sha256_double, &ci->txid);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A node MUST NOT send an `update_commit` message which does
|
||||
* not include any updates.
|
||||
*/
|
||||
assert(ci->prev->cstate->changes != ci->cstate->changes);
|
||||
|
||||
ci->sig = tal(ci, struct bitcoin_signature);
|
||||
ci->sig->stype = SIGHASH_ALL;
|
||||
peer_sign_theircommit(peer, ci->tx, &ci->sig->sig);
|
||||
|
||||
/* Switch to the new commitment. */
|
||||
peer->remote.commit = ci;
|
||||
|
||||
queue_pkt_commit(peer);
|
||||
if (peer->state == STATE_CLEARING) {
|
||||
set_peer_state(peer, STATE_CLEARING_COMMITTING, __func__);
|
||||
@@ -915,6 +1143,14 @@ void remote_changes_pending(struct peer *peer)
|
||||
log_debug(peer->log, "remote_changes_pending: timer already exists");
|
||||
}
|
||||
|
||||
struct commit_info *new_commit_info(const tal_t *ctx)
|
||||
{
|
||||
struct commit_info *ci = talz(ctx, struct commit_info);
|
||||
ci->unacked_changes = tal_arr(ci, union htlc_staging, 0);
|
||||
ci->acked_changes = tal_arr(ci, union htlc_staging, 0);
|
||||
return ci;
|
||||
}
|
||||
|
||||
static struct peer *new_peer(struct lightningd_state *dstate,
|
||||
struct io_conn *conn,
|
||||
int addr_type, int addr_protocol,
|
||||
|
||||
@@ -239,6 +239,20 @@ void add_acked_changes(union htlc_staging **acked,
|
||||
void peer_both_committed_to(struct peer *peer,
|
||||
const union htlc_staging *changes, enum channel_side side);
|
||||
|
||||
/* Allocate a new commit_info struct. */
|
||||
struct commit_info *new_commit_info(const tal_t *ctx);
|
||||
|
||||
struct state_table {
|
||||
enum htlc_state from, to;
|
||||
};
|
||||
bool htlcs_changestate(struct peer *peer,
|
||||
const struct state_table *table, size_t n);
|
||||
void apply_changeset(struct peer *peer,
|
||||
struct peer_visible_state *which,
|
||||
enum channel_side side,
|
||||
const union htlc_staging *changes,
|
||||
size_t num_changes);
|
||||
|
||||
/* Freeing removes from map, too */
|
||||
struct htlc *peer_new_htlc(struct peer *peer,
|
||||
u64 id,
|
||||
|
||||
42
state.c
42
state.c
@@ -1,8 +1,7 @@
|
||||
#include <ccan/build_assert/build_assert.h>
|
||||
#include <daemon/log.h>
|
||||
#ifndef TEST_STATE_COVERAGE
|
||||
#include <daemon/peer.h>
|
||||
#endif
|
||||
#include <daemon/secrets.h>
|
||||
#include <names.h>
|
||||
#include <state.h>
|
||||
|
||||
@@ -22,6 +21,18 @@ static void queue_tx_broadcast(const struct bitcoin_tx **broadcast,
|
||||
*broadcast = tx;
|
||||
}
|
||||
|
||||
static void send_open_pkt(struct peer *peer,
|
||||
OpenChannel__AnchorOffer anchor)
|
||||
{
|
||||
/* Set up out commit info now: rest gets done in setup_first_commit
|
||||
* once anchor is established. */
|
||||
peer->local.commit = new_commit_info(peer);
|
||||
peer->local.commit->revocation_hash = peer->local.next_revocation_hash;
|
||||
peer_get_revocation_hash(peer, 1, &peer->local.next_revocation_hash);
|
||||
|
||||
queue_pkt_open(peer, anchor);
|
||||
}
|
||||
|
||||
enum state state(struct peer *peer,
|
||||
const enum state_input input,
|
||||
const Pkt *pkt,
|
||||
@@ -37,13 +48,13 @@ enum state state(struct peer *peer,
|
||||
*/
|
||||
case STATE_INIT:
|
||||
if (input_is(input, CMD_OPEN_WITH_ANCHOR)) {
|
||||
queue_pkt_open(peer,
|
||||
OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR);
|
||||
send_open_pkt(peer,
|
||||
OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR);
|
||||
return next_state(peer, input,
|
||||
STATE_OPEN_WAIT_FOR_OPEN_WITHANCHOR);
|
||||
} else if (input_is(input, CMD_OPEN_WITHOUT_ANCHOR)) {
|
||||
queue_pkt_open(peer,
|
||||
OPEN_CHANNEL__ANCHOR_OFFER__WONT_CREATE_ANCHOR);
|
||||
send_open_pkt(peer,
|
||||
OPEN_CHANNEL__ANCHOR_OFFER__WONT_CREATE_ANCHOR);
|
||||
return next_state(peer, input,
|
||||
STATE_OPEN_WAIT_FOR_OPEN_NOANCHOR);
|
||||
}
|
||||
@@ -78,6 +89,13 @@ enum state state(struct peer *peer,
|
||||
break;
|
||||
case STATE_OPEN_WAIT_FOR_ANCHOR_CREATE:
|
||||
if (input_is(input, BITCOIN_ANCHOR_CREATED)) {
|
||||
/* This shouldn't happen! */
|
||||
if (!setup_first_commit(peer)) {
|
||||
err = pkt_err(peer,
|
||||
"Own anchor has insufficient funds");
|
||||
peer_open_complete(peer, err->error->problem);
|
||||
goto err_breakdown;
|
||||
}
|
||||
queue_pkt_anchor(peer);
|
||||
return next_state(peer, input,
|
||||
STATE_OPEN_WAIT_FOR_COMMIT_SIG);
|
||||
@@ -94,6 +112,18 @@ enum state state(struct peer *peer,
|
||||
peer_open_complete(peer, err->error->problem);
|
||||
goto err_breakdown;
|
||||
}
|
||||
log_debug_struct(peer->log, "Creating sig for %s",
|
||||
struct bitcoin_tx,
|
||||
peer->remote.commit->tx);
|
||||
log_add_struct(peer->log, " using key %s",
|
||||
struct pubkey, &peer->local.commitkey);
|
||||
|
||||
peer->remote.commit->sig = tal(peer->remote.commit,
|
||||
struct bitcoin_signature);
|
||||
peer->remote.commit->sig->stype = SIGHASH_ALL;
|
||||
peer_sign_theircommit(peer, peer->remote.commit->tx,
|
||||
&peer->remote.commit->sig->sig);
|
||||
|
||||
queue_pkt_open_commit_sig(peer);
|
||||
peer_watch_anchor(peer,
|
||||
BITCOIN_ANCHOR_DEPTHOK,
|
||||
|
||||
7
state.h
7
state.h
@@ -101,11 +101,12 @@ void queue_pkt_anchor(struct peer *peer);
|
||||
void queue_pkt_open_commit_sig(struct peer *peer);
|
||||
void queue_pkt_open_complete(struct peer *peer);
|
||||
void queue_pkt_htlc_add(struct peer *peer, struct htlc *htlc);
|
||||
void queue_pkt_htlc_fulfill(struct peer *peer, struct htlc *htlc,
|
||||
const struct rval *r);
|
||||
void queue_pkt_htlc_fulfill(struct peer *peer, struct htlc *htlc);
|
||||
void queue_pkt_htlc_fail(struct peer *peer, struct htlc *htlc);
|
||||
void queue_pkt_commit(struct peer *peer);
|
||||
void queue_pkt_revocation(struct peer *peer);
|
||||
void queue_pkt_revocation(struct peer *peer,
|
||||
const struct sha256 *preimage,
|
||||
const struct sha256 *next_hash);
|
||||
void queue_pkt_close_clearing(struct peer *peer);
|
||||
void queue_pkt_close_signature(struct peer *peer);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user