From 67f74fe5dbe082ed1436d660c4b27d4ebc765b93 Mon Sep 17 00:00:00 2001 From: Evan Kaloudis Date: Thu, 6 Jun 2024 16:49:33 -0400 Subject: [PATCH] Neutrino: auto-select peers on wallet creation --- locales/en.json | 1 + stores/SettingsStore.ts | 6 ++ utils/LndMobileUtils.ts | 100 +++++++++++++++++++++++++++ views/Intro.tsx | 24 +++++-- views/IntroSplash.tsx | 36 ++++++++-- views/Settings/NodeConfiguration.tsx | 7 +- views/Settings/SeedRecovery.tsx | 9 ++- 7 files changed, 167 insertions(+), 16 deletions(-) diff --git a/locales/en.json b/locales/en.json index f9f578dde..919fc2450 100644 --- a/locales/en.json +++ b/locales/en.json @@ -497,6 +497,7 @@ "views.Intro.lightningLiquidity": "Learn about lightning liquidity", "views.Intro.advancedSetUp": "Advanced set-up", "views.Intro.creatingWallet": "Zeus is creating your wallet.", + "views.Intro.choosingPeers": "ZEUS is choosing your peers.", "views.Intro.carousel1.title": "Payments you can trust", "views.Intro.carousel1.text": "ZEUS runs a Bitcoin and Lightning node to verify and keep your transactions private.", "views.Intro.carousel2.title": "On-chain transfers", diff --git a/stores/SettingsStore.ts b/stores/SettingsStore.ts index 9ec5a6d88..187e1d53f 100644 --- a/stores/SettingsStore.ts +++ b/stores/SettingsStore.ts @@ -976,6 +976,12 @@ export const DEFAULT_NEUTRINO_PEERS_MAINNET = [ 'sg.lnolymp.us' ]; +export const SECONDARY_NEUTRINO_PEERS_MAINNET = [ + 'node.blixtwallet.com', + 'bb1.breez.technology', + 'bb2.breez.technology' +]; + export const DEFAULT_NEUTRINO_PEERS_TESTNET = [ 'testnet.lnolymp.us', 'btcd-testnet.lightning.computer', diff --git a/utils/LndMobileUtils.ts b/utils/LndMobileUtils.ts index 0692d5082..98bc6068c 100644 --- a/utils/LndMobileUtils.ts +++ b/utils/LndMobileUtils.ts @@ -7,6 +7,7 @@ import { import { generateSecureRandom } from 'react-native-securerandom'; import NetInfo from '@react-native-community/netinfo'; +import Ping from 'react-native-ping'; import Log from '../lndmobile/log'; const log = Log('utils/LndMobileUtils.ts'); @@ -22,6 +23,11 @@ import { } from '../lndmobile/index'; import stores from '../stores/Stores'; +import { + DEFAULT_NEUTRINO_PEERS_MAINNET, + SECONDARY_NEUTRINO_PEERS_MAINNET, + DEFAULT_NEUTRINO_PEERS_TESTNET +} from '../stores/SettingsStore'; import { lnrpc } from '../proto/lightning'; @@ -280,6 +286,100 @@ export async function startLnd( }); } +export async function chooseNeutrinoPeers(isTestnet?: boolean) { + console.log('Selecting Neutrino peers with ping times <200ms'); + let peers = isTestnet + ? DEFAULT_NEUTRINO_PEERS_TESTNET + : DEFAULT_NEUTRINO_PEERS_MAINNET; + + const results: any = []; + for (let i = 0; i < peers.length; i++) { + const peer = peers[i]; + await new Promise(async (resolve) => { + try { + const ms = await Ping.start(peer, { + timeout: 1000 + }); + console.log(`# ${peer} - ${ms}`); + results.push({ + peer, + ms + }); + resolve(true); + } catch (e) { + console.log('e', e); + results.push({ + peer, + ms: 'Timed out' + }); + resolve(true); + } + }); + } + + let filteredResults = results.filter((result: any) => { + return Number.isInteger(result.ms) && result.ms < 200; + }); + + if (filteredResults.length < 3 && !isTestnet) { + peers = SECONDARY_NEUTRINO_PEERS_MAINNET; + for (let i = 0; i < peers.length; i++) { + const peer = peers[i]; + await new Promise(async (resolve) => { + try { + const ms = await Ping.start(peer, { + timeout: 1000 + }); + console.log(`# ${peer} - ${ms}`); + results.push({ + peer, + ms + }); + resolve(true); + } catch (e) { + console.log('e', e); + results.push({ + peer, + ms: 'Timed out' + }); + resolve(true); + } + }); + } + } + + filteredResults = results.filter((result: any) => { + return Number.isInteger(result.ms) && result.ms < 200; + }); + + const selectedPeers: string[] = []; + filteredResults.forEach((result: any) => { + selectedPeers.push(result.peer); + }); + + if (selectedPeers.length > 0) { + if (isTestnet) { + await stores.settingsStore.updateSettings({ + neutrinoPeersTestnet: selectedPeers, + dontAllowOtherPeers: selectedPeers.length > 2 ? true : false + }); + } else { + await stores.settingsStore.updateSettings({ + neutrinoPeersMainnet: selectedPeers, + dontAllowOtherPeers: selectedPeers.length > 2 ? true : false + }); + } + + console.log('Selected the following Neutrino peers:', selectedPeers); + } else { + // TODO allow users to manually choose peers if we can't + // pick good defaults for them + console.log('Falling back to the default Neutrino peers.'); + } + + return; +} + export async function createLndWallet( seedMnemonic?: string, walletPassphrase?: string, diff --git a/views/Intro.tsx b/views/Intro.tsx index a0b8b077a..88dfc7e5c 100644 --- a/views/Intro.tsx +++ b/views/Intro.tsx @@ -18,7 +18,7 @@ import LoadingIndicator from '../components/LoadingIndicator'; import Screen from '../components/Screen'; import { ErrorMessage } from '../components/SuccessErrorMessage'; -import { createLndWallet } from '../utils/LndMobileUtils'; +import { chooseNeutrinoPeers, createLndWallet } from '../utils/LndMobileUtils'; import { localeString } from '../utils/LocaleUtils'; import { themeColor } from '../utils/ThemeUtils'; import UrlUtils from '../utils/UrlUtils'; @@ -36,6 +36,7 @@ interface IntroProps { const Intro: React.FC = (props) => { const [creatingWallet, setCreatingWallet] = useState(false); + const [choosingPeers, setChoosingPeers] = useState(false); const [error, setError] = useState(false); let screenWidth: number; @@ -171,12 +172,19 @@ const Intro: React.FC = (props) => {