Skip to content

Commit

Permalink
Merge pull request #252 from synonymdev/close-addresses
Browse files Browse the repository at this point in the history
fix: save addresses only when used for closing a channel
  • Loading branch information
Jasonvdb authored Jun 28, 2024
2 parents 7902df4 + b69de59 commit 105e664
Show file tree
Hide file tree
Showing 12 changed files with 68 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/e2e-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:

jobs:
e2e-android:
runs-on: macos-12
runs-on: macos-13
timeout-minutes: 120

steps:
Expand Down
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ PODS:
- React-jsinspector (0.72.4)
- React-logger (0.72.4):
- glog
- react-native-ldk (0.0.143):
- react-native-ldk (0.0.145):
- React
- react-native-randombytes (3.6.1):
- React-Core
Expand Down Expand Up @@ -621,7 +621,7 @@ SPEC CHECKSUMS:
React-jsiexecutor: c7f826e40fa9cab5d37cab6130b1af237332b594
React-jsinspector: aaed4cf551c4a1c98092436518c2d267b13a673f
React-logger: da1ebe05ae06eb6db4b162202faeafac4b435e77
react-native-ldk: 12d78fe1141ad4343a2842340f7ebf8539dcc3b0
react-native-ldk: 496216796eafbd77c43cd5228342460a242cf7ed
react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846
react-native-tcp-socket: c1b7297619616b4c9caae6889bcb0aba78086989
React-NativeModulesApple: edb5ace14f73f4969df6e7b1f3e41bef0012740f
Expand Down
2 changes: 2 additions & 0 deletions example/ios/exmpl.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@
baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-exmpl-exmplTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = KYH47R284B;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
Expand Down Expand Up @@ -516,6 +517,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = KYH47R284B;
INFOPLIST_FILE = exmpl/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13;
LD_RUNPATH_SEARCH_PATHS = (
Expand Down
7 changes: 4 additions & 3 deletions lib/android/src/main/java/com/reactnativeldk/LdkModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ enum class EventTypes {
network_graph_updated,
channel_manager_restarted,
backup_state_update,
lsp_log
lsp_log,
used_close_address
}
//*****************************************************************

Expand Down Expand Up @@ -242,7 +243,7 @@ class LdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
}

@ReactMethod
fun initKeysManager(seed: String, destinationScriptPublicKey: String, witnessProgram: String, witnessProgramVersion: Double, promise: Promise) {
fun initKeysManager(seed: String, address: String, destinationScriptPublicKey: String, witnessProgram: String, witnessProgramVersion: Double, promise: Promise) {
if (keysManager != null) {
return handleResolve(promise, LdkCallbackResponses.keys_manager_init_success)
}
Expand All @@ -259,11 +260,11 @@ class LdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
seedBytes,
seconds,
nanoSeconds.toInt(),
address,
destinationScriptPublicKey.hexa(),
witnessProgram.hexa(),
witnessProgramVersion.toInt().toByte()
)
//keysManager = KeysManager.of(seedBytes, seconds, nanoSeconds.toInt())

handleResolve(promise, LdkCallbackResponses.keys_manager_init_success)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class CustomKeysManager(
seed: ByteArray,
startingTimeSecs: Long,
startingTimeNanos: Int,
val address: String,
val destinationScriptPublicKey: ByteArray,
val witnessProgram: ByteArray,
val witnessProgramVersion: Byte
Expand Down Expand Up @@ -68,6 +69,7 @@ class CustomSignerProvider : SignerProviderInterface {
val res = ShutdownScript.new_witness_program(witness)

return if (res.is_ok) {
LdkEventEmitter.send(EventTypes.used_close_address, customKeysManager.address)
Result_ShutdownScriptNoneZ.ok((res as Result_ShutdownScriptInvalidShutdownScriptZ.Result_ShutdownScriptInvalidShutdownScriptZ_OK).res)
} else {
Result_ShutdownScriptNoneZ.err()
Expand Down
6 changes: 5 additions & 1 deletion lib/ios/Classes/CustomKeysManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import LightningDevKit
class CustomKeysManager {
let inner: KeysManager
let signerProvider: CustomSignerProvider
let address: String
let destinationScriptPublicKey: [UInt8]
let witnessProgram: [UInt8]
let witnessProgramVersion: UInt8

init(seed: [UInt8], startingTimeSecs: UInt64, startingTimeNanos: UInt32, destinationScriptPublicKey: [UInt8], witnessProgram: [UInt8], witnessProgramVersion: UInt8) {
init(seed: [UInt8], startingTimeSecs: UInt64, startingTimeNanos: UInt32, address: String, destinationScriptPublicKey: [UInt8], witnessProgram: [UInt8], witnessProgramVersion: UInt8) {
self.inner = KeysManager(seed: seed, startingTimeSecs: startingTimeSecs, startingTimeNanos: startingTimeNanos)
self.address = address
self.destinationScriptPublicKey = destinationScriptPublicKey
self.witnessProgram = witnessProgram
self.witnessProgramVersion = witnessProgramVersion
Expand Down Expand Up @@ -61,6 +63,8 @@ class CustomSignerProvider: SignerProvider {
override func getShutdownScriptpubkey() -> Bindings.Result_ShutdownScriptNoneZ {
let res = ShutdownScript.newWitnessProgram(witnessProgram: .init(version: customKeysManager!.witnessProgramVersion, program: customKeysManager!.witnessProgram))
if res.isOk() {
//To record which addresses should be watched for close channel funds
LdkEventEmitter.shared.send(withEvent: .used_close_address, body: customKeysManager!.address)
return Bindings.Result_ShutdownScriptNoneZ.initWithOk(o: res.getValue()!)
}

Expand Down
1 change: 1 addition & 0 deletions lib/ios/Ldk.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ @interface RCT_EXTERN_MODULE(Ldk, NSObject)
RCT_EXTERN_METHOD(initChainMonitor:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(initKeysManager:(NSString *)seed
address:(NSString *)address
destinationScriptPublicKey:(NSString *)destinationScriptPublicKey
witnessProgram:(NSString *)witnessProgram
witnessProgramVersion:(NSInteger *)witnessProgramVersion
Expand Down
6 changes: 4 additions & 2 deletions lib/ios/Ldk.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ enum EventTypes: String, CaseIterable {
case channel_manager_restarted = "channel_manager_restarted"
case backup_state_update = "backup_state_update"
case lsp_log = "lsp_log"
case used_close_address = "used_close_address"
}
//*****************************************************************

Expand Down Expand Up @@ -210,7 +211,7 @@ class Ldk: NSObject {
}

@objc
func initKeysManager(_ seed: NSString, destinationScriptPublicKey: NSString, witnessProgram: NSString, witnessProgramVersion: NSInteger, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
func initKeysManager(_ seed: NSString, address: NSString, destinationScriptPublicKey: NSString, witnessProgram: NSString, witnessProgramVersion: NSInteger, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
if keysManager != nil {
//If previously started with the same key (by backup client) return success.
return handleResolve(resolve, .keys_manager_init_success)
Expand All @@ -228,6 +229,7 @@ class Ldk: NSObject {
seed: String(seed).hexaBytes,
startingTimeSecs: seconds,
startingTimeNanos: nanoSeconds,
address: String(address),
destinationScriptPublicKey: String(destinationScriptPublicKey).hexaBytes,
witnessProgram: String(witnessProgram).hexaBytes,
witnessProgramVersion: UInt8(witnessProgramVersion)
Expand Down Expand Up @@ -661,7 +663,7 @@ class Ldk: NSObject {
droppedPeerTimer = Timer.scheduledTimer(
timeInterval: 5.0,
target: self,
selector: #selector(handleDroppedPeers),
selector: #selector(self.handleDroppedPeers),
userInfo: nil,
repeats: true
)
Expand Down
2 changes: 1 addition & 1 deletion lib/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@synonymdev/react-native-ldk",
"title": "React Native LDK",
"version": "0.0.143",
"version": "0.0.145",
"description": "React Native wrapper for LDK",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand Down
2 changes: 2 additions & 0 deletions lib/src/ldk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,15 @@ class LDK {
*/
async initKeysManager({
seed,
address,
channelCloseDestinationScriptPublicKey,
channelCloseWitnessProgram,
channelCloseWitnessProgramVersion,
}: TInitKeysManager): Promise<Result<string>> {
try {
const res = await NativeLDK.initKeysManager(
seed,
address,
channelCloseDestinationScriptPublicKey,
channelCloseWitnessProgram,
channelCloseWitnessProgramVersion,
Expand Down
50 changes: 42 additions & 8 deletions lib/src/lightning-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ class LightningManager {
this.onChannelManagerRestarted.bind(this),
);
ldk.onEvent(EEventTypes.lsp_log, this.onLspLogEvent.bind(this));
ldk.onEvent(EEventTypes.used_close_address, (address: string) => {
this.saveAddressToFile(address).catch(console.error);
});
}

/**
Expand Down Expand Up @@ -364,14 +367,7 @@ class LightningManager {
this.account = account;
this.network = network;
this.addresses = await this.readAddressesFromFile();
this.getAddress = async () => {
const addressObj = await getAddress();
const address = addressObj?.address;
if (address) {
this.saveAddressToFile(address).then();
}
return addressObj;
};
this.getAddress = getAddress;
this.getScriptPubKeyHistory = getScriptPubKeyHistory;
this.getFees = getFees;
this.broadcastTransaction = broadcastTransaction;
Expand Down Expand Up @@ -452,6 +448,7 @@ class LightningManager {
// ldk.setLogLevel(ELdkLogLevels.trace, true),
ldk.initKeysManager({
seed: this.account.seed,
address: closeAddress.address,
channelCloseDestinationScriptPublicKey: closeAddress.publicKey,
channelCloseWitnessProgram: witnessProgram,
channelCloseWitnessProgramVersion: witnessProgramVersion,
Expand Down Expand Up @@ -513,6 +510,7 @@ class LightningManager {
ldk.nodeStateDump().catch(console.error);

this.cleanupBroadcastedTxs().catch(console.error);
this.resetAddressFileIfUnused().catch(console.error);

this.isStarting = false;
const result = ok('Node started');
Expand Down Expand Up @@ -769,6 +767,37 @@ class LightningManager {
return ok('Watch transactions checked');
};

/*
* Previously we were writing all addresses to file even
* if they may not have been used in a channel shutdown script or
* force close sweeping. So reset the file if there is no evidence of prior channels.
* */
resetAddressFileIfUnused = async (): Promise<void> => {
//If no channel files found and no addresses are being used, reset the address file.
const channelFilesRes = await ldk.listChannelFiles();
if (channelFilesRes.isErr()) {
return;
}

if (channelFilesRes.value.length > 0) {
return;
}

const accountPath = appendPath(this.baseStoragePath, this.account.name);
const writeRes = await ldk.writeToFile({
fileName: ELdkFiles.addresses,
path: accountPath,
content: JSON.stringify([]),
remotePersist: false,
});

this.addresses = [];

if (writeRes.isErr()) {
console.error(writeRes.error);
}
};

saveAddressToFile = async (address: string): Promise<Result<boolean>> => {
if (!address) {
return err('No address provided');
Expand Down Expand Up @@ -1822,6 +1851,7 @@ class LightningManager {
changeDestinationScript: changeDestinationScript,
};
const res = await ldk.reconstructAndSpendOutputs(req);
await this.saveAddressToFile(address.address);

if (res.isOk()) {
reconstructedTxs++;
Expand Down Expand Up @@ -2127,6 +2157,7 @@ class LightningManager {
res: TChannelManagerSpendableOutputs,
): Promise<void> {
const spendableOutputs = await this.getLdkSpendableOutputs();

res.outputsSerialized.forEach((o) => {
if (!spendableOutputs.includes(o)) {
spendableOutputs.push(o);
Expand Down Expand Up @@ -2172,6 +2203,9 @@ class LightningManager {
return;
}

//Address was used to sweep to so wallet needs to watch it
await this.saveAddressToFile(address.address);

await ldk.writeToLogFile(
'info',
`Created tx spending outputs: ${spendRes.value}`,
Expand Down
2 changes: 2 additions & 0 deletions lib/src/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export enum EEventTypes {
channel_manager_restarted = 'channel_manager_restarted',
backup_state_update = 'backup_state_update',
lsp_log = 'lsp_log',
used_close_address = 'used_close_address',
}

//LDK event responses
Expand Down Expand Up @@ -326,6 +327,7 @@ export type TDownloadScorer = {

export type TInitKeysManager = {
seed: string;
address: string;
channelCloseDestinationScriptPublicKey: string;
channelCloseWitnessProgram: string;
channelCloseWitnessProgramVersion: number;
Expand Down

0 comments on commit 105e664

Please sign in to comment.