Skip to content

Commit 26cf59d

Browse files
authored
Add the ability to import/export channel.db
1 parent 31f8d2f commit 26cf59d

File tree

11 files changed

+520
-84
lines changed

11 files changed

+520
-84
lines changed

android/app/src/main/java/com/blixtwallet/LndMobileTools.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import android.Manifest;
88
import android.app.ActivityManager;
99
import android.database.sqlite.SQLiteDatabase;
10+
import android.net.Uri;
1011
import android.os.FileObserver;
1112
import android.os.Process;
1213
import android.util.Base64;
@@ -765,6 +766,56 @@ public void generateSecureRandomAsBase64(int length, Promise promise) {
765766
promise.resolve(Base64.encodeToString(buffer, Base64.NO_WRAP));
766767
}
767768

769+
@ReactMethod
770+
public void saveChannelDbFile(Promise promise) {
771+
// This promise will be resolved in MainActivity
772+
MainActivity.tmpExportChannelDbPromise = promise;
773+
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
774+
intent.addCategory(Intent.CATEGORY_OPENABLE);
775+
intent.setType("application/octet-stream");
776+
intent.putExtra(Intent.EXTRA_TITLE, "channel.db");
777+
getReactApplicationContext().getCurrentActivity().startActivityForResult(intent, MainActivity.INTENT_EXPORTCHANNELDBFILE);
778+
}
779+
780+
@ReactMethod
781+
public void importChannelDbFile(String channelDbImportPath, Promise promise) {
782+
Log.i(TAG, getReactApplicationContext().getFilesDir().toString() + "/data/graph/" + BuildConfig.CHAIN + "/channel.db");
783+
try {
784+
File sourceFile = new File(channelDbImportPath);
785+
786+
String channelDbFilePath = getReactApplicationContext().getFilesDir().toString() + "/data/graph/" + BuildConfig.CHAIN + "/channel.db";
787+
File destChannelDbFile = new File(channelDbFilePath);
788+
789+
// Delete the channel.db file first if there is one
790+
destChannelDbFile.delete();
791+
792+
File destFile = new File(channelDbFilePath);
793+
if (!destFile.exists() && !destFile.createNewFile()) {
794+
promise.reject(new IOException("Failed to create destination channel.db file"));
795+
return;
796+
}
797+
798+
// Copy content
799+
InputStream in = new FileInputStream(sourceFile);
800+
OutputStream out = new FileOutputStream(destFile);
801+
byte[] buffer = new byte[1024];
802+
int read;
803+
while ((read = in.read(buffer)) != -1) {
804+
out.write(buffer, 0, read);
805+
}
806+
in.close();
807+
out.flush();
808+
out.close();
809+
810+
// Delete the cached file
811+
sourceFile.delete();
812+
813+
promise.resolve(true);
814+
} catch (IOException error) {
815+
promise.reject(error);
816+
}
817+
}
818+
768819
private void checkWriteExternalStoragePermission(@NonNull RequestWriteExternalStoragePermissionCallback successCallback,
769820
@NonNull Runnable failCallback,
770821
@NonNull Runnable failPermissionCheckcallback) {

android/app/src/main/java/com/blixtwallet/MainActivity.kt

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import android.os.Bundle
55
import android.widget.Toast
66
import com.facebook.react.ReactActivity
77
import com.facebook.react.ReactActivityDelegate
8+
import com.facebook.react.bridge.Promise
89
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
910
import com.facebook.react.defaults.DefaultReactActivityDelegate
1011
import dev.doubledot.doki.ui.DokiActivity
@@ -92,6 +93,29 @@ class MainActivity : ReactActivity() {
9293
} catch (e: IOException) {
9394
Toast.makeText(this, "Error " + e.message, Toast.LENGTH_LONG).show()
9495
}
96+
} else if (requestCode == INTENT_EXPORTCHANNELDBFILE && resultCode == RESULT_OK) {
97+
val destUri = data!!.data
98+
val sourceLocation = File(filesDir.toString() + "/data/graph/" + BuildConfig.CHAIN + "/channel.db")
99+
try {
100+
val `in`: InputStream = FileInputStream(sourceLocation)
101+
val out = contentResolver.openOutputStream(destUri!!)
102+
val buf = ByteArray(1024)
103+
var len: Int
104+
while (`in`.read(buf).also { len = it } > 0) {
105+
out!!.write(buf, 0, len)
106+
}
107+
`in`.close()
108+
out!!.close()
109+
110+
if (tmpExportChannelDbPromise != null) {
111+
tmpExportChannelDbPromise!!.resolve(true)
112+
} else {
113+
Toast.makeText(this, "promise is null", Toast.LENGTH_LONG).show()
114+
}
115+
} catch (e: IOException) {
116+
Toast.makeText(this, "Error " + e.message, Toast.LENGTH_LONG).show()
117+
tmpExportChannelDbPromise!!.reject(e)
118+
}
95119
}
96120
}
97121

@@ -111,14 +135,19 @@ class MainActivity : ReactActivity() {
111135
@JvmField
112136
var INTENT_EXPORTCHANBACKUP = 101
113137
@JvmField
138+
var tmpChanBackup: ByteArray = ByteArray(0)
139+
@JvmField
114140
var INTENT_EXPORTCHANBACKUPFILE = 102
115141
@JvmField
116142
var INTENT_COPYSPEEDLOADERLOG = 103
117143
@JvmField
118-
var tmpChanBackup: ByteArray = ByteArray(0)
144+
var INTENT_EXPORTCHANNELDBFILE = 104
145+
@JvmField
146+
var tmpExportChannelDbPromise: Promise? = null
147+
@JvmField
119148
var currentActivity: WeakReference<MainActivity>? = null
120149
@JvmStatic
121150
val activity: MainActivity?
122151
get() = currentActivity!!.get()
123152
}
124-
}
153+
}

ios/LndMobile/Lnd.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ open class Lnd {
122122
"VerifyMessage": { bytes, cb in LndmobileVerifyMessage(bytes, cb) },
123123
"SignMessage": { bytes, cb in LndmobileSignMessage(bytes, cb) },
124124
"SignerSignMessage": { bytes, cb in LndmobileSignerSignMessage(bytes, cb) },
125+
"RestoreChannelBackups": { bytes, cb in LndmobileRestoreChannelBackups(bytes, cb) },
125126

126127
// autopilot
127128
"AutopilotStatus": { bytes, cb in LndmobileAutopilotStatus(bytes, cb) },

src/Main.tsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useEffect, useState } from "react";
22
import { StatusBar, Alert, NativeModules } from "react-native";
3-
import { Spinner, H1, H2 } from "native-base";
3+
import { Spinner, H1, H2, Text } from "native-base";
44
import {
55
createStackNavigator,
66
CardStyleInterpolators,
@@ -40,6 +40,7 @@ import useStackNavigationOptions from "./hooks/useStackNavigationOptions";
4040
import { navigator } from "./utils/navigation";
4141
import { PLATFORM } from "./utils/constants";
4242
import Prompt, { IPromptNavigationProps } from "./windows/HelperWindows/Prompt";
43+
import { isInstanceBricked } from "./storage/app";
4344

4445
const RootStack = createStackNavigator();
4546

@@ -86,6 +87,7 @@ export default function Main() {
8687
const appReady = useStoreState((store) => store.appReady);
8788
const lightningReady = useStoreState((store) => store.lightning.ready);
8889
const walletCreated = useStoreState((store) => store.walletCreated);
90+
const importChannelDbOnStartup = useStoreState((store) => store.importChannelDbOnStartup);
8991
const loggedIn = useStoreState((store) => store.security.loggedIn);
9092
const initializeApp = useStoreActions((store) => store.initializeApp);
9193
const [initialRoute, setInitialRoute] = useState("Loading");
@@ -95,13 +97,22 @@ export default function Main() {
9597
(store) => store.settings.screenTransitionsEnabled,
9698
);
9799

98-
const [state, setState] = useState<"init" | "authentication" | "onboarding" | "started">("init");
100+
console.log("walletCreated", walletCreated);
101+
102+
const [state, setState] = useState<
103+
"init" | "authentication" | "onboarding" | "started" | "bricked"
104+
>("init");
99105

100106
useEffect(() => {
101107
// tslint:disable-next-line
102108
(async () => {
103109
if (!appReady) {
104110
try {
111+
if (await isInstanceBricked()) {
112+
setState("bricked");
113+
return;
114+
}
115+
105116
await initializeApp();
106117
} catch (e) {
107118
toast(e.message, 0, "danger");
@@ -120,7 +131,7 @@ export default function Main() {
120131
setState("authentication");
121132
} else if (!lightningReady) {
122133
setState("started");
123-
if (!walletCreated) {
134+
if (!walletCreated && !importChannelDbOnStartup) {
124135
setInitialRoute("Welcome");
125136
} else {
126137
// try {
@@ -225,6 +236,10 @@ export default function Main() {
225236
return <Authentication />;
226237
}
227238

239+
if (state === "bricked") {
240+
return <Text>Bricked</Text>;
241+
}
242+
228243
return (
229244
<RootStack.Navigator initialRouteName={initialRoute} screenOptions={screenOptions}>
230245
<RootStack.Screen

src/lndmobile/LndMobile.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ export interface ILndMobileTools {
5454
DEBUG_deleteSpeedloaderDgraphDirectory(): null;
5555
DEBUG_deleteNeutrinoFiles(): boolean;
5656
getInternalFiles(): Promise<Record<string, number>>;
57+
saveChannelDbFile(): Promise<boolean>;
58+
importChannelDbFile(channelDbPath: string): Promise<boolean>;
5759

5860
// Android-specific
5961
getIntentStringData(): Promise<string | null>;

0 commit comments

Comments
 (0)