Browse Source

daemon: handle bitcoin transaction re-broadcasting.

It's primitive, but we re-broadcast any txs not included in the main
chain every time the tip moves.  We only track transactions we are
watching, but that turns out to cover every transaction we generate
anyway.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 9 years ago
parent
commit
17167704a6
  1. 28
      daemon/bitcoind.c
  2. 3
      daemon/bitcoind.h
  3. 106
      daemon/chaintopology.c
  4. 3
      daemon/chaintopology.h
  5. 13
      daemon/peer.c
  6. 11
      daemon/peer.h

28
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,

3
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,

106
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 <ccan/array_size/array_size.h>
#include <ccan/asort/asort.h>
@ -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,

3
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 */

13
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;

11
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 */

Loading…
Cancel
Save