Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion plugins/xpay/xpay.c
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,31 @@ static struct command_result *param_string_array(struct command *cmd, const char
return NULL;
}

static struct command_result *getchaininfo_success(struct command *cmd,
const char *method,
const char *buffer,
const jsmntok_t *toks,
struct payment *payment)
{
struct xpay *xpay = xpay_of(cmd->plugin);
u32 headercount;
const char *err;

err = json_scan(tmpctx, buffer, toks, "{headercount:%}",
JSON_SCAN(json_to_u32, &headercount));
if (err)
plugin_err(cmd->plugin, "Bad getchaininfo response: %s", err);

if (headercount > xpay->blockheight) {
plugin_log(cmd->plugin, LOG_DBG,
"Updating payment blockheight from %d (blocks "
"synced) to %d (headercount)",
(int)xpay->blockheight, (int)headercount);
xpay->blockheight = headercount;
}
return populate_private_layer(cmd, payment);
}

static struct command_result *
preapproveinvoice_succeed(struct command *cmd,
const char *method,
Expand All @@ -1639,6 +1664,7 @@ preapproveinvoice_succeed(struct command *cmd,
struct payment *payment)
{
struct xpay *xpay = xpay_of(cmd->plugin);
struct out_req *req;

/* Now we can conclude `check` command */
if (command_check_only(cmd)) {
Expand All @@ -1653,7 +1679,11 @@ preapproveinvoice_succeed(struct command *cmd,
if (payment->disable_mpp)
payment_log(payment, LOG_INFORM, "No MPP support: this is going to be hard to pay");

return populate_private_layer(cmd, payment);
/* Fetch the header height for we might be out-of-sync. */
req = jsonrpc_request_start(cmd, "getchaininfo", &getchaininfo_success,
forward_error, payment);
json_add_u32(req->js, "last_height", 0);
return send_outreq(req);
}

static struct command_result *check_offer_payable(struct command *cmd,
Expand Down
34 changes: 34 additions & 0 deletions tests/test_xpay.py
Original file line number Diff line number Diff line change
Expand Up @@ -1018,3 +1018,37 @@ def test_xpay_bip353(node_factory):

node_factory.join_nodes([l2, l1])
l2.rpc.xpay('fake@fake.com', 100)


def test_blockheight_mismatch(node_factory, bitcoind):
"""Test that we can send a payment even if not caught up with the chain.

Since CLTV computations are based on headers and not our own sync height, the
recipient should still be happy with the parameters we chose.

Stolen from pay
"""

send, direct, recv = node_factory.line_graph(3, wait_for_announce=True)
sync_blockheight(bitcoind, [send, recv])

# Pin `send` at the current height. by not returning the next
# block. This error is special-cased not to count as the
# backend failing since it is used to poll for the next block.
def mock_getblock(req):
return {
"id": req["id"],
"error": {"code": -8, "message": "Block height out of range"},
}

send.daemon.rpcproxy.mock_rpc("getblock", mock_getblock)
bitcoind.generate_block(100)

sync_blockheight(bitcoind, [recv])

inv = recv.rpc.invoice(42, "lbl", "desc")["bolt11"]
send.rpc.xpay(inv)

# Test a direct payment as well.
inv = direct.rpc.invoice(13, "lbl", "desc")["bolt11"]
send.rpc.xpay(inv)
Loading