mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 06:41:44 +01:00
packets.c: accept_pkt_* should do less state-mangling.
Move other logic into caller, but it's not complete (it still needs to check some things, and still records some results). Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
6615db32c0
commit
149fa341be
4 changed files with 317 additions and 251 deletions
254
daemon/packets.c
254
daemon/packets.c
|
@ -269,7 +269,9 @@ Pkt *pkt_err_unexpected(struct peer *peer, const Pkt *pkt)
|
|||
}
|
||||
|
||||
/* Process various packets: return an error packet on failure. */
|
||||
Pkt *accept_pkt_open(struct peer *peer, const Pkt *pkt)
|
||||
Pkt *accept_pkt_open(struct peer *peer, const Pkt *pkt,
|
||||
struct sha256 *revocation_hash,
|
||||
struct sha256 *next_revocation_hash)
|
||||
{
|
||||
struct rel_locktime locktime;
|
||||
const OpenChannel *o = pkt->open;
|
||||
|
@ -305,49 +307,8 @@ Pkt *accept_pkt_open(struct peer *peer, const Pkt *pkt)
|
|||
o->final_key, &peer->remote.finalkey))
|
||||
return pkt_err(peer, "Bad finalkey");
|
||||
|
||||
/* Set up their commit info now: rest gets done in setup_first_commit
|
||||
* once anchor is established. */
|
||||
peer->remote.commit = new_commit_info(peer);
|
||||
proto_to_sha256(o->revocation_hash, &peer->remote.commit->revocation_hash);
|
||||
proto_to_sha256(o->next_revocation_hash,
|
||||
&peer->remote.next_revocation_hash);
|
||||
|
||||
/* Witness script for anchor. */
|
||||
peer->anchor.witnessscript
|
||||
= bitcoin_redeem_2of2(peer, peer->dstate->secpctx,
|
||||
&peer->local.commitkey,
|
||||
&peer->remote.commitkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Save and check signature. */
|
||||
static Pkt *check_and_save_commit_sig(struct peer *peer,
|
||||
struct commit_info *ci,
|
||||
const Signature *pb)
|
||||
{
|
||||
struct bitcoin_signature *sig = tal(ci, struct bitcoin_signature);
|
||||
|
||||
assert(!ci->sig);
|
||||
sig->stype = SIGHASH_ALL;
|
||||
if (!proto_to_signature(peer->dstate->secpctx, pb, &sig->sig))
|
||||
return pkt_err(peer, "Malformed signature");
|
||||
|
||||
log_debug(peer->log, "Checking sig 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));
|
||||
|
||||
/* Their sig should sign our commit tx. */
|
||||
if (!check_tx_sig(peer->dstate->secpctx,
|
||||
ci->tx, 0,
|
||||
NULL, 0,
|
||||
peer->anchor.witnessscript,
|
||||
&peer->remote.commitkey,
|
||||
sig))
|
||||
return pkt_err(peer, "Bad signature");
|
||||
|
||||
ci->sig = sig;
|
||||
proto_to_sha256(o->revocation_hash, revocation_hash);
|
||||
proto_to_sha256(o->next_revocation_hash, next_revocation_hash);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -362,18 +323,22 @@ Pkt *accept_pkt_anchor(struct peer *peer, const Pkt *pkt)
|
|||
proto_to_sha256(a->txid, &peer->anchor.txid.sha);
|
||||
peer->anchor.index = a->output_index;
|
||||
peer->anchor.satoshis = a->amount;
|
||||
|
||||
if (!setup_first_commit(peer))
|
||||
return pkt_err(peer, "Insufficient funds for fee");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_open_commit_sig(struct peer *peer, const Pkt *pkt)
|
||||
Pkt *accept_pkt_open_commit_sig(struct peer *peer, const Pkt *pkt,
|
||||
struct bitcoin_signature **sig)
|
||||
{
|
||||
const OpenCommitSig *s = pkt->open_commit_sig;
|
||||
struct signature signature;
|
||||
|
||||
return check_and_save_commit_sig(peer, peer->local.commit, s->sig);
|
||||
if (!proto_to_signature(peer->dstate->secpctx, s->sig, &signature))
|
||||
return pkt_err(peer, "Malformed signature");
|
||||
|
||||
*sig = tal(peer, struct bitcoin_signature);
|
||||
(*sig)->stype = SIGHASH_ALL;
|
||||
(*sig)->sig = signature;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_open_complete(struct peer *peer, const Pkt *pkt)
|
||||
|
@ -385,13 +350,11 @@ Pkt *accept_pkt_open_complete(struct peer *peer, const Pkt *pkt)
|
|||
* We add changes to both our staging cstate (as they did when they sent
|
||||
* it) and theirs (as they will when we ack it).
|
||||
*/
|
||||
Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt)
|
||||
Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt, struct htlc **h)
|
||||
{
|
||||
const UpdateAddHtlc *u = pkt->update_add_htlc;
|
||||
struct sha256 rhash;
|
||||
struct abs_locktime expiry;
|
||||
struct htlc *htlc;
|
||||
union htlc_staging stage;
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
|
@ -430,29 +393,10 @@ Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt)
|
|||
*
|
||||
* ...and the receiving node MUST add the HTLC addition to the
|
||||
* unacked changeset for its local commitment. */
|
||||
htlc = peer_new_htlc(peer, u->id, u->amount_msat, &rhash,
|
||||
abs_locktime_to_blocks(&expiry),
|
||||
u->route->info.data, u->route->info.len,
|
||||
NULL, RCVD_ADD_HTLC);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A node MUST NOT offer `amount_msat` it cannot pay for in
|
||||
* the remote commitment transaction at the current `fee_rate` (see
|
||||
* "Fee Calculation" ). A node SHOULD fail the connection if
|
||||
* this occurs.
|
||||
*/
|
||||
if (!cstate_add_htlc(peer->local.staging_cstate, htlc, THEIRS)) {
|
||||
tal_free(htlc);
|
||||
return pkt_err(peer, "Cannot afford %"PRIu64" milli-satoshis"
|
||||
" in our commitment tx",
|
||||
u->amount_msat);
|
||||
}
|
||||
|
||||
stage.add.add = HTLC_ADD;
|
||||
stage.add.htlc = htlc;
|
||||
add_unacked(&peer->local, &stage);
|
||||
|
||||
*h = peer_new_htlc(peer, u->id, u->amount_msat, &rhash,
|
||||
abs_locktime_to_blocks(&expiry),
|
||||
u->route->info.data, u->route->info.len,
|
||||
NULL, RCVD_ADD_HTLC);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -476,43 +420,27 @@ static Pkt *find_commited_htlc(struct peer *peer, uint64_t id,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_htlc_fail(struct peer *peer, const Pkt *pkt)
|
||||
Pkt *accept_pkt_htlc_fail(struct peer *peer, const Pkt *pkt, struct htlc **h)
|
||||
{
|
||||
const UpdateFailHtlc *f = pkt->update_fail_htlc;
|
||||
struct htlc *htlc;
|
||||
Pkt *err;
|
||||
union htlc_staging stage;
|
||||
|
||||
err = find_commited_htlc(peer, f->id, &htlc);
|
||||
err = find_commited_htlc(peer, f->id, h);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* FIXME: Save reason. */
|
||||
|
||||
cstate_fail_htlc(peer->local.staging_cstate, htlc, OURS);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* ... and the receiving node MUST add the HTLC fulfill/fail
|
||||
* to the unacked changeset for its local commitment.
|
||||
*/
|
||||
stage.fail.fail = HTLC_FAIL;
|
||||
stage.fail.htlc = htlc;
|
||||
add_unacked(&peer->local, &stage);
|
||||
htlc_changestate(htlc, SENT_ADD_ACK_REVOCATION, RCVD_REMOVE_HTLC);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_htlc_fulfill(struct peer *peer, const Pkt *pkt)
|
||||
Pkt *accept_pkt_htlc_fulfill(struct peer *peer, const Pkt *pkt, struct htlc **h)
|
||||
{
|
||||
const UpdateFulfillHtlc *f = pkt->update_fulfill_htlc;
|
||||
struct htlc *htlc;
|
||||
struct sha256 rhash;
|
||||
struct rval r;
|
||||
Pkt *err;
|
||||
union htlc_staging stage;
|
||||
|
||||
err = find_commited_htlc(peer, f->id, &htlc);
|
||||
err = find_commited_htlc(peer, f->id, h);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -520,102 +448,34 @@ Pkt *accept_pkt_htlc_fulfill(struct peer *peer, const Pkt *pkt)
|
|||
proto_to_rval(f->r, &r);
|
||||
sha256(&rhash, &r, sizeof(r));
|
||||
|
||||
if (!structeq(&rhash, &htlc->rhash))
|
||||
if (!structeq(&rhash, &(*h)->rhash))
|
||||
return pkt_err(peer, "Invalid r for %"PRIu64, f->id);
|
||||
|
||||
/* We can relay this upstream immediately. */
|
||||
our_htlc_fulfilled(peer, htlc, &r);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* ... and the receiving node MUST add the HTLC fulfill/fail
|
||||
* to the unacked changeset for its local commitment.
|
||||
*/
|
||||
cstate_fulfill_htlc(peer->local.staging_cstate, htlc, OURS);
|
||||
htlc_changestate(htlc, SENT_ADD_ACK_REVOCATION, RCVD_REMOVE_HTLC);
|
||||
|
||||
stage.fulfill.fulfill = HTLC_FULFILL;
|
||||
stage.fulfill.htlc = htlc;
|
||||
stage.fulfill.r = r;
|
||||
add_unacked(&peer->local, &stage);
|
||||
assert(!(*h)->r);
|
||||
(*h)->r = tal_dup(*h, struct rval, &r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_commit(struct peer *peer, const Pkt *pkt)
|
||||
Pkt *accept_pkt_commit(struct peer *peer, const Pkt *pkt,
|
||||
struct bitcoin_signature *sig)
|
||||
{
|
||||
const UpdateCommit *c = pkt->update_commit;
|
||||
Pkt *err;
|
||||
struct commit_info *ci = new_commit_info(peer);
|
||||
static const struct state_table changes[] = {
|
||||
{ RCVD_ADD_REVOCATION, RCVD_ADD_ACK_COMMIT },
|
||||
{ RCVD_REMOVE_HTLC, RCVD_REMOVE_COMMIT },
|
||||
{ RCVD_ADD_HTLC, RCVD_ADD_COMMIT },
|
||||
{ RCVD_REMOVE_REVOCATION, RCVD_REMOVE_ACK_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)))
|
||||
return pkt_err(peer, "Empty commit");
|
||||
|
||||
/* Create new commit info for this commit tx. */
|
||||
ci->prev = peer->local.commit;
|
||||
ci->commit_num = ci->prev->commit_num + 1;
|
||||
ci->revocation_hash = peer->local.next_revocation_hash;
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A receiving node MUST apply all local acked and unacked
|
||||
* changes except unacked fee changes to the local commitment
|
||||
*/
|
||||
/* (We already applied them to staging_cstate as we went) */
|
||||
ci->cstate = copy_cstate(ci, peer->local.staging_cstate);
|
||||
ci->tx = create_commit_tx(ci, peer, &ci->revocation_hash,
|
||||
ci->cstate, LOCAL, &ci->map);
|
||||
bitcoin_txid(ci->tx, &ci->txid);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A node MUST NOT send an `update_commit` message which does
|
||||
* not include any updates.
|
||||
*/
|
||||
if (ci->prev->cstate->changes == ci->cstate->changes)
|
||||
return pkt_err(peer, "Empty commit");
|
||||
|
||||
err = check_and_save_commit_sig(peer, ci, c->sig);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Switch to the new commitment. */
|
||||
peer->local.commit = ci;
|
||||
peer_get_revocation_hash(peer, ci->commit_num + 1,
|
||||
&peer->local.next_revocation_hash);
|
||||
|
||||
sig->stype = SIGHASH_ALL;
|
||||
if (!proto_to_signature(peer->dstate->secpctx, c->sig, &sig->sig))
|
||||
return pkt_err(peer, "Malformed signature");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool check_preimage(const Sha256Hash *preimage, const struct sha256 *hash)
|
||||
{
|
||||
struct sha256 h;
|
||||
|
||||
proto_to_sha256(preimage, &h);
|
||||
sha256(&h, &h, sizeof(h));
|
||||
return structeq(&h, hash);
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_revocation(struct peer *peer, const Pkt *pkt)
|
||||
Pkt *accept_pkt_revocation(struct peer *peer, const Pkt *pkt,
|
||||
struct commit_info *ci)
|
||||
{
|
||||
const UpdateRevocation *r = pkt->update_revocation;
|
||||
struct commit_info *ci = peer->remote.commit->prev;
|
||||
static const struct state_table changes[] = {
|
||||
{ SENT_ADD_COMMIT, RCVD_ADD_REVOCATION },
|
||||
{ SENT_REMOVE_ACK_COMMIT, RCVD_REMOVE_ACK_REVOCATION },
|
||||
{ SENT_ADD_ACK_COMMIT, RCVD_ADD_ACK_REVOCATION },
|
||||
{ SENT_REMOVE_COMMIT, RCVD_REMOVE_REVOCATION }
|
||||
};
|
||||
struct sha256 h;
|
||||
|
||||
assert(!ci->revocation_preimage);
|
||||
ci->revocation_preimage = tal(ci, struct sha256);
|
||||
proto_to_sha256(r->revocation_preimage, ci->revocation_preimage);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
|
@ -623,45 +483,19 @@ Pkt *accept_pkt_revocation(struct peer *peer, const Pkt *pkt)
|
|||
* SHA256 hash of `revocation_preimage` matches the previous commitment
|
||||
* transaction, and MUST fail if it does not.
|
||||
*/
|
||||
if (!check_preimage(r->revocation_preimage, &ci->revocation_hash))
|
||||
sha256(&h, ci->revocation_preimage, sizeof(*ci->revocation_preimage));
|
||||
if (!structeq(&h, &ci->revocation_hash))
|
||||
return pkt_err(peer, "complete preimage incorrect");
|
||||
|
||||
/* They're revoking the previous one. */
|
||||
assert(!ci->revocation_preimage);
|
||||
ci->revocation_preimage = tal(ci, struct sha256);
|
||||
|
||||
proto_to_sha256(r->revocation_preimage, ci->revocation_preimage);
|
||||
|
||||
// save revocation preimages in shachain
|
||||
if (!shachain_add_hash(&peer->their_preimages, 0xFFFFFFFFFFFFFFFFL - ci->commit_num, ci->revocation_preimage))
|
||||
if (!shachain_add_hash(&peer->their_preimages,
|
||||
0xFFFFFFFFFFFFFFFFL - ci->commit_num,
|
||||
ci->revocation_preimage))
|
||||
return pkt_err(peer, "preimage not next in shachain");
|
||||
|
||||
/* Save next revocation hash. */
|
||||
proto_to_sha256(r->next_revocation_hash,
|
||||
&peer->remote.next_revocation_hash);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The receiver of `update_revocation`... MUST add the remote
|
||||
* unacked changes to the set of local acked changes.
|
||||
*/
|
||||
add_acked_changes(&peer->local.commit->acked_changes, ci->unacked_changes);
|
||||
apply_changeset(peer, &peer->local, OURS,
|
||||
ci->unacked_changes,
|
||||
tal_count(ci->unacked_changes));
|
||||
|
||||
if (!htlcs_changestate(peer, changes, ARRAY_SIZE(changes)))
|
||||
fatal("Revocation received but we made empty commitment?");
|
||||
|
||||
/* Should never examine these again. */
|
||||
ci->unacked_changes = tal_free(ci->unacked_changes);
|
||||
|
||||
/* That revocation has committed them to changes in the current commitment.
|
||||
* Any acked changes come from our commitment, so those are now committed
|
||||
* by both of us.
|
||||
*/
|
||||
peer_both_committed_to(peer, ci->acked_changes, THEIRS);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
244
daemon/peer.c
244
daemon/peer.c
|
@ -368,19 +368,78 @@ static bool closing_pkt_in(struct peer *peer, const Pkt *pkt)
|
|||
static Pkt *handle_pkt_commit(struct peer *peer, const Pkt *pkt)
|
||||
{
|
||||
Pkt *err;
|
||||
struct commit_info *ci;
|
||||
static const struct state_table changes[] = {
|
||||
struct commit_info *ci = new_commit_info(peer);
|
||||
/* FIXME: We can actually merge these two... */
|
||||
static const struct state_table commit_changes[] = {
|
||||
{ RCVD_ADD_REVOCATION, RCVD_ADD_ACK_COMMIT },
|
||||
{ RCVD_REMOVE_HTLC, RCVD_REMOVE_COMMIT },
|
||||
{ RCVD_ADD_HTLC, RCVD_ADD_COMMIT },
|
||||
{ RCVD_REMOVE_REVOCATION, RCVD_REMOVE_ACK_COMMIT }
|
||||
};
|
||||
static const struct state_table revocation_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);
|
||||
ci->sig = tal(ci, struct bitcoin_signature);
|
||||
err = accept_pkt_commit(peer, pkt, ci->sig);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
assert(peer->local.commit);
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A node MUST NOT send an `update_commit` message which does
|
||||
* not include any updates.
|
||||
*/
|
||||
if (!htlcs_changestate(peer, commit_changes, ARRAY_SIZE(commit_changes)))
|
||||
return pkt_err(peer, "Empty commit");
|
||||
|
||||
/* Create new commit info for this commit tx. */
|
||||
ci->prev = peer->local.commit;
|
||||
ci->commit_num = ci->prev->commit_num + 1;
|
||||
ci->revocation_hash = peer->local.next_revocation_hash;
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A receiving node MUST apply all local acked and unacked
|
||||
* changes except unacked fee changes to the local commitment
|
||||
*/
|
||||
/* (We already applied them to staging_cstate as we went) */
|
||||
ci->cstate = copy_cstate(ci, peer->local.staging_cstate);
|
||||
ci->tx = create_commit_tx(ci, peer, &ci->revocation_hash,
|
||||
ci->cstate, LOCAL, &ci->map);
|
||||
bitcoin_txid(ci->tx, &ci->txid);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A node MUST NOT send an `update_commit` message which does
|
||||
* not include any updates.
|
||||
*/
|
||||
if (ci->prev->cstate->changes == ci->cstate->changes)
|
||||
return pkt_err(peer, "Empty commit");
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A receiving node MUST apply all local acked and unacked changes
|
||||
* except unacked fee changes to the local commitment, then it MUST
|
||||
* check `sig` is valid for that transaction.
|
||||
*/
|
||||
if (!check_tx_sig(peer->dstate->secpctx,
|
||||
ci->tx, 0,
|
||||
NULL, 0,
|
||||
peer->anchor.witnessscript,
|
||||
&peer->remote.commitkey,
|
||||
ci->sig))
|
||||
return pkt_err(peer, "Bad signature");
|
||||
|
||||
/* Switch to the new commitment. */
|
||||
peer->local.commit = ci;
|
||||
peer_get_revocation_hash(peer, ci->commit_num + 1,
|
||||
&peer->local.next_revocation_hash);
|
||||
|
||||
/* Now, send the revocation. */
|
||||
ci = peer->local.commit->prev;
|
||||
assert(ci);
|
||||
assert(!ci->revocation_preimage);
|
||||
|
@ -388,7 +447,8 @@ static Pkt *handle_pkt_commit(struct peer *peer, const Pkt *pkt)
|
|||
/* We have their signature on the current one, right? */
|
||||
assert(peer->local.commit->sig);
|
||||
|
||||
if (!htlcs_changestate(peer, changes, ARRAY_SIZE(changes)))
|
||||
if (!htlcs_changestate(peer, revocation_changes,
|
||||
ARRAY_SIZE(revocation_changes)))
|
||||
fatal("sent revoke with no changes");
|
||||
|
||||
ci->revocation_preimage = tal(ci, struct sha256);
|
||||
|
@ -402,7 +462,8 @@ static Pkt *handle_pkt_commit(struct peer *peer, const Pkt *pkt)
|
|||
*/
|
||||
/* Note: this means the unacked changes as of the commit we're
|
||||
* revoking */
|
||||
add_acked_changes(&peer->remote.commit->acked_changes, ci->unacked_changes);
|
||||
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));
|
||||
|
||||
|
@ -412,9 +473,9 @@ static Pkt *handle_pkt_commit(struct peer *peer, const Pkt *pkt)
|
|||
/* 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.
|
||||
/* 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);
|
||||
|
||||
|
@ -423,6 +484,127 @@ static Pkt *handle_pkt_commit(struct peer *peer, const Pkt *pkt)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static Pkt *handle_pkt_htlc_add(struct peer *peer, const Pkt *pkt)
|
||||
{
|
||||
union htlc_staging stage;
|
||||
struct htlc *htlc;
|
||||
Pkt *err;
|
||||
|
||||
err = accept_pkt_htlc_add(peer, pkt, &htlc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A node MUST NOT offer `amount_msat` it cannot pay for in
|
||||
* the remote commitment transaction at the current `fee_rate` (see
|
||||
* "Fee Calculation" ). A node SHOULD fail the connection if
|
||||
* this occurs.
|
||||
*/
|
||||
if (!cstate_add_htlc(peer->local.staging_cstate, htlc, THEIRS)) {
|
||||
tal_free(htlc);
|
||||
return pkt_err(peer, "Cannot afford %"PRIu64" milli-satoshis"
|
||||
" in our commitment tx",
|
||||
htlc->msatoshis);
|
||||
}
|
||||
|
||||
stage.add.add = HTLC_ADD;
|
||||
stage.add.htlc = htlc;
|
||||
add_unacked(&peer->local, &stage);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Pkt *handle_pkt_htlc_fail(struct peer *peer, const Pkt *pkt)
|
||||
{
|
||||
union htlc_staging stage;
|
||||
struct htlc *htlc;
|
||||
Pkt *err;
|
||||
|
||||
err = accept_pkt_htlc_fail(peer, pkt, &htlc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cstate_fail_htlc(peer->local.staging_cstate, htlc, OURS);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* ... and the receiving node MUST add the HTLC fulfill/fail
|
||||
* to the unacked changeset for its local commitment.
|
||||
*/
|
||||
stage.fail.fail = HTLC_FAIL;
|
||||
stage.fail.htlc = htlc;
|
||||
add_unacked(&peer->local, &stage);
|
||||
htlc_changestate(htlc, SENT_ADD_ACK_REVOCATION, RCVD_REMOVE_HTLC);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Pkt *handle_pkt_htlc_fulfill(struct peer *peer, const Pkt *pkt)
|
||||
{
|
||||
union htlc_staging stage;
|
||||
struct htlc *htlc;
|
||||
Pkt *err;
|
||||
|
||||
err = accept_pkt_htlc_fulfill(peer, pkt, &htlc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* We can relay this upstream immediately. */
|
||||
our_htlc_fulfilled(peer, htlc, htlc->r);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* ... and the receiving node MUST add the HTLC fulfill/fail
|
||||
* to the unacked changeset for its local commitment.
|
||||
*/
|
||||
cstate_fulfill_htlc(peer->local.staging_cstate, htlc, OURS);
|
||||
htlc_changestate(htlc, SENT_ADD_ACK_REVOCATION, RCVD_REMOVE_HTLC);
|
||||
|
||||
stage.fulfill.fulfill = HTLC_FULFILL;
|
||||
stage.fulfill.htlc = htlc;
|
||||
stage.fulfill.r = *htlc->r;
|
||||
add_unacked(&peer->local, &stage);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Pkt *handle_pkt_revocation(struct peer *peer, const Pkt *pkt)
|
||||
{
|
||||
struct commit_info *ci = peer->remote.commit->prev;
|
||||
Pkt *err;
|
||||
static const struct state_table changes[] = {
|
||||
{ SENT_ADD_COMMIT, RCVD_ADD_REVOCATION },
|
||||
{ SENT_REMOVE_ACK_COMMIT, RCVD_REMOVE_ACK_REVOCATION },
|
||||
{ SENT_ADD_ACK_COMMIT, RCVD_ADD_ACK_REVOCATION },
|
||||
{ SENT_REMOVE_COMMIT, RCVD_REMOVE_REVOCATION }
|
||||
};
|
||||
|
||||
err = accept_pkt_revocation(peer, pkt, ci);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The receiver of `update_revocation`... MUST add the remote
|
||||
* unacked changes to the set of local acked changes.
|
||||
*/
|
||||
add_acked_changes(&peer->local.commit->acked_changes,
|
||||
ci->unacked_changes);
|
||||
apply_changeset(peer, &peer->local, OURS,
|
||||
ci->unacked_changes,
|
||||
tal_count(ci->unacked_changes));
|
||||
|
||||
if (!htlcs_changestate(peer, changes, ARRAY_SIZE(changes)))
|
||||
fatal("Revocation received but we made empty commitment?");
|
||||
|
||||
/* Should never examine these again. */
|
||||
ci->unacked_changes = tal_free(ci->unacked_changes);
|
||||
|
||||
/* That revocation has committed them to changes in the current
|
||||
* commitment. Any acked changes come from our commitment, so those
|
||||
* are now committed by both of us. */
|
||||
peer_both_committed_to(peer, ci->acked_changes, THEIRS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This is the io loop while we're clearing. */
|
||||
static bool clearing_pkt_in(struct peer *peer, const Pkt *pkt)
|
||||
{
|
||||
|
@ -436,7 +618,7 @@ static bool clearing_pkt_in(struct peer *peer, const Pkt *pkt)
|
|||
if (peer->state == STATE_CLEARING)
|
||||
err = pkt_err_unexpected(peer, pkt);
|
||||
else {
|
||||
err = accept_pkt_revocation(peer, pkt);
|
||||
err = handle_pkt_revocation(peer, pkt);
|
||||
if (!err) {
|
||||
set_peer_state(peer, STATE_CLEARING, __func__);
|
||||
peer_update_complete(peer);
|
||||
|
@ -452,7 +634,7 @@ static bool clearing_pkt_in(struct peer *peer, const Pkt *pkt)
|
|||
if (peer->closing.their_script)
|
||||
err = pkt_err(peer, "Update during clearing");
|
||||
else
|
||||
err = accept_pkt_htlc_add(peer, pkt);
|
||||
err = handle_pkt_htlc_add(peer, pkt);
|
||||
break;
|
||||
|
||||
case PKT__PKT_CLOSE_CLEARING:
|
||||
|
@ -466,10 +648,10 @@ static bool clearing_pkt_in(struct peer *peer, const Pkt *pkt)
|
|||
break;
|
||||
|
||||
case PKT__PKT_UPDATE_FULFILL_HTLC:
|
||||
err = accept_pkt_htlc_fulfill(peer, pkt);
|
||||
err = handle_pkt_htlc_fulfill(peer, pkt);
|
||||
break;
|
||||
case PKT__PKT_UPDATE_FAIL_HTLC:
|
||||
err = accept_pkt_htlc_fail(peer, pkt);
|
||||
err = handle_pkt_htlc_fail(peer, pkt);
|
||||
break;
|
||||
case PKT__PKT_UPDATE_COMMIT:
|
||||
err = handle_pkt_commit(peer, pkt);
|
||||
|
@ -542,15 +724,15 @@ static bool normal_pkt_in(struct peer *peer, const Pkt *pkt)
|
|||
|
||||
switch (pkt->pkt_case) {
|
||||
case PKT_UPDATE_ADD_HTLC:
|
||||
err = accept_pkt_htlc_add(peer, pkt);
|
||||
err = handle_pkt_htlc_add(peer, pkt);
|
||||
break;
|
||||
|
||||
case PKT_UPDATE_FULFILL_HTLC:
|
||||
err = accept_pkt_htlc_fulfill(peer, pkt);
|
||||
err = handle_pkt_htlc_fulfill(peer, pkt);
|
||||
break;
|
||||
|
||||
case PKT_UPDATE_FAIL_HTLC:
|
||||
err = accept_pkt_htlc_fail(peer, pkt);
|
||||
err = handle_pkt_htlc_fail(peer, pkt);
|
||||
break;
|
||||
|
||||
case PKT_UPDATE_COMMIT:
|
||||
|
@ -574,7 +756,7 @@ static bool normal_pkt_in(struct peer *peer, const Pkt *pkt)
|
|||
|
||||
case PKT_UPDATE_REVOCATION:
|
||||
if (peer->state == STATE_NORMAL_COMMITTING) {
|
||||
err = accept_pkt_revocation(peer, pkt);
|
||||
err = handle_pkt_revocation(peer, pkt);
|
||||
if (!err) {
|
||||
peer_update_complete(peer);
|
||||
set_peer_state(peer, STATE_NORMAL, __func__);
|
||||
|
@ -785,14 +967,10 @@ static bool fulfill_onchain(struct peer *peer, struct htlc *htlc)
|
|||
}
|
||||
|
||||
static bool command_htlc_fulfill(struct peer *peer,
|
||||
struct htlc *htlc,
|
||||
const struct rval *r)
|
||||
struct htlc *htlc)
|
||||
{
|
||||
union htlc_staging stage;
|
||||
|
||||
assert(!htlc->r);
|
||||
htlc->r = tal_dup(htlc, struct rval, r);
|
||||
|
||||
if (peer->state == STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL
|
||||
|| peer->state == STATE_CLOSE_ONCHAIN_OUR_UNILATERAL) {
|
||||
return fulfill_onchain(peer, htlc);
|
||||
|
@ -812,7 +990,7 @@ static bool command_htlc_fulfill(struct peer *peer,
|
|||
|
||||
stage.fulfill.fulfill = HTLC_FULFILL;
|
||||
stage.fulfill.htlc = htlc;
|
||||
stage.fulfill.r = *r;
|
||||
stage.fulfill.r = *htlc->r;
|
||||
add_unacked(&peer->remote, &stage);
|
||||
htlc_changestate(htlc, RCVD_ADD_ACK_REVOCATION, SENT_REMOVE_HTLC);
|
||||
|
||||
|
@ -2051,11 +2229,11 @@ static void resolve_our_htlcs(struct peer *peer,
|
|||
void our_htlc_fulfilled(struct peer *peer, struct htlc *htlc,
|
||||
const struct rval *preimage)
|
||||
{
|
||||
if (htlc->src)
|
||||
command_htlc_fulfill(htlc->src->peer, htlc->src, preimage);
|
||||
else {
|
||||
assert(!htlc->r);
|
||||
htlc->r = tal_dup(htlc, struct rval, preimage);
|
||||
if (htlc->src) {
|
||||
assert(!htlc->src->r);
|
||||
htlc->src->r = tal_dup(htlc->src, struct rval, htlc->r);
|
||||
command_htlc_fulfill(htlc->src->peer, htlc->src);
|
||||
} else {
|
||||
complete_pay_command(peer, htlc);
|
||||
}
|
||||
}
|
||||
|
@ -2921,7 +3099,10 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc)
|
|||
|
||||
log_info(peer->log, "Immediately resolving HTLC %"PRIu64,
|
||||
htlc->id);
|
||||
command_htlc_fulfill(peer, htlc, &payment->r);
|
||||
|
||||
assert(!htlc->r);
|
||||
htlc->r = tal_dup(htlc, struct rval, &payment->r);
|
||||
command_htlc_fulfill(peer, htlc);
|
||||
goto free_rest;
|
||||
|
||||
case ROUTE_STEP__NEXT_BITCOIN:
|
||||
|
@ -3336,7 +3517,10 @@ static void json_fulfillhtlc(struct command *cmd,
|
|||
return;
|
||||
}
|
||||
|
||||
if (command_htlc_fulfill(peer, htlc, &r))
|
||||
assert(!htlc->r);
|
||||
htlc->r = tal_dup(htlc, struct rval, &r);
|
||||
|
||||
if (command_htlc_fulfill(peer, htlc))
|
||||
command_success(cmd, null_response(cmd));
|
||||
else
|
||||
command_fail(cmd,
|
||||
|
|
46
state.c
46
state.c
|
@ -1,4 +1,5 @@
|
|||
#include <ccan/build_assert/build_assert.h>
|
||||
#include <daemon/lightningd.h>
|
||||
#include <daemon/log.h>
|
||||
#include <daemon/peer.h>
|
||||
#include <daemon/secrets.h>
|
||||
|
@ -33,6 +34,28 @@ static void send_open_pkt(struct peer *peer,
|
|||
queue_pkt_open(peer, anchor);
|
||||
}
|
||||
|
||||
static Pkt *init_from_pkt_open(struct peer *peer, const Pkt *pkt)
|
||||
{
|
||||
struct commit_info *ci = new_commit_info(peer);
|
||||
Pkt *err;
|
||||
|
||||
err = accept_pkt_open(peer, pkt, &ci->revocation_hash,
|
||||
&peer->remote.next_revocation_hash);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Set up their commit info now: rest gets done in setup_first_commit
|
||||
* once anchor is established. */
|
||||
peer->remote.commit = ci;
|
||||
|
||||
/* Witness script for anchor. */
|
||||
peer->anchor.witnessscript
|
||||
= bitcoin_redeem_2of2(peer, peer->dstate->secpctx,
|
||||
&peer->local.commitkey,
|
||||
&peer->remote.commitkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enum state state(struct peer *peer,
|
||||
const enum state_input input,
|
||||
const Pkt *pkt,
|
||||
|
@ -61,7 +84,7 @@ enum state state(struct peer *peer,
|
|||
break;
|
||||
case STATE_OPEN_WAIT_FOR_OPEN_NOANCHOR:
|
||||
if (input_is(input, PKT_OPEN)) {
|
||||
err = accept_pkt_open(peer, pkt);
|
||||
err = init_from_pkt_open(peer, pkt);
|
||||
if (err) {
|
||||
peer_open_complete(peer, err->error->problem);
|
||||
goto err_breakdown;
|
||||
|
@ -74,7 +97,7 @@ enum state state(struct peer *peer,
|
|||
break;
|
||||
case STATE_OPEN_WAIT_FOR_OPEN_WITHANCHOR:
|
||||
if (input_is(input, PKT_OPEN)) {
|
||||
err = accept_pkt_open(peer, pkt);
|
||||
err = init_from_pkt_open(peer, pkt);
|
||||
if (err) {
|
||||
peer_open_complete(peer, err->error->problem);
|
||||
goto err_breakdown;
|
||||
|
@ -112,6 +135,13 @@ enum state state(struct peer *peer,
|
|||
peer_open_complete(peer, err->error->problem);
|
||||
goto err_breakdown;
|
||||
}
|
||||
|
||||
if (!setup_first_commit(peer)) {
|
||||
err = pkt_err(peer, "Insufficient funds for fee");
|
||||
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);
|
||||
|
@ -138,7 +168,17 @@ enum state state(struct peer *peer,
|
|||
break;
|
||||
case STATE_OPEN_WAIT_FOR_COMMIT_SIG:
|
||||
if (input_is(input, PKT_OPEN_COMMIT_SIG)) {
|
||||
err = accept_pkt_open_commit_sig(peer, pkt);
|
||||
err = accept_pkt_open_commit_sig(peer, pkt,
|
||||
&peer->local.commit->sig);
|
||||
if (!err &&
|
||||
!check_tx_sig(peer->dstate->secpctx,
|
||||
peer->local.commit->tx, 0,
|
||||
NULL, 0,
|
||||
peer->anchor.witnessscript,
|
||||
&peer->remote.commitkey,
|
||||
peer->local.commit->sig))
|
||||
err = pkt_err(peer, "Bad signature");
|
||||
|
||||
if (err) {
|
||||
bitcoin_release_anchor(peer, INPUT_NONE);
|
||||
peer_open_complete(peer, err->error->problem);
|
||||
|
|
24
state.h
24
state.h
|
@ -73,6 +73,7 @@ static inline bool state_can_remove_htlc(enum state s)
|
|||
|
||||
struct peer;
|
||||
struct bitcoin_tx;
|
||||
struct commit_info;
|
||||
|
||||
static inline bool input_is_pkt(enum state_input input)
|
||||
{
|
||||
|
@ -115,25 +116,32 @@ void queue_pkt_err(struct peer *peer, Pkt *err);
|
|||
Pkt *pkt_err_unexpected(struct peer *peer, const Pkt *pkt);
|
||||
|
||||
/* Process various packets: return an error packet on failure. */
|
||||
Pkt *accept_pkt_open(struct peer *peer, const Pkt *pkt);
|
||||
Pkt *accept_pkt_open(struct peer *peer, const Pkt *pkt,
|
||||
struct sha256 *revocation_hash,
|
||||
struct sha256 *next_revocation_hash);
|
||||
|
||||
|
||||
Pkt *accept_pkt_anchor(struct peer *peer, const Pkt *pkt);
|
||||
|
||||
Pkt *accept_pkt_open_commit_sig(struct peer *peer, const Pkt *pkt);
|
||||
|
||||
Pkt *accept_pkt_open_commit_sig(struct peer *peer, const Pkt *pkt,
|
||||
struct bitcoin_signature **sig);
|
||||
|
||||
Pkt *accept_pkt_open_complete(struct peer *peer, const Pkt *pkt);
|
||||
|
||||
Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt);
|
||||
Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt, struct htlc **h);
|
||||
|
||||
Pkt *accept_pkt_htlc_fail(struct peer *peer, const Pkt *pkt);
|
||||
Pkt *accept_pkt_htlc_fail(struct peer *peer, const Pkt *pkt, struct htlc **h);
|
||||
|
||||
Pkt *accept_pkt_htlc_fulfill(struct peer *peer, const Pkt *pkt);
|
||||
Pkt *accept_pkt_htlc_fulfill(struct peer *peer, const Pkt *pkt, struct htlc **h);
|
||||
|
||||
Pkt *accept_pkt_update_accept(struct peer *peer, const Pkt *pkt);
|
||||
|
||||
Pkt *accept_pkt_commit(struct peer *peer, const Pkt *pkt);
|
||||
Pkt *accept_pkt_commit(struct peer *peer, const Pkt *pkt,
|
||||
struct bitcoin_signature *sig);
|
||||
|
||||
Pkt *accept_pkt_revocation(struct peer *peer, const Pkt *pkt,
|
||||
struct commit_info *ci);
|
||||
|
||||
Pkt *accept_pkt_revocation(struct peer *peer, const Pkt *pkt);
|
||||
Pkt *accept_pkt_close_clearing(struct peer *peer, const Pkt *pkt);
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue