Skip to content

Blixt autopilot#1495

Merged
hsjoberg merged 1 commit intomasterfrom
blixt-autopilot
Feb 16, 2026
Merged

Blixt autopilot#1495
hsjoberg merged 1 commit intomasterfrom
blixt-autopilot

Conversation

@hsjoberg
Copy link
Member

This PR removes the usage of lnd's internal autopilot in favor of our own. We introduce the Autopilot easy-peasy store which will listen to incoming onchain transactions and check

This way we have have more control over how it's supposed to function -- for example we now prompt the user whether they want to open a channel, and can also choose to set a custom fee rate.

@hsjoberg
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 78b4f92569

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

log.w("Could not get node address from graph for autopilot peer", [error.message]);
}

return nodePubkey;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Return a routable peer URI when node lookup fails

When getAutopilotPeerUri cannot resolve an address, it falls back to returning only the pubkey, but the open-channel path expects a pubkey@host peer string and splits on @ before calling connectPeer; this means autopilot attempts can fail for nodes that are not already resolvable in the local graph (for example early startup or custom nodes), leaving users unable to auto-open despite confirming the prompt.

Useful? React with 👍 / 👎.


feeRate = Number.parseInt(prompt, 10);

if (feeRate === -1 || Number.isNaN(feeRate) || feeRate < 0 || feeRate > 100) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 Badge Reject zero as a custom autopilot feerate

The custom feerate validation allows 0 because it only checks feeRate < 0, even though the dialog says valid values are 1–100 sat/vB; entering 0 is then treated as falsy downstream and the channel open falls back to default fee selection, so the user's explicit custom-fee choice is silently ignored.

Useful? React with 👍 / 👎.

@hsjoberg hsjoberg force-pushed the blixt-autopilot branch 2 times, most recently from eef2c5e to 9b258b0 Compare February 16, 2026 12:40
@hsjoberg
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9b258b08c1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +48 to +49
transaction.numConfirmations < 1 ||
getStoreState().onChain.transactionNotificationBlacklist.includes(transaction.txHash)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ignore outgoing transactions in autopilot trigger

Filter logic in the subscribeTransactions callback only checks confirmations and the on-chain blacklist, so confirmed outgoing transactions can still call checkAutopilot(). Because the blacklist is populated only for positive-amount receives in OnChain.initialize (Number(transaction.amount) > 0), spending from wallet UTXOs can unexpectedly prompt users to open a new channel even though no inbound funds arrived, which is a behavior regression for the new “incoming transaction” autopilot flow.

Useful? React with 👍 / 👎.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure there is any worry here because checkAutopilot() will check whether the autopilot feature is even activated, and so if there is any onchain funds available in the first place the user is forced to open a channel or disable autopilot.

debugShowStartupInfo &&
toast("syncedToChain time: " + (new Date().getTime() - start.getTime()) / 1000 + "s");
await actions.setupAutopilot(getStoreState().settings.autopilotEnabled);
await getStoreActions().autopilot.checkAutopilot();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Run startup autopilot check after graph sync

Startup calls checkAutopilot() before waitForGraphSync(), but checkAutopilot() resolves the target peer via getNodeInfo and throws when the pubkey is not yet in the graph. On nodes that are chain-synced but still graph-syncing, this can fail the only startup autopilot attempt; if no new on-chain transaction arrives afterward, users with existing confirmed balance will never be prompted to open a channel until they manually retrigger it.

Useful? React with 👍 / 👎.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good point, however it is possible to get node info while graph is being synced.
To get on-boarded quicker I will try first without graph synced, and then stay in a wait-loop for graph to be synced.

@hsjoberg
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9d3952d81b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +48 to +49
transaction.numConfirmations < 1 ||
getStoreState().onChain.transactionNotificationBlacklist.includes(transaction.txHash)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ignore non-receive txs before triggering autopilot

subscribeTransactions currently triggers checkAutopilot() for any confirmed transaction that is not blacklisted, but it never checks that the tx is incoming (amount > 0). In practice this means confirmed outgoing spends can also trigger the auto-open flow, and because outgoing txids are not added to transactionNotificationBlacklist by onChain.initialize (that path only blacklists positive amounts), users can get repeated autopilot prompts on their own spend confirmations.

Useful? React with 👍 / 👎.

Copy link
Member Author

@hsjoberg hsjoberg Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

