mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-17 19:03:42 +01:00
state: simplify effect.
Make it a linked list of effects, rather than one big union. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
4d22b4e3eb
commit
85f4a7cf14
215
state.h
215
state.h
@ -6,12 +6,34 @@
|
||||
#include <state_types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
enum cmd_complete_status {
|
||||
CMD_STATUS_ONGOING,
|
||||
CMD_STATUS_FAILED,
|
||||
CMD_STATUS_SUCCESS,
|
||||
CMD_STATUS_REQUEUE
|
||||
};
|
||||
enum state_effect_type {
|
||||
STATE_EFFECT_new_state,
|
||||
STATE_EFFECT_in_error,
|
||||
STATE_EFFECT_broadcast_tx,
|
||||
STATE_EFFECT_send_pkt,
|
||||
STATE_EFFECT_watch,
|
||||
STATE_EFFECT_unwatch,
|
||||
STATE_EFFECT_cmd_defer,
|
||||
STATE_EFFECT_cmd_requeue,
|
||||
STATE_EFFECT_cmd_success,
|
||||
/* (never applies to CMD_CLOSE) */
|
||||
STATE_EFFECT_cmd_fail,
|
||||
STATE_EFFECT_cmd_close_done,
|
||||
STATE_EFFECT_stop_packets,
|
||||
STATE_EFFECT_stop_commands,
|
||||
/* FIXME: Use a watch for this?. */
|
||||
STATE_EFFECT_close_timeout,
|
||||
STATE_EFFECT_htlc_in_progress,
|
||||
STATE_EFFECT_update_theirsig,
|
||||
STATE_EFFECT_htlc_abandon,
|
||||
STATE_EFFECT_htlc_fulfill,
|
||||
STATE_EFFECT_r_value,
|
||||
/* FIXME: Combine into watches? */
|
||||
STATE_EFFECT_watch_htlcs,
|
||||
STATE_EFFECT_unwatch_htlc,
|
||||
STATE_EFFECT_watch_htlc_spend,
|
||||
STATE_EFFECT_unwatch_htlc_spend
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the core state machine.
|
||||
@ -20,69 +42,74 @@ enum cmd_complete_status {
|
||||
* and populates the "effect" struct with what it wants done.
|
||||
*/
|
||||
struct state_effect {
|
||||
/* Transaction to broadcast. */
|
||||
struct bitcoin_tx *broadcast;
|
||||
struct state_effect *next;
|
||||
|
||||
/* Packet to send. */
|
||||
Pkt *send;
|
||||
enum state_effect_type etype;
|
||||
union {
|
||||
/* New state to enter. */
|
||||
enum state new_state;
|
||||
|
||||
/* Event to watch for. */
|
||||
struct watch *watch;
|
||||
/* Transaction to broadcast. */
|
||||
struct bitcoin_tx *broadcast_tx;
|
||||
|
||||
/* Events to no longer watch for. */
|
||||
struct watch *unwatch;
|
||||
/* Packet to send. */
|
||||
Pkt *send_pkt;
|
||||
|
||||
/* Defer an input. */
|
||||
enum state_input defer;
|
||||
/* Event to watch for. */
|
||||
struct watch *watch;
|
||||
|
||||
/* Complete a command. */
|
||||
enum state_input complete;
|
||||
enum cmd_complete_status status;
|
||||
void *faildata;
|
||||
/* Events to no longer watch for. */
|
||||
struct watch *unwatch;
|
||||
|
||||
/* Completing a CMD_CLOSE */
|
||||
enum cmd_complete_status close_status;
|
||||
/* Defer an input. */
|
||||
enum state_input cmd_defer;
|
||||
|
||||
/* Stop taking packets? commands? */
|
||||
bool stop_packets, stop_commands;
|
||||
/* Requeue/succeed/fail command. */
|
||||
enum state_input cmd_requeue;
|
||||
enum state_input cmd_success;
|
||||
void *cmd_fail;
|
||||
|
||||
/* Set a timeout for close tx. */
|
||||
enum state_input close_timeout;
|
||||
/* CMD_CLOSE is complete (true if successful mutual close). */
|
||||
bool cmd_close_done;
|
||||
|
||||
/* Error received from other side. */
|
||||
Pkt *in_error;
|
||||
/* Stop taking packets? commands? */
|
||||
bool stop_packets, stop_commands;
|
||||
|
||||
/* HTLC we're working on. */
|
||||
struct htlc_progress *htlc_in_progress;
|
||||
/* Set a timeout for close tx. */
|
||||
enum state_input close_timeout;
|
||||
|
||||
/* Their signature for the new commit tx. */
|
||||
struct signature *update_theirsig;
|
||||
/* Error received from other side. */
|
||||
Pkt *in_error;
|
||||
|
||||
/* HTLC we're working on. */
|
||||
struct htlc_progress *htlc_in_progress;
|
||||
|
||||
/* Their signature for the new commit tx. */
|
||||
struct signature *update_theirsig;
|
||||
|
||||
/* Stop working on HTLC. */
|
||||
bool htlc_abandon;
|
||||
/* Stop working on HTLC. */
|
||||
bool htlc_abandon;
|
||||
|
||||
/* Finished working on HTLC. */
|
||||
bool htlc_fulfill;
|
||||
/* Finished working on HTLC. */
|
||||
bool htlc_fulfill;
|
||||
|
||||
/* R value. */
|
||||
const struct htlc_rval *r_value;
|
||||
/* R value. */
|
||||
const struct htlc_rval *r_value;
|
||||
|
||||
/* HTLC outputs to watch. */
|
||||
const struct htlc_watch *watch_htlcs;
|
||||
/* HTLC outputs to watch. */
|
||||
const struct htlc_watch *watch_htlcs;
|
||||
|
||||
/* HTLC output to unwatch. */
|
||||
const struct htlc_unwatch *unwatch_htlc;
|
||||
/* HTLC output to unwatch. */
|
||||
const struct htlc_unwatch *unwatch_htlc;
|
||||
|
||||
/* HTLC spends to watch/unwatch. */
|
||||
const struct htlc_spend_watch *watch_htlc_spend;
|
||||
const struct htlc_spend_watch *unwatch_htlc_spend;
|
||||
/* HTLC spends to watch/unwatch. */
|
||||
const struct htlc_spend_watch *watch_htlc_spend;
|
||||
const struct htlc_spend_watch *unwatch_htlc_spend;
|
||||
|
||||
/* FIXME: More to come (for accept_*) */
|
||||
/* FIXME: More to come (for accept_*) */
|
||||
} u;
|
||||
};
|
||||
|
||||
/* Initialize the above struct. */
|
||||
void state_effect_init(struct state_effect *effect);
|
||||
|
||||
static inline bool state_is_error(enum state s)
|
||||
{
|
||||
return s >= STATE_ERR_ANCHOR_TIMEOUT && s <= STATE_ERR_INTERNAL;
|
||||
@ -103,9 +130,11 @@ union input {
|
||||
struct htlc_progress *htlc_prog;
|
||||
};
|
||||
|
||||
enum state state(const enum state state, const struct state_data *sdata,
|
||||
const enum state_input input, const union input *idata,
|
||||
struct state_effect *effect);
|
||||
struct state_effect *state(const tal_t *ctx,
|
||||
const enum state state,
|
||||
const struct state_data *sdata,
|
||||
const enum state_input input,
|
||||
const union input *idata);
|
||||
|
||||
/* Any CMD_SEND_HTLC_* */
|
||||
#define CMD_SEND_UPDATE_ANY INPUT_MAX
|
||||
@ -154,58 +183,72 @@ Pkt *pkt_close_ack(const tal_t *ctx, const struct state_data *sdata);
|
||||
Pkt *unexpected_pkt(const tal_t *ctx, enum state_input input);
|
||||
|
||||
/* Process various packets: return an error packet on failure. */
|
||||
Pkt *accept_pkt_open(struct state_effect *effect,
|
||||
Pkt *accept_pkt_open(const tal_t *ctx,
|
||||
const struct state_data *sdata,
|
||||
const Pkt *pkt);
|
||||
const Pkt *pkt,
|
||||
struct state_effect **effect);
|
||||
|
||||
Pkt *accept_pkt_anchor(struct state_effect *effect,
|
||||
Pkt *accept_pkt_anchor(const tal_t *ctx,
|
||||
const struct state_data *sdata,
|
||||
const Pkt *pkt);
|
||||
const Pkt *pkt,
|
||||
struct state_effect **effect);
|
||||
|
||||
Pkt *accept_pkt_open_commit_sig(struct state_effect *effect,
|
||||
const struct state_data *sdata, const Pkt *pkt);
|
||||
Pkt *accept_pkt_open_commit_sig(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct state_effect **effect);
|
||||
|
||||
Pkt *accept_pkt_htlc_update(struct state_effect *effect,
|
||||
Pkt *accept_pkt_htlc_update(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
Pkt **decline,
|
||||
struct htlc_progress **htlcprog);
|
||||
struct htlc_progress **htlcprog,
|
||||
struct state_effect **effect);
|
||||
|
||||
Pkt *accept_pkt_htlc_routefail(struct state_effect *effect,
|
||||
Pkt *accept_pkt_htlc_routefail(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct htlc_progress **htlcprog);
|
||||
struct htlc_progress **htlcprog,
|
||||
struct state_effect **effect);
|
||||
|
||||
Pkt *accept_pkt_htlc_timedout(struct state_effect *effect,
|
||||
Pkt *accept_pkt_htlc_timedout(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct htlc_progress **htlcprog);
|
||||
struct htlc_progress **htlcprog,
|
||||
struct state_effect **effect);
|
||||
|
||||
Pkt *accept_pkt_htlc_fulfill(struct state_effect *effect,
|
||||
Pkt *accept_pkt_htlc_fulfill(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct htlc_progress **htlcprog,
|
||||
struct state_effect **effect);
|
||||
|
||||
Pkt *accept_pkt_update_accept(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct htlc_progress **htlcprog);
|
||||
struct signature **sig,
|
||||
struct state_effect **effect);
|
||||
|
||||
Pkt *accept_pkt_update_accept(struct state_effect *effect,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct signature **sig);
|
||||
Pkt *accept_pkt_update_complete(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct state_effect **effect);
|
||||
|
||||
Pkt *accept_pkt_update_complete(struct state_effect *effect,
|
||||
const struct state_data *sdata, const Pkt *pkt);
|
||||
|
||||
Pkt *accept_pkt_update_signature(struct state_effect *effect,
|
||||
Pkt *accept_pkt_update_signature(const tal_t *ctx,
|
||||
const struct state_data *sdata,
|
||||
const Pkt *pkt,
|
||||
struct signature **sig);
|
||||
struct signature **sig,
|
||||
struct state_effect **effect);
|
||||
|
||||
Pkt *accept_pkt_close(struct state_effect *effect,
|
||||
const struct state_data *sdata, const Pkt *pkt);
|
||||
Pkt *accept_pkt_close(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct state_effect **effect);
|
||||
|
||||
Pkt *accept_pkt_close_complete(struct state_effect *effect,
|
||||
const struct state_data *sdata, const Pkt *pkt);
|
||||
Pkt *accept_pkt_close_complete(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct state_effect **effect);
|
||||
|
||||
Pkt *accept_pkt_simultaneous_close(struct state_effect *effect,
|
||||
Pkt *accept_pkt_simultaneous_close(const tal_t *ctx,
|
||||
const struct state_data *sdata,
|
||||
const Pkt *pkt);
|
||||
const Pkt *pkt,
|
||||
struct state_effect **effect);
|
||||
|
||||
Pkt *accept_pkt_close_ack(struct state_effect *effect,
|
||||
const struct state_data *sdata, const Pkt *pkt);
|
||||
Pkt *accept_pkt_close_ack(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct state_effect **effect);
|
||||
|
||||
/**
|
||||
* committed_to_htlcs: do we have any locked-in HTLCs?
|
||||
@ -252,26 +295,26 @@ struct watch *bitcoin_unwatch_anchor_depth(const tal_t *ctx,
|
||||
|
||||
/**
|
||||
* bitcoin_watch_delayed: watch this (commit) tx, tell me when I can spend it
|
||||
* @effect: the context to tal the watch off
|
||||
* @ctx: the context to tal the watch off
|
||||
* @tx: the tx we're watching.
|
||||
* @canspend: the input to give when commit reaches spendable depth.
|
||||
*
|
||||
* Note that this tx may be malleated, as it's dual-signed.
|
||||
*/
|
||||
struct watch *bitcoin_watch_delayed(const struct state_effect *effect,
|
||||
struct watch *bitcoin_watch_delayed(const tal_t *ctx,
|
||||
const struct bitcoin_tx *tx,
|
||||
enum state_input canspend);
|
||||
|
||||
/**
|
||||
* bitcoin_watch: watch this tx until it's "irreversible"
|
||||
* @effect: the context to tal the watch off
|
||||
* @ctx: the context to tal the watch off
|
||||
* @tx: the tx we're watching.
|
||||
* @done: the input to give when tx is completely buried.
|
||||
*
|
||||
* The tx should be immalleable by BIP62; once this fires we consider
|
||||
* the channel completely closed and stop watching (eg 100 txs down).
|
||||
*/
|
||||
struct watch *bitcoin_watch(const struct state_effect *effect,
|
||||
struct watch *bitcoin_watch(const tal_t *ctx,
|
||||
const struct bitcoin_tx *tx,
|
||||
enum state_input done);
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Test for state machine. */
|
||||
#include <stdbool.h>
|
||||
#include <ccan/cast/cast.h>
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
@ -649,40 +650,47 @@ Pkt *unexpected_pkt(const tal_t *ctx, enum state_input input)
|
||||
return pkt_err(ctx, "Unexpected pkt");
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_open(struct state_effect *effect, const struct state_data *sdata, const Pkt *pkt)
|
||||
Pkt *accept_pkt_open(const tal_t *ctx,
|
||||
const struct state_data *sdata,
|
||||
const Pkt *pkt, struct state_effect **effect)
|
||||
{
|
||||
if (fail(sdata, FAIL_ACCEPT_OPEN))
|
||||
return pkt_err(effect, "Error inject");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_anchor(struct state_effect *effect, const struct state_data *sdata, const Pkt *pkt)
|
||||
Pkt *accept_pkt_anchor(const tal_t *ctx,
|
||||
const struct state_data *sdata,
|
||||
const Pkt *pkt, struct state_effect **effect)
|
||||
{
|
||||
if (fail(sdata, FAIL_ACCEPT_ANCHOR))
|
||||
return pkt_err(effect, "Error inject");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_open_commit_sig(struct state_effect *effect, const struct state_data *sdata, const Pkt *pkt)
|
||||
Pkt *accept_pkt_open_commit_sig(const tal_t *ctx,
|
||||
const struct state_data *sdata,
|
||||
const Pkt *pkt, struct state_effect **effect)
|
||||
{
|
||||
if (fail(sdata, FAIL_ACCEPT_OPEN_COMMIT_SIG))
|
||||
return pkt_err(effect, "Error inject");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_htlc_update(struct state_effect *effect,
|
||||
Pkt *accept_pkt_htlc_update(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
Pkt **decline,
|
||||
struct htlc_progress **htlcprog)
|
||||
struct htlc_progress **htlcprog,
|
||||
struct state_effect **effect)
|
||||
{
|
||||
if (fail(sdata, FAIL_ACCEPT_HTLC_UPDATE))
|
||||
return pkt_err(effect, "Error inject");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
|
||||
if (fail(sdata, FAIL_DECLINE_HTLC))
|
||||
*decline = new_pkt(effect, PKT_UPDATE_DECLINE_HTLC);
|
||||
*decline = new_pkt(ctx, PKT_UPDATE_DECLINE_HTLC);
|
||||
else {
|
||||
*decline = NULL;
|
||||
*htlcprog = tal(effect, struct htlc_progress);
|
||||
*htlcprog = tal(ctx, struct htlc_progress);
|
||||
/* If they propose it, it's to us. */
|
||||
(*htlcprog)->htlc.to_them = false;
|
||||
(*htlcprog)->htlc.id = htlc_id_from_pkt(pkt);
|
||||
@ -691,114 +699,132 @@ Pkt *accept_pkt_htlc_update(struct state_effect *effect,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_htlc_routefail(struct state_effect *effect,
|
||||
Pkt *accept_pkt_htlc_routefail(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct htlc_progress **htlcprog)
|
||||
struct htlc_progress **htlcprog,
|
||||
struct state_effect **effect)
|
||||
{
|
||||
unsigned int id = htlc_id_from_pkt(pkt);
|
||||
const struct htlc *h = find_htlc(sdata, id);
|
||||
|
||||
if (fail(sdata, FAIL_ACCEPT_HTLC_ROUTEFAIL))
|
||||
return pkt_err(effect, "Error inject");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
|
||||
/* The shouldn't fail unless it's to them */
|
||||
assert(h->to_them);
|
||||
|
||||
*htlcprog = tal(effect, struct htlc_progress);
|
||||
*htlcprog = tal(ctx, struct htlc_progress);
|
||||
(*htlcprog)->htlc = *h;
|
||||
(*htlcprog)->adding = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_htlc_timedout(struct state_effect *effect,
|
||||
Pkt *accept_pkt_htlc_timedout(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct htlc_progress **htlcprog)
|
||||
struct htlc_progress **htlcprog,
|
||||
struct state_effect **effect)
|
||||
{
|
||||
unsigned int id = htlc_id_from_pkt(pkt);
|
||||
const struct htlc *h = find_htlc(sdata, id);
|
||||
|
||||
if (fail(sdata, FAIL_ACCEPT_HTLC_TIMEDOUT))
|
||||
return pkt_err(effect, "Error inject");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
|
||||
/* The shouldn't timeout unless it's to us */
|
||||
assert(!h->to_them);
|
||||
|
||||
*htlcprog = tal(effect, struct htlc_progress);
|
||||
*htlcprog = tal(ctx, struct htlc_progress);
|
||||
(*htlcprog)->htlc = *h;
|
||||
(*htlcprog)->adding = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_htlc_fulfill(struct state_effect *effect,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct htlc_progress **htlcprog)
|
||||
Pkt *accept_pkt_htlc_fulfill(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct htlc_progress **htlcprog,
|
||||
struct state_effect **effect)
|
||||
{
|
||||
unsigned int id = htlc_id_from_pkt(pkt);
|
||||
const struct htlc *h = find_htlc(sdata, id);
|
||||
|
||||
if (fail(sdata, FAIL_ACCEPT_HTLC_FULFILL))
|
||||
return pkt_err(effect, "Error inject");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
|
||||
/* The shouldn't complete unless it's to them */
|
||||
assert(h->to_them);
|
||||
|
||||
*htlcprog = tal(effect, struct htlc_progress);
|
||||
*htlcprog = tal(ctx, struct htlc_progress);
|
||||
(*htlcprog)->htlc = *h;
|
||||
(*htlcprog)->adding = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_update_accept(struct state_effect *effect, const struct state_data *sdata, const Pkt *pkt, struct signature **sig)
|
||||
Pkt *accept_pkt_update_accept(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct signature **sig,
|
||||
struct state_effect **effect)
|
||||
{
|
||||
if (fail(sdata, FAIL_ACCEPT_UPDATE_ACCEPT))
|
||||
return pkt_err(effect, "Error inject");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
|
||||
*sig = (struct signature *)tal_strdup(effect, "from PKT_UPDATE_ACCEPT");
|
||||
*sig = (struct signature *)tal_strdup(ctx, "from PKT_UPDATE_ACCEPT");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_update_complete(struct state_effect *effect, const struct state_data *sdata, const Pkt *pkt)
|
||||
Pkt *accept_pkt_update_complete(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct state_effect **effect)
|
||||
{
|
||||
if (fail(sdata, FAIL_ACCEPT_UPDATE_COMPLETE))
|
||||
return pkt_err(effect, "Error inject");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_update_signature(struct state_effect *effect,
|
||||
Pkt *accept_pkt_update_signature(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct signature **sig)
|
||||
struct signature **sig,
|
||||
struct state_effect **effect)
|
||||
{
|
||||
if (fail(sdata, FAIL_ACCEPT_UPDATE_SIGNATURE))
|
||||
return pkt_err(effect, "Error inject");
|
||||
*sig = (struct signature *)tal_strdup(effect, "from PKT_UPDATE_SIGNATURE");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
*sig = (struct signature *)tal_strdup(ctx, "from PKT_UPDATE_SIGNATURE");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_close(struct state_effect *effect, const struct state_data *sdata, const Pkt *pkt)
|
||||
Pkt *accept_pkt_close(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct state_effect **effect)
|
||||
{
|
||||
if (fail(sdata, FAIL_ACCEPT_CLOSE))
|
||||
return pkt_err(effect, "Error inject");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_close_complete(struct state_effect *effect, const struct state_data *sdata, const Pkt *pkt)
|
||||
Pkt *accept_pkt_close_complete(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct state_effect **effect)
|
||||
{
|
||||
if (fail(sdata, FAIL_ACCEPT_CLOSE_COMPLETE))
|
||||
return pkt_err(effect, "Error inject");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_simultaneous_close(struct state_effect *effect, const struct state_data *sdata, const Pkt *pkt)
|
||||
Pkt *accept_pkt_simultaneous_close(const tal_t *ctx,
|
||||
const struct state_data *sdata,
|
||||
const Pkt *pkt,
|
||||
struct state_effect **effect)
|
||||
{
|
||||
if (fail(sdata, FAIL_ACCEPT_SIMULTANEOUS_CLOSE))
|
||||
return pkt_err(effect, "Error inject");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pkt *accept_pkt_close_ack(struct state_effect *effect, const struct state_data *sdata, const Pkt *pkt)
|
||||
Pkt *accept_pkt_close_ack(const tal_t *ctx,
|
||||
const struct state_data *sdata, const Pkt *pkt,
|
||||
struct state_effect **effect)
|
||||
{
|
||||
if (fail(sdata, FAIL_ACCEPT_CLOSE_ACK))
|
||||
return pkt_err(effect, "Error inject");
|
||||
return pkt_err(ctx, "Error inject");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -905,11 +931,11 @@ struct watch *bitcoin_unwatch_anchor_depth(const tal_t *ctx,
|
||||
}
|
||||
|
||||
/* Wait for our commit to be spendable. */
|
||||
struct watch *bitcoin_watch_delayed(const struct state_effect *effect,
|
||||
struct watch *bitcoin_watch_delayed(const tal_t *ctx,
|
||||
const struct bitcoin_tx *tx,
|
||||
enum state_input canspend)
|
||||
{
|
||||
struct watch *watch = talz(effect, struct watch);
|
||||
struct watch *watch = talz(ctx, struct watch);
|
||||
|
||||
assert(bitcoin_tx_is(tx, "our commit"));
|
||||
add_event(&watch->events, canspend);
|
||||
@ -918,11 +944,11 @@ struct watch *bitcoin_watch_delayed(const struct state_effect *effect,
|
||||
|
||||
/* Wait for commit to be very deeply buried (so we no longer need to
|
||||
* even watch) */
|
||||
struct watch *bitcoin_watch(const struct state_effect *effect,
|
||||
struct watch *bitcoin_watch(const tal_t *ctx,
|
||||
const struct bitcoin_tx *tx,
|
||||
enum state_input done)
|
||||
{
|
||||
struct watch *watch = talz(effect, struct watch);
|
||||
struct watch *watch = talz(ctx, struct watch);
|
||||
|
||||
if (done == BITCOIN_STEAL_DONE)
|
||||
assert(bitcoin_tx_is(tx, "steal"));
|
||||
@ -1232,11 +1258,11 @@ static void init_trail(struct trail *t,
|
||||
|
||||
static void update_trail(struct trail *t,
|
||||
const struct state_data *after,
|
||||
const struct state_effect *effects)
|
||||
const Pkt *output)
|
||||
{
|
||||
t->after = after;
|
||||
t->num_peer_outputs = after->peer->core.num_outputs;
|
||||
t->pkt_sent = (const char *)effects->send;
|
||||
t->pkt_sent = (const char *)output;
|
||||
}
|
||||
|
||||
static void report_trail_rev(const struct trail *t)
|
||||
@ -1382,11 +1408,62 @@ static bool rval_known(const struct state_data *sdata, unsigned int id)
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char *apply_effects(struct state_data *sdata,
|
||||
const struct state_effect *effect)
|
||||
/* Some assertions once they've already been applied. */
|
||||
static char *check_effects(struct state_data *sdata,
|
||||
const struct state_effect *effect)
|
||||
{
|
||||
if (effect->send) {
|
||||
const char *pkt = (const char *)effect->send;
|
||||
while (effect) {
|
||||
if (effect->etype == STATE_EFFECT_in_error) {
|
||||
/* We should stop talking to them after error recvd. */
|
||||
if (sdata->core.pkt_inputs)
|
||||
return "packets still open after error pkt";
|
||||
} else if (effect->etype == STATE_EFFECT_stop_commands) {
|
||||
if (sdata->core.current_command != INPUT_NONE)
|
||||
return tal_fmt(NULL,
|
||||
"stop_commands with pending command %s",
|
||||
input_name(sdata->core.current_command));
|
||||
if (sdata->core.closing_cmd)
|
||||
return "stop_commands with pending CMD_CLOSE";
|
||||
}
|
||||
effect = effect->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We apply them backwards, which helps our assertions. It's not actually
|
||||
* required. */
|
||||
static const char *apply_effects(struct state_data *sdata,
|
||||
const struct state_effect *effect,
|
||||
uint64_t *effects,
|
||||
Pkt **output)
|
||||
{
|
||||
const struct htlc *h;
|
||||
|
||||
if (!effect)
|
||||
return NULL;
|
||||
|
||||
if (effect->next) {
|
||||
const char *problem = apply_effects(sdata, effect->next,
|
||||
effects, output);
|
||||
if (problem)
|
||||
return problem;
|
||||
}
|
||||
|
||||
if (*effects & (1ULL << effect->etype))
|
||||
return tal_fmt(NULL, "Effect %u twice", effect->etype);
|
||||
*effects |= (1ULL << effect->etype);
|
||||
|
||||
switch (effect->etype) {
|
||||
case STATE_EFFECT_new_state:
|
||||
sdata->core.state = effect->u.new_state;
|
||||
break;
|
||||
case STATE_EFFECT_in_error:
|
||||
break;
|
||||
case STATE_EFFECT_broadcast_tx:
|
||||
break;
|
||||
case STATE_EFFECT_send_pkt: {
|
||||
const char *pkt = (const char *)effect->u.send_pkt;
|
||||
*output = effect->u.send_pkt;
|
||||
|
||||
/* Check for errors. */
|
||||
if (strstarts(pkt, "ERROR_PKT:")) {
|
||||
@ -1404,61 +1481,68 @@ static const char *apply_effects(struct state_data *sdata,
|
||||
sdata->core.outputs[sdata->core.num_outputs]
|
||||
= input_by_name(pkt);
|
||||
sdata->pkt_data[sdata->core.num_outputs++]
|
||||
= htlc_id_from_pkt(effect->send);
|
||||
= htlc_id_from_pkt(effect->u.send_pkt);
|
||||
break;
|
||||
}
|
||||
if (effect->watch) {
|
||||
/* We can have multiple steals or spendtheirs in flight,
|
||||
so make exceptions for BITCOIN_STEAL_DONE/BITCOIN_SPEND_THEIRS_DONE */
|
||||
case STATE_EFFECT_watch:
|
||||
/* We can have multiple steals or spendtheirs
|
||||
in flight, so make exceptions for
|
||||
BITCOIN_STEAL_DONE/BITCOIN_SPEND_THEIRS_DONE */
|
||||
if (sdata->core.event_notifies & (1ULL << BITCOIN_STEAL_DONE)
|
||||
& effect->watch->events)
|
||||
remove_event(&effect->watch->events, BITCOIN_STEAL_DONE);
|
||||
& effect->u.watch->events)
|
||||
remove_event(&effect->u.watch->events, BITCOIN_STEAL_DONE);
|
||||
|
||||
if (sdata->core.event_notifies
|
||||
& (1ULL << BITCOIN_SPEND_THEIRS_DONE)
|
||||
& effect->watch->events)
|
||||
remove_event(&effect->watch->events,
|
||||
& effect->u.watch->events)
|
||||
remove_event(&effect->u.watch->events,
|
||||
BITCOIN_SPEND_THEIRS_DONE);
|
||||
|
||||
if (sdata->core.event_notifies & effect->watch->events)
|
||||
if (sdata->core.event_notifies & effect->u.watch->events)
|
||||
return "event set twice";
|
||||
sdata->core.event_notifies |= effect->watch->events;
|
||||
}
|
||||
if (effect->unwatch) {
|
||||
if ((sdata->core.event_notifies & effect->unwatch->events)
|
||||
!= effect->unwatch->events)
|
||||
sdata->core.event_notifies |= effect->u.watch->events;
|
||||
break;
|
||||
case STATE_EFFECT_unwatch:
|
||||
if ((sdata->core.event_notifies & effect->u.unwatch->events)
|
||||
!= effect->u.unwatch->events)
|
||||
return "unset event unwatched";
|
||||
sdata->core.event_notifies &= ~effect->unwatch->events;
|
||||
}
|
||||
if (effect->defer != INPUT_NONE) {
|
||||
sdata->core.event_notifies &= ~effect->u.unwatch->events;
|
||||
break;
|
||||
case STATE_EFFECT_cmd_defer:
|
||||
/* If it was current command, it is no longer. */
|
||||
if (is_current_command(sdata, effect->defer))
|
||||
if (is_current_command(sdata, effect->u.cmd_defer))
|
||||
sdata->core.current_command = INPUT_NONE;
|
||||
else if (input_is_pkt(effect->defer)) {
|
||||
else if (input_is_pkt(effect->u.cmd_defer)) {
|
||||
/* Unlike commands, which we always resubmit,
|
||||
* we have to remember deferred packets. */
|
||||
/* We assume only one deferrment! */
|
||||
assert(sdata->core.deferred_pkt == INPUT_NONE
|
||||
|| sdata->core.deferred_pkt == effect->defer);
|
||||
sdata->core.deferred_pkt = effect->defer;
|
||||
|| sdata->core.deferred_pkt == effect->u.cmd_defer);
|
||||
sdata->core.deferred_pkt = effect->u.cmd_defer;
|
||||
sdata->core.deferred_state = sdata->core.state;
|
||||
}
|
||||
}
|
||||
if (effect->complete != INPUT_NONE) {
|
||||
if (!is_current_command(sdata, effect->complete)) {
|
||||
return tal_fmt(NULL, "Completed %s not %s",
|
||||
input_name(effect->complete),
|
||||
input_name(sdata->core.current_command));
|
||||
}
|
||||
break;
|
||||
case STATE_EFFECT_cmd_requeue:
|
||||
assert(is_current_command(sdata, effect->u.cmd_requeue));
|
||||
sdata->core.current_command = INPUT_NONE;
|
||||
}
|
||||
if (effect->close_status != CMD_STATUS_ONGOING) {
|
||||
break;
|
||||
case STATE_EFFECT_cmd_success:
|
||||
assert(is_current_command(sdata, effect->u.cmd_success));
|
||||
sdata->core.current_command = INPUT_NONE;
|
||||
break;
|
||||
case STATE_EFFECT_cmd_fail:
|
||||
if (sdata->core.current_command == INPUT_NONE)
|
||||
return "Failed command with none current";
|
||||
sdata->core.current_command = INPUT_NONE;
|
||||
break;
|
||||
case STATE_EFFECT_cmd_close_done:
|
||||
if (!sdata->core.closing_cmd)
|
||||
return tal_fmt(NULL, "%s but not closing",
|
||||
effect->close_status == CMD_STATUS_SUCCESS ? "Success"
|
||||
: "Failure");
|
||||
effect->u.cmd_close_done
|
||||
? "Success" : "Failure");
|
||||
sdata->core.closing_cmd = false;
|
||||
}
|
||||
if (effect->stop_packets) {
|
||||
break;
|
||||
case STATE_EFFECT_stop_packets:
|
||||
if (!sdata->core.pkt_inputs)
|
||||
return "stop_packets twice";
|
||||
sdata->core.pkt_inputs = false;
|
||||
@ -1466,58 +1550,50 @@ static const char *apply_effects(struct state_data *sdata,
|
||||
/* Can no longer receive packet timeouts, either. */
|
||||
remove_event_(&sdata->core.event_notifies,
|
||||
INPUT_CLOSE_COMPLETE_TIMEOUT);
|
||||
}
|
||||
if (effect->stop_commands) {
|
||||
break;
|
||||
case STATE_EFFECT_stop_commands:
|
||||
if (!sdata->core.cmd_inputs)
|
||||
return "stop_commands twice";
|
||||
if (sdata->core.current_command != INPUT_NONE)
|
||||
return tal_fmt(NULL, "stop_commands with pending command %s",
|
||||
input_name(sdata->core.current_command));
|
||||
if (sdata->core.closing_cmd)
|
||||
return "stop_commands with pending CMD_CLOSE";
|
||||
sdata->core.cmd_inputs = false;
|
||||
}
|
||||
if (effect->close_timeout != INPUT_NONE) {
|
||||
add_event(&sdata->core.event_notifies, effect->close_timeout);
|
||||
break;
|
||||
case STATE_EFFECT_close_timeout:
|
||||
add_event(&sdata->core.event_notifies,
|
||||
effect->u.close_timeout);
|
||||
/* We assume this. */
|
||||
assert(effect->close_timeout == INPUT_CLOSE_COMPLETE_TIMEOUT);
|
||||
}
|
||||
if (effect->in_error) {
|
||||
/* We should stop talking to them after error received. */
|
||||
if (sdata->core.pkt_inputs)
|
||||
return "packets still open after error pkt";
|
||||
}
|
||||
/* We can abandon and add a new one, if we're LOWPRIO */
|
||||
if (effect->htlc_abandon) {
|
||||
if (sdata->current_htlc.htlc.id == -1)
|
||||
return "HTLC not in progress, can't abandon";
|
||||
if (effect->htlc_fulfill)
|
||||
return "Complete and abandon?";
|
||||
sdata->current_htlc.htlc.id = -1;
|
||||
}
|
||||
if (effect->htlc_in_progress) {
|
||||
assert(effect->u.close_timeout
|
||||
== INPUT_CLOSE_COMPLETE_TIMEOUT);
|
||||
break;
|
||||
case STATE_EFFECT_htlc_in_progress:
|
||||
if (sdata->current_htlc.htlc.id != -1)
|
||||
return "HTLC already in progress";
|
||||
if (effect->htlc_fulfill)
|
||||
return "Complete in one step?";
|
||||
sdata->current_htlc = *effect->htlc_in_progress;
|
||||
}
|
||||
if (effect->htlc_fulfill) {
|
||||
sdata->current_htlc = *effect->u.htlc_in_progress;
|
||||
break;
|
||||
case STATE_EFFECT_update_theirsig:
|
||||
break;
|
||||
case STATE_EFFECT_htlc_abandon:
|
||||
if (sdata->current_htlc.htlc.id == -1)
|
||||
return "HTLC not in progress, can't abandon";
|
||||
sdata->current_htlc.htlc.id = -1;
|
||||
break;
|
||||
case STATE_EFFECT_htlc_fulfill:
|
||||
if (sdata->current_htlc.htlc.id == -1)
|
||||
return "HTLC not in progress, can't complete";
|
||||
|
||||
if (sdata->current_htlc.adding) {
|
||||
add_htlc(sdata->htlcs_to_us, &sdata->num_htlcs_to_us,
|
||||
add_htlc(sdata->htlcs_to_us,
|
||||
&sdata->num_htlcs_to_us,
|
||||
sdata->htlcs_to_them,
|
||||
&sdata->num_htlcs_to_them,
|
||||
ARRAY_SIZE(sdata->htlcs_to_us),
|
||||
&sdata->current_htlc.htlc);
|
||||
} else {
|
||||
const struct htlc *h;
|
||||
h = find_htlc(sdata, sdata->current_htlc.htlc.id);
|
||||
h = find_htlc(sdata,
|
||||
sdata->current_htlc.htlc.id);
|
||||
if (!h)
|
||||
return "Removing nonexistent HTLC?";
|
||||
if (h->to_them != sdata->current_htlc.htlc.to_them)
|
||||
if (h->to_them !=
|
||||
sdata->current_htlc.htlc.to_them)
|
||||
return "Removing disagreed about to_them";
|
||||
remove_htlc(sdata->htlcs_to_us, &sdata->num_htlcs_to_us,
|
||||
sdata->htlcs_to_them,
|
||||
@ -1526,81 +1602,46 @@ static const char *apply_effects(struct state_data *sdata,
|
||||
h);
|
||||
}
|
||||
sdata->current_htlc.htlc.id = -1;
|
||||
}
|
||||
|
||||
if (effect->r_value) {
|
||||
/* We set r_value when they spend an HTLC, so we can set this
|
||||
* multiple times (multiple commit txs) */
|
||||
if (!rval_known(sdata, effect->r_value->id)) {
|
||||
break;
|
||||
case STATE_EFFECT_r_value:
|
||||
/* We set r_value when they spend an HTLC, so
|
||||
* we can set this multiple times (multiple commit
|
||||
* txs) */
|
||||
if (!rval_known(sdata, effect->u.r_value->id)) {
|
||||
if (sdata->num_rvals_known
|
||||
== ARRAY_SIZE(sdata->rvals_known))
|
||||
return "Too many rvals";
|
||||
|
||||
sdata->rvals_known[sdata->num_rvals_known++]
|
||||
= effect->r_value->id;
|
||||
= effect->u.r_value->id;
|
||||
}
|
||||
}
|
||||
|
||||
if (effect->watch_htlcs) {
|
||||
break;
|
||||
|
||||
case STATE_EFFECT_watch_htlcs:
|
||||
assert(sdata->num_live_htlcs_to_us
|
||||
+ effect->watch_htlcs->num_htlcs_to_us
|
||||
+ effect->u.watch_htlcs->num_htlcs_to_us
|
||||
<= ARRAY_SIZE(sdata->live_htlcs_to_us));
|
||||
assert(sdata->num_live_htlcs_to_them
|
||||
+ effect->watch_htlcs->num_htlcs_to_them
|
||||
+ effect->u.watch_htlcs->num_htlcs_to_them
|
||||
<= ARRAY_SIZE(sdata->live_htlcs_to_them));
|
||||
memcpy(sdata->live_htlcs_to_us + sdata->num_live_htlcs_to_us,
|
||||
effect->watch_htlcs->htlcs_to_us,
|
||||
effect->watch_htlcs->num_htlcs_to_us
|
||||
* sizeof(effect->watch_htlcs->htlcs_to_us[0]));
|
||||
effect->u.watch_htlcs->htlcs_to_us,
|
||||
effect->u.watch_htlcs->num_htlcs_to_us
|
||||
* sizeof(effect->u.watch_htlcs->htlcs_to_us[0]));
|
||||
memcpy(sdata->live_htlcs_to_them + sdata->num_live_htlcs_to_them,
|
||||
effect->watch_htlcs->htlcs_to_them,
|
||||
effect->watch_htlcs->num_htlcs_to_them
|
||||
* sizeof(effect->watch_htlcs->htlcs_to_them[0]));
|
||||
effect->u.watch_htlcs->htlcs_to_them,
|
||||
effect->u.watch_htlcs->num_htlcs_to_them
|
||||
* sizeof(effect->u.watch_htlcs->htlcs_to_them[0]));
|
||||
sdata->num_live_htlcs_to_us
|
||||
+= effect->watch_htlcs->num_htlcs_to_us;
|
||||
+= effect->u.watch_htlcs->num_htlcs_to_us;
|
||||
sdata->num_live_htlcs_to_them
|
||||
+= effect->watch_htlcs->num_htlcs_to_them;
|
||||
+= effect->u.watch_htlcs->num_htlcs_to_them;
|
||||
/* Can happen if we were finished, then new commit tx */
|
||||
remove_event_(&sdata->core.event_notifies, INPUT_NO_MORE_HTLCS);
|
||||
}
|
||||
if (effect->watch_htlc_spend) {
|
||||
const struct htlc *h;
|
||||
|
||||
h = find_live_htlc(sdata, effect->watch_htlc_spend->id);
|
||||
add_htlc(sdata->htlc_spends_to_us, &sdata->num_htlc_spends_to_us,
|
||||
sdata->htlc_spends_to_them,
|
||||
&sdata->num_htlc_spends_to_them,
|
||||
ARRAY_SIZE(sdata->htlc_spends_to_us),
|
||||
h);
|
||||
|
||||
/* We assume this */
|
||||
if (h->to_them)
|
||||
assert(effect->watch_htlc_spend->done
|
||||
== BITCOIN_HTLC_RETURN_SPEND_DONE);
|
||||
else
|
||||
assert(effect->watch_htlc_spend->done
|
||||
== BITCOIN_HTLC_FULFILL_SPEND_DONE);
|
||||
}
|
||||
if (effect->unwatch_htlc_spend) {
|
||||
const struct htlc *h;
|
||||
|
||||
h = find_htlc_spend(sdata, effect->unwatch_htlc_spend->id);
|
||||
remove_htlc(sdata->htlc_spends_to_us,
|
||||
&sdata->num_htlc_spends_to_us,
|
||||
sdata->htlc_spends_to_them,
|
||||
&sdata->num_htlc_spends_to_them,
|
||||
ARRAY_SIZE(sdata->htlc_spends_to_us),
|
||||
h);
|
||||
if (!outstanding_htlc_watches(sdata)) {
|
||||
assert(effect->unwatch_htlc_spend->done
|
||||
== INPUT_NO_MORE_HTLCS);
|
||||
add_event(&sdata->core.event_notifies,
|
||||
effect->unwatch_htlc_spend->done);
|
||||
}
|
||||
}
|
||||
if (effect->unwatch_htlc) {
|
||||
break;
|
||||
case STATE_EFFECT_unwatch_htlc:
|
||||
/* Unwatch all? */
|
||||
if (effect->unwatch_htlc->id == -1) {
|
||||
if (effect->u.unwatch_htlc->id == -1) {
|
||||
/* This can happen if we get in front of
|
||||
* INPUT_NO_MORE_HTLCS */
|
||||
if (!outstanding_htlc_watches(sdata)
|
||||
@ -1614,7 +1655,7 @@ static const char *apply_effects(struct state_data *sdata,
|
||||
} else {
|
||||
const struct htlc *h;
|
||||
|
||||
h = find_live_htlc(sdata, effect->unwatch_htlc->id);
|
||||
h = find_live_htlc(sdata, effect->u.unwatch_htlc->id);
|
||||
|
||||
/* That can fail, when we see them spend (and
|
||||
* thus stop watching) after we've timed out,
|
||||
@ -1629,17 +1670,65 @@ static const char *apply_effects(struct state_data *sdata,
|
||||
|
||||
/* If that was last, fire INPUT_NO_MORE_HTLCS */
|
||||
if (!outstanding_htlc_watches(sdata)) {
|
||||
assert(effect->unwatch_htlc->all_done
|
||||
assert(effect->u.unwatch_htlc->all_done
|
||||
== INPUT_NO_MORE_HTLCS);
|
||||
add_event(&sdata->core.event_notifies,
|
||||
effect->unwatch_htlc->all_done);
|
||||
effect->u.unwatch_htlc->all_done);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATE_EFFECT_watch_htlc_spend:
|
||||
h = find_live_htlc(sdata, effect->u.watch_htlc_spend->id);
|
||||
add_htlc(sdata->htlc_spends_to_us, &sdata->num_htlc_spends_to_us,
|
||||
sdata->htlc_spends_to_them,
|
||||
&sdata->num_htlc_spends_to_them,
|
||||
ARRAY_SIZE(sdata->htlc_spends_to_us),
|
||||
h);
|
||||
|
||||
/* We assume this */
|
||||
if (h->to_them)
|
||||
assert(effect->u.watch_htlc_spend->done
|
||||
== BITCOIN_HTLC_RETURN_SPEND_DONE);
|
||||
else
|
||||
assert(effect->u.watch_htlc_spend->done
|
||||
== BITCOIN_HTLC_FULFILL_SPEND_DONE);
|
||||
break;
|
||||
case STATE_EFFECT_unwatch_htlc_spend:
|
||||
h = find_htlc_spend(sdata, effect->u.unwatch_htlc_spend->id);
|
||||
remove_htlc(sdata->htlc_spends_to_us,
|
||||
&sdata->num_htlc_spends_to_us,
|
||||
sdata->htlc_spends_to_them,
|
||||
&sdata->num_htlc_spends_to_them,
|
||||
ARRAY_SIZE(sdata->htlc_spends_to_us),
|
||||
h);
|
||||
if (!outstanding_htlc_watches(sdata)) {
|
||||
assert(effect->u.unwatch_htlc_spend->done
|
||||
== INPUT_NO_MORE_HTLCS);
|
||||
add_event(&sdata->core.event_notifies,
|
||||
effect->u.unwatch_htlc_spend->done);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return tal_fmt(NULL, "Unknown effect %u", effect->etype);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *apply_all_effects(struct state_data *sdata,
|
||||
const struct state_effect *effect,
|
||||
Pkt **output)
|
||||
{
|
||||
const char *problem;
|
||||
uint64_t effects = 0;
|
||||
*output = NULL;
|
||||
problem = apply_effects(sdata, effect, &effects, output);
|
||||
if (!problem)
|
||||
problem = check_effects(sdata, effect);
|
||||
return problem;
|
||||
}
|
||||
|
||||
static void eliminate_input(enum state_input **inputs, enum state_input in)
|
||||
{
|
||||
size_t i, n = tal_count(*inputs);
|
||||
@ -1820,6 +1909,34 @@ static bool has_packets(const struct state_data *sdata)
|
||||
|| sdata->core.num_outputs != 0;
|
||||
}
|
||||
|
||||
static struct state_effect *get_effect(const struct state_effect *effect,
|
||||
enum state_effect_type type)
|
||||
{
|
||||
while (effect) {
|
||||
if (effect->etype == type)
|
||||
break;
|
||||
effect = effect->next;
|
||||
}
|
||||
return cast_const(struct state_effect *, effect);
|
||||
}
|
||||
|
||||
static enum state get_state_effect(const struct state_effect *effect,
|
||||
enum state current)
|
||||
{
|
||||
effect = get_effect(effect, STATE_EFFECT_new_state);
|
||||
if (effect)
|
||||
return effect->u.new_state;
|
||||
return current;
|
||||
}
|
||||
|
||||
static Pkt *get_send_pkt(const struct state_effect *effect)
|
||||
{
|
||||
effect = get_effect(effect, STATE_EFFECT_send_pkt);
|
||||
if (effect)
|
||||
return effect->u.send_pkt;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void try_input(const struct state_data *sdata,
|
||||
enum state_input i,
|
||||
const union input *idata,
|
||||
@ -1829,11 +1946,12 @@ static void try_input(const struct state_data *sdata,
|
||||
{
|
||||
struct state_data copy, peer;
|
||||
struct trail t;
|
||||
struct state_effect *effect = tal(NULL, struct state_effect);
|
||||
enum state newstate;
|
||||
struct state_effect *effect;
|
||||
const char *problem;
|
||||
Pkt *output;
|
||||
const tal_t *ctx = tal(NULL, char);
|
||||
|
||||
state_effect_init(effect);
|
||||
copy_peers(©, &peer, sdata);
|
||||
|
||||
copy.current_input = i;
|
||||
@ -1842,7 +1960,9 @@ static void try_input(const struct state_data *sdata,
|
||||
copy.trail = &t;
|
||||
|
||||
eliminate_input(&hist->inputs_per_state[copy.core.state], i);
|
||||
newstate = state(copy.core.state, ©, i, idata, effect);
|
||||
effect = state(ctx, copy.core.state, ©, i, idata);
|
||||
|
||||
newstate = get_state_effect(effect, sdata->core.state);
|
||||
|
||||
normalpath &= normal_path(i, sdata->core.state, newstate);
|
||||
errorpath |= error_path(i, sdata->core.state, newstate);
|
||||
@ -1862,13 +1982,12 @@ static void try_input(const struct state_data *sdata,
|
||||
newstr = state_name(newstate) + 6;
|
||||
}
|
||||
if (newstr != oldstr || include_nops)
|
||||
add_dot(&hist->edges, oldstr, newstr, i, effect->send);
|
||||
add_dot(&hist->edges, oldstr, newstr, i,
|
||||
get_send_pkt(effect));
|
||||
}
|
||||
|
||||
copy.core.state = newstate;
|
||||
|
||||
problem = apply_effects(©, effect);
|
||||
update_trail(&t, ©, effect);
|
||||
problem = apply_all_effects(©, effect, &output);
|
||||
update_trail(&t, ©, output);
|
||||
if (problem)
|
||||
report_trail(&t, problem);
|
||||
|
||||
@ -1879,14 +1998,14 @@ static void try_input(const struct state_data *sdata,
|
||||
|
||||
|
||||
/* Record any output. */
|
||||
if (effect->send) {
|
||||
if (output) {
|
||||
record_output(&hist->outputs,
|
||||
input_by_name((const char *)effect->send));
|
||||
input_by_name((const char *)output));
|
||||
}
|
||||
|
||||
if (hist->state_dump) {
|
||||
record_state(&hist->state_dump[sdata->core.state], i, newstate,
|
||||
(const char *)effect->send);
|
||||
(const char *)output);
|
||||
}
|
||||
|
||||
/* Have we been in this overall situation before? */
|
||||
@ -1899,13 +2018,14 @@ static void try_input(const struct state_data *sdata,
|
||||
*
|
||||
* And if we're being quick, always stop.
|
||||
*/
|
||||
if (effect->defer != INPUT_NONE
|
||||
if (quick
|
||||
|| get_effect(effect, STATE_EFFECT_cmd_defer)
|
||||
|| newstate == STATE_NORMAL_LOWPRIO
|
||||
|| newstate == STATE_NORMAL_HIGHPRIO
|
||||
|| i == BITCOIN_ANCHOR_OTHERSPEND
|
||||
|| i == BITCOIN_ANCHOR_THEIRSPEND
|
||||
|| quick) {
|
||||
tal_free(effect);
|
||||
tal_free(ctx);
|
||||
return;
|
||||
}
|
||||
if (t.depth > STATE_MAX * 10)
|
||||
@ -1914,7 +2034,7 @@ static void try_input(const struct state_data *sdata,
|
||||
|
||||
/* Don't continue if we reached a different error state. */
|
||||
if (state_is_error(newstate)) {
|
||||
tal_free(effect);
|
||||
tal_free(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1942,7 +2062,7 @@ static void try_input(const struct state_data *sdata,
|
||||
|
||||
if (outstanding_htlc_watches(©))
|
||||
report_trail(&t, "CLOSED but watching HTLCs?");
|
||||
tal_free(effect);
|
||||
tal_free(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1952,7 +2072,7 @@ static void try_input(const struct state_data *sdata,
|
||||
/* Don't bother running other peer we can't communicate. */
|
||||
if (copy.core.pkt_inputs || peer.core.pkt_inputs)
|
||||
run_peer(&peer, normalpath, errorpath, &t, hist);
|
||||
tal_free(effect);
|
||||
tal_free(ctx);
|
||||
}
|
||||
|
||||
static void sanity_check(const struct state_data *sdata)
|
||||
@ -2230,22 +2350,21 @@ static enum state_input **map_inputs(void)
|
||||
{
|
||||
enum state_input **inps = tal_arr(NULL, enum state_input *, STATE_MAX);
|
||||
unsigned int i;
|
||||
struct state_effect *effect = tal(inps, struct state_effect);
|
||||
const tal_t *ctx = tal(NULL, char);
|
||||
|
||||
for (i = 0; i < STATE_MAX; i++) {
|
||||
/* This is a global */
|
||||
mapping_inputs = tal_arr(inps, enum state_input, 0);
|
||||
|
||||
state_effect_init(effect);
|
||||
/* This adds to mapping_inputs every input_is() call */
|
||||
if (!state_is_error(i))
|
||||
state(i, NULL, INPUT_NONE, NULL, effect);
|
||||
state(ctx, i, NULL, INPUT_NONE, NULL);
|
||||
inps[i] = mapping_inputs;
|
||||
}
|
||||
|
||||
/* Reset global */
|
||||
mapping_inputs = NULL;
|
||||
tal_free(effect);
|
||||
tal_free(ctx);
|
||||
return inps;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user