diff --git a/.gitignore b/.gitignore index de5bb22..1ffa656 100644 --- a/.gitignore +++ b/.gitignore @@ -28,10 +28,6 @@ doc/api/ .idea/ -lib/git_versions.dart - # Ignore build artifacts. -scripts/*/cache/ -scripts/*/sparkmobile -scripts/*/CMakeLists/sparkmobile/CMakeLists.txt -scripts/*/CMakeLists/secp256k1/CMakeLists.txt +src/build +src/deps/sparkmobile diff --git a/.gitmodules b/.gitmodules index 106ded7..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "sparkmobile"] - path = sparkmobile - url = https://github.com/firoorg/sparkmobile diff --git a/android/build.gradle b/android/build.gradle index 5b34770..5e16d23 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,20 +1,21 @@ +// The Android Gradle Plugin builds the native code with the Android NDK. + group 'com.cypherstack.flutter_libsparkmobile' -version '1.0-SNAPSHOT' +version '1.0' buildscript { - ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() } dependencies { + // The Android Gradle Plugin knows how to build native code with the NDK. classpath 'com.android.tools.build:gradle:7.3.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } -allprojects { +rootProject.allprojects { repositories { google() mavenCentral() @@ -22,43 +23,37 @@ allprojects { } apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' android { + // Bumping the plugin compileSdkVersion requires all clients of this plugin + // to bump the version in their app. compileSdkVersion 31 + // Bumping the plugin ndkVersion requires all clients of this plugin to bump + // the version in their app and to download a newer version of the NDK. + ndkVersion "23.1.7779620" + + // Invoke the shared CMake build with the Android Gradle Plugin. + externalNativeBuild { + cmake { + path "../src/CMakeLists.txt" + + // The default CMake version for the Android Gradle Plugin is 3.10.2. + // https://developer.android.com/studio/projects/install-ndk#vanilla_cmake + // + // The Flutter tooling requires that developers have CMake 3.10 or later + // installed. You should not increase this version, as doing so will cause + // the plugin to fail to compile for some customers of the plugin. + // version "3.10.2" + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - test.java.srcDirs += 'src/test/kotlin' - } - defaultConfig { minSdkVersion 16 } - - dependencies { - testImplementation 'org.jetbrains.kotlin:kotlin-test' - testImplementation 'org.mockito:mockito-core:5.0.0' - } - - testOptions { - unitTests.all { - useJUnitPlatform() - - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true - } - } - } } diff --git a/android/src/main/kotlin/com/cypherstack/flutter_libsparkmobile/FlutterLibsparkmobilePlugin.kt b/android/src/main/kotlin/com/cypherstack/flutter_libsparkmobile/FlutterLibsparkmobilePlugin.kt deleted file mode 100644 index d5caa06..0000000 --- a/android/src/main/kotlin/com/cypherstack/flutter_libsparkmobile/FlutterLibsparkmobilePlugin.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.cypherstack.flutter_libsparkmobile - -import androidx.annotation.NonNull - -import io.flutter.embedding.engine.plugins.FlutterPlugin -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import io.flutter.plugin.common.MethodChannel.MethodCallHandler -import io.flutter.plugin.common.MethodChannel.Result - -/** FlutterLibsparkmobilePlugin */ -class FlutterLibsparkmobilePlugin: FlutterPlugin, MethodCallHandler { - /// The MethodChannel that will the communication between Flutter and native Android - /// - /// This local reference serves to register the plugin with the Flutter Engine and unregister it - /// when the Flutter Engine is detached from the Activity - private lateinit var channel : MethodChannel - - override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { - channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_libsparkmobile") - channel.setMethodCallHandler(this) - } - - override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { - if (call.method == "getPlatformVersion") { - result.success("Android ${android.os.Build.VERSION.RELEASE}") - } else { - result.notImplemented() - } - } - - override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { - channel.setMethodCallHandler(null) - } -} diff --git a/android/src/test/kotlin/com/cypherstack/flutter_libsparkmobile/FlutterLibsparkmobilePluginTest.kt b/android/src/test/kotlin/com/cypherstack/flutter_libsparkmobile/FlutterLibsparkmobilePluginTest.kt deleted file mode 100644 index 6680e9d..0000000 --- a/android/src/test/kotlin/com/cypherstack/flutter_libsparkmobile/FlutterLibsparkmobilePluginTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.cypherstack.flutter_libsparkmobile - -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import kotlin.test.Test -import org.mockito.Mockito - -/* - * This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation. - * - * Once you have built the plugin's example app, you can run these tests from the command - * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or - * you can run them directly from IDEs that support JUnit such as Android Studio. - */ - -internal class FlutterLibsparkmobilePluginTest { - @Test - fun onMethodCall_getPlatformVersion_returnsExpectedValue() { - val plugin = FlutterLibsparkmobilePlugin() - - val call = MethodCall("getPlatformVersion", null) - val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java) - plugin.onMethodCall(call, mockResult) - - Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE) - } -} diff --git a/example/ios/RunnerTests/RunnerTests.swift b/example/ios/RunnerTests/RunnerTests.swift index 80121f3..86a7c3b 100644 --- a/example/ios/RunnerTests/RunnerTests.swift +++ b/example/ios/RunnerTests/RunnerTests.swift @@ -2,25 +2,11 @@ import Flutter import UIKit import XCTest -@testable import flutter_libsparkmobile - -// This demonstrates a simple unit test of the Swift portion of this plugin's implementation. -// -// See https://developer.apple.com/documentation/xctest for more information about using XCTest. - class RunnerTests: XCTestCase { - func testGetPlatformVersion() { - let plugin = FlutterLibsparkmobilePlugin() - - let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: []) - - let resultExpectation = expectation(description: "result block must be called.") - plugin.handle(call) { result in - XCTAssertEqual(result as! String, "iOS " + UIDevice.current.systemVersion) - resultExpectation.fulfill() - } - waitForExpectations(timeout: 1) + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. } } diff --git a/example/linux/CMakeLists.txt b/example/linux/CMakeLists.txt index c04c15e..698aa1c 100644 --- a/example/linux/CMakeLists.txt +++ b/example/linux/CMakeLists.txt @@ -86,8 +86,6 @@ set_target_properties(${BINARY_NAME} RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" ) -# Enable the test target. -set(include_flutter_libsparkmobile_tests TRUE) # Generated plugin build rules, which manage building the plugins and adding # them to the application. @@ -119,10 +117,6 @@ install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR} install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) -install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/linux/build/libsparkmobile.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -# Must have ran build script(s) in order for this library to exist. - foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) install(FILES "${bundled_library}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" diff --git a/example/linux/flutter/generated_plugin_registrant.cc b/example/linux/flutter/generated_plugin_registrant.cc index 5ed4ab0..e71a16d 100644 --- a/example/linux/flutter/generated_plugin_registrant.cc +++ b/example/linux/flutter/generated_plugin_registrant.cc @@ -6,10 +6,6 @@ #include "generated_plugin_registrant.h" -#include void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) flutter_libsparkmobile_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterLibsparkmobilePlugin"); - flutter_libsparkmobile_plugin_register_with_registrar(flutter_libsparkmobile_registrar); } diff --git a/example/linux/flutter/generated_plugins.cmake b/example/linux/flutter/generated_plugins.cmake index 5fcfe4f..bfd0f0a 100644 --- a/example/linux/flutter/generated_plugins.cmake +++ b/example/linux/flutter/generated_plugins.cmake @@ -3,11 +3,11 @@ # list(APPEND FLUTTER_PLUGIN_LIST - flutter_libsparkmobile ) list(APPEND FLUTTER_FFI_PLUGIN_LIST coinlib_flutter + flutter_libsparkmobile ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 67bb95b..cccf817 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,8 +5,6 @@ import FlutterMacOS import Foundation -import flutter_libsparkmobile func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - FlutterLibsparkmobilePlugin.register(with: registry.registrar(forPlugin: "FlutterLibsparkmobilePlugin")) } diff --git a/example/macos/RunnerTests/RunnerTests.swift b/example/macos/RunnerTests/RunnerTests.swift index d277d02..5418c9f 100644 --- a/example/macos/RunnerTests/RunnerTests.swift +++ b/example/macos/RunnerTests/RunnerTests.swift @@ -2,26 +2,11 @@ import FlutterMacOS import Cocoa import XCTest -@testable import flutter_libsparkmobile - -// This demonstrates a simple unit test of the Swift portion of this plugin's implementation. -// -// See https://developer.apple.com/documentation/xctest for more information about using XCTest. - class RunnerTests: XCTestCase { - func testGetPlatformVersion() { - let plugin = FlutterLibsparkmobilePlugin() - - let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: []) - - let resultExpectation = expectation(description: "result block must be called.") - plugin.handle(call) { result in - XCTAssertEqual(result as! String, - "macOS " + ProcessInfo.processInfo.operatingSystemVersionString) - resultExpectation.fulfill() - } - waitForExpectations(timeout: 1) + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. } } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 97408a7..33f71d8 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -4,6 +4,20 @@ description: Demonstrates how to use the flutter_libsparkmobile plugin. # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + environment: sdk: '>=3.0.6 <4.0.0' diff --git a/example/windows/CMakeLists.txt b/example/windows/CMakeLists.txt index 1e2dfb5..65aa5fa 100644 --- a/example/windows/CMakeLists.txt +++ b/example/windows/CMakeLists.txt @@ -52,8 +52,6 @@ add_subdirectory(${FLUTTER_MANAGED_DIR}) # Application build; see runner/CMakeLists.txt. add_subdirectory("runner") -# Enable the test target. -set(include_flutter_libsparkmobile_tests TRUE) # Generated plugin build rules, which manage building the plugins and adding # them to the application. diff --git a/example/windows/flutter/generated_plugin_registrant.cc b/example/windows/flutter/generated_plugin_registrant.cc index b533861..8b6d468 100644 --- a/example/windows/flutter/generated_plugin_registrant.cc +++ b/example/windows/flutter/generated_plugin_registrant.cc @@ -6,9 +6,6 @@ #include "generated_plugin_registrant.h" -#include void RegisterPlugins(flutter::PluginRegistry* registry) { - FlutterLibsparkmobilePluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("FlutterLibsparkmobilePluginCApi")); } diff --git a/example/windows/flutter/generated_plugins.cmake b/example/windows/flutter/generated_plugins.cmake index 1db7564..91a9b4f 100644 --- a/example/windows/flutter/generated_plugins.cmake +++ b/example/windows/flutter/generated_plugins.cmake @@ -3,10 +3,10 @@ # list(APPEND FLUTTER_PLUGIN_LIST - flutter_libsparkmobile ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + flutter_libsparkmobile ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/ffigen.yaml b/ffigen.yaml new file mode 100644 index 0000000..e4fd06e --- /dev/null +++ b/ffigen.yaml @@ -0,0 +1,19 @@ +# Run with `flutter pub run ffigen --config ffigen.yaml`. +name: FlutterLibsparkmobileBindings +description: | + Bindings for `src/flutter_libsparkmobile.h`. + + Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`. +output: 'lib/flutter_libsparkmobile_bindings_generated.dart' +headers: + entry-points: + - 'src/flutter_libsparkmobile.h' + include-directives: + - 'src/flutter_libsparkmobile.h' +preamble: | + // ignore_for_file: always_specify_types + // ignore_for_file: camel_case_types + // ignore_for_file: non_constant_identifier_names +comments: + style: any + length: full diff --git a/flutter_libsparkmobile.iml b/flutter_libsparkmobile.iml index 812c8dd..25103f8 100644 --- a/flutter_libsparkmobile.iml +++ b/flutter_libsparkmobile.iml @@ -3,7 +3,7 @@ - + diff --git a/ios/.gitignore b/ios/.gitignore deleted file mode 100644 index 0c88507..0000000 --- a/ios/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -.idea/ -.vagrant/ -.sconsign.dblite -.svn/ - -.DS_Store -*.swp -profile - -DerivedData/ -build/ -GeneratedPluginRegistrant.h -GeneratedPluginRegistrant.m - -.generated/ - -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 - -!default.pbxuser -!default.mode1v3 -!default.mode2v3 -!default.perspectivev3 - -xcuserdata - -*.moved-aside - -*.pyc -*sync/ -Icon? -.tags* - -/Flutter/Generated.xcconfig -/Flutter/ephemeral/ -/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/ios/Assets/.gitkeep b/ios/Assets/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/ios/Classes/FlutterLibsparkmobilePlugin.swift b/ios/Classes/FlutterLibsparkmobilePlugin.swift deleted file mode 100644 index 82693e9..0000000 --- a/ios/Classes/FlutterLibsparkmobilePlugin.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Flutter -import UIKit - -public class FlutterLibsparkmobilePlugin: NSObject, FlutterPlugin { - public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "flutter_libsparkmobile", binaryMessenger: registrar.messenger()) - let instance = FlutterLibsparkmobilePlugin() - registrar.addMethodCallDelegate(instance, channel: channel) - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - switch call.method { - case "getPlatformVersion": - result("iOS " + UIDevice.current.systemVersion) - default: - result(FlutterMethodNotImplemented) - } - } -} diff --git a/ios/Classes/flutter_libsparkmobile.c b/ios/Classes/flutter_libsparkmobile.c new file mode 100644 index 0000000..1837bfa --- /dev/null +++ b/ios/Classes/flutter_libsparkmobile.c @@ -0,0 +1,3 @@ +// Relative import to be able to reuse the C sources. +// See the comment in ../{projectName}}.podspec for more information. +#include flutter_libsparkmobile.cpp diff --git a/ios/flutter_libsparkmobile.podspec b/ios/flutter_libsparkmobile.podspec index 7084714..5d1a8cf 100644 --- a/ios/flutter_libsparkmobile.podspec +++ b/ios/flutter_libsparkmobile.podspec @@ -5,13 +5,18 @@ Pod::Spec.new do |s| s.name = 'flutter_libsparkmobile' s.version = '0.0.1' - s.summary = 'A new Flutter plugin project.' + s.summary = 'A new Flutter project.' s.description = <<-DESC -A new Flutter plugin project. +A new Flutter project. DESC s.homepage = 'http://example.com' s.license = { :file => '../LICENSE' } s.author = { 'Your Company' => 'email@example.com' } + + # This will ensure the source files in Classes/ are included in the native + # builds of apps using this FFI plugin. Podspec does not support relative + # paths, so Classes contains a forwarder C file that relatively imports + # `../src/*` so that the C sources can be shared among all target platforms. s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'Flutter' diff --git a/lib/flutter_libsparkmobile.dart b/lib/flutter_libsparkmobile.dart index adaa9e3..5f8b2db 100644 --- a/lib/flutter_libsparkmobile.dart +++ b/lib/flutter_libsparkmobile.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:ffi'; import 'dart:io'; import 'dart:typed_data'; @@ -5,46 +6,67 @@ import 'dart:typed_data'; import 'package:ffi/ffi.dart'; import 'package:flutter_libsparkmobile/extensions.dart'; -import 'flutter_libsparkmobile_bindings.dart'; +import 'flutter_libsparkmobile_bindings_generated.dart'; const kSparkChain = 6; const kSparkBaseDerivationPath = "m/44'/136'/0'/$kSparkChain/"; +const String _kLibName = 'flutter_libsparkmobile'; + +/// The dynamic library in which the symbols for [FlutterLibsparkmobileBindings] can be found. +final DynamicLibrary _dylib = () { + if (Platform.isMacOS || Platform.isIOS) { + return DynamicLibrary.open('$_kLibName.framework/$_kLibName'); + } + if (Platform.isAndroid || Platform.isLinux) { + return DynamicLibrary.open('lib$_kLibName.so'); + } + if (Platform.isWindows) { + return DynamicLibrary.open('$_kLibName.dll'); + } + throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}'); +}(); + +/// The bindings to the native functions in [_dylib]. +final FlutterLibsparkmobileBindings _bindings = + FlutterLibsparkmobileBindings(_dylib); + abstract final class LibSpark { - static SparkMobileBindings? _bindings; - - static void _checkLoaded() { - _bindings ??= SparkMobileBindings(_loadLibrary()); - } - - static DynamicLibrary _loadLibrary() { - // hack in prefix for test env - String testPrefix = ""; - if (Platform.environment.containsKey('FLUTTER_TEST')) { - if (Platform.isLinux) { - testPrefix = 'scripts/linux/build/'; - } else if (Platform.isMacOS) { - testPrefix = 'scripts/macos/build/'; - } else if (Platform.isWindows) { - testPrefix = 'scripts/windows/build/'; - } else { - throw UnsupportedError('This platform is not supported'); - } - } - - if (Platform.isLinux) { - return DynamicLibrary.open('${testPrefix}libsparkmobile.so'); - } else if (Platform.isAndroid) { - // return DynamicLibrary.open('${testPrefix}libsparkmobile.so'); - } else if (Platform.isIOS) { - // return DynamicLibrary.open('${testPrefix}libsparkmobile.dylib'); - } else if (Platform.isMacOS) { - // return DynamicLibrary.open('${testPrefix}libsparkmobile.dylib'); - } else if (Platform.isWindows) { - // return DynamicLibrary.open('${testPrefix}sparkmobile.dll'); - } - throw UnsupportedError('This platform is not supported'); - } + static final FlutterLibsparkmobileBindings _bindings = + FlutterLibsparkmobileBindings(_dylib); + // + // static void _checkLoaded() { + // _bindings ??= SparkMobileBindings(_loadLibrary()); + // } + // + // static DynamicLibrary _loadLibrary() { + // // hack in prefix for test env + // String testPrefix = ""; + // if (Platform.environment.containsKey('FLUTTER_TEST')) { + // if (Platform.isLinux) { + // testPrefix = 'scripts/linux/build/'; + // } else if (Platform.isMacOS) { + // testPrefix = 'scripts/macos/build/'; + // } else if (Platform.isWindows) { + // testPrefix = 'scripts/windows/build/'; + // } else { + // throw UnsupportedError('This platform is not supported'); + // } + // } + // + // if (Platform.isLinux) { + // return DynamicLibrary.open('${testPrefix}libsparkmobile.so'); + // } else if (Platform.isAndroid) { + // // return DynamicLibrary.open('${testPrefix}libsparkmobile.so'); + // } else if (Platform.isIOS) { + // // return DynamicLibrary.open('${testPrefix}libsparkmobile.dylib'); + // } else if (Platform.isMacOS) { + // // return DynamicLibrary.open('${testPrefix}libsparkmobile.dylib'); + // } else if (Platform.isWindows) { + // // return DynamicLibrary.open('${testPrefix}sparkmobile.dll'); + // } + // throw UnsupportedError('This platform is not supported'); + // } // SparkMobileBindings methods: @@ -55,7 +77,7 @@ abstract final class LibSpark { required int diversifier, bool isTestNet = false, }) async { - _checkLoaded(); + // _checkLoaded(); if (index < 0) { throw Exception("Index must not be negative."); @@ -75,7 +97,7 @@ abstract final class LibSpark { final keyDataPointer = privateKey.toHexString().toNativeUtf8().cast(); // Call the native method with the pointer. - final addressPointer = _bindings!.getAddress( + final addressPointer = _bindings.getAddress( keyDataPointer, index, diversifier, @@ -92,3 +114,128 @@ abstract final class LibSpark { return addressString; } } + +// +// /// A very short-lived native function. +// /// +// /// For very short-lived functions, it is fine to call them on the main isolate. +// /// They will block the Dart execution while running the native function, so +// /// only do this for native functions which are guaranteed to be short-lived. +// int sum(int a, int b) => _bindings.sum(a, b); +// +// /// A longer lived native function, which occupies the thread calling it. +// /// +// /// Do not call these kind of native functions in the main isolate. They will +// /// block Dart execution. This will cause dropped frames in Flutter applications. +// /// Instead, call these native functions on a separate isolate. +// /// +// /// Modify this to suit your own use case. Example use cases: +// /// +// /// 1. Reuse a single isolate for various different kinds of requests. +// /// 2. Use multiple helper isolates for parallel execution. +// Future sumAsync(int a, int b) async { +// final SendPort helperIsolateSendPort = await _helperIsolateSendPort; +// final int requestId = _nextSumRequestId++; +// final _SumRequest request = _SumRequest(requestId, a, b); +// final Completer completer = Completer(); +// _sumRequests[requestId] = completer; +// helperIsolateSendPort.send(request); +// return completer.future; +// } +// +// const String _libName = 'flutter_libsparkmobile'; +// +// /// The dynamic library in which the symbols for [FlutterLibsparkmobileBindings] can be found. +// final DynamicLibrary _dylib = () { +// if (Platform.isMacOS || Platform.isIOS) { +// return DynamicLibrary.open('$_libName.framework/$_libName'); +// } +// if (Platform.isAndroid || Platform.isLinux) { +// return DynamicLibrary.open('lib$_libName.so'); +// } +// if (Platform.isWindows) { +// return DynamicLibrary.open('$_libName.dll'); +// } +// throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}'); +// }(); +// +// /// The bindings to the native functions in [_dylib]. +// final FlutterLibsparkmobileBindings _bindings = FlutterLibsparkmobileBindings(_dylib); + +// +// /// A request to compute `sum`. +// /// +// /// Typically sent from one isolate to another. +// class _SumRequest { +// final int id; +// final int a; +// final int b; +// +// const _SumRequest(this.id, this.a, this.b); +// } +// +// /// A response with the result of `sum`. +// /// +// /// Typically sent from one isolate to another. +// class _SumResponse { +// final int id; +// final int result; +// +// const _SumResponse(this.id, this.result); +// } +// +// /// Counter to identify [_SumRequest]s and [_SumResponse]s. +// int _nextSumRequestId = 0; +// +// /// Mapping from [_SumRequest] `id`s to the completers corresponding to the correct future of the pending request. +// final Map> _sumRequests = >{}; +// +// /// The SendPort belonging to the helper isolate. +// Future _helperIsolateSendPort = () async { +// // The helper isolate is going to send us back a SendPort, which we want to +// // wait for. +// final Completer completer = Completer(); +// +// // Receive port on the main isolate to receive messages from the helper. +// // We receive two types of messages: +// // 1. A port to send messages on. +// // 2. Responses to requests we sent. +// final ReceivePort receivePort = ReceivePort() +// ..listen((dynamic data) { +// if (data is SendPort) { +// // The helper isolate sent us the port on which we can sent it requests. +// completer.complete(data); +// return; +// } +// if (data is _SumResponse) { +// // The helper isolate sent us a response to a request we sent. +// final Completer completer = _sumRequests[data.id]!; +// _sumRequests.remove(data.id); +// completer.complete(data.result); +// return; +// } +// throw UnsupportedError('Unsupported message type: ${data.runtimeType}'); +// }); +// +// // Start the helper isolate. +// await Isolate.spawn((SendPort sendPort) async { +// final ReceivePort helperReceivePort = ReceivePort() +// ..listen((dynamic data) { +// // On the helper isolate listen to requests and respond to them. +// if (data is _SumRequest) { +// final int result = _bindings.sum_long_running(data.a, data.b); +// final _SumResponse response = _SumResponse(data.id, result); +// sendPort.send(response); +// return; +// } +// throw UnsupportedError('Unsupported message type: ${data.runtimeType}'); +// }); +// +// // Send the port to the main isolate on which we can receive requests. +// sendPort.send(helperReceivePort.sendPort); +// }, receivePort.sendPort); +// +// // Wait until the helper isolate has sent us back the SendPort on which we +// // can start sending requests. +// return completer.future; +// }(); diff --git a/lib/flutter_libsparkmobile_bindings.dart b/lib/flutter_libsparkmobile_bindings.dart deleted file mode 100644 index 9c59580..0000000 --- a/lib/flutter_libsparkmobile_bindings.dart +++ /dev/null @@ -1,439 +0,0 @@ -// ignore_for_file: camel_case_types, non_constant_identifier_names, unused_element, unused_field, return_of_invalid_type, void_checks, annotate_overrides, no_leading_underscores_for_local_identifiers, library_private_types_in_public_api - -// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. -// ignore_for_file: type=lint -import 'dart:ffi' as ffi; - -/// Bindings for sparkmobile. -class SparkMobileBindings { - /// Holds the symbol lookup function. - final ffi.Pointer Function(String symbolName) - _lookup; - - /// The symbols are looked up in [dynamicLibrary]. - SparkMobileBindings(ffi.DynamicLibrary dynamicLibrary) - : _lookup = dynamicLibrary.lookup; - - /// The symbols are looked up with [lookup]. - SparkMobileBindings.fromLookup( - ffi.Pointer Function(String symbolName) - lookup) - : _lookup = lookup; - - ffi.Pointer getAddress( - ffi.Pointer keyDataHex, - int index, - int diversifier, - int isTestNet, - ) { - return _getAddress( - keyDataHex, - index, - diversifier, - isTestNet, - ); - } - - late final _getAddressPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int, ffi.Int, ffi.Int)>>('getAddress'); - late final _getAddress = _getAddressPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, int, int)>(); - - CIdentifiedCoinData identifyCoin( - CCoin c_struct, - ffi.Pointer keyDataHex, - int index, - ) { - return _identifyCoin( - c_struct, - keyDataHex, - index, - ); - } - - late final _identifyCoinPtr = _lookup< - ffi.NativeFunction< - CIdentifiedCoinData Function( - CCoin, ffi.Pointer, ffi.Int)>>('identifyCoin'); - late final _identifyCoin = _identifyCoinPtr.asFunction< - CIdentifiedCoinData Function(CCoin, ffi.Pointer, int)>(); - - ffi.Pointer createSparkMintRecipients( - int numRecipients, - ffi.Pointer pubKeyScripts, - ffi.Pointer amounts, - ffi.Pointer memo, - int subtractFee, - ) { - return _createSparkMintRecipients( - numRecipients, - pubKeyScripts, - amounts, - memo, - subtractFee, - ); - } - - late final _createSparkMintRecipientsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Int)>>('createSparkMintRecipients'); - late final _createSparkMintRecipients = - _createSparkMintRecipientsPtr.asFunction< - ffi.Pointer Function(int, ffi.Pointer, - ffi.Pointer, ffi.Pointer, int)>(); -} - -final class __fsid_t extends ffi.Struct { - @ffi.Array.multi([2]) - external ffi.Array __val; -} - -final class CCoin extends ffi.Struct { - @ffi.Char() - external int type; - - external ffi.Pointer k; - - @ffi.Int() - external int kLength; - - external ffi.Pointer address; - - @ffi.Uint64() - external int v; - - external ffi.Pointer memo; - - @ffi.Int() - external int memoLength; - - external ffi.Pointer serial_context; - - @ffi.Int() - external int serial_contextLength; -} - -final class CIdentifiedCoinData extends ffi.Struct { - @ffi.Uint64() - external int i; - - external ffi.Pointer d; - - @ffi.Int() - external int dLength; - - @ffi.Uint64() - external int v; - - external ffi.Pointer k; - - @ffi.Int() - external int kLength; - - external ffi.Pointer memo; - - @ffi.Int() - external int memoLength; -} - -final class CCRecipient extends ffi.Struct { - external ffi.Pointer pubKey; - - @ffi.Int() - external int pubKeyLength; - - @ffi.Uint64() - external int cAmount; - - @ffi.Int() - external int subtractFee; -} - -final class CMintedCoinData extends ffi.Struct { - external ffi.Pointer address; - - @ffi.Uint64() - external int value; - - external ffi.Pointer memo; -} - -final class PubKeyScript extends ffi.Struct { - external ffi.Pointer bytes; - - @ffi.Int() - external int length; -} - -final class COutputCoinData extends ffi.Struct { - external ffi.Pointer address; - - @ffi.Uint64() - external int value; - - external ffi.Pointer memo; -} - -final class CCSparkMintMeta extends ffi.Struct { - @ffi.Uint64() - external int height; - - external ffi.Pointer id; - - @ffi.Int() - external int isUsed; - - external ffi.Pointer txid; - - @ffi.Uint64() - external int i; - - external ffi.Pointer d; - - @ffi.Int() - external int dLength; - - @ffi.Uint64() - external int v; - - external ffi.Pointer k; - - @ffi.Int() - external int kLength; - - external ffi.Pointer memo; - - @ffi.Int() - external int memoLength; - - external ffi.Pointer serial_context; - - @ffi.Int() - external int serial_contextLength; - - @ffi.Char() - external int type; - - external CCoin coin; -} - -const int _STDINT_H = 1; - -const int _FEATURES_H = 1; - -const int _DEFAULT_SOURCE = 1; - -const int __GLIBC_USE_ISOC2X = 1; - -const int __USE_ISOC11 = 1; - -const int __USE_ISOC99 = 1; - -const int __USE_ISOC95 = 1; - -const int _POSIX_SOURCE = 1; - -const int _POSIX_C_SOURCE = 200809; - -const int __USE_POSIX = 1; - -const int __USE_POSIX2 = 1; - -const int __USE_POSIX199309 = 1; - -const int __USE_POSIX199506 = 1; - -const int __USE_XOPEN2K = 1; - -const int __USE_XOPEN2K8 = 1; - -const int _ATFILE_SOURCE = 1; - -const int __USE_MISC = 1; - -const int __USE_ATFILE = 1; - -const int __USE_FORTIFY_LEVEL = 0; - -const int __GLIBC_USE_DEPRECATED_GETS = 0; - -const int __GLIBC_USE_DEPRECATED_SCANF = 0; - -const int _STDC_PREDEF_H = 1; - -const int __STDC_IEC_559__ = 1; - -const int __STDC_IEC_559_COMPLEX__ = 1; - -const int __STDC_ISO_10646__ = 201706; - -const int __GNU_LIBRARY__ = 6; - -const int __GLIBC__ = 2; - -const int __GLIBC_MINOR__ = 31; - -const int _SYS_CDEFS_H = 1; - -const int __glibc_c99_flexarr_available = 1; - -const int __WORDSIZE = 64; - -const int __WORDSIZE_TIME64_COMPAT32 = 1; - -const int __SYSCALL_WORDSIZE = 64; - -const int __LONG_DOUBLE_USES_FLOAT128 = 0; - -const int __HAVE_GENERIC_SELECTION = 0; - -const int __GLIBC_USE_LIB_EXT2 = 1; - -const int __GLIBC_USE_IEC_60559_BFP_EXT = 1; - -const int __GLIBC_USE_IEC_60559_BFP_EXT_C2X = 1; - -const int __GLIBC_USE_IEC_60559_FUNCS_EXT = 1; - -const int __GLIBC_USE_IEC_60559_FUNCS_EXT_C2X = 1; - -const int __GLIBC_USE_IEC_60559_TYPES_EXT = 1; - -const int _BITS_TYPES_H = 1; - -const int __TIMESIZE = 64; - -const int _BITS_TYPESIZES_H = 1; - -const int __OFF_T_MATCHES_OFF64_T = 1; - -const int __INO_T_MATCHES_INO64_T = 1; - -const int __RLIM_T_MATCHES_RLIM64_T = 1; - -const int __STATFS_MATCHES_STATFS64 = 1; - -const int __FD_SETSIZE = 1024; - -const int _BITS_TIME64_H = 1; - -const int _BITS_WCHAR_H = 1; - -const int __WCHAR_MAX = 2147483647; - -const int __WCHAR_MIN = -2147483648; - -const int _BITS_STDINT_INTN_H = 1; - -const int _BITS_STDINT_UINTN_H = 1; - -const int INT8_MIN = -128; - -const int INT16_MIN = -32768; - -const int INT32_MIN = -2147483648; - -const int INT64_MIN = -9223372036854775808; - -const int INT8_MAX = 127; - -const int INT16_MAX = 32767; - -const int INT32_MAX = 2147483647; - -const int INT64_MAX = 9223372036854775807; - -const int UINT8_MAX = 255; - -const int UINT16_MAX = 65535; - -const int UINT32_MAX = 4294967295; - -const int UINT64_MAX = -1; - -const int INT_LEAST8_MIN = -128; - -const int INT_LEAST16_MIN = -32768; - -const int INT_LEAST32_MIN = -2147483648; - -const int INT_LEAST64_MIN = -9223372036854775808; - -const int INT_LEAST8_MAX = 127; - -const int INT_LEAST16_MAX = 32767; - -const int INT_LEAST32_MAX = 2147483647; - -const int INT_LEAST64_MAX = 9223372036854775807; - -const int UINT_LEAST8_MAX = 255; - -const int UINT_LEAST16_MAX = 65535; - -const int UINT_LEAST32_MAX = 4294967295; - -const int UINT_LEAST64_MAX = -1; - -const int INT_FAST8_MIN = -128; - -const int INT_FAST16_MIN = -9223372036854775808; - -const int INT_FAST32_MIN = -9223372036854775808; - -const int INT_FAST64_MIN = -9223372036854775808; - -const int INT_FAST8_MAX = 127; - -const int INT_FAST16_MAX = 9223372036854775807; - -const int INT_FAST32_MAX = 9223372036854775807; - -const int INT_FAST64_MAX = 9223372036854775807; - -const int UINT_FAST8_MAX = 255; - -const int UINT_FAST16_MAX = -1; - -const int UINT_FAST32_MAX = -1; - -const int UINT_FAST64_MAX = -1; - -const int INTPTR_MIN = -9223372036854775808; - -const int INTPTR_MAX = 9223372036854775807; - -const int UINTPTR_MAX = -1; - -const int INTMAX_MIN = -9223372036854775808; - -const int INTMAX_MAX = 9223372036854775807; - -const int UINTMAX_MAX = -1; - -const int PTRDIFF_MIN = -9223372036854775808; - -const int PTRDIFF_MAX = 9223372036854775807; - -const int SIG_ATOMIC_MIN = -2147483648; - -const int SIG_ATOMIC_MAX = 2147483647; - -const int SIZE_MAX = -1; - -const int WCHAR_MIN = -2147483648; - -const int WCHAR_MAX = 2147483647; - -const int WINT_MIN = 0; - -const int WINT_MAX = 4294967295; diff --git a/lib/flutter_libsparkmobile_bindings_generated.dart b/lib/flutter_libsparkmobile_bindings_generated.dart new file mode 100644 index 0000000..53b0213 --- /dev/null +++ b/lib/flutter_libsparkmobile_bindings_generated.dart @@ -0,0 +1,198 @@ +// ignore_for_file: always_specify_types +// ignore_for_file: camel_case_types +// ignore_for_file: non_constant_identifier_names + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// Bindings for `src/flutter_libsparkmobile.h`. +/// +/// Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`. +/// +class FlutterLibsparkmobileBindings { + /// Holds the symbol lookup function. + final ffi.Pointer Function(String symbolName) + _lookup; + + /// The symbols are looked up in [dynamicLibrary]. + FlutterLibsparkmobileBindings(ffi.DynamicLibrary dynamicLibrary) + : _lookup = dynamicLibrary.lookup; + + /// The symbols are looked up with [lookup]. + FlutterLibsparkmobileBindings.fromLookup( + ffi.Pointer Function(String symbolName) + lookup) + : _lookup = lookup; + + /// FFI-friendly wrapper for spark::getAddress. + ffi.Pointer getAddress( + ffi.Pointer keyDataHex, + int index, + int diversifier, + int isTestNet, + ) { + return _getAddress( + keyDataHex, + index, + diversifier, + isTestNet, + ); + } + + late final _getAddressPtr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer, ffi.Int, ffi.Int, ffi.Int)>>('getAddress'); + late final _getAddress = _getAddressPtr.asFunction< + ffi.Pointer Function(ffi.Pointer, int, int, int)>(); + + /// FFI-friendly wrapper for spark::identifyCoin. + CIdentifiedCoinData identifyCoin( + CCoin c_struct, + ffi.Pointer keyDataHex, + int index, + ) { + return _identifyCoin( + c_struct, + keyDataHex, + index, + ); + } + + late final _identifyCoinPtr = _lookup< + ffi.NativeFunction< + CIdentifiedCoinData Function( + CCoin, ffi.Pointer, ffi.Int)>>('identifyCoin'); + late final _identifyCoin = _identifyCoinPtr.asFunction< + CIdentifiedCoinData Function(CCoin, ffi.Pointer, int)>(); + + /// FFI-friendly wrapper for spark::createSparkMintRecipients. + ffi.Pointer createSparkMintRecipients( + int numRecipients, + ffi.Pointer pubKeyScripts, + ffi.Pointer amounts, + ffi.Pointer memo, + int subtractFee, + ) { + return _createSparkMintRecipients( + numRecipients, + pubKeyScripts, + amounts, + memo, + subtractFee, + ); + } + + late final _createSparkMintRecipientsPtr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Int, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Int)>>('createSparkMintRecipients'); + late final _createSparkMintRecipients = + _createSparkMintRecipientsPtr.asFunction< + ffi.Pointer Function(int, ffi.Pointer, + ffi.Pointer, ffi.Pointer, int)>(); +} + +/// FFI-friendly wrapper for a spark::Coin. +/// +/// A Coin is a type, a key, an index, a value, a memo, and a serial context. We accept these params +/// as a C struct, deriving the key from the keyData and index. +final class CCoin extends ffi.Struct { + @ffi.Char() + external int type; + + external ffi.Pointer k; + + @ffi.Int() + external int kLength; + + external ffi.Pointer keyData; + + @ffi.Int() + external int index; + + @ffi.Uint64() + external int v; + + external ffi.Pointer memo; + + @ffi.Int() + external int memoLength; + + external ffi.Pointer serial_context; + + @ffi.Int() + external int serial_contextLength; +} + +/// FFI-friendly wrapper for a spark::IdentifiedCoinData. +/// +/// An IdentifiedCoinData is a diversifier, encrypted diversifier, value, nonce, and memo. We accept +/// these params as a C struct. +final class CIdentifiedCoinData extends ffi.Struct { + @ffi.Uint64() + external int i; + + external ffi.Pointer d; + + @ffi.Int() + external int dLength; + + @ffi.Uint64() + external int v; + + external ffi.Pointer k; + + @ffi.Int() + external int kLength; + + external ffi.Pointer memo; + + @ffi.Int() + external int memoLength; +} + +/// FFI-friendly wrapper for a spark::CRecipient. +/// +/// A CRecipient is a CScript, CAmount, and a bool. We accept a C-style, FFI-friendly CCRecipient +/// struct in order to construct a C++ CRecipient. A CScript is constructed from a hex string, a +/// CAmount is just a uint64_t, and the bool will be an int. +final class CCRecipient extends ffi.Struct { + external ffi.Pointer pubKey; + + @ffi.Int() + external int pubKeyLength; + + @ffi.Uint64() + external int cAmount; + + @ffi.Int() + external int subtractFee; +} + +/// FFI-friendly wrapper for a spark::MintedCoinData. +/// +/// A MintedCoinData is a struct that contains an Address, a uint64_t value, and a string memo. We +/// accept these as a CMintedCoinData from the Dart interface, and convert them to a MintedCoinData +/// struct. +final class CMintedCoinData extends ffi.Struct { + external ffi.Pointer address; + + @ffi.Uint64() + external int value; + + external ffi.Pointer memo; +} + +final class PubKeyScript extends ffi.Struct { + external ffi.Pointer bytes; + + @ffi.Int() + external int length; +} diff --git a/lib/flutter_libsparkmobile_method_channel.dart b/lib/flutter_libsparkmobile_method_channel.dart deleted file mode 100644 index eac777e..0000000 --- a/lib/flutter_libsparkmobile_method_channel.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; - -import 'flutter_libsparkmobile_platform_interface.dart'; - -/// An implementation of [FlutterLibsparkmobilePlatform] that uses method channels. -class MethodChannelFlutterLibsparkmobile extends FlutterLibsparkmobilePlatform { - /// The method channel used to interact with the native platform. - @visibleForTesting - final methodChannel = const MethodChannel('flutter_libsparkmobile'); - - @override - Future getPlatformVersion() async { - final version = await methodChannel.invokeMethod('getPlatformVersion'); - return version; - } -} diff --git a/lib/flutter_libsparkmobile_platform_interface.dart b/lib/flutter_libsparkmobile_platform_interface.dart deleted file mode 100644 index 07ba833..0000000 --- a/lib/flutter_libsparkmobile_platform_interface.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; - -import 'flutter_libsparkmobile_method_channel.dart'; - -abstract class FlutterLibsparkmobilePlatform extends PlatformInterface { - /// Constructs a FlutterLibsparkmobilePlatform. - FlutterLibsparkmobilePlatform() : super(token: _token); - - static final Object _token = Object(); - - static FlutterLibsparkmobilePlatform _instance = MethodChannelFlutterLibsparkmobile(); - - /// The default instance of [FlutterLibsparkmobilePlatform] to use. - /// - /// Defaults to [MethodChannelFlutterLibsparkmobile]. - static FlutterLibsparkmobilePlatform get instance => _instance; - - /// Platform-specific implementations should set this with their own - /// platform-specific class that extends [FlutterLibsparkmobilePlatform] when - /// they register themselves. - static set instance(FlutterLibsparkmobilePlatform instance) { - PlatformInterface.verifyToken(instance, _token); - _instance = instance; - } - - Future getPlatformVersion() { - throw UnimplementedError('platformVersion() has not been implemented.'); - } -} diff --git a/lib/git_versions_example.dart b/lib/git_versions_example.dart deleted file mode 100644 index f94e377..0000000 --- a/lib/git_versions_example.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'dart:io'; - -/*ANDROID_VERSION*/ const ANDROID_VERSION = ""; -/*IOS_VERSION*/ const IOS_VERSION = ""; -/*MACOS_VERSION*/ const MACOS_VERSION = ""; -/*LINUX_VERSION*/ const LINUX_VERSION = ""; -/*WINDOWS_VERSION*/ const WINDOWS_VERSION = ""; - -String getPluginVersion() { - if (Platform.isAndroid) { - return ANDROID_VERSION; - } else if (Platform.isIOS) { - return IOS_VERSION; - } else if (Platform.isMacOS) { - return MACOS_VERSION; - } else if (Platform.isLinux) { - return LINUX_VERSION; - } else if (Platform.isWindows) { - return WINDOWS_VERSION; - } else { - return "Unknown version"; - } -} diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 6bd482e..a47162d 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -5,90 +5,20 @@ cmake_minimum_required(VERSION 3.10) # Project-level configuration. set(PROJECT_NAME "flutter_libsparkmobile") +set(PROJECT_SYSTEM_NAME "linux") + project(${PROJECT_NAME} LANGUAGES CXX) -# This value is used when generating builds using this plugin, so it must -# not be changed. -set(PLUGIN_NAME "flutter_libsparkmobile_plugin") - -# Any new source files that you add to the plugin should be added here. -list(APPEND PLUGIN_SOURCES - "flutter_libsparkmobile_plugin.cc" -) - -# Define the plugin library target. Its name must not be changed (see comment -# on PLUGIN_NAME above). -add_library(${PLUGIN_NAME} SHARED - ${PLUGIN_SOURCES} -) - -# Apply a standard set of build settings that are configured in the -# application-level CMakeLists.txt. This can be removed for plugins that want -# full control over build settings. -apply_standard_settings(${PLUGIN_NAME}) - -# Symbols are hidden by default to reduce the chance of accidental conflicts -# between plugins. This should not be removed; any symbols that should be -# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro. -set_target_properties(${PLUGIN_NAME} PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) - -# Source include directories and library dependencies. Add any plugin-specific -# dependencies here. -target_include_directories(${PLUGIN_NAME} INTERFACE - "${CMAKE_CURRENT_SOURCE_DIR}/include") -target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) -target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) +# Invoke the build for native code shared with the other target platforms. +# This can be changed to accommodate different builds. +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared") # List of absolute paths to libraries that should be bundled with the plugin. # This list could contain prebuilt libraries, or libraries created by an # external build triggered from this build file. set(flutter_libsparkmobile_bundled_libraries - "" + # Defined in ../src/CMakeLists.txt. + # This can be changed to accommodate different builds. + $ PARENT_SCOPE ) - -# === Tests === -# These unit tests can be run from a terminal after building the example. - -# Only enable test builds when building the example (which sets this variable) -# so that plugin clients aren't building the tests. -if (${include_${PROJECT_NAME}_tests}) -if(${CMAKE_VERSION} VERSION_LESS "3.11.0") -message("Unit tests require CMake 3.11.0 or later") -else() -set(TEST_RUNNER "${PROJECT_NAME}_test") -enable_testing() - -# Add the Google Test dependency. -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/release-1.11.0.zip -) -# Prevent overriding the parent project's compiler/linker settings -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -# Disable install commands for gtest so it doesn't end up in the bundle. -set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE) - -FetchContent_MakeAvailable(googletest) - -# The plugin's exported API is not very useful for unit testing, so build the -# sources directly into the test binary rather than using the shared library. -add_executable(${TEST_RUNNER} - test/flutter_libsparkmobile_plugin_test.cc - ${PLUGIN_SOURCES} -) -apply_standard_settings(${TEST_RUNNER}) -target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") -target_link_libraries(${TEST_RUNNER} PRIVATE flutter) -target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::GTK) -target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock) - -# Enable automatic test discovery. -include(GoogleTest) -gtest_discover_tests(${TEST_RUNNER}) - -endif() # CMake version check -endif() # include_${PROJECT_NAME}_tests \ No newline at end of file diff --git a/linux/flutter_libsparkmobile_plugin.cc b/linux/flutter_libsparkmobile_plugin.cc deleted file mode 100644 index ca80edf..0000000 --- a/linux/flutter_libsparkmobile_plugin.cc +++ /dev/null @@ -1,76 +0,0 @@ -#include "include/flutter_libsparkmobile/flutter_libsparkmobile_plugin.h" - -#include -#include -#include - -#include - -#include "flutter_libsparkmobile_plugin_private.h" - -#define FLUTTER_LIBSPARKMOBILE_PLUGIN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), flutter_libsparkmobile_plugin_get_type(), \ - FlutterLibsparkmobilePlugin)) - -struct _FlutterLibsparkmobilePlugin { - GObject parent_instance; -}; - -G_DEFINE_TYPE(FlutterLibsparkmobilePlugin, flutter_libsparkmobile_plugin, g_object_get_type()) - -// Called when a method call is received from Flutter. -static void flutter_libsparkmobile_plugin_handle_method_call( - FlutterLibsparkmobilePlugin* self, - FlMethodCall* method_call) { - g_autoptr(FlMethodResponse) response = nullptr; - - const gchar* method = fl_method_call_get_name(method_call); - - if (strcmp(method, "getPlatformVersion") == 0) { - response = get_platform_version(); - } else { - response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); - } - - fl_method_call_respond(method_call, response, nullptr); -} - -FlMethodResponse* get_platform_version() { - struct utsname uname_data = {}; - uname(&uname_data); - g_autofree gchar *version = g_strdup_printf("Linux %s", uname_data.version); - g_autoptr(FlValue) result = fl_value_new_string(version); - return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); -} - -static void flutter_libsparkmobile_plugin_dispose(GObject* object) { - G_OBJECT_CLASS(flutter_libsparkmobile_plugin_parent_class)->dispose(object); -} - -static void flutter_libsparkmobile_plugin_class_init(FlutterLibsparkmobilePluginClass* klass) { - G_OBJECT_CLASS(klass)->dispose = flutter_libsparkmobile_plugin_dispose; -} - -static void flutter_libsparkmobile_plugin_init(FlutterLibsparkmobilePlugin* self) {} - -static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call, - gpointer user_data) { - FlutterLibsparkmobilePlugin* plugin = FLUTTER_LIBSPARKMOBILE_PLUGIN(user_data); - flutter_libsparkmobile_plugin_handle_method_call(plugin, method_call); -} - -void flutter_libsparkmobile_plugin_register_with_registrar(FlPluginRegistrar* registrar) { - FlutterLibsparkmobilePlugin* plugin = FLUTTER_LIBSPARKMOBILE_PLUGIN( - g_object_new(flutter_libsparkmobile_plugin_get_type(), nullptr)); - - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(FlMethodChannel) channel = - fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), - "flutter_libsparkmobile", - FL_METHOD_CODEC(codec)); - fl_method_channel_set_method_call_handler(channel, method_call_cb, - g_object_ref(plugin), - g_object_unref); - - g_object_unref(plugin); -} diff --git a/linux/flutter_libsparkmobile_plugin_private.h b/linux/flutter_libsparkmobile_plugin_private.h deleted file mode 100644 index 7ad62c4..0000000 --- a/linux/flutter_libsparkmobile_plugin_private.h +++ /dev/null @@ -1,10 +0,0 @@ -#include - -#include "include/flutter_libsparkmobile/flutter_libsparkmobile_plugin.h" - -// This file exposes some plugin internals for unit testing. See -// https://github.com/flutter/flutter/issues/88724 for current limitations -// in the unit-testable API. - -// Handles the getPlatformVersion method call. -FlMethodResponse *get_platform_version(); diff --git a/linux/include/flutter_libsparkmobile/flutter_libsparkmobile_plugin.h b/linux/include/flutter_libsparkmobile/flutter_libsparkmobile_plugin.h deleted file mode 100644 index d48edd1..0000000 --- a/linux/include/flutter_libsparkmobile/flutter_libsparkmobile_plugin.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_H_ -#define FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_H_ - -#include - -G_BEGIN_DECLS - -#ifdef FLUTTER_PLUGIN_IMPL -#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) -#else -#define FLUTTER_PLUGIN_EXPORT -#endif - -typedef struct _FlutterLibsparkmobilePlugin FlutterLibsparkmobilePlugin; -typedef struct { - GObjectClass parent_class; -} FlutterLibsparkmobilePluginClass; - -FLUTTER_PLUGIN_EXPORT GType flutter_libsparkmobile_plugin_get_type(); - -FLUTTER_PLUGIN_EXPORT void flutter_libsparkmobile_plugin_register_with_registrar( - FlPluginRegistrar* registrar); - -G_END_DECLS - -#endif // FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_H_ diff --git a/linux/test/flutter_libsparkmobile_plugin_test.cc b/linux/test/flutter_libsparkmobile_plugin_test.cc deleted file mode 100644 index 0f91ac4..0000000 --- a/linux/test/flutter_libsparkmobile_plugin_test.cc +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include - -#include "include/flutter_libsparkmobile/flutter_libsparkmobile_plugin.h" -#include "flutter_libsparkmobile_plugin_private.h" - -// This demonstrates a simple unit test of the C portion of this plugin's -// implementation. -// -// Once you have built the plugin's example app, you can run these tests -// from the command line. For instance, for a plugin called my_plugin -// built for x64 debug, run: -// $ build/linux/x64/debug/plugins/my_plugin/my_plugin_test - -namespace flutter_libsparkmobile { -namespace test { - -TEST(FlutterLibsparkmobilePlugin, GetPlatformVersion) { - g_autoptr(FlMethodResponse) response = get_platform_version(); - ASSERT_NE(response, nullptr); - ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - FlValue* result = fl_method_success_response_get_result( - FL_METHOD_SUCCESS_RESPONSE(response)); - ASSERT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_STRING); - // The full string varies, so just validate that it has the right format. - EXPECT_THAT(fl_value_get_string(result), testing::StartsWith("Linux ")); -} - -} // namespace test -} // namespace flutter_libsparkmobile diff --git a/macos/Classes/FlutterLibsparkmobilePlugin.swift b/macos/Classes/FlutterLibsparkmobilePlugin.swift deleted file mode 100644 index 57f6153..0000000 --- a/macos/Classes/FlutterLibsparkmobilePlugin.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Cocoa -import FlutterMacOS - -public class FlutterLibsparkmobilePlugin: NSObject, FlutterPlugin { - public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "flutter_libsparkmobile", binaryMessenger: registrar.messenger) - let instance = FlutterLibsparkmobilePlugin() - registrar.addMethodCallDelegate(instance, channel: channel) - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - switch call.method { - case "getPlatformVersion": - result("macOS " + ProcessInfo.processInfo.operatingSystemVersionString) - default: - result(FlutterMethodNotImplemented) - } - } -} diff --git a/macos/Classes/flutter_libsparkmobile.c b/macos/Classes/flutter_libsparkmobile.c new file mode 100644 index 0000000..1837bfa --- /dev/null +++ b/macos/Classes/flutter_libsparkmobile.c @@ -0,0 +1,3 @@ +// Relative import to be able to reuse the C sources. +// See the comment in ../{projectName}}.podspec for more information. +#include flutter_libsparkmobile.cpp diff --git a/macos/flutter_libsparkmobile.podspec b/macos/flutter_libsparkmobile.podspec index 63085cb..6f84cfe 100644 --- a/macos/flutter_libsparkmobile.podspec +++ b/macos/flutter_libsparkmobile.podspec @@ -5,14 +5,18 @@ Pod::Spec.new do |s| s.name = 'flutter_libsparkmobile' s.version = '0.0.1' - s.summary = 'A new Flutter plugin project.' + s.summary = 'A new Flutter project.' s.description = <<-DESC -A new Flutter plugin project. +A new Flutter project. DESC s.homepage = 'http://example.com' s.license = { :file => '../LICENSE' } s.author = { 'Your Company' => 'email@example.com' } + # This will ensure the source files in Classes/ are included in the native + # builds of apps using this FFI plugin. Podspec does not support relative + # paths, so Classes contains a forwarder C file that relatively imports + # `../src/*` so that the C sources can be shared among all target platforms. s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'FlutterMacOS' diff --git a/pubspec.yaml b/pubspec.yaml index e317364..453800d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: flutter_libsparkmobile -description: A new Flutter plugin project. +description: Flutter Sparkmobile ffi wrapper version: 0.0.1 homepage: @@ -12,14 +12,12 @@ dependencies: flutter: sdk: flutter plugin_platform_interface: ^2.0.2 - test: ^1.24.1 - typed_data: ^1.3.2 dev_dependencies: + ffigen: ^6.1.2 flutter_test: sdk: flutter flutter_lints: ^2.0.0 - ffigen: ^9.0.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec @@ -36,19 +34,20 @@ flutter: # This is required for using `dart:ffi`. # All these are used by the tooling to maintain consistency when # adding or updating assets for this project. + # + # Please refer to README.md for a detailed explanation. plugin: platforms: android: - package: com.cypherstack.flutter_libsparkmobile - pluginClass: FlutterLibsparkmobilePlugin + ffiPlugin: true ios: - pluginClass: FlutterLibsparkmobilePlugin + ffiPlugin: true linux: - pluginClass: FlutterLibsparkmobilePlugin + ffiPlugin: true macos: - pluginClass: FlutterLibsparkmobilePlugin + ffiPlugin: true windows: - pluginClass: FlutterLibsparkmobilePluginCApi + ffiPlugin: true # To add assets to your plugin package, add an assets section, like this: # assets: @@ -80,15 +79,3 @@ flutter: # # For details regarding fonts in packages, see # https://flutter.dev/custom-fonts/#from-packages - -ffigen: - name: SparkMobileBindings - description: Bindings for sparkmobile. - language: c - output: 'lib/flutter_libsparkmobile_bindings.dart' - headers: - entry-points: - - 'sparkmobile/src/dart_interface.h' - # copyCMakeLists.sh creates this header, see build_all.sh. - preamble: | - // ignore_for_file: camel_case_types, non_constant_identifier_names, unused_element, unused_field, return_of_invalid_type, void_checks, annotate_overrides, no_leading_underscores_for_local_identifiers, library_private_types_in_public_api diff --git a/scripts/linux/build_all.sh b/scripts/linux/build_all.sh index b1763d3..8f3a16b 100755 --- a/scripts/linux/build_all.sh +++ b/scripts/linux/build_all.sh @@ -1,5 +1,7 @@ #!/bin/bash -mkdir -p build +set -e + ./build_openssl.sh -./build_sharedfile.sh + + diff --git a/scripts/linux/build_openssl.sh b/scripts/linux/build_openssl.sh index dac17e5..3979806 100755 --- a/scripts/linux/build_openssl.sh +++ b/scripts/linux/build_openssl.sh @@ -2,67 +2,66 @@ set -e +export WORKDIR="$(pwd)/../../src/build/linux" +export ORIGINAL_PATH=$PATH +export THREADS=16 +export TYPES_OF_BUILD="x86_64" + if [ -z "$IS_ARM" ]; then - TYPES_OF_BUILD="x86_64" + export TYPES_OF_BUILD="x86_64" else - TYPES_OF_BUILD="aarch64" + export TYPES_OF_BUILD="aarch64" fi -THREADS=16 -WORKDIR="$(pwd)/"build -CACHEDIR="$(pwd)/"cache -mkdir -p $CACHEDIR +if [ ! -d "$WORKDIR" ] ; then + mkdir -p "$WORKDIR" +fi -OPENSSL_FILENAME=openssl-1.1.1k.tar.gz -OPENSSL_FILE_PATH=$CACHEDIR/$OPENSSL_FILENAME -OPENSSL_SRC_DIR=$WORKDIR/openssl-1.1.1k + +OPENSSL_FILENAME="openssl-1.1.1k.tar.gz" +OPENSSL_FILE_PATH="$WORKDIR/$OPENSSL_FILENAME" +OPENSSL_SRC_DIR="$WORKDIR/openssl-1.1.1k" OPENSSL_SHA256="892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5" - -ZLIB_DIR=$WORKDIR/zlib -ZLIB_TAG=v1.2.11 +ZLIB_DIR="$WORKDIR/zlib" +ZLIB_TAG="v1.2.11" ZLIB_COMMIT_HASH="cacf7f1d4e3d44d871b605da3b647f07d718623f" -# If a zlib dir exists, we assume that it's already been built. -# TODO make a better zlib-validity check. + if [ ! -d "$ZLIB_DIR" ] ; then git clone -b $ZLIB_TAG --depth 1 https://github.com/madler/zlib $ZLIB_DIR - cd $ZLIB_DIR - git reset --hard $ZLIB_COMMIT_HASH - ./configure --static - make fi +cd $ZLIB_DIR +git reset --hard $ZLIB_COMMIT_HASH +./configure --static +make -# Download openssl if it doesn't exist. curl https://www.openssl.org/source/$OPENSSL_FILENAME -o $OPENSSL_FILE_PATH - -# Validate checksum. echo $OPENSSL_SHA256 $OPENSSL_FILE_PATH | sha256sum -c - || exit 1 -# Build openssl for each arch. for arch in $TYPES_OF_BUILD do - echo "Building $TYPES_OF_BUILD" - PREFIX=$WORKDIR/prefix_${arch} +echo "Building $TYPES_OF_BUILD" +PREFIX=$WORKDIR/prefix_${arch} - case $arch in - "x86_64") X_ARCH="linux-x86_64";; - "aarch64") X_ARCH="linux-aarch64";; - *) X_ARCH="linux-x86_64";; - esac +case $arch in + "x86_64") X_ARCH="linux-x86_64";; + "aarch64") X_ARCH="linux-aarch64";; + *) X_ARCH="linux-x86_64";; +esac - cd $WORKDIR - # Don't delete the openssl source dir. We don't need clean builds every time. - # rm -rf $OPENSSL_SRC_DIR - tar -xzf $OPENSSL_FILE_PATH -C $WORKDIR - cd $OPENSSL_SRC_DIR +cd $WORKDIR +rm -rf $OPENSSL_SRC_DIR +tar -xzf $OPENSSL_FILE_PATH -C $WORKDIR +cd $OPENSSL_SRC_DIR + +./Configure ${X_ARCH} \ + no-asm no-shared \ + --with-zlib-include=${PREFIX}/include \ + --with-zlib-lib=${PREFIX}/lib \ + --prefix=${PREFIX} \ + --openssldir=${PREFIX} +make -j$THREADS +make -j$THREADS install_sw - #sed -i -e "s/mandroid/target\ ${TARGET}\-linux\-android/" Configure - ./Configure ${X_ARCH} \ - no-asm no-shared \ - --with-zlib-include=${PREFIX}/include \ - --with-zlib-lib=${PREFIX}/lib \ - --prefix=${PREFIX} \ - --openssldir=${PREFIX} - make -j$THREADS - make -j$THREADS install_sw done + diff --git a/scripts/linux/build_sharedfile.sh b/scripts/linux/build_sharedfile.sh deleted file mode 100755 index 5ed013b..0000000 --- a/scripts/linux/build_sharedfile.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -# Copy the sparkmobile submodule to the build directory for interfacing to Dart. -# -# We copy the fresh and unmodified sparkmobile submodule to the build directory in order to graft -# an additional Dart interface onto the sparkmobile library. -cp -r ../../sparkmobile . - -WORKDIR="$(pwd)/build" -SEDWORKDIR=$(echo $WORKDIR | sed 's/\//\\\//g') - -# Create new CMakelists.txt files for the sparkmobile and secp256k1 directories. -# -# Copy the template CMakelists.txt files to the working sparkmobile directory and replace the -# distribution_DIR variable with the working directory. -sed "s/SET(distribution_DIR \/opt\/android)/SET(distribution_DIR $SEDWORKDIR)/g" ./CMakeLists/sparkmobile/template_CMakeLists.txt > ./CMakeLists/sparkmobile/CMakeLists.txt -sed "s/SET(distribution_DIR \/opt\/android)/SET(distribution_DIR $SEDWORKDIR)/g" ./CMakeLists/secp256k1/template_CMakeLists.txt > ./CMakeLists/secp256k1/CMakeLists.txt - -# Copy the sparkmobile and secp256k1 CMakeLists.txts. -cp CMakeLists/sparkmobile/CMakeLists.txt sparkmobile/ -cp CMakeLists/secp256k1/CMakeLists.txt sparkmobile/secp256k1/ - -# Git versioning. -echo ''$(git log -1 --pretty=format:"%H")' '$(date) >> build/git_commit_version.txt -VERSIONS_FILE=../../lib/git_versions.dart -EXAMPLE_VERSIONS_FILE=../../lib/git_versions_example.dart -if [ ! -f "$VERSIONS_FILE" ]; then - cp $EXAMPLE_VERSIONS_FILE $VERSIONS_FILE -fi -COMMIT=$(git log -1 --pretty=format:"%H") -OS="LINUX" - -# Write the commit hash to the versions file. -sed -i "/\/\*${OS}_VERSION/c\\/\*${OS}_VERSION\*\/ const ${OS}_VERSION = \"$COMMIT\";" $VERSIONS_FILE - -# Build the shared library. -cd build -cmake ../sparkmobile -make -j$(nproc) diff --git a/scripts/prebuild.sh b/scripts/prebuild.sh new file mode 100755 index 0000000..a1a0966 --- /dev/null +++ b/scripts/prebuild.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -e + +cd ../src/deps + +if [ -d sparkmobile ]; then + rm -rf sparkmobile +fi + +git clone https://github.com/firoorg/sparkmobile.git +cd sparkmobile +git checkout ef2e39aae18ecc49e0ddc63a3183e9764b96012e + +cd .. +cp CMakeLists/sparkmobile/CMakeLists.txt sparkmobile/ +cp CMakeLists/secp256k1/CMakeLists.txt sparkmobile/secp256k1/ \ No newline at end of file diff --git a/sparkmobile b/sparkmobile deleted file mode 160000 index fe2148f..0000000 --- a/sparkmobile +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fe2148f01b04180cf3615dcecc6b1a6841c1ffe5 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..2b32120 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,26 @@ +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +project(flutter_libsparkmobile_library VERSION 0.0.1) + +SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}") + + + +add_library(flutter_libsparkmobile SHARED + "flutter_libsparkmobile.cpp" + "utils.cpp" +) + +add_subdirectory("deps/sparkmobile") + +set_target_properties(flutter_libsparkmobile PROPERTIES + PUBLIC_HEADER flutter_libsparkmobile.h + OUTPUT_NAME "flutter_libsparkmobile" +) + +target_link_libraries(flutter_libsparkmobile sparkmobile) + +target_compile_definitions(flutter_libsparkmobile PUBLIC DART_SHARED_LIB) diff --git a/src/cmake/FindGMP.cmake b/src/cmake/FindGMP.cmake new file mode 100644 index 0000000..bc4f035 --- /dev/null +++ b/src/cmake/FindGMP.cmake @@ -0,0 +1,7 @@ +find_path(GMP_INCLUDE_DIRS NAMES gmp.h) +find_library(GMP_LIBRARY NAMES gmp libgmp) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GMP DEFAULT_MSG + GMP_INCLUDE_DIRS + GMP_LIBRARY) +mark_as_advanced(GMP_INCLUDE_DIRS GMP_LIBRARY) \ No newline at end of file diff --git a/scripts/linux/CMakeLists/secp256k1/template_CMakeLists.txt b/src/deps/CMakeLists/secp256k1/CMakeLists.txt similarity index 63% rename from scripts/linux/CMakeLists/secp256k1/template_CMakeLists.txt rename to src/deps/CMakeLists/secp256k1/CMakeLists.txt index 00edb80..753eacf 100644 --- a/scripts/linux/CMakeLists/secp256k1/template_CMakeLists.txt +++ b/src/deps/CMakeLists/secp256k1/CMakeLists.txt @@ -1,9 +1,9 @@ # Copyright (c) 2017 The Bitcoin developers cmake_minimum_required(VERSION 3.1) -project(secp256k1) +project(secp256k1_spark) -SET(distribution_DIR /opt/android) +SET(distribution_DIR "../../../build/${BUILD_FOR_SYSTEM_NAME}") SET(OPENSSL_ROOT_DIR ${distribution_DIR}/prefix_${ANDROID_ABI}) SET(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/lib") @@ -22,14 +22,14 @@ LINK_DIRECTORIES(${OPENSSL_LIBRARIES_DIR}) # TODO: change this to include when possible include_directories(. include src/modules/ecdh src) -add_library(secp256k1 src/secp256k1.c src/cpp/GroupElement.cpp src/cpp/MultiExponent.cpp src/cpp/Scalar.cpp src/modules/ecdh/main_impl.h include/secp256k1_ecdh.h src/scratch_impl.h src/scratch.h) +add_library(secp256k1_spark src/secp256k1.c src/cpp/GroupElement.cpp src/cpp/MultiExponent.cpp src/cpp/Scalar.cpp src/modules/ecdh/main_impl.h include/secp256k1_ecdh.h src/scratch_impl.h src/scratch.h) # We need to link in GMP find_package(GMP) if(GMP_INCLUDE_DIR AND GMP_LIBRARIES) target_include_directories(secp256k1 PUBLIC ${GMP_INCLUDE_DIR}) - target_link_libraries(secp256k1 ${GMP_LIBRARIES}) - target_compile_definitions(secp256k1 + target_link_libraries(secp256k1_spark ${GMP_LIBRARIES}) + target_compile_definitions(secp256k1_spark PUBLIC HAVE_LIBGMP USE_NUM_GMP @@ -37,7 +37,7 @@ if(GMP_INCLUDE_DIR AND GMP_LIBRARIES) USE_SCALAR_INV_BUILTIN ) else() - target_compile_definitions(secp256k1 + target_compile_definitions(secp256k1_spark PUBLIC USE_NUM_NONE USE_FIELD_INV_BUILTIN @@ -49,7 +49,7 @@ endif() include(CheckTypeSize) check_type_size(__int128 SIZEOF___INT128) if(SIZEOF___INT128 EQUAL 16) - target_compile_definitions(secp256k1 PUBLIC HAVE___INT128) + target_compile_definitions(secp256k1_spark PUBLIC HAVE___INT128) else() # If we do not support __int128, we should be falling back # on 32bits implementations for field and scalar. @@ -64,17 +64,17 @@ if(CMAKE_SIZEOF_VOID_P EQUAL 8) message(SEND_ERROR "Compiler does not support __int128") endif() - target_compile_definitions(secp256k1 PUBLIC USE_SCALAR_4X64) - target_compile_definitions(secp256k1 PUBLIC USE_FIELD_5X52) + target_compile_definitions(secp256k1_spark PUBLIC USE_SCALAR_4X64) + target_compile_definitions(secp256k1_spark PUBLIC USE_FIELD_5X52) else() - target_compile_definitions(secp256k1 PUBLIC USE_SCALAR_8X32) - target_compile_definitions(secp256k1 PUBLIC USE_FIELD_10X26) + target_compile_definitions(secp256k1_spark PUBLIC USE_SCALAR_8X32) + target_compile_definitions(secp256k1_spark PUBLIC USE_FIELD_10X26) endif() # TODO: emult static precomputation # TODO: ecdh module # TODO: RECOVERY module -TARGET_INCLUDE_DIRECTORIES(secp256k1 PUBLIC ${OPENSSL_INCLUDE_DIR}) -TARGET_LINK_LIBRARIES(secp256k1 ${OPENSSL_LIBRARIES}) -#target_link_libraries(secp256k1 ${OPENSSL_LIBRARIES}) +TARGET_INCLUDE_DIRECTORIES(secp256k1_spark PUBLIC ${OPENSSL_INCLUDE_DIR}) +TARGET_LINK_LIBRARIES(secp256k1_spark ${OPENSSL_LIBRARIES}) +#target_link_libraries(secp256k1_spark ${OPENSSL_LIBRARIES}) diff --git a/scripts/linux/CMakeLists/sparkmobile/template_CMakeLists.txt b/src/deps/CMakeLists/sparkmobile/CMakeLists.txt similarity index 86% rename from scripts/linux/CMakeLists/sparkmobile/template_CMakeLists.txt rename to src/deps/CMakeLists/sparkmobile/CMakeLists.txt index 0301285..c5363ef 100644 --- a/scripts/linux/CMakeLists/sparkmobile/template_CMakeLists.txt +++ b/src/deps/CMakeLists/sparkmobile/CMakeLists.txt @@ -4,7 +4,7 @@ project(sparkmobile) set(OPENSSL_USE_STATIC_LIBS OFF CACHE BOOL "" FORCE) -SET(distribution_DIR /opt/android) +SET(distribution_DIR "../../build/${BUILD_FOR_SYSTEM_NAME}") SET(OPENSSL_ROOT_DIR ${distribution_DIR}/prefix_${ANDROID_ABI}) SET(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/lib") @@ -42,9 +42,7 @@ set_property(SOURCE src/spark.cpp src/schnorr.cpp src/spend_transaction.cpp src/transcript.cpp - src/util.cpp - src/utils.cpp - src/dart_interface.cpp + src/util.cpp PROPERTY COMPILE_FLAGS "-std=c++17" ) add_library(sparkmobile SHARED @@ -75,12 +73,10 @@ add_library(sparkmobile SHARED src/schnorr.cpp src/spend_transaction.cpp src/transcript.cpp - src/util.cpp - src/utils.cpp - src/dart_interface.cpp) + src/util.cpp) -target_link_libraries(sparkmobile ${OPENSSL_LIBRARIES} secp256k1) +target_link_libraries(sparkmobile ${OPENSSL_LIBRARIES} secp256k1_spark) -add_dependencies(sparkmobile secp256k1) +add_dependencies(sparkmobile secp256k1_spark) -target_include_directories(sparkmobile PUBLIC secp256k1 ${OPENSSL_INCLUDE_DIR}) +target_include_directories(sparkmobile PUBLIC secp256k1_spark ${OPENSSL_INCLUDE_DIR}) diff --git a/scripts/linux/CMakeLists/sparkmobile/LICENSE b/src/deps/CMakeLists/sparkmobile/LICENSE similarity index 100% rename from scripts/linux/CMakeLists/sparkmobile/LICENSE rename to src/deps/CMakeLists/sparkmobile/LICENSE diff --git a/src/flutter_libsparkmobile.cpp b/src/flutter_libsparkmobile.cpp new file mode 100644 index 0000000..c869e91 --- /dev/null +++ b/src/flutter_libsparkmobile.cpp @@ -0,0 +1,111 @@ +#include "flutter_libsparkmobile.h" +#include "utils.h" +#include "deps/sparkmobile/include/spark.h" + +#include +#include // Just for printing. + +using namespace spark; + + +/* + * FFI-friendly wrapper for spark::getAddress. + */ +FFI_PLUGIN_EXPORT +const char* getAddress(const char* keyDataHex, int index, int diversifier, int isTestNet) { + try { + // Use the hex string directly to create the SpendKey. + spark::SpendKey spendKey = createSpendKeyFromData(keyDataHex, index); + + spark::FullViewKey fullViewKey(spendKey); + spark::IncomingViewKey incomingViewKey(fullViewKey); + spark::Address address(incomingViewKey, static_cast(diversifier)); + + // Encode the Address object into a string using the appropriate network. + std::string encodedAddress = address.encode(isTestNet ? spark::ADDRESS_NETWORK_TESTNET : spark::ADDRESS_NETWORK_MAINNET); + + // Allocate memory for the C-style string. + char* cstr = new char[encodedAddress.length() + 1]; + std::strcpy(cstr, encodedAddress.c_str()); + + return cstr; + } catch (const std::exception& e) { + std::cerr << "Exception: " << e.what() << std::endl; + return nullptr; + } +} + +/* + * FFI-friendly wrapper for spark:identifyCoin. + * + * Uses the utility functions spark::Coin fromFFI(const CCoin& c_struct) to pass parameters to the + * C++ function spark::identifyCoin(const Coin& coin), then uses the utility function + * CIdentifiedCoinData toFFI(const spark::IdentifiedCoinData& cpp_struct) to convert the result back + * to a C struct. + * + * We also need the incoming view key or we need to derive it, so accept keyDataHex and index. + */ +FFI_PLUGIN_EXPORT +struct CIdentifiedCoinData identifyCoin(struct CCoin c_struct, const char* keyDataHex, int index) { + try { + spark::Coin coin = fromFFI(c_struct); + + // Derive the incoming view key from the key data and index. + spark::SpendKey spendKey = createSpendKeyFromData(keyDataHex, index); + spark::FullViewKey fullViewKey(spendKey); + spark::IncomingViewKey incomingViewKey(fullViewKey); + + spark::IdentifiedCoinData identifiedCoinData = coin.identify(incomingViewKey); + return toFFI(identifiedCoinData); + } catch (const std::exception& e) { + std::cerr << "Exception: " << e.what() << std::endl; + return CIdentifiedCoinData(); + } +} + +/* + * FFI-friendly wrapper for spark::createSparkMintRecipients. + */ +FFI_PLUGIN_EXPORT +struct CCRecipient* createSparkMintRecipients( + int numRecipients, + struct PubKeyScript* pubKeyScripts, + uint64_t* amounts, + const char* memo, + int subtractFee) +{ + try { + std::vector recipients; + + for (int i = 0; i < numRecipients; i++) { + CScript scriptPubKey = createCScriptFromBytes( + pubKeyScripts[i].bytes, + pubKeyScripts[i].length + ); + + CRecipient recipient; + recipient.pubKey = scriptPubKey; + + recipient.amount = amounts[i]; + + recipient.subtractFeeFromAmount = (bool)subtractFee; + + recipients.push_back(recipient); + } + + std::vector ccRecipients; + + for (const CRecipient& recipient : recipients) { + CCRecipient ccRecipient = toFFI(recipient); + ccRecipients.push_back(ccRecipient); + } + + CCRecipient* result = new CCRecipient[numRecipients]; + std::copy(ccRecipients.begin(), ccRecipients.end(), result); + + return result; + } catch (const std::exception& e) { + std::cerr << "Exception: " << e.what() << std::endl; + return nullptr; + } +} diff --git a/src/flutter_libsparkmobile.h b/src/flutter_libsparkmobile.h new file mode 100644 index 0000000..dd86981 --- /dev/null +++ b/src/flutter_libsparkmobile.h @@ -0,0 +1,118 @@ + +#ifndef ORG_FIRO_SPARK_DART_INTERFACE_H +#define ORG_FIRO_SPARK_DART_INTERFACE_H + +#include + +#ifndef FFI_PLUGIN_EXPORT +#ifdef __cplusplus +#define FFI_PLUGIN_EXPORT extern "C" __attribute__((visibility("default"))) __attribute__((used)) +#else +#define FFI_PLUGIN_EXPORT __attribute__((visibility("default"))) __attribute__((used)) +#endif +#ifdef _WIN32 +#define FFI_PLUGIN_EXPORT __declspec(dllexport) +#endif +#endif + + +/* + * FFI-friendly wrapper for spark::getAddress. + */ +FFI_PLUGIN_EXPORT +const char* getAddress(const char* keyDataHex, int index, int diversifier, int isTestNet); + +/* +FFI_PLUGIN_EXPORT +const char *createFullViewKey(const char* keyData, int index); + +FFI_PLUGIN_EXPORT +const char* createIncomingViewKey(const char* keyData, int index); +*/ + +/* + * FFI-friendly wrapper for a spark::Coin. + * + * A Coin is a type, a key, an index, a value, a memo, and a serial context. We accept these params + * as a C struct, deriving the key from the keyData and index. + */ +struct CCoin { + char type; + const unsigned char* k; + int kLength; + const char* keyData; + int index; + uint64_t v; + const unsigned char* memo; + int memoLength; + const unsigned char* serial_context; + int serial_contextLength; +}; + +/* + * FFI-friendly wrapper for a spark::IdentifiedCoinData. + * + * An IdentifiedCoinData is a diversifier, encrypted diversifier, value, nonce, and memo. We accept + * these params as a C struct. + */ +struct CIdentifiedCoinData { + uint64_t i; + const unsigned char* d; + int dLength; + uint64_t v; + const unsigned char* k; + int kLength; + const char* memo; + int memoLength; +}; + +/* + * FFI-friendly wrapper for spark::identifyCoin. + */ +FFI_PLUGIN_EXPORT +struct CIdentifiedCoinData identifyCoin(struct CCoin c_struct, const char* keyDataHex, int index); + +/* + * FFI-friendly wrapper for a spark::CRecipient. + * + * A CRecipient is a CScript, CAmount, and a bool. We accept a C-style, FFI-friendly CCRecipient + * struct in order to construct a C++ CRecipient. A CScript is constructed from a hex string, a + * CAmount is just a uint64_t, and the bool will be an int. + */ +struct CCRecipient { + const unsigned char* pubKey; + int pubKeyLength; + uint64_t cAmount; + int subtractFee; +}; + +/* + * FFI-friendly wrapper for a spark::MintedCoinData. + * + * A MintedCoinData is a struct that contains an Address, a uint64_t value, and a string memo. We + * accept these as a CMintedCoinData from the Dart interface, and convert them to a MintedCoinData + * struct. + */ +struct CMintedCoinData { + const char* address; + uint64_t value; + const char* memo; +}; + +struct PubKeyScript { + unsigned char* bytes; + int length; +}; + +/* + * FFI-friendly wrapper for spark::createSparkMintRecipients. + */ +FFI_PLUGIN_EXPORT +struct CCRecipient* createSparkMintRecipients( + int numRecipients, + struct PubKeyScript* pubKeyScripts, + uint64_t* amounts, + const char* memo, + int subtractFee); + +#endif //ORG_FIRO_SPARK_DART_INTERFACE_H diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 0000000..0c8d3ad --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,318 @@ +#include "utils.h" +#include +#include +#include +#include +#include +#include + + +#include "flutter_libsparkmobile.h" +#include "deps/sparkmobile/src/coin.h" +#include "deps/sparkmobile/src/keys.h" +#include "deps/sparkmobile//bitcoin/script.h" // For CScript. + +/* + * Utility function to generate an address from keyData, index, and a diversifier. + */ +const char* getAddressFromData(const char* keyData, int index, const uint64_t diversifier) { + try { + spark::SpendKey spendKey = createSpendKeyFromData(keyData, index); + spark::FullViewKey fullViewKey(spendKey); + spark::IncomingViewKey incomingViewKey(fullViewKey); + spark::Address address(incomingViewKey, diversifier); + + // Encode the Address object into a string. + std::string encodedAddress = address.encode(spark::ADDRESS_NETWORK_TESTNET); + + // Allocate memory for the C-style string and return it. + char* result = new char[encodedAddress.size() + 1]; + std::copy(encodedAddress.begin(), encodedAddress.end(), result); + result[encodedAddress.size()] = '\0'; // Null-terminate the C string. + + return result; + } catch (const std::exception& e) { + return nullptr; + } +} + +/* + * Utility function to generate SpendKey from keyData and index. + */ +spark::SpendKey createSpendKeyFromData(const char *keyData, int index) { + try { + // Convert the keyData from hex string to binary + unsigned char* key_data_bin = hexToBytes(keyData); + + const SpendKeyData *data = new SpendKeyData(key_data_bin, index); + + return createSpendKey(*data); + } catch (const std::exception& e) { + // We can't return here, so just throw the exception again. + throw e; + } +} + +/* + * CCoin factory. + * + * TODO manage the memory allocated by this function. + */ +struct CCoin createCCoin(char type, const unsigned char* k, int kLength, const char* keyData, int index, uint64_t v, const unsigned char* memo, int memoLength, const unsigned char* serial_context, int serial_contextLength) { + CCoin coin; + coin.type = type; + coin.k = copyBytes(k, kLength); + coin.kLength = kLength; + coin.keyData = strdup(keyData); + coin.index = index; + coin.v = v; + coin.memo = copyBytes(memo, memoLength); + coin.memoLength = memoLength; + coin.serial_context = copyBytes(serial_context, serial_contextLength); + coin.serial_contextLength = serial_contextLength; + return coin; +} + +/* + * Utility function to convert an FFI-friendly C CCoin struct to a C++ Coin struct. + */ +spark::Coin fromFFI(const CCoin& c_struct) { + spark::Coin cpp_struct( + // The test params are only used for unit tests. + spark::Params::get_default(), + c_struct.type, + spark::Scalar(c_struct.k), + spark::Address(spark::IncomingViewKey(spark::FullViewKey(createSpendKeyFromData(c_struct.keyData, c_struct.index))), c_struct.index), + c_struct.v, + std::string(reinterpret_cast(c_struct.memo), c_struct.memoLength), + std::vector(c_struct.serial_context, c_struct.serial_context + c_struct.serial_contextLength) + ); + + return cpp_struct; +} + +/* + * Utility function to convert a C++ IdentifiedCoinData struct to an FFI-friendly struct. + */ +CIdentifiedCoinData toFFI(const spark::IdentifiedCoinData& cpp_struct) { + CIdentifiedCoinData c_struct; + + c_struct.i = cpp_struct.i; + c_struct.d = copyBytes(cpp_struct.d.data(), cpp_struct.d.size()); + c_struct.dLength = cpp_struct.d.size(); + c_struct.v = cpp_struct.v; + + // Serialize and copy the Scalar k. + std::vector scalarBytes(32); + cpp_struct.k.serialize(scalarBytes.data()); + c_struct.k = copyBytes(scalarBytes.data(), scalarBytes.size()); + c_struct.kLength = scalarBytes.size(); + + // Copy the memo. + c_struct.memo = strdup(cpp_struct.memo.c_str()); + c_struct.memoLength = cpp_struct.memo.size(); + + return c_struct; +} + +/* + * Factory function to create a CScript from a byte array. + */ +CScript createCScriptFromBytes(const unsigned char* bytes, int length) { + // Construct a CScript object + CScript script; + + // Check if bytes is not nullptr and length is positive + if (bytes != nullptr && length > 0) { + // Append each byte to the script + for (int i = 0; i < length; ++i) { + script << bytes[i]; + } + } + + return script; +} + +/* + * Utility function to convert a C++ CScript to a byte array. + */ +std::vector serializeCScript(const CScript& script) { + return std::vector(script.begin(), script.end()); +} + +/* + * Utility function to convert an FFI-friendly C CCRecipient struct to a C++ CRecipient struct. + */ +CRecipient fromFFI(const CCRecipient& c_struct) { + // Use the factory function to create a CScript object. + CScript script = createCScriptFromBytes(c_struct.pubKey, c_struct.pubKeyLength); + + CRecipient cpp_struct = createCRecipient( + script, + c_struct.cAmount, + static_cast(c_struct.subtractFee) + ); + + return cpp_struct; +} + +/* + * CCRecipient factory. + * + * TODO manage the memory allocated by this function. + */ +struct CCRecipient createCCRecipient(const unsigned char* pubKey, uint64_t amount, int subtractFee) { + CCRecipient recipient; + recipient.pubKey = copyBytes(pubKey, 32); + recipient.cAmount = amount; + recipient.subtractFee = subtractFee; + return recipient; +} + +/* + * Utility function to convert a C++ CRecipient struct to an FFI-friendly struct. + */ +CCRecipient toFFI(const CRecipient& cpp_struct) { + CCRecipient c_struct; + + // Serialize CScript and copy. + std::vector scriptBytes = serializeCScript(cpp_struct.pubKey); + if (!scriptBytes.empty()) { + c_struct.pubKey = copyBytes(scriptBytes.data(), scriptBytes.size()); + c_struct.pubKeyLength = static_cast(scriptBytes.size()); + } else { + c_struct.pubKey = nullptr; + c_struct.pubKeyLength = 0; + } + + c_struct.cAmount = cpp_struct.amount; + c_struct.subtractFee = static_cast(cpp_struct.subtractFeeFromAmount); + + return c_struct; +} + +/* + * CRecipient factory. + * + * TODO manage the memory allocated by this function. + */ +CRecipient createCRecipient(const CScript& script, CAmount amount, bool subtractFee) { + CRecipient recipient; + recipient.pubKey = script; + recipient.amount = amount; + recipient.subtractFeeFromAmount = subtractFee; + return recipient; +} + +/* + * Utility function to decode an Address from a string. + */ +spark::Address decodeAddress(const std::string& str) { + spark::Address address; + address.decode(str); + + return address; +} + +/* + * MintedCoinData factory. + */ +spark::MintedCoinData createMintedCoinData(const char* address, uint64_t v, const char* memo) { + return { + decodeAddress(address), + v, + memo + }; +} + +/* + * Utility function to convert an FFI-friendly C CMintedCoinData struct to a C++ MintedCoinData. + */ +spark::MintedCoinData fromFFI(const CMintedCoinData& c_struct) { + return createMintedCoinData( + c_struct.address, + c_struct.value, + c_struct.memo + ); +} + +/* + * CMintedCoinData factory. + */ +CMintedCoinData createCMintedCoinData(const char* address, uint64_t value, const char* memo) { + CMintedCoinData c_struct; + c_struct.address = strdup(address); + c_struct.value = value; + c_struct.memo = strdup(memo); + return c_struct; +} + +/* + * Utility function to convert a C++ MintedCoinData struct to an FFI-friendly CMintedCoinData. + */ +CMintedCoinData toFFI(const spark::MintedCoinData& cpp_struct) { + return createCMintedCoinData( + cpp_struct.address.encode(true).c_str(), + cpp_struct.v, + cpp_struct.memo.c_str() + ); +} + +/* + * Utility function for deep copying byte arrays. + * + * Used by createCCoin. + */ +unsigned char* copyBytes(const unsigned char* source, int length) { + if (source == nullptr || length <= 0) return nullptr; + + unsigned char* dest = new unsigned char[length]; + std::memcpy(dest, source, length); + return dest; +} + +unsigned char *hexToBytes(const char *hexstr) { + size_t length = strlen(hexstr) / 2; + auto *chrs = (unsigned char *) malloc((length + 1) * sizeof(unsigned char)); + for (size_t i = 0, j = 0; j < length; i += 2, j++) { + chrs[j] = (hexstr[i] % 32 + 9) % 25 * 16 + (hexstr[i + 1] % 32 + 9) % 25; + } + chrs[length] = '\0'; + return chrs; +} + +const char *bytesToHex(const unsigned char *bytes, int size) { + std::string str; + for (int i = 0; i < size; ++i) { + const unsigned char ch = bytes[i]; + str.append(&hexArray[(ch & 0xF0) >> 4], 1); + str.append(&hexArray[ch & 0xF], 1); + } + char *new_str = new char[std::strlen(str.c_str()) + 1]; + std::strcpy(new_str, str.c_str()); + return new_str; +} + +const char *bytesToHex(const char *bytes, int size) { + std::string str; + for (int i = 0; i < size; ++i) { + const unsigned char ch = (const unsigned char) bytes[i]; + str.append(&hexArray[(ch & 0xF0) >> 4], 1); + str.append(&hexArray[ch & 0xF], 1); + } + char *new_str = new char[std::strlen(str.c_str()) + 1]; + std::strcpy(new_str, str.c_str()); + return new_str; +} + +const char *bytesToHex(std::vector bytes, int size) { + std::string str; + for (int i = 0; i < size; ++i) { + const unsigned char ch = bytes[i]; + str.append(&hexArray[(ch & 0xF0) >> 4], 1); + str.append(&hexArray[ch & 0xF], 1); + } + char *new_str = new char[std::strlen(str.c_str()) + 1]; + std::strcpy(new_str, str.c_str()); + return new_str; +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..3bdbb3f --- /dev/null +++ b/src/utils.h @@ -0,0 +1,62 @@ +#ifndef ORG_FIRO_SPARK_UTILS_H +#define ORG_FIRO_SPARK_UTILS_H + +#include +#include +#include +#include + +#include "flutter_libsparkmobile.h" +#include "deps/sparkmobile/include/spark.h" + +const char* getAddressFromData(const char* keyData, int index, const uint64_t diversifier); + +spark::SpendKey createSpendKeyFromData(const char *keyData, int index); + +spark::Coin fromFFI(const CCoin& c_struct); + +CCoin toFFI(const spark::Coin& cpp_struct); + +struct CCoin createCCoin(char type, const unsigned char* k, int kLength, const char* keyData, int index, uint64_t v, const unsigned char* memo, int memoLength, const unsigned char* serial_context, int serial_contextLength); + +spark::IdentifiedCoinData fromFFI(const CIdentifiedCoinData& c_struct); + +CIdentifiedCoinData toFFI(const spark::IdentifiedCoinData& cpp_struct); + +CScript createCScriptFromBytes(const unsigned char* bytes, int length); + +std::vector serializeCScript(const CScript& script); + +CRecipient createCRecipient(const CScript& script, CAmount amount, bool subtractFee); + +CRecipient fromFFI(const CCRecipient& c_struct); + +struct CCRecipient createCCRecipient(const unsigned char* pubKey, uint64_t amount, int subtractFee); + +CCRecipient toFFI(const CRecipient& cpp_struct); + +spark::Address decodeAddress(const std::string& str); + +spark::MintedCoinData createMintedCoinData(const char* address, uint64_t v, const char* memo); + +spark::MintedCoinData fromFFI(const CMintedCoinData& c_struct); + +CMintedCoinData createCMintedCoinData(const char* address, uint64_t value, const char* memo); + +CMintedCoinData toFFI(const spark::MintedCoinData& cpp_struct); + +char const hexArray[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', + 'e', 'f'}; + +unsigned char* copyBytes(const unsigned char* source, int length); + +unsigned char *hexToBytes(const char *str); + +const char *bytesToHex(const unsigned char *bytes, int size); + +const char *bytesToHex(const char *bytes, int size); + +const char *bytesToHex(std::vector bytes, int size); + + +#endif //ORG_FIRO_SPARK_UTILS_H diff --git a/test/flutter_libsparkmobile_method_channel_test.dart b/test/flutter_libsparkmobile_method_channel_test.dart deleted file mode 100644 index 51256d0..0000000 --- a/test/flutter_libsparkmobile_method_channel_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_libsparkmobile/flutter_libsparkmobile_method_channel.dart'; - -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - - MethodChannelFlutterLibsparkmobile platform = MethodChannelFlutterLibsparkmobile(); - const MethodChannel channel = MethodChannel('flutter_libsparkmobile'); - - setUp(() { - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( - channel, - (MethodCall methodCall) async { - return '42'; - }, - ); - }); - - tearDown(() { - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(channel, null); - }); - - test('getPlatformVersion', () async { - expect(await platform.getPlatformVersion(), '42'); - }); -} diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index a9dfa73..c1cebf3 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -8,89 +8,16 @@ cmake_minimum_required(VERSION 3.14) set(PROJECT_NAME "flutter_libsparkmobile") project(${PROJECT_NAME} LANGUAGES CXX) -# This value is used when generating builds using this plugin, so it must -# not be changed -set(PLUGIN_NAME "flutter_libsparkmobile_plugin") - -# Any new source files that you add to the plugin should be added here. -list(APPEND PLUGIN_SOURCES - "flutter_libsparkmobile_plugin.cpp" - "flutter_libsparkmobile_plugin.h" -) - -# Define the plugin library target. Its name must not be changed (see comment -# on PLUGIN_NAME above). -add_library(${PLUGIN_NAME} SHARED - "include/flutter_libsparkmobile/flutter_libsparkmobile_plugin_c_api.h" - "flutter_libsparkmobile_plugin_c_api.cpp" - ${PLUGIN_SOURCES} -) - -# Apply a standard set of build settings that are configured in the -# application-level CMakeLists.txt. This can be removed for plugins that want -# full control over build settings. -apply_standard_settings(${PLUGIN_NAME}) - -# Symbols are hidden by default to reduce the chance of accidental conflicts -# between plugins. This should not be removed; any symbols that should be -# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro. -set_target_properties(${PLUGIN_NAME} PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) - -# Source include directories and library dependencies. Add any plugin-specific -# dependencies here. -target_include_directories(${PLUGIN_NAME} INTERFACE - "${CMAKE_CURRENT_SOURCE_DIR}/include") -target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) +# Invoke the build for native code shared with the other target platforms. +# This can be changed to accommodate different builds. +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared") # List of absolute paths to libraries that should be bundled with the plugin. # This list could contain prebuilt libraries, or libraries created by an # external build triggered from this build file. set(flutter_libsparkmobile_bundled_libraries - "" + # Defined in ../src/CMakeLists.txt. + # This can be changed to accommodate different builds. + $ PARENT_SCOPE ) - -# === Tests === -# These unit tests can be run from a terminal after building the example, or -# from Visual Studio after opening the generated solution file. - -# Only enable test builds when building the example (which sets this variable) -# so that plugin clients aren't building the tests. -if (${include_${PROJECT_NAME}_tests}) -set(TEST_RUNNER "${PROJECT_NAME}_test") -enable_testing() - -# Add the Google Test dependency. -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/release-1.11.0.zip -) -# Prevent overriding the parent project's compiler/linker settings -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -# Disable install commands for gtest so it doesn't end up in the bundle. -set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE) -FetchContent_MakeAvailable(googletest) - -# The plugin's C API is not very useful for unit testing, so build the sources -# directly into the test binary rather than using the DLL. -add_executable(${TEST_RUNNER} - test/flutter_libsparkmobile_plugin_test.cpp - ${PLUGIN_SOURCES} -) -apply_standard_settings(${TEST_RUNNER}) -target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") -target_link_libraries(${TEST_RUNNER} PRIVATE flutter_wrapper_plugin) -target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock) -# flutter_wrapper_plugin has link dependencies on the Flutter DLL. -add_custom_command(TARGET ${TEST_RUNNER} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${FLUTTER_LIBRARY}" $ -) - -# Enable automatic test discovery. -include(GoogleTest) -gtest_discover_tests(${TEST_RUNNER}) -endif() diff --git a/windows/flutter_libsparkmobile_plugin.cpp b/windows/flutter_libsparkmobile_plugin.cpp deleted file mode 100644 index 4d101c6..0000000 --- a/windows/flutter_libsparkmobile_plugin.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "flutter_libsparkmobile_plugin.h" - -// This must be included before many other Windows headers. -#include - -// For getPlatformVersion; remove unless needed for your plugin implementation. -#include - -#include -#include -#include - -#include -#include - -namespace flutter_libsparkmobile { - -// static -void FlutterLibsparkmobilePlugin::RegisterWithRegistrar( - flutter::PluginRegistrarWindows *registrar) { - auto channel = - std::make_unique>( - registrar->messenger(), "flutter_libsparkmobile", - &flutter::StandardMethodCodec::GetInstance()); - - auto plugin = std::make_unique(); - - channel->SetMethodCallHandler( - [plugin_pointer = plugin.get()](const auto &call, auto result) { - plugin_pointer->HandleMethodCall(call, std::move(result)); - }); - - registrar->AddPlugin(std::move(plugin)); -} - -FlutterLibsparkmobilePlugin::FlutterLibsparkmobilePlugin() {} - -FlutterLibsparkmobilePlugin::~FlutterLibsparkmobilePlugin() {} - -void FlutterLibsparkmobilePlugin::HandleMethodCall( - const flutter::MethodCall &method_call, - std::unique_ptr> result) { - if (method_call.method_name().compare("getPlatformVersion") == 0) { - std::ostringstream version_stream; - version_stream << "Windows "; - if (IsWindows10OrGreater()) { - version_stream << "10+"; - } else if (IsWindows8OrGreater()) { - version_stream << "8"; - } else if (IsWindows7OrGreater()) { - version_stream << "7"; - } - result->Success(flutter::EncodableValue(version_stream.str())); - } else { - result->NotImplemented(); - } -} - -} // namespace flutter_libsparkmobile diff --git a/windows/flutter_libsparkmobile_plugin.h b/windows/flutter_libsparkmobile_plugin.h deleted file mode 100644 index 915de79..0000000 --- a/windows/flutter_libsparkmobile_plugin.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_H_ -#define FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_H_ - -#include -#include - -#include - -namespace flutter_libsparkmobile { - -class FlutterLibsparkmobilePlugin : public flutter::Plugin { - public: - static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); - - FlutterLibsparkmobilePlugin(); - - virtual ~FlutterLibsparkmobilePlugin(); - - // Disallow copy and assign. - FlutterLibsparkmobilePlugin(const FlutterLibsparkmobilePlugin&) = delete; - FlutterLibsparkmobilePlugin& operator=(const FlutterLibsparkmobilePlugin&) = delete; - - // Called when a method is called on this plugin's channel from Dart. - void HandleMethodCall( - const flutter::MethodCall &method_call, - std::unique_ptr> result); -}; - -} // namespace flutter_libsparkmobile - -#endif // FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_H_ diff --git a/windows/flutter_libsparkmobile_plugin_c_api.cpp b/windows/flutter_libsparkmobile_plugin_c_api.cpp deleted file mode 100644 index db909b6..0000000 --- a/windows/flutter_libsparkmobile_plugin_c_api.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "include/flutter_libsparkmobile/flutter_libsparkmobile_plugin_c_api.h" - -#include - -#include "flutter_libsparkmobile_plugin.h" - -void FlutterLibsparkmobilePluginCApiRegisterWithRegistrar( - FlutterDesktopPluginRegistrarRef registrar) { - flutter_libsparkmobile::FlutterLibsparkmobilePlugin::RegisterWithRegistrar( - flutter::PluginRegistrarManager::GetInstance() - ->GetRegistrar(registrar)); -} diff --git a/windows/include/flutter_libsparkmobile/flutter_libsparkmobile_plugin_c_api.h b/windows/include/flutter_libsparkmobile/flutter_libsparkmobile_plugin_c_api.h deleted file mode 100644 index 2d02f3c..0000000 --- a/windows/include/flutter_libsparkmobile/flutter_libsparkmobile_plugin_c_api.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_C_API_H_ -#define FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_C_API_H_ - -#include - -#ifdef FLUTTER_PLUGIN_IMPL -#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) -#else -#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -FLUTTER_PLUGIN_EXPORT void FlutterLibsparkmobilePluginCApiRegisterWithRegistrar( - FlutterDesktopPluginRegistrarRef registrar); - -#if defined(__cplusplus) -} // extern "C" -#endif - -#endif // FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_C_API_H_ diff --git a/windows/test/flutter_libsparkmobile_plugin_test.cpp b/windows/test/flutter_libsparkmobile_plugin_test.cpp deleted file mode 100644 index f5511c2..0000000 --- a/windows/test/flutter_libsparkmobile_plugin_test.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "flutter_libsparkmobile_plugin.h" - -namespace flutter_libsparkmobile { -namespace test { - -namespace { - -using flutter::EncodableMap; -using flutter::EncodableValue; -using flutter::MethodCall; -using flutter::MethodResultFunctions; - -} // namespace - -TEST(FlutterLibsparkmobilePlugin, GetPlatformVersion) { - FlutterLibsparkmobilePlugin plugin; - // Save the reply value from the success callback. - std::string result_string; - plugin.HandleMethodCall( - MethodCall("getPlatformVersion", std::make_unique()), - std::make_unique>( - [&result_string](const EncodableValue* result) { - result_string = std::get(*result); - }, - nullptr, nullptr)); - - // Since the exact string varies by host, just ensure that it's a string - // with the expected format. - EXPECT_TRUE(result_string.rfind("Windows ", 0) == 0); -} - -} // namespace test -} // namespace flutter_libsparkmobile