amount in lnrpc.Transaction is always positive (EDIT: this is wrong).
Furthermore, Onchain store's sendCoins() adds the wallet's own transactions to the blacklist before `subscribeTransactions(), causing it to get caught in the blacklist.

Comment on lines +149 to +152
const prompt = await Alert.promisePromptCallback(
"Set custom feerate",
"Enter the feerate in sat/vB for opening the channel",
);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Handle dismissed custom-feerate prompt

When the user selects Yes and set custom feerate, this code awaits Alert.promisePromptCallback(...) after setting autopilotPrompting=true; if the prompt is dismissed/canceled, that promise can remain unresolved for function callbacks (see cancel/dismiss branches in src/utils/alert.ts), so the thunk never reaches its finally and autopilotPrompting stays true indefinitely. After that, all future checkAutopilot() calls are skipped as "already prompting" until restart.

Useful? React with 👍 / 👎.

@hsjoberg
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 09bf94f43c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +48 to +50
transaction.numConfirmations < 1 ||
getStoreState().onChain.transactionNotificationBlacklist.includes(transaction.txHash)
) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Filter outgoing txs before running autopilot check

This transaction callback triggers checkAutopilot() for any confirmed tx that is not blacklisted, but it never verifies that the tx is incoming. In LND transaction streams, confirmed outgoing spends also pass this condition, so users can get channel-open prompts after sending on-chain funds (as long as they still have enough balance), which is inconsistent with the intended "incoming transaction" trigger path. Add an incoming-amount guard (like the on-chain notifier’s amount > 0 check) before invoking autopilot.

Useful? React with 👍 / 👎.

@hsjoberg hsjoberg force-pushed the blixt-autopilot branch 2 times, most recently from 7a745d2 to 7fbd540 Compare February 16, 2026 14:04
@hsjoberg
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7fbd540c5a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (
transaction.numConfirmations < 1 ||
getStoreState().onChain.transactionNotificationBlacklist.includes(transaction.txHash) ||
Number(transaction.amount) > 0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Trigger autopilot on incoming txs, not outgoing ones

The transaction guard currently exits when Number(transaction.amount) > 0, but in this codebase positive on-chain amounts represent received funds (see the incoming-notification check in src/state/OnChain.ts), so this inverts the autopilot trigger. In practice, confirmed deposits are skipped while non-positive (outgoing) transactions can invoke checkAutopilot, which breaks the new auto-open flow and can prompt users at the wrong time. Reverse this amount check so incoming confirmed transactions are the ones that trigger autopilot.

Useful? React with 👍 / 👎.

@hsjoberg
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d36a9b8332

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +270 to +272
changeAutopilotEnabled(!autopilotEnabled);
setupAutopilot(!autopilotEnabled);
if (!autopilotEnabled) {
checkAutopilot();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Await autopilot toggle before triggering a check

changeAutopilotEnabled is an async thunk that persists to storage before it updates settings.autopilotEnabled, but checkAutopilot() is called immediately afterward without awaiting that update. In the enable flow (autopilotEnabled was false), checkAutopilot can read the stale disabled state and exit at its early guard, so users with sufficient on-chain funds may not get the expected prompt until a later trigger (e.g., another transaction or restart).

Useful? React with 👍 / 👎.

@hsjoberg
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2886f1b660

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +270 to +272
changeAutopilotEnabled(!autopilotEnabled);
setupAutopilot(!autopilotEnabled);
if (!autopilotEnabled) {
await checkAutopilot();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Await setting write before running autopilot check

When the user enables autopilot here, changeAutopilotEnabled is fired but not awaited, and checkAutopilot() is called immediately afterward. Since checkAutopilot gates on settings.autopilotEnabled, it can read the old false value and return early, so the expected prompt to open a channel does not appear until a later trigger (e.g., a new transaction or manual force). This is a regression from the previous flow, which passed the intended enable state directly.

Useful? React with 👍 / 👎.

Comment on lines +139 to +141
{ text: "Yes" },
{ text: "Yes and set custom feerate" },
{ text: "No and disable autopilot", style: "cancel" },

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 Badge Keep autopilot prompt choices representable on web alerts

This adds two non-cancel choices to Alert.promiseAlert, but the web implementation (WebAlert.alert) is still backed by window.confirm, which only supports a boolean choice and resolves the first non-cancel button. In web builds, users can never select Yes and set custom feerate, so that new branch is unreachable and custom fee entry is effectively broken on that platform.

Useful? React with 👍 / 👎.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The web implementation is just a demo and in the future HelperWindows/Prompt.tsx can be used instead.

@hsjoberg
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7d57843499

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

debugShowStartupInfo &&
toast("syncedToChain time: " + (new Date().getTime() - start.getTime()) / 1000 + "s");
await actions.setupAutopilot(getStoreState().settings.autopilotEnabled);
await getStoreActions().autopilot.checkAutopilot();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Disable legacy lnd autopilot on startup

Replacing the startup call with autopilot.checkAutopilot() removed the only production path that called autopilotModifyStatus, so existing daemons that were already running with lnd autopilot enabled (from previous app versions) are no longer forced off. In the SERVER_ACTIVE/already-running-daemon flow, this means lnd can continue opening channels in the background without the new prompt flow, and even after the user toggles autopilot off in settings, because only app state is changed now.

Useful? React with 👍 / 👎.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't true because autopilot always starts as inactive, and modifyStatus gRPC call isn't a persistent change (it's only for the current runtime).

[autopilot]
autopilot.active=0

@hsjoberg hsjoberg merged commit 85b5318 into master Feb 16, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant