What changed, and why it matters
This commit changes how the Stack Wallet app handles a helper program called mwebd on Windows. Instead of using a built-in library, it now extracts a separate mwebd.exe file from the app bundle, writes it to disk, checks its SHA256 hash, and runs it as a standalone process. The change also updates build instructions and dependency versions. There is no claim in the commit that this fixes a security issue, but the new code introduces a few security-relevant patterns worth reviewing: it executes a bundled binary, relies on a compile-time hash check, and uses a dynamic object wrapper to hide platform-specific server types.
Review the build script's supply-chain exposure: it clones an external GitHub repo at a fixed tag during the build and cross-compiles a binary that is later bundled and hash-checked. Verify that the SHA256 is generated and embedded in a reproducible, tamper-evident way and that the runtime extraction path is not writable by other users. Audit the argument passing to mwebd.exe for shell injection or path-traversal risks, and confirm the DynamicObject type checks cannot be bypassed to call methods on the wrong underlying object. Treat this as a routine defensive review, not as a confirmed vulnerability.
Security signals we found
Execution of a bundled, cross-compiled native binary (mwebd.exe) extracted from app assets at runtime.
SHA256 hash verification of the extracted binary against a compile-time constant before execution.
Use of runInShell: true and wsl/cmd invocations in the build script, plus git clone of an external repository during the build.
Dynamic typing via DynamicObject to store platform-specific server handles, replacing a typed OpaqueMwebdServer wrapper.
No vendor statement in commit or references that this is a security fix; appears to be a build/runtime architecture change.
Evidence from the diff
The patch adds a standalone Windows mwebd build path. A new tool script (tool/build_standalone_mwebd_windows.dart) clones ltcmweb/mwebd v0.1.8 and cross-compiles mwebd.exe. The configure_stack_wallet.sh script records the resulting SHA256 into app_config.dart as windowsMwebdExeHash. At runtime, the generated MWEBD_mwebd_server_interface_impl.template.dart extracts assets/windows/mwebd.exe to the application mwebd directory, verifies its SHA256 against the compile-time constant, then starts it as a subprocess with chain/dataDir/listen/peer/proxy arguments. On non-Windows platforms the existing in-process flutter_mwebd server path remains. The OpaqueMwebdServer type is replaced by a new DynamicObject wrapper so the map can hold either a MwebdServer object or a (Process, MwebdServer) tuple. Status polling is changed to use the mweb_client package’s StatusRequest/StatusResponse instead of the server interface’s getServerStatus.
Changed components
lib/services/mwebd_service.dartlib/wl_gen/interfaces/mwebd_server_interface.darttool/build_standalone_mwebd_windows.darttool/wl_templates/MWEBD_mwebd_server_interface_impl.template.dartscripts/app_config/configure_stack_wallet.shlib/app_config.dartlib/utilities/dynamic_object.dartInspect captured patch +269 / −103
diff --git a/.gitignore b/.gitignore
index 0a8db4d..04721dd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -122,3 +122,6 @@ lib/wl_gen/generated/
/linux/flutter/generated_plugins.cmake
/windows/flutter/generated_plugins.cmake
/macos/Flutter/GeneratedPluginRegistrant.swift
+
+/assets/windows/mwebd.exe
+/tool/build
diff --git a/docs/building.md b/docs/building.md
index 6aa647e..41df95b 100644
--- a/docs/building.md
+++ b/docs/building.md
@@ -4,7 +4,7 @@ Here you will find instructions on how to install the necessary tools for buildi
## Prerequisites
-- The only OS supported for building Android and Linux desktop is Ubuntu 20.04. Windows builds require using Ubuntu 20.04 on WSL2. macOS builds for itself and iOS. Advanced users may also be able to build on other Debian-based distributions like Linux Mint.
+- The only OS supported for building Android and Linux desktop is Ubuntu 24.04. Windows builds require using Ubuntu 24.04 on WSL2. macOS builds for itself and iOS. Advanced users may also be able to build on other Debian-based distributions like Linux Mint.
- Android setup ([Android Studio](https://developer.android.com/studio) and subsequent dependencies)
- 100 GB of storage
- Install go: [https://go.dev/doc/install](https://go.dev/doc/install)
@@ -77,12 +77,12 @@ pip3 install --upgrade meson==0.64.1 markdown==3.4.1 markupsafe==2.1.1 jinja2==3
```
### Flutter
-Install Flutter 3.29.2 by [following their guide](https://docs.flutter.dev/get-started/install/linux/desktop?tab=download#install-the-flutter-sdk). You can also clone https://github.com/flutter/flutter, check out the `3.29.2` tag, and add its `flutter/bin` folder to your PATH as in
+Install Flutter 3.35.7 by [following their guide](https://docs.flutter.dev/get-started/install/linux/desktop?tab=download#install-the-flutter-sdk). You can also clone https://github.com/flutter/flutter, check out the `3.35.7` tag, and add its `flutter/bin` folder to your PATH as in
```sh
FLUTTER_DIR="$HOME/development/flutter"
git clone https://github.com/flutter/flutter.git "$FLUTTER_DIR"
cd "$FLUTTER_DIR"
-git checkout 3.29.2
+git checkout 3.35.7
echo 'export PATH="$PATH:'"$FLUTTER_DIR"'/bin"' >> "$HOME/.profile"
source "$HOME/.profile"
flutter precache
@@ -165,6 +165,7 @@ cd scripts/windows
```
install go in WSL [https://go.dev/doc/install](https://go.dev/doc/install) (follow linux instructions) and ensure you have `x86_64-w64-mingw32-gcc`
+go version should be at least 1.24
and use `scripts/build_app.sh` to build plugins:
```
@@ -292,13 +293,13 @@ If the DLLs were built on the WSL filesystem instead of on Windows, copy the res
Frostdart will be built by the Windows host later.
### Install Flutter on Windows host
-Install Flutter 3.29.2 on your Windows host (not in WSL2) by [following their guide](https://docs.flutter.dev/get-started/install/windows/desktop?tab=download#install-the-flutter-sdk) or by cloning https://github.com/flutter/flutter, checking out the `3.29.2` tag, and adding its `flutter/bin` folder to your PATH as in
+Install Flutter 3.35.7 on your Windows host (not in WSL2) by [following their guide](https://docs.flutter.dev/get-started/install/windows/desktop?tab=download#install-the-flutter-sdk) or by cloning https://github.com/flutter/flutter, checking out the `3.35.7` tag, and adding its `flutter/bin` folder to your PATH as in
```bat
@echo off
set "FLUTTER_DIR=%USERPROFILE%\development\flutter"
git clone https://github.com/flutter/flutter.git "%FLUTTER_DIR%"
cd /d "%FLUTTER_DIR%"
-git checkout 3.29.2
+git checkout 3.35.7
setx PATH "%PATH%;%FLUTTER_DIR%\bin"
echo Flutter setup completed. Please restart your command prompt.
```
diff --git a/lib/app_config.dart b/lib/app_config.dart
index 3004413..ab5d1da 100644
--- a/lib/app_config.dart
+++ b/lib/app_config.dart
@@ -16,6 +16,8 @@ abstract class AppConfig {
static const emptyWalletsMessage = _emptyWalletsMessage;
+ static const windowsMwebdExeHash = _mwebdExeHash;
+
static String get appDefaultDataDirName => _appDataDirName;
static String get shortDescriptionText => _shortDescriptionText;
static String get commitHash => _commitHash;
diff --git a/lib/services/mwebd_service.dart b/lib/services/mwebd_service.dart
index 2462257..a3c2194 100644
--- a/lib/services/mwebd_service.dart
+++ b/lib/services/mwebd_service.dart
@@ -6,6 +6,7 @@ import 'dart:math';
import 'package:mutex/mutex.dart';
import 'package:mweb_client/mweb_client.dart';
+import '../utilities/dynamic_object.dart';
import '../utilities/logger.dart';
import '../utilities/prefs.dart';
import '../utilities/stack_file_system.dart';
@@ -24,10 +25,7 @@ final class MwebdService {
CryptoCurrencyNetwork.test4 => throw UnimplementedError(),
};
- final Map<
- CryptoCurrencyNetwork,
- ({OpaqueMwebdServer server, MwebClient client})
- >
+ final Map<CryptoCurrencyNetwork, ({DynamicObject server, MwebClient client})>
_map = {};
late final StreamSubscription<TorConnectionStatusChangedEvent>
@@ -178,9 +176,9 @@ final class MwebdService {
}
/// Get server status. Returns null if no server was initialized.
- Future<Status?> getServerStatus(CryptoCurrencyNetwork net) {
- return _updateLock.protect(() {
- return mwebdServerInterface.getServerStatus(_map[net]?.server);
+ Future<StatusResponse?> getServerStatus(CryptoCurrencyNetwork net) {
+ return _updateLock.protect(() async {
+ return _map[net]?.client.status(StatusRequest());
});
}
diff --git a/lib/utilities/dynamic_object.dart b/lib/utilities/dynamic_object.dart
new file mode 100644
index 0000000..bbb7728
--- /dev/null
+++ b/lib/utilities/dynamic_object.dart
@@ -0,0 +1,25 @@
+class DynamicObjectTypeException implements Exception {
+ final Type actual, expected;
+
+ DynamicObjectTypeException({required this.actual, required this.expected});
+
+ @override
+ String toString() =>
+ "DynamicObjectException: Found $actual, expected $expected";
+}
+
+class DynamicObject {
+ final Object _value;
+
+ DynamicObject(this._value);
+
+ T get<T>() {
+ if (_value is T) return _value as T;
+ throw DynamicObjectTypeException(actual: _value.runtimeType, expected: T);
+ }
+
+ T? getIfMatch<T>() {
+ if (_value is T) return _value as T;
+ return null;
+ }
+}
diff --git a/lib/wl_gen/interfaces/mwebd_server_interface.dart b/lib/wl_gen/interfaces/mwebd_server_interface.dart
index 8b597d0..451a96d 100644
--- a/lib/wl_gen/interfaces/mwebd_server_interface.dart
+++ b/lib/wl_gen/interfaces/mwebd_server_interface.dart
@@ -1,3 +1,4 @@
+import '../../utilities/dynamic_object.dart';
import '../../wallets/crypto_currency/crypto_currency.dart';
export '../generated/mwebd_server_interface_impl.dart';
@@ -5,7 +6,7 @@ export '../generated/mwebd_server_interface_impl.dart';
abstract class MwebdServerInterface {
const MwebdServerInterface();
- Future<({OpaqueMwebdServer server, int port})> createAndStartServer(
+ Future<({DynamicObject server, int port})> createAndStartServer(
CryptoCurrencyNetwork net, {
required String chain,
required String dataDir,
@@ -15,58 +16,6 @@ abstract class MwebdServerInterface {
});
Future<({String chain, String dataDir, String peer})> stopServer(
- OpaqueMwebdServer server,
+ DynamicObject server,
);
-
- Future<Status?> getServerStatus(OpaqueMwebdServer? server);
-}
-
-// local copy
-class Status {
- final int blockHeaderHeight;
- final int mwebHeaderHeight;
- final int mwebUtxosHeight;
- final int blockTime;
-
- Status({
- required this.blockHeaderHeight,
- required this.mwebHeaderHeight,
- required this.mwebUtxosHeight,
- required this.blockTime,
- });
-
- @override
- String toString() {
- return 'Status('
- 'blockHeaderHeight: $blockHeaderHeight, '
- 'mwebHeaderHeight: $mwebHeaderHeight, '
- 'mwebUtxosHeight: $mwebUtxosHeight, '
- 'blockTime: $blockTime'
- ')';
- }
-
- @override
- bool operator ==(Object other) =>
- identical(this, other) ||
- other is Status &&
- blockHeaderHeight == other.blockHeaderHeight &&
- mwebHeaderHeight == other.mwebHeaderHeight &&
- mwebUtxosHeight == other.mwebUtxosHeight &&
- blockTime == other.blockTime;
-
- @override
- int get hashCode => Object.hash(
- blockHeaderHeight,
- mwebHeaderHeight,
- mwebUtxosHeight,
- blockTime,
- );
-}
-
-final class OpaqueMwebdServer {
- final Object _value;
-
- const OpaqueMwebdServer(this._value);
-
- T get<T>() => _value as T;
}
diff --git a/pubspec.lock b/pubspec.lock
index 8dca524..d308938 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -623,10 +623,10 @@ packages:
dependency: "direct main"
description:
name: cs_wownero_flutter_libs
- sha256: "68b6c682c6cce0915418aa6b01b137ef77652932f8b3fb1bc868bfd20d15c562"
+ sha256: ba1156d015a9f75c841f927ff2ce6565cd7cd37f15aaedd9aaf36703453a9884
url: "https://pub.dev"
source: hosted
- version: "2.0.0"
+ version: "2.0.3"
cs_wownero_flutter_libs_android:
dependency: transitive
description:
@@ -663,18 +663,18 @@ packages:
dependency: transitive
description:
name: cs_wownero_flutter_libs_ios
- sha256: f80dd0164902565d4fd0058da5be446a3ea5eaee2ca8651289a35d7fc93f3ca4
+ sha256: "9ffd158469a0a45668d89ce56b90e846dd823ffd44ee6997b50b76129e6f613c"
url: "https://pub.dev"
source: hosted
- version: "1.2.0"
+ version: "1.3.0"
cs_wownero_flutter_libs_linux:
dependency: transitive
description:
name: cs_wownero_flutter_libs_linux
- sha256: b60a700f0ef676405bfa67793fb7431f7d2ffbaccc1f6ad69001da0c2e0a07b0
+ sha256: "441c9a7b28e28434942709915e6a54ea2392b3261f90c116e03b27b02fce7492"
url: "https://pub.dev"
source: hosted
- version: "1.2.0"
+ version: "1.4.0"
cs_wownero_flutter_libs_macos:
dependency: transitive
description:
diff --git a/scripts/app_config/configure_campfire.sh b/scripts/app_config/configure_campfire.sh
index 04054b9..e12697b 100755
--- a/scripts/app_config/configure_campfire.sh
+++ b/scripts/app_config/configure_campfire.sh
@@ -63,6 +63,8 @@ const _appDataDirName = "campfire";
const _shortDescriptionText = "Your privacy. Your wallet. Your Firo.";
const _commitHash = "$BUILT_COMMIT_HASH";
+const _mwebdExeHash = "";
+
const Set<AppFeature> _features = {
AppFeature.tor,
AppFeature.swap
diff --git a/scripts/app_config/configure_stack_duo.sh b/scripts/app_config/configure_stack_duo.sh
index 148775a..c410a18 100755
--- a/scripts/app_config/configure_stack_duo.sh
+++ b/scripts/app_config/configure_stack_duo.sh
@@ -59,6 +59,8 @@ const _appDataDirName = "stackduo";
const _shortDescriptionText = "An open-source, multicoin wallet for everyone";
const _commitHash = "$BUILT_COMMIT_HASH";
+const _mwebdExeHash = "";
+
const Set<AppFeature> _features = {
AppFeature.themeSelection,
AppFeature.buy,
diff --git a/scripts/app_config/configure_stack_wallet.sh b/scripts/app_config/configure_stack_wallet.sh
index 0ec22f5..3de44a6 100755
--- a/scripts/app_config/configure_stack_wallet.sh
+++ b/scripts/app_config/configure_stack_wallet.sh
@@ -50,6 +50,16 @@ dart "${APP_PROJECT_ROOT_DIR}/tool/gen_interfaces.dart" \
XEL \
FROST
+
+MWEBD_EXE_SHA256=""
+if [[ "$1" == "windows" ]]; then
+ dart "${APP_PROJECT_ROOT_DIR}/tool/build_standalone_mwebd_windows.dart"
+ MWEBD_EXE_SHA256="$(sha256sum "${APP_PROJECT_ROOT_DIR}/assets/windows/mwebd.exe" | awk '{print $1}')"
+ dart "${APP_PROJECT_ROOT_DIR}/tool/process_pubspec_deps.dart" \
+ "${PUBSPEC_FILE}" MWEBDEXE
+fi
+
+
export INCLUDE_EPIC_SO="ON"
export INCLUDE_MWC_SO="ON"
@@ -73,6 +83,8 @@ const _appDataDirName = "stackwallet";
const _shortDescriptionText = "An open-source, multicoin wallet for everyone";
const _commitHash = "$BUILT_COMMIT_HASH";
+const _mwebdExeHash = "$MWEBD_EXE_SHA256";
+
const Set<AppFeature> _features = {
AppFeature.themeSelection,
AppFeature.buy,
diff --git a/scripts/app_config/templates/pubspec.template.yaml b/scripts/app_config/templates/pubspec.template.yaml
index e225a20..b627779 100644
--- a/scripts/app_config/templates/pubspec.template.yaml
+++ b/scripts/app_config/templates/pubspec.template.yaml
@@ -388,6 +388,10 @@ flutter:
# default themes_testing
- assets/default_themes/
+# %%ENABLE_MWEBDEXE%%
+# - assets/windows/mwebd.exe
+# %%END_ENABLE_MWEBDEXE%%
+
import_sorter:
comments: false # Optional, defaults to true
ignored_files: # Optional, defaults to []
diff --git a/test/utilities/dynamic_object_test.dart b/test/utilities/dynamic_object_test.dart
new file mode 100644
index 0000000..9999bf0
--- /dev/null
+++ b/test/utilities/dynamic_object_test.dart
@@ -0,0 +1,23 @@
+import 'package:flutter_test/flutter_test.dart';
+import 'package:stackwallet/utilities/dynamic_object.dart';
+
+void main() {
+ test("DynamicObject get success", () {
+ final object = DynamicObject(1);
+ expect(object.get<int>(), isA<int>());
+ });
+
+ test("DynamicObject get failure", () {
+ final object = DynamicObject(1);
+ expect(object.get<String>(), throwsA(isA<DynamicObjectTypeException>()));
+ });
+ test("DynamicObject get if match success", () {
+ final object = DynamicObject(1);
+ expect(object.getIfMatch<int>(), isA<int?>());
+ });
+
+ test("DynamicObject get if match failure", () {
+ final object = DynamicObject(1);
+ expect(object.getIfMatch<String>(), isNull);
+ });
+}
diff --git a/tool/build_standalone_mwebd_windows.dart b/tool/build_standalone_mwebd_windows.dart
new file mode 100644
index 0000000..b956e4f
--- /dev/null
+++ b/tool/build_standalone_mwebd_windows.dart
@@ -0,0 +1,99 @@
+import 'dart:io';
+
+Future<void> main() async {
+ final projectToolDir = File(() {
+ String path = Platform.script.path;
+ if (Platform.isWindows) {
+ while (!path.startsWith("C:")) {
+ path = path.substring(1);
+ }
+ }
+ return path;
+ }()).parent;
+
+ // setup temp build dir
+ final tempBuildDir = Directory(
+ "${projectToolDir.path}"
+ "${Platform.pathSeparator}build",
+ );
+ if (await tempBuildDir.exists()) {
+ await tempBuildDir.delete(recursive: true);
+ }
+ await tempBuildDir.create();
+
+ // change working dir and clone mwebd
+ Directory.current = tempBuildDir;
+ final clone = await Process.start("git", [
+ "clone",
+ "https://www.github.com/ltcmweb/mwebd.git",
+ "--branch",
+ "v0.1.8",
+ ], runInShell: true);
+ await _waitForProcess(clone);
+
+ // change working dir and build mwebd.exe
+ Directory.current = Directory(
+ "${tempBuildDir.path}"
+ "${Platform.pathSeparator}mwebd",
+ );
+ final wslBuild = Platform.isWindows
+ ? await Process.start("wsl", [
+ "bash",
+ "-l",
+ "-c",
+ "GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc "
+ "go build -o ../mwebd.exe github.com/ltcmweb/mwebd/cmd/mwebd",
+ ], runInShell: true)
+ : await Process.start(
+ "go",
+ ["build", "-o", "../mwebd.exe", "github.com/ltcmweb/mwebd/cmd/mwebd"],
+ environment: {
+ "GOOS": "windows",
+ "GOARCH": "amd64",
+ "CGO_ENABLED": "1",
+ "CC": "x86_64-w64-mingw32-gcc",
+ },
+ runInShell: true,
+ );
+ await _waitForProcess(wslBuild);
+
+ // create assets/windows dir if needed
+ final winAssetsDir = Directory(
+ "${Directory.current.parent.parent.parent.path}"
+ "${Platform.pathSeparator}assets"
+ "${Platform.pathSeparator}windows",
+ );
+ if (!(await winAssetsDir.exists())) {
+ await winAssetsDir.create();
+ }
+
+ // copy the build mwebd.exe to assets/windows
+ final copy = Platform.isWindows
+ ? await Process.start("cmd", [
+ "/C",
+ "copy",
+ "${Directory.current.parent.path}"
+ "${Platform.pathSeparator}mwebd.exe",
+ "${winAssetsDir.path}"
+ "${Platform.pathSeparator}mwebd.exe",
+ ])
+ : await Process.start("cp", [
+ "${Directory.current.parent.path}"
+ "${Platform.pathSeparator}mwebd.exe",
+ "${winAssetsDir.path}"
+ "${Platform.pathSeparator}mwebd.exe",
+ ]);
+ await _waitForProcess(copy);
+
+ // cleanup
+ Directory.current = projectToolDir;
+ await tempBuildDir.delete(recursive: true);
+}
+
+Future<void> _waitForProcess(Process process) async {
+ final exitCode = await process.exitCode;
+ if (exitCode != 0) {
+ print("Exited process with code=$exitCode\n${StackTrace.current}");
+ exit(exitCode);
+ }
+}
diff --git a/tool/wl_templates/MWEBD_mwebd_server_interface_impl.template.dart b/tool/wl_templates/MWEBD_mwebd_server_interface_impl.template.dart
index 55ba2c6..4098f8a 100644
--- a/tool/wl_templates/MWEBD_mwebd_server_interface_impl.template.dart
+++ b/tool/wl_templates/MWEBD_mwebd_server_interface_impl.template.dart
@@ -1,7 +1,17 @@
//ON
-import 'package:flutter_mwebd/flutter_mwebd.dart' hide Status;
+import 'dart:async';
+import 'dart:io';
+import 'package:crypto/crypto.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_mwebd/flutter_mwebd.dart';
+import 'package:path/path.dart';
+
+import '../../app_config.dart';
//END_ON
+import '../../utilities/dynamic_object.dart';
+import '../../utilities/extensions/extensions.dart';
+import '../../utilities/stack_file_system.dart';
import '../../wallets/crypto_currency/crypto_currency.dart';
import '../interfaces/mwebd_server_interface.dart';
@@ -14,15 +24,36 @@ MwebdServerInterface _getInterface() => throw Exception("MWEBD not enabled!");
//ON
MwebdServerInterface _getInterface() => const _MwebdServerInterfaceImpl();
-extension _OpaqueMwebdServerExt on OpaqueMwebdServer {
- MwebdServer get value => get();
-}
-
class _MwebdServerInterfaceImpl extends MwebdServerInterface {
const _MwebdServerInterfaceImpl();
+ static const _kExe = "mwebd.exe";
+
+ Future<String> _prepareWindowsExeDirPath() async {
+ final dir = (await StackFileSystem.applicationMwebdDirectory(
+ "dummy",
+ )).parent.path;
+ final exe = File(join(dir, _kExe));
+
+ if (!(await exe.exists())) {
+ final bytes = await rootBundle.load("assets/windows/mwebd.exe");
+ await exe.writeAsBytes(
+ bytes.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes),
+ flush: true,
+ );
+ }
+
+ final hash = await sha256.bind(exe.openRead()).first;
+ final hexHash = Uint8List.fromList(hash.bytes).toHex;
+ if (AppConfig.windowsMwebdExeHash != hexHash) {
+ throw Exception("Windows mwebd.exe sha256 has mismatch!!!");
+ }
+
+ return exe.parent.path;
+ }
+
@override
- Future<({OpaqueMwebdServer server, int port})> createAndStartServer(
+ Future<({DynamicObject server, int port})> createAndStartServer(
CryptoCurrencyNetwork net, {
required String chain,
required String dataDir,
@@ -37,36 +68,51 @@ class _MwebdServerInterfaceImpl extends MwebdServerInterface {
proxy: proxy,
serverPort: serverPort,
);
- await newServer.createServer();
- await newServer.startServer();
- return (server: OpaqueMwebdServer(newServer), port: newServer.serverPort);
+
+ if (Platform.isWindows) {
+ final exeDirPath = await _prepareWindowsExeDirPath();
+ final process = await Process.start(join(exeDirPath, _kExe), [
+ "-c",
+ chain,
+ "-d",
+ chain,
+ "-l",
+ "127.0.0.1:$serverPort",
+ "-p",
+ peer,
+ "-proxy",
+ proxy,
+ ], workingDirectory: exeDirPath);
+ return (server: DynamicObject((process, newServer)), port: serverPort);
+ } else {
+ await newServer.createServer();
+ await newServer.startServer();
+ return (server: DynamicObject(newServer), port: newServer.serverPort);
+ }
}
@override
Future<({String chain, String dataDir, String peer})> stopServer(
- OpaqueMwebdServer server,
+ DynamicObject server,
) async {
- final actual = server.value;
- final data = (
- chain: actual.chain,
- dataDir: actual.dataDir,
- peer: actual.peer,
- );
- await actual.stopServer();
- return data;
- }
-
- @override
- Future<Status?> getServerStatus(OpaqueMwebdServer? server) async {
- final status = await server?.value.getStatus();
- if (status == null) return null;
-
- return Status(
- blockHeaderHeight: status.blockHeaderHeight,
- mwebHeaderHeight: status.mwebHeaderHeight,
- mwebUtxosHeight: status.mwebUtxosHeight,
- blockTime: status.blockTime,
- );
+ if (server.get<Object>() is (Process, MwebdServer)) {
+ final actual = server.get<(Process, MwebdServer)>();
+ actual.$1.kill();
+ return (
+ chain: actual.$2.chain,
+ dataDir: actual.$2.dataDir,
+ peer: actual.$2.peer,
+ );
+ } else {
+ final actual = server.get<MwebdServer>();
+ final data = (
+ chain: actual.chain,
+ dataDir: actual.dataDir,
+ peer: actual.peer,
+ );
+ await actual.stopServer();
+ return data;
+ }
}
}
Why this scored 35/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.