From abc002ff1563706124425118ca84bdc394a659ec Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 22 Jan 2016 06:44:13 +1030 Subject: [PATCH] daemon: add state.c. Signed-off-by: Rusty Russell --- daemon/Makefile | 6 +- daemon/packets.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++ daemon/peer.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++- daemon/peer.h | 13 ++- 4 files changed, 561 insertions(+), 3 deletions(-) create mode 100644 daemon/packets.c diff --git a/daemon/Makefile b/daemon/Makefile index 24b432d64..6cd22ed4d 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -21,9 +21,13 @@ DAEMON_SRC := \ daemon/lightningd.c \ daemon/netaddr.c \ daemon/peer.c \ + daemon/packets.c \ daemon/secrets.c \ daemon/timeout.c \ - daemon/watch.c + daemon/watch.c \ + names.c \ + state.c + DAEMON_OBJS := $(DAEMON_SRC:.c=.o) DAEMON_CLI_SRC := daemon/lightning-cli.c diff --git a/daemon/packets.c b/daemon/packets.c new file mode 100644 index 000000000..df1c49d64 --- /dev/null +++ b/daemon/packets.c @@ -0,0 +1,270 @@ +#include "lightningd.h" +#include "log.h" +#include "names.h" +#include "peer.h" +#include "protobuf_convert.h" +#include "secrets.h" +#include "state.h" +#include +#include + +#define FIXME_STUB(peer) do { log_broken((peer)->dstate->base_log, "%s:%u: Implement %s!", __FILE__, __LINE__, __func__); abort(); } while(0) + +/* Wrap (and own!) member inside Pkt */ +static Pkt *make_pkt(const tal_t *ctx, Pkt__PktCase type, const void *msg) +{ + Pkt *pkt = tal(ctx, Pkt); + + pkt__init(pkt); + pkt->pkt_case = type; + /* This is a union, so doesn't matter which we assign. */ + pkt->error = (Error *)tal_steal(ctx, msg); + + /* This makes sure all packets are valid. */ +#ifndef NDEBUG + { + size_t len; + u8 *packed; + Pkt *cpy; + + len = pkt__get_packed_size(pkt); + packed = tal_arr(pkt, u8, len); + pkt__pack(pkt, packed); + cpy = pkt__unpack(NULL, len, memcheck(packed, len)); + assert(cpy); + pkt__free_unpacked(cpy, NULL); + tal_free(packed); + } +#endif + return pkt; +} + +Pkt *pkt_open(const tal_t *ctx, const struct peer *peer, + OpenChannel__AnchorOffer anchor) +{ + struct sha256 revocation_hash; + OpenChannel *o = tal(ctx, OpenChannel); + + open_channel__init(o); + peer_get_revocation_hash(peer, 0, &revocation_hash); + o->revocation_hash = sha256_to_proto(ctx, &revocation_hash); + o->commit_key = pubkey_to_proto(o, &peer->us.commitkey); + o->final_key = pubkey_to_proto(o, &peer->us.finalkey); + o->delay = tal(o, Locktime); + locktime__init(o->delay); + o->delay->locktime_case = LOCKTIME__LOCKTIME_SECONDS; + o->delay->seconds = rel_locktime_to_seconds(&peer->us.locktime); + o->commitment_fee = peer->us.commit_fee; + if (anchor == OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR) + assert(peer->us.offer_anchor == CMD_OPEN_WITH_ANCHOR); + else { + assert(anchor == OPEN_CHANNEL__ANCHOR_OFFER__WONT_CREATE_ANCHOR); + assert(peer->us.offer_anchor == CMD_OPEN_WITHOUT_ANCHOR); + } + + o->anch = anchor; + o->min_depth = peer->us.mindepth; + return make_pkt(ctx, PKT__PKT_OPEN, o); +} + +Pkt *pkt_anchor(const tal_t *ctx, const struct peer *peer) +{ + FIXME_STUB(peer); +} + +Pkt *pkt_open_commit_sig(const tal_t *ctx, const struct peer *peer) +{ + FIXME_STUB(peer); +} + +Pkt *pkt_open_complete(const tal_t *ctx, const struct peer *peer) +{ + FIXME_STUB(peer); +} + +Pkt *pkt_htlc_update(const tal_t *ctx, const struct peer *peer, + const struct htlc_progress *htlc_prog) +{ + FIXME_STUB(peer); +} + +Pkt *pkt_htlc_fulfill(const tal_t *ctx, const struct peer *peer, + const struct htlc_progress *htlc_prog) +{ + FIXME_STUB(peer); +} + +Pkt *pkt_htlc_timedout(const tal_t *ctx, const struct peer *peer, + const struct htlc_progress *htlc_prog) +{ + FIXME_STUB(peer); +} + +Pkt *pkt_htlc_routefail(const tal_t *ctx, const struct peer *peer, + const struct htlc_progress *htlc_prog) +{ + FIXME_STUB(peer); +} + +Pkt *pkt_update_accept(const tal_t *ctx, const struct peer *peer) +{ + FIXME_STUB(peer); +} + +Pkt *pkt_update_signature(const tal_t *ctx, const struct peer *peer) +{ + FIXME_STUB(peer); +} + +Pkt *pkt_update_complete(const tal_t *ctx, const struct peer *peer) +{ + FIXME_STUB(peer); +} + +Pkt *pkt_err(const tal_t *ctx, const char *msg, ...) +{ + abort(); +} + +Pkt *pkt_close(const tal_t *ctx, const struct peer *peer) +{ + FIXME_STUB(peer); +} + +Pkt *pkt_close_complete(const tal_t *ctx, const struct peer *peer) +{ + FIXME_STUB(peer); +} + +Pkt *pkt_close_ack(const tal_t *ctx, const struct peer *peer) +{ + FIXME_STUB(peer); +} + +Pkt *pkt_err_unexpected(const tal_t *ctx, const Pkt *pkt) +{ + return pkt_err(ctx, "Unexpected packet %s", state_name(pkt->pkt_case)); +} + +/* Process various packets: return an error packet on failure. */ +Pkt *accept_pkt_open(const tal_t *ctx, + struct peer *peer, const Pkt *pkt) +{ + struct rel_locktime locktime; + OpenChannel *o = pkt->open; + + if (!proto_to_rel_locktime(o->delay, &locktime)) + return pkt_err(ctx, "Invalid delay"); + /* FIXME: handle blocks in locktime */ + if (o->delay->locktime_case != LOCKTIME__LOCKTIME_SECONDS) + return pkt_err(ctx, "Delay in blocks not accepted"); + if (o->delay->seconds > peer->dstate->config.rel_locktime_max) + return pkt_err(ctx, "Delay too great"); + if (o->min_depth > peer->dstate->config.anchor_confirms_max) + return pkt_err(ctx, "min_depth too great"); + if (o->commitment_fee < peer->dstate->config.commitment_fee_min) + return pkt_err(ctx, "Commitment fee too low"); + if (o->anch == OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR) + peer->them.offer_anchor = CMD_OPEN_WITH_ANCHOR; + else if (o->anch == OPEN_CHANNEL__ANCHOR_OFFER__WONT_CREATE_ANCHOR) + peer->them.offer_anchor = CMD_OPEN_WITHOUT_ANCHOR; + else + return pkt_err(ctx, "Unknown offer anchor value"); + + if (peer->them.offer_anchor == peer->us.offer_anchor) + return pkt_err(ctx, "Only one side can offer anchor"); + + if (!proto_to_rel_locktime(o->delay, &peer->them.locktime)) + return pkt_err(ctx, "Malformed locktime"); + peer->them.mindepth = o->min_depth; + peer->them.commit_fee = o->commitment_fee; + if (!proto_to_pubkey(peer->dstate->secpctx, + o->commit_key, &peer->them.commitkey)) + return pkt_err(ctx, "Bad commitkey"); + if (!proto_to_pubkey(peer->dstate->secpctx, + o->final_key, &peer->them.finalkey)) + return pkt_err(ctx, "Bad finalkey"); + proto_to_sha256(o->revocation_hash, &peer->their_rhash); + + return NULL; +} + +Pkt *accept_pkt_anchor(const tal_t *ctx, + struct peer *peer, + const Pkt *pkt) +{ + FIXME_STUB(peer); +} + +Pkt *accept_pkt_open_commit_sig(const tal_t *ctx, + struct peer *peer, const Pkt *pkt) +{ + FIXME_STUB(peer); +} + +Pkt *accept_pkt_htlc_update(const tal_t *ctx, + struct peer *peer, const Pkt *pkt, + Pkt **decline) +{ + FIXME_STUB(peer); +} + +Pkt *accept_pkt_htlc_routefail(const tal_t *ctx, + struct peer *peer, const Pkt *pkt) +{ + FIXME_STUB(peer); +} + +Pkt *accept_pkt_htlc_timedout(const tal_t *ctx, + struct peer *peer, const Pkt *pkt) +{ + FIXME_STUB(peer); +} + +Pkt *accept_pkt_htlc_fulfill(const tal_t *ctx, + struct peer *peer, const Pkt *pkt) +{ + FIXME_STUB(peer); +} + +Pkt *accept_pkt_update_accept(const tal_t *ctx, + struct peer *peer, const Pkt *pkt) +{ + FIXME_STUB(peer); +} + +Pkt *accept_pkt_update_complete(const tal_t *ctx, + struct peer *peer, const Pkt *pkt) +{ + FIXME_STUB(peer); +} + +Pkt *accept_pkt_update_signature(const tal_t *ctx, + struct peer *peer, + const Pkt *pkt) +{ + FIXME_STUB(peer); +} + +Pkt *accept_pkt_close(const tal_t *ctx, struct peer *peer, const Pkt *pkt) +{ + FIXME_STUB(peer); +} + +Pkt *accept_pkt_close_complete(const tal_t *ctx, + struct peer *peer, const Pkt *pkt) +{ + FIXME_STUB(peer); +} + +Pkt *accept_pkt_simultaneous_close(const tal_t *ctx, + struct peer *peer, + const Pkt *pkt) +{ + FIXME_STUB(peer); +} + +Pkt *accept_pkt_close_ack(const tal_t *ctx, struct peer *peer, const Pkt *pkt) +{ + FIXME_STUB(peer); +} diff --git a/daemon/peer.c b/daemon/peer.c index a18585de6..a643d3326 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -4,6 +4,7 @@ #include "lightningd.h" #include "log.h" #include "peer.h" +#include "state.h" #include #include #include @@ -15,6 +16,8 @@ #include #include +#define FIXME_STUB(peer) do { log_broken((peer)->dstate->base_log, "%s:%u: Implement %s!", __FILE__, __LINE__, __func__); abort(); } while(0) + struct json_connecting { /* This owns us, so we're freed after command_fail or command_success */ struct command *cmd; @@ -69,6 +72,8 @@ static struct peer *new_peer(struct lightningd_state *dstate, /* FIXME: Stop listening if too many peers? */ list_add(&dstate->peers, &peer->list); + peer->state = STATE_INIT; + peer->cond = PEER_CMD_OK; peer->dstate = dstate; peer->addr.type = addr_type; peer->addr.protocol = addr_protocol; @@ -77,7 +82,10 @@ static struct peer *new_peer(struct lightningd_state *dstate, list_head_init(&peer->watches); peer->us.offer_anchor = offer_anchor; - peer->us.locktime = dstate->config.rel_locktime; + if (!seconds_to_rel_locktime(dstate->config.rel_locktime, + &peer->us.locktime)) + fatal("Invalid locktime configuration %u", + dstate->config.rel_locktime); peer->us.mindepth = dstate->config.anchor_confirms; /* FIXME: Make this dynamic. */ peer->us.commit_fee = dstate->config.commitment_fee; @@ -261,6 +269,271 @@ const struct json_command connect_command = { "Returns an empty result on success" }; +struct anchor_watch { + struct peer *peer; + enum state_input depthok; + enum state_input timeout; + enum state_input unspent; + enum state_input theyspent; + enum state_input otherspent; +}; + +void peer_watch_anchor(struct peer *peer, + enum state_input depthok, + enum state_input timeout, + enum state_input unspent, + enum state_input theyspent, + enum state_input otherspent) +{ + FIXME_STUB(peer); +} + +void peer_unwatch_anchor_depth(struct peer *peer, + enum state_input depthok, + enum state_input timeout) +{ + FIXME_STUB(peer); +} + +void peer_watch_delayed(struct peer *peer, + const struct bitcoin_tx *tx, + enum state_input canspend) +{ + FIXME_STUB(peer); +} +void peer_watch_tx(struct peer *peer, + const struct bitcoin_tx *tx, + enum state_input done) +{ + FIXME_STUB(peer); +} +void peer_watch_close(struct peer *peer, + enum state_input done, enum state_input timedout) +{ + FIXME_STUB(peer); +} +void peer_unwatch_close_timeout(struct peer *peer, enum state_input timedout) +{ + FIXME_STUB(peer); +} +bool peer_watch_our_htlc_outputs(struct peer *peer, + const struct bitcoin_tx *tx, + enum state_input tous_timeout, + enum state_input tothem_spent, + enum state_input tothem_timeout) +{ + FIXME_STUB(peer); +} +bool peer_watch_their_htlc_outputs(struct peer *peer, + const struct bitcoin_event *tx, + enum state_input tous_timeout, + enum state_input tothem_spent, + enum state_input tothem_timeout) +{ + FIXME_STUB(peer); +} +void peer_unwatch_htlc_output(struct peer *peer, + const struct htlc *htlc, + enum state_input all_done) +{ + FIXME_STUB(peer); +} +void peer_unwatch_all_htlc_outputs(struct peer *peer) +{ + FIXME_STUB(peer); +} +void peer_watch_htlc_spend(struct peer *peer, + const struct bitcoin_tx *tx, + const struct htlc *htlc, + enum state_input done) +{ + FIXME_STUB(peer); +} +void peer_unwatch_htlc_spend(struct peer *peer, + const struct htlc *htlc, + enum state_input all_done) +{ + FIXME_STUB(peer); +} +void peer_unexpected_pkt(struct peer *peer, const Pkt *pkt) +{ + FIXME_STUB(peer); +} + +/* Someone declined our HTLC: details in pkt (we will also get CMD_FAIL) */ +void peer_htlc_declined(struct peer *peer, const Pkt *pkt) +{ + FIXME_STUB(peer); +} + +/* Called when their update overrides our update cmd. */ +void peer_htlc_ours_deferred(struct peer *peer) +{ + FIXME_STUB(peer); +} + +/* Successfully added/fulfilled/timedout/routefail an HTLC. */ +void peer_htlc_done(struct peer *peer) +{ + FIXME_STUB(peer); +} + +/* Someone aborted an existing HTLC. */ +void peer_htlc_aborted(struct peer *peer) +{ + FIXME_STUB(peer); +} + +/* An on-chain transaction revealed an R value. */ +const struct htlc *peer_tx_revealed_r_value(struct peer *peer, + const struct bitcoin_event *btc) +{ + FIXME_STUB(peer); +} + +bool committed_to_htlcs(const struct peer *peer) +{ + FIXME_STUB(peer); +} + +/* Create a bitcoin close tx. */ +const struct bitcoin_tx *bitcoin_close(const tal_t *ctx, + const struct peer *peer) +{ +#if 0 + struct bitcoin_tx *close_tx; + u8 *redeemscript; + + close_tx = create_close_tx(ctx, peer->us.openpkt, peer->them.openpkt, + peer->anchorpkt, + peer->cstate.a.pay_msat / 1000, + peer->cstate.b.pay_msat / 1000); + + /* This is what the anchor pays to. */ + redeemscript = bitcoin_redeem_2of2(close_tx, &peer->us.commitkey, + &peer->them.commitkey); + + /* Combined signatures must validate correctly. */ + if (!check_2of2_sig(close_tx, 0, redeemscript, tal_count(redeemscript), + &peer->us.finalkey, &peer->them.finalkey, + &peer->us.closesig, &peer->them.closesig)) + fatal("bitcoin_close signature failed"); + + /* Create p2sh input for close_tx */ + close_tx->input[0].script = scriptsig_p2sh_2of2(close_tx, + &peer->us.closesig, + &peer->them.closesig, + &peer->us.finalkey, + &peer->them.finalkey); + close_tx->input[0].script_length = tal_count(close_tx->input[0].script); + + return close_tx; +#endif + FIXME_STUB(peer); +} + +/* Create a bitcoin spend tx (to spend our commit's outputs) */ +const struct bitcoin_tx *bitcoin_spend_ours(const tal_t *ctx, + const struct peer *peer) +{ +#if 0 + u8 *redeemscript; + + redeemscript = bitcoin_redeem_secret_or_delay(ctx, + &peer->us.commitkey, + &peer->them.locktime, + &peer->them.commitkey, + &peer->revocation_hash); + + /* Now, create transaction to spend it. */ + tx = bitcoin_tx(ctx, 1, 1); + bitcoin_txid(commit, &tx->input[0].txid); + p2sh_out = find_p2sh_out(commit, redeemscript); + tx->input[0].index = p2sh_out; + tx->input[0].input_amount = commit->output[p2sh_out].amount; + tx->fee = fee; + + tx->input[0].sequence_number = bitcoin_nsequence(locktime); + + if (commit->output[p2sh_out].amount <= fee) + errx(1, "Amount of %llu won't exceed fee", + (unsigned long long)commit->output[p2sh_out].amount); + + tx->output[0].amount = commit->output[p2sh_out].amount - fee; + tx->output[0].script = scriptpubkey_p2sh(tx, + bitcoin_redeem_single(tx, &outpubkey)); + tx->output[0].script_length = tal_count(tx->output[0].script); + + /* Now get signature, to set up input script. */ + if (!sign_tx_input(tx, 0, redeemscript, tal_count(redeemscript), + &privkey, &pubkey1, &sig.sig)) + errx(1, "Could not sign tx"); + sig.stype = SIGHASH_ALL; + tx->input[0].script = scriptsig_p2sh_secret(tx, NULL, 0, &sig, + redeemscript, + tal_count(redeemscript)); + tx->input[0].script_length = tal_count(tx->input[0].script); +#endif + FIXME_STUB(peer); +} + +/* Create a bitcoin spend tx (to spend their commit's outputs) */ +const struct bitcoin_tx *bitcoin_spend_theirs(const tal_t *ctx, + const struct peer *peer, + const struct bitcoin_event *btc) +{ + FIXME_STUB(peer); +} + +/* Create a bitcoin steal tx (to steal all their commit's outputs) */ +const struct bitcoin_tx *bitcoin_steal(const tal_t *ctx, + const struct peer *peer, + struct bitcoin_event *btc) +{ + FIXME_STUB(peer); +} + +/* Create our commit tx */ +const struct bitcoin_tx *bitcoin_commit(const tal_t *ctx, struct peer *peer) +{ + FIXME_STUB(peer); +} + +/* Create a HTLC refund collection */ +const struct bitcoin_tx *bitcoin_htlc_timeout(const tal_t *ctx, + const struct peer *peer, + const struct htlc *htlc) +{ + FIXME_STUB(peer); +} + +/* Create a HTLC collection */ +const struct bitcoin_tx *bitcoin_htlc_spend(const tal_t *ctx, + const struct peer *peer, + const struct htlc *htlc) +{ + FIXME_STUB(peer); +} + +/* Start creation of the bitcoin anchor tx. */ +void bitcoin_create_anchor(struct peer *peer, enum state_input done) +{ + FIXME_STUB(peer); +} + +/* We didn't end up broadcasting the anchor: release the utxos. + * If done != INPUT_NONE, remove existing create_anchor too. */ +void bitcoin_release_anchor(struct peer *peer, enum state_input done) +{ + FIXME_STUB(peer); +} + +/* Get the bitcoin anchor tx. */ +const struct bitcoin_tx *bitcoin_anchor(const tal_t *ctx, struct peer *peer) +{ + FIXME_STUB(peer); +} + /* FIXME: Somehow we should show running DNS lookups! */ /* FIXME: Show status of peers! */ static void json_getpeers(struct command *cmd, diff --git a/daemon/peer.h b/daemon/peer.h index 8a419900e..aa7591052 100644 --- a/daemon/peer.h +++ b/daemon/peer.h @@ -1,10 +1,12 @@ #ifndef LIGHTNING_DAEMON_PEER_H #define LIGHTNING_DAEMON_PEER_H #include "config.h" +#include "bitcoin/locktime.h" #include "bitcoin/pubkey.h" #include "lightning.pb-c.h" #include "netaddr.h" #include "state_types.h" +#include #include struct peer_visible_state { @@ -13,7 +15,7 @@ struct peer_visible_state { /* Key for commitment tx inputs, then key for commitment tx outputs */ struct pubkey commitkey, finalkey; /* How long to they want the other's outputs locked (seconds) */ - unsigned int locktime; + struct rel_locktime locktime; /* Minimum depth of anchor before channel usable. */ unsigned int mindepth; /* Commitment fee they're offering (satoshi). */ @@ -24,6 +26,12 @@ struct peer { /* dstate->peers list */ struct list_node list; + /* State in state machine. */ + enum state state; + + /* Condition of communications */ + enum state_peercond cond; + /* Global state. */ struct lightningd_state *dstate; @@ -50,6 +58,9 @@ struct peer { /* Stuff we have in common. */ struct peer_visible_state us, them; + + /* Their last revocation hash. */ + struct sha256 their_rhash; }; void setup_listeners(struct lightningd_state *dstate, unsigned int portnum);