|
|
|
#include "bitcoin/block.h"
|
|
|
|
#include "bitcoin/feerate.h"
|
|
|
|
#include "bitcoin/script.h"
|
|
|
|
#include "bitcoin/tx.h"
|
|
|
|
#include "bitcoind.h"
|
|
|
|
#include "chaintopology.h"
|
|
|
|
#include "channel.h"
|
|
|
|
#include "jsonrpc.h"
|
|
|
|
#include "lightningd.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "watch.h"
|
|
|
|
#include <ccan/array_size/array_size.h>
|
|
|
|
#include <ccan/asort/asort.h>
|
|
|
|
#include <ccan/build_assert/build_assert.h>
|
|
|
|
#include <ccan/io/io.h>
|
|
|
|
#include <ccan/tal/str/str.h>
|
|
|
|
#include <common/json_command.h>
|
|
|
|
#include <common/jsonrpc_errors.h>
|
|
|
|
#include <common/memleak.h>
|
|
|
|
#include <common/param.h>
|
|
|
|
#include <common/timeout.h>
|
|
|
|
#include <common/utils.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <lightningd/channel_control.h>
|
|
|
|
#include <lightningd/gossip_control.h>
|
|
|
|
#include <lightningd/io_loop_with_timers.h>
|
|
|
|
|
|
|
|
/* Mutual recursion via timer. */
|
|
|
|
static void try_extend_tip(struct chain_topology *topo);
|
|
|
|
|
|
|
|
/* get_init_blockhash sets topo->root, start_fee_estimate clears
|
|
|
|
* feerate_uninitialized (even if unsuccessful) */
|
|
|
|
static void maybe_completed_init(struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
if (topo->feerate_uninitialized)
|
|
|
|
return;
|
|
|
|
if (!topo->root)
|
|
|
|
return;
|
|
|
|
io_break(topo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void next_topology_timer(struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
/* This takes care of its own lifetime. */
|
|
|
|
notleak(new_reltimer(topo->timers, topo,
|
|
|
|
time_from_sec(topo->poll_seconds),
|
|
|
|
try_extend_tip, topo));
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool we_broadcast(const struct chain_topology *topo,
|
|
|
|
const struct bitcoin_txid *txid)
|
|
|
|
{
|
|
|
|
const struct outgoing_tx *otx;
|
|
|
|
|
|
|
|
list_for_each(&topo->outgoing_txs, otx, list) {
|
|
|
|
if (bitcoin_txid_eq(&otx->txid, txid))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void filter_block_txs(struct chain_topology *topo, struct block *b)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
struct amount_sat owned;
|
|
|
|
|
|
|
|
/* Now we see if any of those txs are interesting. */
|
|
|
|
for (i = 0; i < tal_count(b->full_txs); i++) {
|
|
|
|
const struct bitcoin_tx *tx = b->full_txs[i];
|
|
|
|
struct bitcoin_txid txid;
|
|
|
|
size_t j;
|
|
|
|
|
|
|
|
/* Tell them if it spends a txo we care about. */
|
|
|
|
for (j = 0; j < tx->wtx->num_inputs; j++) {
|
|
|
|
struct txwatch_output out;
|
|
|
|
struct txowatch *txo;
|
|
|
|
bitcoin_tx_input_get_txid(tx, j, &out.txid);
|
|
|
|
out.index = tx->wtx->inputs[j].index;
|
|
|
|
|
|
|
|
txo = txowatch_hash_get(&topo->txowatches, &out);
|
|
|
|
if (txo) {
|
|
|
|
wallet_transaction_add(topo->ld->wallet,
|
|
|
|
tx, b->height, i);
|
|
|
|
txowatch_fire(txo, tx, j, b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
owned = AMOUNT_SAT(0);
|
|
|
|
bitcoin_txid(tx, &txid);
|
|
|
|
if (txfilter_match(topo->bitcoind->ld->owned_txfilter, tx)) {
|
|
|
|
wallet_extract_owned_outputs(topo->bitcoind->ld->wallet,
|
|
|
|
tx, &b->height, &owned);
|
|
|
|
wallet_transaction_add(topo->ld->wallet, tx, b->height,
|
|
|
|
i);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We did spends first, in case that tells us to watch tx. */
|
|
|
|
if (watching_txid(topo, &txid) || we_broadcast(topo, &txid)) {
|
|
|
|
wallet_transaction_add(topo->ld->wallet,
|
|
|
|
tx, b->height, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
txwatch_inform(topo, &txid, tx);
|
|
|
|
}
|
|
|
|
b->full_txs = tal_free(b->full_txs);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t get_tx_depth(const struct chain_topology *topo,
|
|
|
|
const struct bitcoin_txid *txid)
|
|
|
|
{
|
|
|
|
u32 blockheight = wallet_transaction_height(topo->ld->wallet, txid);
|
|
|
|
|
|
|
|
if (blockheight == 0)
|
|
|
|
return 0;
|
|
|
|
return topo->tip->height - blockheight + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct txs_to_broadcast {
|
|
|
|
/* We just sent txs[cursor] */
|
|
|
|
size_t cursor;
|
|
|
|
/* These are hex encoded already, for bitcoind_sendrawtx */
|
|
|
|
const char **txs;
|
|
|
|
|
|
|
|
/* Command to complete when we're done, if and only if dev-broadcast triggered */
|
|
|
|
struct command *cmd;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* We just sent the last entry in txs[]. Shrink and send the next last. */
|
|
|
|
static void broadcast_remainder(struct bitcoind *bitcoind,
|
|
|
|
int exitstatus, const char *msg,
|
|
|
|
struct txs_to_broadcast *txs)
|
|
|
|
{
|
|
|
|
/* These are expected. */
|
|
|
|
if (strstr(msg, "txn-mempool-conflict")
|
|
|
|
|| strstr(msg, "transaction already in block chain")
|
|
|
|
|| exitstatus)
|
|
|
|
log_debug(bitcoind->log,
|
|
|
|
"Expected error broadcasting tx %s: %s",
|
|
|
|
txs->txs[txs->cursor], msg);
|
|
|
|
|
|
|
|
txs->cursor++;
|
|
|
|
if (txs->cursor == tal_count(txs->txs)) {
|
|
|
|
if (txs->cmd)
|
|
|
|
was_pending(command_success(txs->cmd,
|
|
|
|
json_stream_success(txs->cmd)));
|
|
|
|
tal_free(txs);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Broadcast next one. */
|
|
|
|
bitcoind_sendrawtx(bitcoind, txs->txs[txs->cursor],
|
|
|
|
broadcast_remainder, txs);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 chain_topology *topo, struct command *cmd)
|
|
|
|
{
|
|
|
|
/* Copy txs now (peers may go away, and they own txs). */
|
|
|
|
struct txs_to_broadcast *txs;
|
|
|
|
struct outgoing_tx *otx;
|
|
|
|
|
|
|
|
txs = tal(topo, struct txs_to_broadcast);
|
|
|
|
txs->cmd = cmd;
|
|
|
|
|
|
|
|
/* Put any txs we want to broadcast in ->txs. */
|
|
|
|
txs->txs = tal_arr(txs, const char *, 0);
|
|
|
|
list_for_each(&topo->outgoing_txs, otx, list) {
|
|
|
|
if (wallet_transaction_height(topo->ld->wallet, &otx->txid))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
tal_arr_expand(&txs->txs, tal_strdup(txs, otx->hextx));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Let this do the dirty work. */
|
|
|
|
txs->cursor = (size_t)-1;
|
|
|
|
broadcast_remainder(topo->bitcoind, 0, "", txs);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void destroy_outgoing_tx(struct outgoing_tx *otx)
|
|
|
|
{
|
|
|
|
list_del(&otx->list);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void clear_otx_channel(struct channel *channel, struct outgoing_tx *otx)
|
|
|
|
{
|
|
|
|
if (otx->channel != channel)
|
|
|
|
fatal("channel %p, otx %p has channel %p", channel, otx, otx->channel);
|
|
|
|
otx->channel = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void broadcast_done(struct bitcoind *bitcoind,
|
|
|
|
int exitstatus, const char *msg,
|
|
|
|
struct outgoing_tx *otx)
|
|
|
|
{
|
|
|
|
/* Channel gone? Stop. */
|
|
|
|
if (!otx->channel) {
|
|
|
|
tal_free(otx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No longer needs to be disconnected if channel dies. */
|
|
|
|
tal_del_destructor2(otx->channel, clear_otx_channel, otx);
|
|
|
|
|
|
|
|
if (otx->failed_or_success) {
|
|
|
|
otx->failed_or_success(otx->channel, exitstatus, msg);
|
|
|
|
tal_free(otx);
|
|
|
|
} else {
|
|
|
|
/* For continual rebroadcasting, until channel freed. */
|
|
|
|
tal_steal(otx->channel, otx);
|
|
|
|
list_add_tail(&bitcoind->ld->topology->outgoing_txs, &otx->list);
|
|
|
|
tal_add_destructor(otx, destroy_outgoing_tx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void broadcast_tx(struct chain_topology *topo,
|
|
|
|
struct channel *channel, const struct bitcoin_tx *tx,
|
|
|
|
void (*failed_or_success)(struct channel *channel,
|
|
|
|
int exitstatus, const char *err))
|
|
|
|
{
|
|
|
|
/* Channel might vanish: topo owns it to start with. */
|
|
|
|
struct outgoing_tx *otx = tal(topo, struct outgoing_tx);
|
|
|
|
const u8 *rawtx = linearize_tx(otx, tx);
|
|
|
|
|
|
|
|
otx->channel = channel;
|
|
|
|
bitcoin_txid(tx, &otx->txid);
|
|
|
|
otx->hextx = tal_hex(otx, rawtx);
|
|
|
|
otx->failed_or_success = failed_or_success;
|
|
|
|
tal_free(rawtx);
|
|
|
|
tal_add_destructor2(channel, clear_otx_channel, otx);
|
|
|
|
|
|
|
|
log_debug(topo->log, "Broadcasting txid %s",
|
|
|
|
type_to_string(tmpctx, struct bitcoin_txid, &otx->txid));
|
|
|
|
|
|
|
|
wallet_transaction_add(topo->ld->wallet, tx, 0, 0);
|
|
|
|
bitcoind_sendrawtx(topo->bitcoind, otx->hextx, broadcast_done, otx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum watch_result closeinfo_txid_confirmed(struct lightningd *ld,
|
|
|
|
struct channel *channel,
|
|
|
|
const struct bitcoin_txid *txid,
|
|
|
|
const struct bitcoin_tx *tx,
|
|
|
|
unsigned int depth)
|
|
|
|
{
|
|
|
|
/* Sanity check. */
|
|
|
|
if (tx != NULL) {
|
|
|
|
struct bitcoin_txid txid2;
|
|
|
|
|
|
|
|
bitcoin_txid(tx, &txid2);
|
|
|
|
if (!bitcoin_txid_eq(txid, &txid2)) {
|
|
|
|
channel_internal_error(channel, "Txid for %s is not %s",
|
|
|
|
type_to_string(tmpctx,
|
|
|
|
struct bitcoin_tx,
|
|
|
|
tx),
|
|
|
|
type_to_string(tmpctx,
|
|
|
|
struct bitcoin_txid,
|
|
|
|
txid));
|
|
|
|
return DELETE_WATCH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We delete ourselves first time, so should not be reorged out!! */
|
|
|
|
assert(depth > 0);
|
|
|
|
/* Subtle: depth 1 == current block. */
|
|
|
|
wallet_confirm_tx(ld->wallet, txid,
|
|
|
|
get_block_height(ld->topology) + 1 - depth);
|
|
|
|
return DELETE_WATCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We need to know if close_info UTXOs (which the wallet doesn't natively know
|
|
|
|
* how to spend, so is not in the normal path) get reconfirmed.
|
|
|
|
*
|
|
|
|
* This can happen on startup (where we manually unwind 100 blocks) or on a
|
|
|
|
* reorg. The db NULLs out the confirmation_height, so we can't easily figure
|
|
|
|
* out just the new ones (and removing the ON DELETE SET NULL clause is
|
|
|
|
* non-trivial).
|
|
|
|
*
|
|
|
|
* So every time, we just set a notification for every tx in this class we're
|
|
|
|
* not already watching: there are not usually many, nor many reorgs, so the
|
|
|
|
* redundancy is OK.
|
|
|
|
*/
|
|
|
|
static void watch_for_utxo_reconfirmation(struct chain_topology *topo,
|
|
|
|
struct wallet *wallet)
|
|
|
|
{
|
|
|
|
struct utxo **unconfirmed;
|
|
|
|
|
|
|
|
unconfirmed = wallet_get_unconfirmed_closeinfo_utxos(tmpctx, wallet);
|
|
|
|
for (size_t i = 0; i < tal_count(unconfirmed); i++) {
|
|
|
|
assert(unconfirmed[i]->close_info != NULL);
|
|
|
|
assert(unconfirmed[i]->blockheight == NULL);
|
|
|
|
|
|
|
|
if (find_txwatch(topo, &unconfirmed[i]->txid, NULL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
notleak(watch_txid(topo, topo, NULL, &unconfirmed[i]->txid,
|
|
|
|
closeinfo_txid_confirmed));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *feerate_name(enum feerate feerate)
|
|
|
|
{
|
|
|
|
switch (feerate) {
|
|
|
|
case FEERATE_URGENT: return "urgent";
|
|
|
|
case FEERATE_NORMAL: return "normal";
|
|
|
|
case FEERATE_SLOW: return "slow";
|
|
|
|
}
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
struct command_result *param_feerate_estimate(struct command *cmd,
|
|
|
|
u32 **feerate_per_kw,
|
|
|
|
enum feerate feerate)
|
|
|
|
{
|
|
|
|
*feerate_per_kw = tal(cmd, u32);
|
|
|
|
**feerate_per_kw = try_get_feerate(cmd->ld->topology, feerate);
|
|
|
|
if (!**feerate_per_kw)
|
|
|
|
return command_fail(cmd, LIGHTNINGD, "Cannot estimate fees");
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mutual recursion via timer. */
|
|
|
|
static void next_updatefee_timer(struct chain_topology *topo);
|
|
|
|
|
|
|
|
static void init_feerate_history(struct chain_topology *topo,
|
|
|
|
enum feerate feerate, u32 val)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < FEE_HISTORY_NUM; i++)
|
|
|
|
topo->feehistory[feerate][i] = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_feerate_history(struct chain_topology *topo,
|
|
|
|
enum feerate feerate, u32 val)
|
|
|
|
{
|
|
|
|
memmove(&topo->feehistory[feerate][1], &topo->feehistory[feerate][0],
|
|
|
|
(FEE_HISTORY_NUM - 1) * sizeof(u32));
|
|
|
|
topo->feehistory[feerate][0] = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We sanitize feerates if necessary to put them in descending order. */
|
|
|
|
static void update_feerates(struct bitcoind *bitcoind,
|
|
|
|
const u32 *satoshi_per_kw,
|
|
|
|
struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
u32 old_feerates[NUM_FEERATES];
|
|
|
|
bool changed = false;
|
|
|
|
/* Smoothing factor alpha for simple exponential smoothing. The goal is to
|
|
|
|
* have the feerate account for 90 percent of the values polled in the last
|
|
|
|
* 2 minutes. The following will do that in a polling interval
|
|
|
|
* independent manner. */
|
|
|
|
double alpha = 1 - pow(0.1,(double)topo->poll_seconds / 120);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < NUM_FEERATES; i++) {
|
|
|
|
u32 feerate = satoshi_per_kw[i];
|
|
|
|
|
|
|
|
/* Takes into account override_fee_rate */
|
|
|
|
old_feerates[i] = try_get_feerate(topo, i);
|
|
|
|
|
|
|
|
/* If estimatefee failed, don't do anything. */
|
|
|
|
if (!feerate)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Initial smoothed feerate is the polled feerate */
|
|
|
|
if (!old_feerates[i]) {
|
|
|
|
old_feerates[i] = feerate;
|
|
|
|
init_feerate_history(topo, i, feerate);
|
|
|
|
|
|
|
|
log_debug(topo->log,
|
|
|
|
"Smoothed feerate estimate for %s initialized to polled estimate %u",
|
|
|
|
feerate_name(i), feerate);
|
|
|
|
} else
|
|
|
|
add_feerate_history(topo, i, feerate);
|
|
|
|
|
|
|
|
/* Smooth the feerate to avoid spikes. */
|
|
|
|
u32 feerate_smooth = feerate * alpha + old_feerates[i] * (1 - alpha);
|
|
|
|
/* But to avoid updating forever, only apply smoothing when its
|
|
|
|
* effect is more then 10 percent */
|
|
|
|
if (abs((int)feerate - (int)feerate_smooth) > (0.1 * feerate)) {
|
|
|
|
feerate = feerate_smooth;
|
|
|
|
log_debug(topo->log,
|
|
|
|
"... polled feerate estimate for %s (%u) smoothed to %u (alpha=%.2f)",
|
|
|
|
feerate_name(i), satoshi_per_kw[i],
|
|
|
|
feerate, alpha);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (feerate < feerate_floor()) {
|
|
|
|
feerate = feerate_floor();
|
|
|
|
log_debug(topo->log,
|
|
|
|
"... feerate estimate for %s hit floor %u",
|
|
|
|
feerate_name(i), feerate);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (feerate != topo->feerate[i]) {
|
|
|
|
log_debug(topo->log, "Feerate estimate for %s set to %u (was %u)",
|
|
|
|
feerate_name(i),
|
|
|
|
feerate, topo->feerate[i]);
|
|
|
|
}
|
|
|
|
topo->feerate[i] = feerate;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (topo->feerate_uninitialized) {
|
|
|
|
/* This doesn't mean we *have* a fee estimate, but it does
|
|
|
|
* mean we tried. */
|
|
|
|
topo->feerate_uninitialized = false;
|
|
|
|
maybe_completed_init(topo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure (known) fee rates are in order. */
|
|
|
|
for (size_t i = 0; i < NUM_FEERATES; i++) {
|
|
|
|
if (!topo->feerate[i])
|
|
|
|
continue;
|
|
|
|
for (size_t j = 0; j < i; j++) {
|
|
|
|
if (!topo->feerate[j])
|
|
|
|
continue;
|
|
|
|
if (topo->feerate[j] < topo->feerate[i]) {
|
|
|
|
log_unusual(topo->log,
|
|
|
|
"Feerate estimate for %s (%u) above %s (%u)",
|
|
|
|
feerate_name(i), topo->feerate[i],
|
|
|
|
feerate_name(j), topo->feerate[j]);
|
|
|
|
topo->feerate[j] = topo->feerate[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (try_get_feerate(topo, i) != old_feerates[i])
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changed)
|
|
|
|
notify_feerate_change(bitcoind->ld);
|
|
|
|
|
|
|
|
next_updatefee_timer(topo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void start_fee_estimate(struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
/* FEERATE_IMMEDIATE, FEERATE_NORMAL, FEERATE_SLOW */
|
|
|
|
const char *estmodes[] = { "CONSERVATIVE", "ECONOMICAL", "ECONOMICAL" };
|
|
|
|
const u32 blocks[] = { 2, 4, 100 };
|
|
|
|
|
|
|
|
BUILD_ASSERT(ARRAY_SIZE(blocks) == NUM_FEERATES);
|
|
|
|
|
|
|
|
/* Once per new block head, update fee estimates. */
|
|
|
|
bitcoind_estimate_fees(topo->bitcoind, blocks, estmodes, NUM_FEERATES,
|
|
|
|
update_feerates, topo);
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 mutual_close_feerate(struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
return try_get_feerate(topo, FEERATE_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 opening_feerate(struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
return try_get_feerate(topo, FEERATE_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 unilateral_feerate(struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
return try_get_feerate(topo, FEERATE_URGENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 feerate_from_style(u32 feerate, enum feerate_style style)
|
|
|
|
{
|
|
|
|
switch (style) {
|
|
|
|
case FEERATE_PER_KSIPA:
|
|
|
|
return feerate;
|
|
|
|
case FEERATE_PER_KBYTE:
|
|
|
|
/* Everyone uses satoshi per kbyte, but we use satoshi per ksipa
|
|
|
|
* (don't round down to zero though)! */
|
|
|
|
return (feerate + 3) / 4;
|
|
|
|
}
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 feerate_to_style(u32 feerate_perkw, enum feerate_style style)
|
|
|
|
{
|
|
|
|
switch (style) {
|
|
|
|
case FEERATE_PER_KSIPA:
|
|
|
|
return feerate_perkw;
|
|
|
|
case FEERATE_PER_KBYTE:
|
|
|
|
if ((u64)feerate_perkw * 4 > UINT_MAX)
|
|
|
|
return UINT_MAX;
|
|
|
|
return feerate_perkw * 4;
|
|
|
|
}
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct command_result *json_feerates(struct command *cmd,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *obj UNNEEDED,
|
|
|
|
const jsmntok_t *params)
|
|
|
|
{
|
|
|
|
struct chain_topology *topo = cmd->ld->topology;
|
|
|
|
struct json_stream *response;
|
|
|
|
u32 feerates[NUM_FEERATES];
|
|
|
|
bool missing;
|
|
|
|
enum feerate_style *style;
|
|
|
|
|
|
|
|
if (!param(cmd, buffer, params,
|
|
|
|
p_req("style", param_feerate_style, &style),
|
|
|
|
NULL))
|
|
|
|
return command_param_failed();
|
|
|
|
|
|
|
|
missing = false;
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(feerates); i++) {
|
|
|
|
feerates[i] = try_get_feerate(topo, i);
|
|
|
|
if (!feerates[i])
|
|
|
|
missing = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
response = json_stream_success(cmd);
|
|
|
|
json_object_start(response, json_feerate_style_name(*style));
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(feerates); i++) {
|
|
|
|
if (!feerates[i])
|
|
|
|
continue;
|
|
|
|
json_add_num(response, feerate_name(i),
|
|
|
|
feerate_to_style(feerates[i], *style));
|
|
|
|
}
|
|
|
|
json_add_u64(response, "min_acceptable",
|
|
|
|
feerate_to_style(feerate_min(cmd->ld, NULL), *style));
|
|
|
|
json_add_u64(response, "max_acceptable",
|
|
|
|
feerate_to_style(feerate_max(cmd->ld, NULL), *style));
|
|
|
|
json_object_end(response);
|
|
|
|
|
|
|
|
if (missing)
|
|
|
|
json_add_string(response, "warning",
|
|
|
|
"Some fee estimates unavailable: bitcoind startup?");
|
|
|
|
else {
|
|
|
|
json_object_start(response, "onchain_fee_estimates");
|
|
|
|
/* eg 020000000001016f51de645a47baa49a636b8ec974c28bdff0ac9151c0f4eda2dbe3b41dbe711d000000001716001401fad90abcd66697e2592164722de4a95ebee165ffffffff0240420f00000000002200205b8cd3b914cf67cdd8fa6273c930353dd36476734fbd962102c2df53b90880cdb73f890000000000160014c2ccab171c2a5be9dab52ec41b825863024c54660248304502210088f65e054dbc2d8f679de3e40150069854863efa4a45103b2bb63d060322f94702200d3ae8923924a458cffb0b7360179790830027bb6b29715ba03e12fc22365de1012103d745445c9362665f22e0d96e9e766f273f3260dea39c8a76bfa05dd2684ddccf00000000 == weight 702 */
|
|
|
|
json_add_num(response, "opening_channel_satoshis",
|
|
|
|
opening_feerate(cmd->ld->topology) * 702 / 1000);
|
|
|
|
/* eg. 02000000000101afcfac637d44d4e0df52031dba55b18d3f1bd79ad4b7ebbee964f124c5163dc30100000000ffffffff02400d03000000000016001427213e2217b4f56bd19b6c8393dc9f61be691233ca1f0c0000000000160014071c49cad2f420f3c805f9f6b98a57269cb1415004004830450221009a12b4d5ae1d41781f79bedecfa3e65542b1799a46c272287ba41f009d2e27ff0220382630c899207487eba28062f3989c4b656c697c23a8c89c1d115c98d82ff261014730440220191ddf13834aa08ea06dca8191422e85d217b065462d1b405b665eefa0684ed70220252409bf033eeab3aae89ae27596d7e0491bcc7ae759c5644bced71ef3cccef30147522102324266de8403b3ab157a09f1f784d587af61831c998c151bcc21bb74c2b2314b2102e3bd38009866c9da8ec4aa99cc4ea9c6c0dd46df15c61ef0ce1f271291714e5752ae00000000 == weight 673 */
|
|
|
|
json_add_u64(response, "mutual_close_satoshis",
|
|
|
|
mutual_close_feerate(cmd->ld->topology) * 673 / 1000);
|
|
|
|
/* eg. 02000000000101c4fecaae1ea940c15ec502de732c4c386d51f981317605bbe5ad2c59165690ab00000000009db0e280010a2d0f00000000002200208d290003cedb0dd00cd5004c2d565d55fc70227bf5711186f4fa9392f8f32b4a0400483045022100952fcf8c730c91cf66bcb742cd52f046c0db3694dc461e7599be330a22466d790220740738a6f9d9e1ae5c86452fa07b0d8dddc90f8bee4ded24a88fe4b7400089eb01483045022100db3002a93390fc15c193da57d6ce1020e82705e760a3aa935ebe864bd66dd8e8022062ee9c6aa7b88ff4580e2671900a339754116371d8f40eba15b798136a76cd150147522102324266de8403b3ab157a09f1f784d587af61831c998c151bcc21bb74c2b2314b2102e3bd38009866c9da8ec4aa99cc4ea9c6c0dd46df15c61ef0ce1f271291714e5752ae9a3ed620 == weight 598 */
|
|
|
|
json_add_u64(response, "unilateral_close_satoshis",
|
|
|
|
unilateral_feerate(cmd->ld->topology) * 598 / 1000);
|
|
|
|
json_object_end(response);
|
|
|
|
}
|
|
|
|
|
|
|
|
return command_success(cmd, response);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct json_command feerates_command = {
|
|
|
|
"feerates",
|
|
|
|
"bitcoin",
|
|
|
|
json_feerates,
|
|
|
|
"Return feerate estimates, either satoshi-per-kw ({style} perkw) or satoshi-per-kb ({style} perkb)."
|
|
|
|
};
|
|
|
|
AUTODATA(json_command, &feerates_command);
|
|
|
|
|
|
|
|
static void next_updatefee_timer(struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
/* This takes care of its own lifetime. */
|
|
|
|
notleak(new_reltimer(topo->timers, topo,
|
|
|
|
time_from_sec(topo->poll_seconds),
|
|
|
|
start_fee_estimate, topo));
|
|
|
|
}
|
|
|
|
|
|
|
|
struct sync_waiter {
|
|
|
|
/* Linked from chain_topology->sync_waiters */
|
|
|
|
struct list_node list;
|
|
|
|
void (*cb)(struct chain_topology *topo, void *arg);
|
|
|
|
void *arg;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void destroy_sync_waiter(struct sync_waiter *waiter)
|
|
|
|
{
|
|
|
|
list_del(&waiter->list);
|
|
|
|
}
|
|
|
|
|
|
|
|
void topology_add_sync_waiter_(const tal_t *ctx,
|
|
|
|
struct chain_topology *topo,
|
|
|
|
void (*cb)(struct chain_topology *topo,
|
|
|
|
void *arg),
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
struct sync_waiter *w = tal(ctx, struct sync_waiter);
|
|
|
|
w->cb = cb;
|
|
|
|
w->arg = arg;
|
|
|
|
list_add_tail(topo->sync_waiters, &w->list);
|
|
|
|
tal_add_destructor(w, destroy_sync_waiter);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Once we're run out of new blocks to add, call this. */
|
|
|
|
static void updates_complete(struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
if (!bitcoin_blkid_eq(&topo->tip->blkid, &topo->prev_tip)) {
|
|
|
|
/* Tell lightningd about new block. */
|
|
|
|
notify_new_block(topo->bitcoind->ld, topo->tip->height);
|
|
|
|
|
|
|
|
/* Tell watch code to re-evaluate all txs. */
|
|
|
|
watch_topology_changed(topo);
|
|
|
|
|
|
|
|
/* Maybe need to rebroadcast. */
|
|
|
|
rebroadcast_txs(topo, NULL);
|
|
|
|
|
|
|
|
/* We've processed these UTXOs */
|
|
|
|
db_set_intvar(topo->bitcoind->ld->wallet->db,
|
|
|
|
"last_processed_block", topo->tip->height);
|
|
|
|
|
|
|
|
topo->prev_tip = topo->tip->blkid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If bitcoind is synced, we're now synced. */
|
|
|
|
if (topo->bitcoind->synced && !topology_synced(topo)) {
|
|
|
|
struct sync_waiter *w;
|
|
|
|
struct list_head *list = topo->sync_waiters;
|
|
|
|
|
|
|
|
/* Mark topology_synced() before callbacks. */
|
|
|
|
topo->sync_waiters = NULL;
|
|
|
|
|
|
|
|
while ((w = list_pop(list, struct sync_waiter, list))) {
|
|
|
|
/* In case it doesn't free itself. */
|
|
|
|
tal_del_destructor(w, destroy_sync_waiter);
|
|
|
|
tal_steal(list, w);
|
|
|
|
w->cb(topo, w->arg);
|
|
|
|
}
|
|
|
|
tal_free(list);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try again soon. */
|
|
|
|
next_topology_timer(topo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* topo_update_spends -- Tell the wallet about all spent outpoints
|
|
|
|
*/
|
|
|
|
static void topo_update_spends(struct chain_topology *topo, struct block *b)
|
|
|
|
{
|
|
|
|
const struct short_channel_id *scid;
|
|
|
|
for (size_t i = 0; i < tal_count(b->full_txs); i++) {
|
|
|
|
const struct bitcoin_tx *tx = b->full_txs[i];
|
|
|
|
for (size_t j = 0; j < tx->wtx->num_inputs; j++) {
|
|
|
|
const struct wally_tx_input *input = &tx->wtx->inputs[j];
|
|
|
|
struct bitcoin_txid txid;
|
|
|
|
bitcoin_tx_input_get_txid(tx, j, &txid);
|
|
|
|
|
|
|
|
scid = wallet_outpoint_spend(topo->ld->wallet, tmpctx,
|
|
|
|
b->height, &txid,
|
|
|
|
input->index);
|
|
|
|
if (scid) {
|
|
|
|
gossipd_notify_spend(topo->bitcoind->ld, scid);
|
|
|
|
tal_free(scid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void topo_add_utxos(struct chain_topology *topo, struct block *b)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < tal_count(b->full_txs); i++) {
|
|
|
|
const struct bitcoin_tx *tx = b->full_txs[i];
|
|
|
|
for (size_t j = 0; j < tx->wtx->num_outputs; j++) {
|
|
|
|
if (tx->wtx->outputs[j].features & WALLY_TX_IS_COINBASE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const u8 *script = bitcoin_tx_output_get_script(tmpctx, tx, j);
|
|
|
|
struct amount_asset amt = bitcoin_tx_output_get_amount(tx, j);
|
|
|
|
|
|
|
|
if (amount_asset_is_main(&amt) && is_p2wsh(script, NULL)) {
|
|
|
|
wallet_utxoset_add(topo->ld->wallet, tx, j,
|
|
|
|
b->height, i, script,
|
|
|
|
amount_asset_to_sat(&amt));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_tip(struct chain_topology *topo, struct block *b)
|
|
|
|
{
|
|
|
|
/* Attach to tip; b is now the tip. */
|
|
|
|
assert(b->height == topo->tip->height + 1);
|
|
|
|
b->prev = topo->tip;
|
|
|
|
topo->tip->next = b; /* FIXME this doesn't seem to be used anywhere */
|
|
|
|
topo->tip = b;
|
|
|
|
wallet_block_add(topo->ld->wallet, b);
|
|
|
|
|
|
|
|
topo_add_utxos(topo, b);
|
|
|
|
topo_update_spends(topo, b);
|
|
|
|
|
|
|
|
/* Only keep the transactions we care about. */
|
|
|
|
filter_block_txs(topo, b);
|
|
|
|
|
|
|
|
block_map_add(&topo->block_map, b);
|
|
|
|
topo->max_blockheight = b->height;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct block *new_block(struct chain_topology *topo,
|
|
|
|
struct bitcoin_block *blk,
|
|
|
|
unsigned int height)
|
|
|
|
{
|
|
|
|
struct block *b = tal(topo, struct block);
|
|
|
|
|
|
|
|
bitcoin_block_blkid(blk, &b->blkid);
|
|
|
|
log_debug(topo->log, "Adding block %u: %s",
|
|
|
|
height,
|
|
|
|
type_to_string(tmpctx, struct bitcoin_blkid, &b->blkid));
|
|
|
|
assert(!block_map_get(&topo->block_map, &b->blkid));
|
|
|
|
b->next = NULL;
|
|
|
|
b->prev = NULL;
|
|
|
|
|
|
|
|
b->height = height;
|
|
|
|
|
|
|
|
b->hdr = blk->hdr;
|
|
|
|
|
|
|
|
b->txnums = tal_arr(b, u32, 0);
|
|
|
|
b->full_txs = tal_steal(b, blk->tx);
|
|
|
|
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void remove_tip(struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
struct block *b = topo->tip;
|
|
|
|
struct bitcoin_txid *txs;
|
|
|
|
size_t i, n;
|
|
|
|
|
|
|
|
log_debug(topo->log, "Removing stale block %u: %s",
|
|
|
|
topo->tip->height,
|
|
|
|
type_to_string(tmpctx, struct bitcoin_blkid, &b->blkid));
|
|
|
|
|
|
|
|
/* Move tip back one. */
|
|
|
|
topo->tip = b->prev;
|
|
|
|
|
|
|
|
if (!topo->tip)
|
|
|
|
fatal("Initial block %u (%s) reorganized out!",
|
|
|
|
b->height,
|
|
|
|
type_to_string(tmpctx, struct bitcoin_blkid, &b->blkid));
|
|
|
|
|
|
|
|
txs = wallet_transactions_by_height(b, topo->ld->wallet, b->height);
|
|
|
|
n = tal_count(txs);
|
|
|
|
|
|
|
|
/* Notify that txs are kicked out (their height will be set NULL in db) */
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
txwatch_fire(topo, &txs[i], 0);
|
|
|
|
|
|
|
|
wallet_block_remove(topo->ld->wallet, b);
|
|
|
|
/* This may have unconfirmed txs: reconfirm as we add blocks. */
|
|
|
|
watch_for_utxo_reconfirmation(topo, topo->ld->wallet);
|
|
|
|
block_map_del(&topo->block_map, b);
|
|
|
|
tal_free(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void have_new_block(struct bitcoind *bitcoind UNUSED,
|
|
|
|
struct bitcoin_block *blk,
|
|
|
|
struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
/* Annotate all transactions with the chainparams */
|
|
|
|
for (size_t i=0; i<tal_count(blk->tx); i++)
|
|
|
|
blk->tx[i]->chainparams = chainparams;
|
|
|
|
|
|
|
|
|
|
|
|
/* Unexpected predecessor? Free predecessor, refetch it. */
|
|
|
|
if (!bitcoin_blkid_eq(&topo->tip->blkid, &blk->hdr.prev_hash))
|
|
|
|
remove_tip(topo);
|
|
|
|
else
|
|
|
|
add_tip(topo, new_block(topo, blk, topo->tip->height + 1));
|
|
|
|
|
|
|
|
/* Try for next one. */
|
|
|
|
try_extend_tip(topo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void get_new_block(struct bitcoind *bitcoind,
|
|
|
|
const struct bitcoin_blkid *blkid,
|
|
|
|
struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
if (!blkid) {
|
|
|
|
/* No such block, we're done. */
|
|
|
|
updates_complete(topo);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
bitcoind_getrawblock(bitcoind, blkid, have_new_block, topo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void try_extend_tip(struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
bitcoind_getblockhash(topo->bitcoind, topo->tip->height + 1,
|
|
|
|
get_new_block, topo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void init_topo(struct bitcoind *bitcoind UNUSED,
|
|
|
|
struct bitcoin_block *blk,
|
|
|
|
struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
topo->root = new_block(topo, blk, topo->max_blockheight);
|
|
|
|
block_map_add(&topo->block_map, topo->root);
|
|
|
|
topo->tip = topo->root;
|
|
|
|
topo->prev_tip = topo->tip->blkid;
|
|
|
|
|
|
|
|
/* In case we don't get all the way to updates_complete */
|
|
|
|
db_set_intvar(topo->bitcoind->ld->wallet->db,
|
|
|
|
"last_processed_block", topo->tip->height);
|
|
|
|
|
|
|
|
maybe_completed_init(topo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void get_init_block(struct bitcoind *bitcoind,
|
|
|
|
const struct bitcoin_blkid *blkid,
|
|
|
|
struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
bitcoind_getrawblock(bitcoind, blkid, init_topo, topo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void get_init_blockhash(struct bitcoind *bitcoind, u32 blockcount,
|
|
|
|
struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
/* If bitcoind's current blockheight is below the requested
|
|
|
|
* height, refuse. You can always explicitly request a reindex from
|
|
|
|
* that block number using --rescan=. */
|
|
|
|
if (blockcount < topo->max_blockheight) {
|
|
|
|
/* UINT32_MAX == no blocks in database */
|
|
|
|
if (topo->max_blockheight == UINT32_MAX) {
|
|
|
|
/* Relative rescan, but we didn't know the blockheight */
|
|
|
|
/* Protect against underflow in subtraction.
|
|
|
|
* Possible in regtest mode. */
|
|
|
|
if (blockcount < bitcoind->ld->config.rescan)
|
|
|
|
topo->max_blockheight = 0;
|
|
|
|
else
|
|
|
|
topo->max_blockheight = blockcount - bitcoind->ld->config.rescan;
|
|
|
|
} else
|
|
|
|
fatal("bitcoind has gone backwards from %u to %u blocks!",
|
|
|
|
topo->max_blockheight, blockcount);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Rollback to the given blockheight, so we start track
|
|
|
|
* correctly again */
|
|
|
|
wallet_blocks_rollback(topo->ld->wallet, topo->max_blockheight);
|
|
|
|
/* This may have unconfirmed txs: reconfirm as we add blocks. */
|
|
|
|
watch_for_utxo_reconfirmation(topo, topo->ld->wallet);
|
|
|
|
|
|
|
|
/* Get up to speed with topology. */
|
|
|
|
bitcoind_getblockhash(bitcoind, topo->max_blockheight,
|
|
|
|
get_init_block, topo);
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 get_block_height(const struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
return topo->tip->height;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 try_get_feerate(const struct chain_topology *topo, enum feerate feerate)
|
|
|
|
{
|
|
|
|
return topo->feerate[feerate];
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 feerate_min(struct lightningd *ld, bool *unknown)
|
|
|
|
{
|
|
|
|
u32 min;
|
|
|
|
|
|
|
|
if (unknown)
|
|
|
|
*unknown = false;
|
|
|
|
|
|
|
|
/* We can't allow less than feerate_floor, since that won't relay */
|
|
|
|
if (ld->config.ignore_fee_limits)
|
|
|
|
min = 1;
|
|
|
|
else {
|
|
|
|
min = try_get_feerate(ld->topology, FEERATE_SLOW);
|
|
|
|
if (!min) {
|
|
|
|
if (unknown)
|
|
|
|
*unknown = true;
|
|
|
|
} else {
|
|
|
|
const u32 *hist = ld->topology->feehistory[FEERATE_SLOW];
|
|
|
|
|
|
|
|
/* If one of last three was an outlier, use that. */
|
|
|
|
for (size_t i = 0; i < FEE_HISTORY_NUM; i++) {
|
|
|
|
if (hist[i] < min)
|
|
|
|
min = hist[i];
|
|
|
|
}
|
|
|
|
/* Normally, we use half of slow rate. */
|
|
|
|
min /= 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (min < feerate_floor())
|
|
|
|
return feerate_floor();
|
|
|
|
return min;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* BOLT #2:
|
|
|
|
*
|
|
|
|
* Given the variance in fees, and the fact that the transaction may be
|
|
|
|
* spent in the future, it's a good idea for the fee payer to keep a good
|
|
|
|
* margin (say 5x the expected fee requirement)
|
|
|
|
*/
|
|
|
|
u32 feerate_max(struct lightningd *ld, bool *unknown)
|
|
|
|
{
|
|
|
|
u32 feerate;
|
|
|
|
const u32 *feehistory = ld->topology->feehistory[FEERATE_URGENT];
|
|
|
|
|
|
|
|
if (unknown)
|
|
|
|
*unknown = false;
|
|
|
|
|
|
|
|
if (ld->config.ignore_fee_limits)
|
|
|
|
return UINT_MAX;
|
|
|
|
|
|
|
|
/* If we don't know feerate, don't limit other side. */
|
|
|
|
feerate = try_get_feerate(ld->topology, FEERATE_URGENT);
|
|
|
|
if (!feerate) {
|
|
|
|
if (unknown)
|
|
|
|
*unknown = true;
|
|
|
|
return UINT_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If one of last three was an outlier, use that. */
|
|
|
|
for (size_t i = 0; i < FEE_HISTORY_NUM; i++) {
|
|
|
|
if (feehistory[i] > feerate)
|
|
|
|
feerate = feehistory[i];
|
|
|
|
}
|
|
|
|
return feerate * ld->config.max_fee_multiplier;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* On shutdown, channels get deleted last. That frees from our list, so
|
|
|
|
* do it now instead. */
|
|
|
|
static void destroy_chain_topology(struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
struct outgoing_tx *otx;
|
|
|
|
|
|
|
|
while ((otx = list_pop(&topo->outgoing_txs, struct outgoing_tx, list)))
|
|
|
|
tal_free(otx);
|
|
|
|
|
|
|
|
/* htable uses malloc, so it would leak here */
|
|
|
|
txwatch_hash_clear(&topo->txwatches);
|
|
|
|
txowatch_hash_clear(&topo->txowatches);
|
|
|
|
block_map_clear(&topo->block_map);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct chain_topology *new_topology(struct lightningd *ld, struct log *log)
|
|
|
|
{
|
|
|
|
struct chain_topology *topo = tal(ld, struct chain_topology);
|
|
|
|
|
|
|
|
topo->ld = ld;
|
|
|
|
block_map_init(&topo->block_map);
|
|
|
|
list_head_init(&topo->outgoing_txs);
|
|
|
|
txwatch_hash_init(&topo->txwatches);
|
|
|
|
txowatch_hash_init(&topo->txowatches);
|
|
|
|
topo->log = log;
|
|
|
|
memset(topo->feerate, 0, sizeof(topo->feerate));
|
|
|
|
topo->bitcoind = new_bitcoind(topo, ld, log);
|
|
|
|
topo->poll_seconds = 30;
|
|
|
|
topo->feerate_uninitialized = true;
|
|
|
|
topo->root = NULL;
|
|
|
|
topo->sync_waiters = tal(topo, struct list_head);
|
|
|
|
list_head_init(topo->sync_waiters);
|
|
|
|
return topo;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setup_topology(struct chain_topology *topo,
|
|
|
|
struct timers *timers,
|
|
|
|
u32 min_blockheight, u32 max_blockheight)
|
|
|
|
{
|
|
|
|
memset(&topo->feerate, 0, sizeof(topo->feerate));
|
|
|
|
topo->timers = timers;
|
|
|
|
|
|
|
|
topo->min_blockheight = min_blockheight;
|
|
|
|
topo->max_blockheight = max_blockheight;
|
|
|
|
|
|
|
|
/* Make sure bitcoind is started, and ready */
|
|
|
|
wait_for_bitcoind(topo->bitcoind);
|
|
|
|
|
|
|
|
bitcoind_getclientversion(topo->bitcoind);
|
|
|
|
|
|
|
|
bitcoind_getblockcount(topo->bitcoind, get_init_blockhash, topo);
|
|
|
|
|
|
|
|
tal_add_destructor(topo, destroy_chain_topology);
|
|
|
|
|
|
|
|
start_fee_estimate(topo);
|
|
|
|
|
|
|
|
/* Once it gets initial block, it calls io_break() and we return. */
|
|
|
|
io_loop_with_timers(topo->ld);
|
|
|
|
}
|
|
|
|
|
|
|
|
void begin_topology(struct chain_topology *topo)
|
|
|
|
{
|
|
|
|
try_extend_tip(topo);
|
|
|
|
}
|