Skip to content

Commit

Permalink
Mweb enhancements (#1715)
Browse files Browse the repository at this point in the history
* node peer enhancement, delay mweb address generation, increase logging

* prevent unnecessary sync status changes if we can't connect to the ltc node

* handle potential errors

* set nodeUri to null for testing

* [skip ci] redo good changes

* [skip ci] draft

* [skip ci] minor

* [skip ci] cleanup

* [skip ci] minor

* [skip ci] minor

* [skip ci] localization

* [skip ci] save

* [skip ci] wip

* use proxy layer

* ui

* minor changes
Add ToDos for later

* fixes

* [skip ci] minor

* [skip ci] minor

* [skip ci] ui

* handle case where there are no addresses with txcount > 0

* comment out pegin button

---------

Co-authored-by: OmarHatem <[email protected]>
  • Loading branch information
fossephate and OmarHatem28 authored Oct 5, 2024
1 parent 382a0ff commit 37b822b
Show file tree
Hide file tree
Showing 46 changed files with 845 additions and 413 deletions.
4 changes: 3 additions & 1 deletion cw_bitcoin/lib/electrum_wallet_addresses.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,12 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
static const gap = 20;

final ObservableList<BitcoinAddressRecord> _addresses;
late ObservableList<BaseBitcoinAddressRecord> addressesByReceiveType;
final ObservableList<BaseBitcoinAddressRecord> addressesByReceiveType;
final ObservableList<BitcoinAddressRecord> receiveAddresses;
final ObservableList<BitcoinAddressRecord> changeAddresses;
// TODO: add this variable in `bitcoin_wallet_addresses` and just add a cast in cw_bitcoin to use it
final ObservableList<BitcoinSilentPaymentAddressRecord> silentAddresses;
// TODO: add this variable in `litecoin_wallet_addresses` and just add a cast in cw_bitcoin to use it
final ObservableList<BitcoinAddressRecord> mwebAddresses;
final BasedUtxoNetwork network;
final Bip32Slip10Secp256k1 mainHd;
Expand Down
90 changes: 53 additions & 37 deletions cw_bitcoin/lib/litecoin_wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -236,16 +236,18 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
Future<void> waitForMwebAddresses() async {
// ensure that we have the full 1000 mweb addresses generated before continuing:
// should no longer be needed, but leaving here just in case
final mwebAddrs = (walletAddresses as LitecoinWalletAddresses).mwebAddrs;
while (mwebAddrs.length < 1000) {
print("waiting for mweb addresses to finish generating...");
await Future.delayed(const Duration(milliseconds: 1000));
}
// final mwebAddrs = (walletAddresses as LitecoinWalletAddresses).mwebAddrs;
// while (mwebAddrs.length < 1000) {
// print("waiting for mweb addresses to finish generating...");
// await Future.delayed(const Duration(milliseconds: 1000));
// }
await (walletAddresses as LitecoinWalletAddresses).ensureMwebAddressUpToIndexExists(1020);
}

@action
@override
Future<void> startSync() async {
print("startSync() called!");
if (syncStatus is SyncronizingSyncStatus) {
return;
}
Expand Down Expand Up @@ -289,45 +291,58 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
_syncTimer = Timer.periodic(const Duration(milliseconds: 1500), (timer) async {
if (syncStatus is FailedSyncStatus) return;

print("SYNCING....");

final nodeHeight =
await electrumClient.getCurrentBlockChainTip() ?? 0; // current block height of our node

if (nodeHeight == 0) {
// we aren't connected to the ltc node yet
if (syncStatus is! NotConnectedSyncStatus) {
syncStatus = FailedSyncStatus(error: "Failed to connect to Litecoin node");
}
return;
}

final resp = await CwMweb.status(StatusRequest());
print("resp.mwebUtxosHeight: ${resp.mwebUtxosHeight}");
print("resp.mwebHeaderHeight: ${resp.mwebHeaderHeight}");
print("resp.blockHeaderHeight: ${resp.blockHeaderHeight}");

if (resp.blockHeaderHeight < nodeHeight) {
int h = resp.blockHeaderHeight;
syncStatus = SyncingSyncStatus(nodeHeight - h, h / nodeHeight);
} else if (resp.mwebHeaderHeight < nodeHeight) {
int h = resp.mwebHeaderHeight;
syncStatus = SyncingSyncStatus(nodeHeight - h, h / nodeHeight);
} else if (resp.mwebUtxosHeight < nodeHeight) {
syncStatus = SyncingSyncStatus(1, 0.999);
} else {
if (resp.mwebUtxosHeight > walletInfo.restoreHeight) {
await walletInfo.updateRestoreHeight(resp.mwebUtxosHeight);
await checkMwebUtxosSpent();
// update the confirmations for each transaction:
for (final transaction in transactionHistory.transactions.values) {
if (transaction.isPending) continue;
int txHeight = transaction.height ?? resp.mwebUtxosHeight;
final confirmations = (resp.mwebUtxosHeight - txHeight) + 1;
if (transaction.confirmations == confirmations) continue;
transaction.confirmations = confirmations;
transactionHistory.addOne(transaction);

try {
if (resp.blockHeaderHeight < nodeHeight) {
int h = resp.blockHeaderHeight;
syncStatus = SyncingSyncStatus(nodeHeight - h, h / nodeHeight);
} else if (resp.mwebHeaderHeight < nodeHeight) {
int h = resp.mwebHeaderHeight;
syncStatus = SyncingSyncStatus(nodeHeight - h, h / nodeHeight);
} else if (resp.mwebUtxosHeight < nodeHeight) {
syncStatus = SyncingSyncStatus(1, 0.999);
} else {
if (resp.mwebUtxosHeight > walletInfo.restoreHeight) {
await walletInfo.updateRestoreHeight(resp.mwebUtxosHeight);
await checkMwebUtxosSpent();
// update the confirmations for each transaction:
for (final transaction in transactionHistory.transactions.values) {
if (transaction.isPending) continue;
int txHeight = transaction.height ?? resp.mwebUtxosHeight;
final confirmations = (resp.mwebUtxosHeight - txHeight) + 1;
if (transaction.confirmations == confirmations) continue;
transaction.confirmations = confirmations;
transactionHistory.addOne(transaction);
}
await transactionHistory.save();
}
await transactionHistory.save();
}

// prevent unnecessary reaction triggers:
if (syncStatus is! SyncedSyncStatus) {
// mwebd is synced, but we could still be processing incoming utxos:
if (!processingUtxos) {
syncStatus = SyncedSyncStatus();
// prevent unnecessary reaction triggers:
if (syncStatus is! SyncedSyncStatus) {
// mwebd is synced, but we could still be processing incoming utxos:
if (!processingUtxos) {
syncStatus = SyncedSyncStatus();
}
}
return;
}
return;
} catch (e) {
print("error syncing: $e");
syncStatus = FailedSyncStatus(error: e.toString());
}
});
}
Expand Down Expand Up @@ -411,6 +426,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
}

Future<void> handleIncoming(MwebUtxo utxo, RpcClient stub) async {
print("handleIncoming() called!");
final status = await stub.status(StatusRequest());
var date = DateTime.now();
var confirmations = 0;
Expand Down
30 changes: 23 additions & 7 deletions cw_bitcoin/lib/litecoin_wallet_addresses.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,9 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
await Future.delayed(Duration(milliseconds: 100));
}
}
}

Future<void> initMwebAddresses() async {
if (mwebAddrs.length < 1000) {
print("Generating MWEB addresses...");
await ensureMwebAddressUpToIndexExists(1020);
print("done generating MWEB addresses");
// ensure mweb addresses are up to date:
if (mwebAddresses.length < mwebAddrs.length) {
List<BitcoinAddressRecord> addressRecords = mwebAddrs
.asMap()
.entries
Expand All @@ -88,7 +84,27 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
))
.toList();
addMwebAddresses(addressRecords);
print("added ${addressRecords.length} mweb addresses");
print("set ${addressRecords.length} mweb addresses");
}
}

Future<void> initMwebAddresses() async {
if (mwebAddrs.length < 1000) {
print("Generating MWEB addresses...");
await ensureMwebAddressUpToIndexExists(20);
print("done generating MWEB addresses");
// List<BitcoinAddressRecord> addressRecords = mwebAddrs
// .asMap()
// .entries
// .map((e) => BitcoinAddressRecord(
// e.value,
// index: e.key,
// type: SegwitAddresType.mweb,
// network: network,
// ))
// .toList();
// addMwebAddresses(addressRecords);
// print("added ${addressRecords.length} mweb addresses");
return;
}
}
Expand Down
10 changes: 8 additions & 2 deletions cw_core/lib/sync_status.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,13 @@ class AttemptingScanSyncStatus extends SyncStatus {
double progress() => 0.0;
}

class FailedSyncStatus extends NotConnectedSyncStatus {}
class FailedSyncStatus extends NotConnectedSyncStatus {
String? error;
FailedSyncStatus({this.error});

@override
String toString() => error ?? super.toString();
}

class ConnectingSyncStatus extends SyncStatus {
@override
Expand All @@ -89,4 +95,4 @@ class TimedOutSyncStatus extends NotConnectedSyncStatus {
class LostConnectionSyncStatus extends NotConnectedSyncStatus {
@override
String toString() => 'Reconnecting';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class CwMwebPlugin: FlutterPlugin, MethodCallHandler {
if (call.method == "start") {
server?.stop()
val dataDir = call.argument("dataDir") ?: ""
server = server ?: Mwebd.newServer("", dataDir, "")
val nodeUri = call.argument("nodeUri") ?: ""
server = server ?: Mwebd.newServer("", dataDir, nodeUri)
port = server?.start(0)
result.success(port)
} else if (call.method == "stop") {
Expand Down
5 changes: 4 additions & 1 deletion cw_mweb/ios/Classes/CwMwebPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public static func register(with registrar: FlutterPluginRegistrar) {
private static var server: MwebdServer?
private static var port: Int = 0
private static var dataDir: String?
private static var nodeUri: String?

public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
Expand All @@ -22,7 +23,9 @@ public static func register(with registrar: FlutterPluginRegistrar) {
stopServer()
let args = call.arguments as? [String: String]
let dataDir = args?["dataDir"]
let nodeUri = args?["nodeUri"]
CwMwebPlugin.dataDir = dataDir
CwMwebPlugin.nodeUri = nodeUri
startServer(result: result)
break
case "stop":
Expand All @@ -48,7 +51,7 @@ public static func register(with registrar: FlutterPluginRegistrar) {
private func startServer(result: @escaping FlutterResult) {
if CwMwebPlugin.server == nil {
var error: NSError?
CwMwebPlugin.server = MwebdNewServer("", CwMwebPlugin.dataDir, "", &error)
CwMwebPlugin.server = MwebdNewServer("", CwMwebPlugin.dataDir, CwMwebPlugin.nodeUri, &error)

if let server = CwMwebPlugin.server {
do {
Expand Down
3 changes: 2 additions & 1 deletion cw_mweb/lib/cw_mweb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class CwMweb {
await Future.delayed(const Duration(seconds: 5));

final appDir = await getApplicationSupportDirectory();
_port = await CwMwebPlatform.instance.start(appDir.path);
const ltcNodeUri = "45.79.13.180:9333";
_port = await CwMwebPlatform.instance.start(appDir.path, ltcNodeUri);
if (_port == null || _port == 0) {
throw Exception("Failed to start server");
}
Expand Down
5 changes: 3 additions & 2 deletions cw_mweb/lib/cw_mweb_method_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ class MethodChannelCwMweb extends CwMwebPlatform {
final methodChannel = const MethodChannel('cw_mweb');

@override
Future<int?> start(String dataDir) async {
final result = await methodChannel.invokeMethod<int>('start', {'dataDir': dataDir});
Future<int?> start(String dataDir, String nodeUri) async {
final result =
await methodChannel.invokeMethod<int>('start', {'dataDir': dataDir, 'nodeUri': nodeUri});
return result;
}

Expand Down
2 changes: 1 addition & 1 deletion cw_mweb/lib/cw_mweb_platform_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ abstract class CwMwebPlatform extends PlatformInterface {
_instance = instance;
}

Future<int?> start(String dataDir) {
Future<int?> start(String dataDir, String nodeUri) {
throw UnimplementedError('start() has not been implemented.');
}

Expand Down
11 changes: 11 additions & 0 deletions lib/bitcoin/cw_bitcoin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -654,4 +654,15 @@ class CWBitcoin extends Bitcoin {
// TODO: this could be improved:
return inputAddressesContainMweb || outputAddressesContainMweb;
}

String? getUnusedMwebAddress(Object wallet) {
try {
final electrumWallet = wallet as ElectrumWallet;
final walletAddresses = electrumWallet.walletAddresses as ElectrumWalletAddresses;
final mwebAddress = walletAddresses.mwebAddresses.firstWhere((element) => !element.isUsed);
return mwebAddress.address;
} catch (_) {
return null;
}
}
}
11 changes: 7 additions & 4 deletions lib/core/sync_status_title.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ String syncStatusTitle(SyncStatus syncStatus) {
return S.current.sync_status_syncronized;
}

if (syncStatus is FailedSyncStatus) {
if (syncStatus.error != null) {
return syncStatus.error!;
}
return S.current.sync_status_failed_connect;
}

if (syncStatus is NotConnectedSyncStatus) {
return S.current.sync_status_not_connected;
}
Expand All @@ -24,10 +31,6 @@ String syncStatusTitle(SyncStatus syncStatus) {
return S.current.sync_status_attempting_sync;
}

if (syncStatus is FailedSyncStatus) {
return S.current.sync_status_failed_connect;
}

if (syncStatus is ConnectingSyncStatus) {
return S.current.sync_status_connecting;
}
Expand Down
Loading

0 comments on commit 37b822b

Please sign in to comment.