diff --git a/daemon/bitcoind.c b/daemon/bitcoind.c index ba75d7743..5cd7e6798 100644 --- a/daemon/bitcoind.c +++ b/daemon/bitcoind.c @@ -220,34 +220,6 @@ void bitcoind_estimate_fee_(struct lightningd_state *dstate, "estimatefee", "2", NULL); } -static void process_sendtx(struct bitcoin_cli *bcli) -{ - struct sha256_double txid; - const char *out = (char *)bcli->output; - - /* We expect a txid, plus \n */ - if (bcli->output_bytes == 0 - || !bitcoin_txid_from_hex(out, bcli->output_bytes-1, &txid)) - fatal("sendrawtransaction bad hex: %.*s", - (int)bcli->output_bytes, out); - - log_debug(bcli->dstate->base_log, "sendrawtx gave %.*s", - (int)bcli->output_bytes, out); - - /* FIXME: Compare against expected txid? */ -} - -void bitcoind_send_tx(struct lightningd_state *dstate, - const struct bitcoin_tx *tx) -{ - u8 *raw = linearize_tx(dstate, tx); - char *hex = tal_hexstr(raw, raw, tal_count(raw)); - - start_bitcoin_cli(dstate, process_sendtx, false, NULL, NULL, - "sendrawtransaction", hex, NULL); - tal_free(raw); -} - static void process_sendrawtx(struct bitcoin_cli *bcli) { void (*cb)(struct lightningd_state *dstate, diff --git a/daemon/bitcoind.h b/daemon/bitcoind.h index d28933bdf..c192b1b0c 100644 --- a/daemon/bitcoind.h +++ b/daemon/bitcoind.h @@ -27,9 +27,6 @@ void bitcoind_estimate_fee_(struct lightningd_state *dstate, u64), \ (arg)) -void bitcoind_send_tx(struct lightningd_state *dstate, - const struct bitcoin_tx *tx); - void bitcoind_sendrawtx_(struct lightningd_state *dstate, const char *hextx, void (*cb)(struct lightningd_state *dstate, diff --git a/daemon/chaintopology.c b/daemon/chaintopology.c index b3529ae77..558efaa04 100644 --- a/daemon/chaintopology.c +++ b/daemon/chaintopology.c @@ -4,7 +4,9 @@ #include "chaintopology.h" #include "lightningd.h" #include "log.h" +#include "peer.h" #include "timeout.h" +#include "utils.h" #include "watch.h" #include #include @@ -308,6 +310,107 @@ static struct block *find_common(struct topology *topo, } #endif +static void try_broadcast(struct lightningd_state *dstate, + const char *msg, char **txs) +{ + size_t num_txs = tal_count(txs); + const char *this_tx; + + /* These are expected. */ + if (strstr(msg, "txn-mempool-conflict") + || strstr(msg, "transaction already in block chain")) + log_debug(dstate->base_log, + "Expected error broadcasting tx %s: %s", + txs[num_txs-1], msg); + else + log_unusual(dstate->base_log, "Broadcasting tx %s: %s", + txs[num_txs-1], msg); + + if (num_txs == 1) { + tal_free(txs); + return; + } + + /* Strip off last one. */ + this_tx = txs[num_txs-1]; + tal_resize(&txs, num_txs-1); + + bitcoind_sendrawtx(dstate, this_tx, try_broadcast, txs); +} + +static bool found_in_main(const struct block *b, + const struct sha256_double *txid) +{ + struct tx_in_block *tx; + + do { + list_for_each(&b->txs, tx, list) { + if (structeq(&tx->w->txid, txid)) + return true; + } + b = b->prev; + } while (b); + + return false; +} + +/* FIXME: This is dumb. We can group txs and avoid bothering bitcoind + * if any one tx is in the main chain. */ +static void rebroadcast_txs(struct lightningd_state *dstate) +{ + /* Copy txs now (peers may go away, and they own txs). */ + size_t num_txs = 0; + char **txs = tal_arr(dstate, char *, 0); + struct peer *peer; + + list_for_each(&dstate->peers, peer, list) { + struct outgoing_tx *otx; + + list_for_each(&peer->outgoing_txs, otx, list) { + u8 *rawtx; + + if (found_in_main(dstate->topology->tips[0], &otx->txid)) + continue; + + tal_resize(&txs, num_txs+1); + rawtx = linearize_tx(txs, otx->tx); + txs[num_txs] = tal_hexstr(txs, rawtx, tal_count(rawtx)); + num_txs++; + } + } + + if (num_txs) + bitcoind_sendrawtx(dstate, txs[num_txs-1], try_broadcast, txs); + else + tal_free(txs); +} + +static void destroy_outgoing_tx(struct outgoing_tx *otx) +{ + list_del(&otx->list); +} + +void broadcast_tx(struct peer *peer, const struct bitcoin_tx *tx) +{ + struct outgoing_tx *otx = tal(peer, struct outgoing_tx); + char **txs = tal_arr(peer->dstate, char *, 1); + u8 *rawtx; + + otx->tx = tal_steal(otx, tx); + bitcoin_txid(otx->tx, &otx->txid); + list_add_tail(&peer->outgoing_txs, &otx->list); + tal_add_destructor(otx, destroy_outgoing_tx); + + /* FIXME: log_struct */ + log_add(peer->log, " (tx %02x%02x%02x%02x...)", + otx->txid.sha.u.u8[0], otx->txid.sha.u.u8[1], + otx->txid.sha.u.u8[2], otx->txid.sha.u.u8[3]); + + rawtx = linearize_tx(txs, otx->tx); + txs[0] = tal_hexstr(txs, rawtx, tal_count(rawtx)); + bitcoind_sendrawtx(peer->dstate, txs[0], try_broadcast, txs); +} + static void topology_changed(struct lightningd_state *dstate) { struct topology *topo = dstate->topology; @@ -333,6 +436,9 @@ static void topology_changed(struct lightningd_state *dstate) /* Tell watch code to re-evaluate all txs. */ watch_topology_changed(dstate); + + /* Maybe need to rebroadcast. */ + rebroadcast_txs(dstate); } static struct block *add_block(struct lightningd_state *dstate, diff --git a/daemon/chaintopology.h b/daemon/chaintopology.h index 16432ecc7..e24786d53 100644 --- a/daemon/chaintopology.h +++ b/daemon/chaintopology.h @@ -18,6 +18,9 @@ u32 get_last_mediantime(struct lightningd_state *dstate, /* Get mediantime of the tip; if more than one, pick greatest time. */ u32 get_tip_mediantime(struct lightningd_state *dstate); +/* Broadcast a single tx, and rebroadcast as reqd (takes ownership of tx) */ +void broadcast_tx(struct peer *peer, const struct bitcoin_tx *tx); + void setup_topology(struct lightningd_state *dstate); #endif /* LIGHTNING_DAEMON_CRYPTOPKT_H */ diff --git a/daemon/peer.c b/daemon/peer.c index ad4ccfc10..6ea69d35a 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -148,16 +148,8 @@ static void state_single(struct peer *peer, Pkt *outpkt = peer->outpkt[old_outpkts].pkt; log_add(peer->log, " (out %s)", input_name(outpkt->pkt_case)); } - if (broadcast) { - struct sha256_double txid; - - bitcoin_txid(broadcast, &txid); - /* FIXME: log_struct */ - log_add(peer->log, " (tx %02x%02x%02x%02x...)", - txid.sha.u.u8[0], txid.sha.u.u8[1], - txid.sha.u.u8[2], txid.sha.u.u8[3]); - bitcoind_send_tx(peer->dstate, broadcast); - } + if (broadcast) + broadcast_tx(peer, broadcast); /* Start output if not running already; it will close conn. */ if (peer->cond == PEER_CLOSED) @@ -414,6 +406,7 @@ static struct peer *new_peer(struct lightningd_state *dstate, peer->curr_cmd.cmd = INPUT_NONE; list_head_init(&peer->pending_cmd); list_head_init(&peer->pending_input); + list_head_init(&peer->outgoing_txs); peer->commit_tx_counter = 0; peer->close_watch_timeout = NULL; peer->anchor.watches = NULL; diff --git a/daemon/peer.h b/daemon/peer.h index 23e818faa..0f3f2f2d1 100644 --- a/daemon/peer.h +++ b/daemon/peer.h @@ -99,6 +99,13 @@ struct out_pkt { void *ack_arg; }; +/* Off peer->outgoing_txs */ +struct outgoing_tx { + struct list_node list; + const struct bitcoin_tx *tx; + struct sha256_double txid; +}; + struct peer { /* dstate->peers list */ struct list_node list; @@ -191,6 +198,9 @@ struct peer { /* Things we're watching for (see watches.c) */ struct list_head watches; + /* Bitcoin transctions we're broadcasting (see chaintopology.c) */ + struct list_head outgoing_txs; + /* Timeout for close_watch. */ struct oneshot *close_watch_timeout; @@ -219,4 +229,5 @@ struct bitcoin_tx *peer_create_close_tx(struct peer *peer, u64 fee); uint64_t commit_tx_fee(const struct bitcoin_tx *commit, uint64_t anchor_satoshis); + #endif /* LIGHTNING_DAEMON_PEER_H */