[#971] Refactor Rust FFI to separate module
--------- Co-authored-by: Honza <rychnovsky.honza@gmail.com>
This commit is contained in:
parent
ca0e69d97f
commit
bc19797125
|
@ -357,6 +357,9 @@ jobs:
|
||||||
ORG_GRADLE_PROJECT_ZCASH_RELEASE_KEY_ALIAS: androiddebugkey
|
ORG_GRADLE_PROJECT_ZCASH_RELEASE_KEY_ALIAS: androiddebugkey
|
||||||
ORG_GRADLE_PROJECT_ZCASH_RELEASE_KEY_ALIAS_PASSWORD: android
|
ORG_GRADLE_PROJECT_ZCASH_RELEASE_KEY_ALIAS_PASSWORD: android
|
||||||
run: |
|
run: |
|
||||||
|
# Due to issues with the Rust integration, building the release APK requires running the task twice to
|
||||||
|
# ensure the native libraries are bundled in the APK
|
||||||
|
./gradlew assembleRelease
|
||||||
./gradlew assembleRelease
|
./gradlew assembleRelease
|
||||||
- name: Collect Artifacts
|
- name: Collect Artifacts
|
||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name=":backend-lib:connectedAndroidTest" type="AndroidTestRunConfigurationType" factoryName="Android Instrumented Tests">
|
||||||
|
<module name="zcash-android-sdk.backend-lib.androidTest" />
|
||||||
|
<option name="TESTING_TYPE" value="0" />
|
||||||
|
<option name="METHOD_NAME" value="" />
|
||||||
|
<option name="CLASS_NAME" value="" />
|
||||||
|
<option name="PACKAGE_NAME" value="" />
|
||||||
|
<option name="TEST_NAME_REGEX" value="" />
|
||||||
|
<option name="INSTRUMENTATION_RUNNER_CLASS" value="" />
|
||||||
|
<option name="EXTRA_OPTIONS" value="" />
|
||||||
|
<option name="RETENTION_ENABLED" value="No" />
|
||||||
|
<option name="RETENTION_MAX_SNAPSHOTS" value="2" />
|
||||||
|
<option name="RETENTION_COMPRESS_SNAPSHOTS" value="false" />
|
||||||
|
<option name="CLEAR_LOGCAT" value="false" />
|
||||||
|
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
||||||
|
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
|
||||||
|
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
||||||
|
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="2147483645" />
|
||||||
|
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="locale-debug-48db7" />
|
||||||
|
<option name="DEBUGGER_TYPE" value="Auto" />
|
||||||
|
<Auto>
|
||||||
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
|
<option name="WORKING_DIR" value="" />
|
||||||
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Auto>
|
||||||
|
<Hybrid>
|
||||||
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
|
<option name="WORKING_DIR" value="" />
|
||||||
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Hybrid>
|
||||||
|
<Java>
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Java>
|
||||||
|
<Native>
|
||||||
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
|
<option name="WORKING_DIR" value="" />
|
||||||
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Native>
|
||||||
|
<Profilers>
|
||||||
|
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
||||||
|
<option name="STARTUP_PROFILING_ENABLED" value="false" />
|
||||||
|
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
|
||||||
|
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Callstack Sample" />
|
||||||
|
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
|
||||||
|
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
|
||||||
|
</Profilers>
|
||||||
|
<method v="2">
|
||||||
|
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
|
@ -0,0 +1,64 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name=":lightwallet-client-lib:connectedAndroidTest" type="AndroidTestRunConfigurationType" factoryName="Android Instrumented Tests">
|
||||||
|
<module name="zcash-android-sdk.lightwallet-client-lib.androidTest" />
|
||||||
|
<option name="TESTING_TYPE" value="0" />
|
||||||
|
<option name="METHOD_NAME" value="" />
|
||||||
|
<option name="CLASS_NAME" value="" />
|
||||||
|
<option name="PACKAGE_NAME" value="" />
|
||||||
|
<option name="TEST_NAME_REGEX" value="" />
|
||||||
|
<option name="INSTRUMENTATION_RUNNER_CLASS" value="" />
|
||||||
|
<option name="EXTRA_OPTIONS" value="" />
|
||||||
|
<option name="RETENTION_ENABLED" value="No" />
|
||||||
|
<option name="RETENTION_MAX_SNAPSHOTS" value="2" />
|
||||||
|
<option name="RETENTION_COMPRESS_SNAPSHOTS" value="false" />
|
||||||
|
<option name="CLEAR_LOGCAT" value="false" />
|
||||||
|
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
||||||
|
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
|
||||||
|
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
||||||
|
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="2147483645" />
|
||||||
|
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="locale-debug-48db7" />
|
||||||
|
<option name="DEBUGGER_TYPE" value="Auto" />
|
||||||
|
<Auto>
|
||||||
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
|
<option name="WORKING_DIR" value="" />
|
||||||
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Auto>
|
||||||
|
<Hybrid>
|
||||||
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
|
<option name="WORKING_DIR" value="" />
|
||||||
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Hybrid>
|
||||||
|
<Java>
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Java>
|
||||||
|
<Native>
|
||||||
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
|
<option name="WORKING_DIR" value="" />
|
||||||
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Native>
|
||||||
|
<Profilers>
|
||||||
|
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
||||||
|
<option name="STARTUP_PROFILING_ENABLED" value="false" />
|
||||||
|
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
|
||||||
|
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Callstack Sample" />
|
||||||
|
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
|
||||||
|
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
|
||||||
|
</Profilers>
|
||||||
|
<method v="2">
|
||||||
|
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
|
@ -0,0 +1,64 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name=":sdk-incubator-lib:connectedAndroidTest" type="AndroidTestRunConfigurationType" factoryName="Android Instrumented Tests">
|
||||||
|
<module name="zcash-android-sdk.sdk-incubator-lib.androidTest" />
|
||||||
|
<option name="TESTING_TYPE" value="0" />
|
||||||
|
<option name="METHOD_NAME" value="" />
|
||||||
|
<option name="CLASS_NAME" value="" />
|
||||||
|
<option name="PACKAGE_NAME" value="" />
|
||||||
|
<option name="TEST_NAME_REGEX" value="" />
|
||||||
|
<option name="INSTRUMENTATION_RUNNER_CLASS" value="" />
|
||||||
|
<option name="EXTRA_OPTIONS" value="" />
|
||||||
|
<option name="RETENTION_ENABLED" value="No" />
|
||||||
|
<option name="RETENTION_MAX_SNAPSHOTS" value="2" />
|
||||||
|
<option name="RETENTION_COMPRESS_SNAPSHOTS" value="false" />
|
||||||
|
<option name="CLEAR_LOGCAT" value="false" />
|
||||||
|
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
||||||
|
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
|
||||||
|
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
||||||
|
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="2147483645" />
|
||||||
|
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="locale-debug-48db7" />
|
||||||
|
<option name="DEBUGGER_TYPE" value="Auto" />
|
||||||
|
<Auto>
|
||||||
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
|
<option name="WORKING_DIR" value="" />
|
||||||
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Auto>
|
||||||
|
<Hybrid>
|
||||||
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
|
<option name="WORKING_DIR" value="" />
|
||||||
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Hybrid>
|
||||||
|
<Java>
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Java>
|
||||||
|
<Native>
|
||||||
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
|
<option name="WORKING_DIR" value="" />
|
||||||
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Native>
|
||||||
|
<Profilers>
|
||||||
|
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
||||||
|
<option name="STARTUP_PROFILING_ENABLED" value="false" />
|
||||||
|
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
|
||||||
|
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Callstack Sample" />
|
||||||
|
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
|
||||||
|
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
|
||||||
|
</Profilers>
|
||||||
|
<method v="2">
|
||||||
|
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
|
@ -1,7 +1,6 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="demo-app-benchmark-test:connectedBenchmarkAndroidTest"
|
<configuration default="false" name="demo-app-benchmark-test:connectedBenchmarkAndroidTest" type="AndroidTestRunConfigurationType" factoryName="Android Instrumented Tests">
|
||||||
type="AndroidTestRunConfigurationType" factoryName="Android Instrumented Tests">
|
<module name="zcash-android-sdk.demo-app-benchmark-test.main" />
|
||||||
<module name="zcash-android-sdk.demo-app-benchmark-test" />
|
|
||||||
<option name="TESTING_TYPE" value="0" />
|
<option name="TESTING_TYPE" value="0" />
|
||||||
<option name="METHOD_NAME" value="" />
|
<option name="METHOD_NAME" value="" />
|
||||||
<option name="CLASS_NAME" value="" />
|
<option name="CLASS_NAME" value="" />
|
||||||
|
@ -16,8 +15,8 @@
|
||||||
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
||||||
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
|
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
|
||||||
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
||||||
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
|
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="2147483645" />
|
||||||
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="" />
|
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="locale-debug-48db7" />
|
||||||
<option name="DEBUGGER_TYPE" value="Auto" />
|
<option name="DEBUGGER_TYPE" value="Auto" />
|
||||||
<Auto>
|
<Auto>
|
||||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
@ -25,6 +24,8 @@
|
||||||
<option name="WORKING_DIR" value="" />
|
<option name="WORKING_DIR" value="" />
|
||||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
</Auto>
|
</Auto>
|
||||||
<Hybrid>
|
<Hybrid>
|
||||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
@ -32,14 +33,21 @@
|
||||||
<option name="WORKING_DIR" value="" />
|
<option name="WORKING_DIR" value="" />
|
||||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
</Hybrid>
|
</Hybrid>
|
||||||
<Java />
|
<Java>
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Java>
|
||||||
<Native>
|
<Native>
|
||||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
<option name="SHOW_STATIC_VARS" value="true" />
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
<option name="WORKING_DIR" value="" />
|
<option name="WORKING_DIR" value="" />
|
||||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
</Native>
|
</Native>
|
||||||
<Profilers>
|
<Profilers>
|
||||||
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name=":darkside-test-lib:connectedAndroidTest" type="AndroidTestRunConfigurationType" factoryName="Android Instrumented Tests">
|
<configuration default="false" name=":darkside-test-lib:connectedAndroidTest" type="AndroidTestRunConfigurationType" factoryName="Android Instrumented Tests">
|
||||||
<module name="zcash-android-sdk.darkside-test-lib" />
|
<module name="zcash-android-sdk.darkside-test-lib.androidTest" />
|
||||||
<option name="TESTING_TYPE" value="0" />
|
<option name="TESTING_TYPE" value="0" />
|
||||||
<option name="METHOD_NAME" value="" />
|
<option name="METHOD_NAME" value="" />
|
||||||
<option name="CLASS_NAME" value="" />
|
<option name="CLASS_NAME" value="" />
|
||||||
<option name="PACKAGE_NAME" value="" />
|
<option name="PACKAGE_NAME" value="" />
|
||||||
|
<option name="TEST_NAME_REGEX" value="" />
|
||||||
<option name="INSTRUMENTATION_RUNNER_CLASS" value="" />
|
<option name="INSTRUMENTATION_RUNNER_CLASS" value="" />
|
||||||
<option name="EXTRA_OPTIONS" value="" />
|
<option name="EXTRA_OPTIONS" value="" />
|
||||||
<option name="INCLUDE_GRADLE_EXTRA_OPTIONS" value="true" />
|
<option name="RETENTION_ENABLED" value="No" />
|
||||||
|
<option name="RETENTION_MAX_SNAPSHOTS" value="2" />
|
||||||
|
<option name="RETENTION_COMPRESS_SNAPSHOTS" value="false" />
|
||||||
<option name="CLEAR_LOGCAT" value="false" />
|
<option name="CLEAR_LOGCAT" value="false" />
|
||||||
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
||||||
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
|
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
|
||||||
<option name="FORCE_STOP_RUNNING_APP" value="true" />
|
|
||||||
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
||||||
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="2147483645" />
|
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="2147483645" />
|
||||||
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="api-9130115880275692386-873230" />
|
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="locale-debug-48db7" />
|
||||||
<option name="DEBUGGER_TYPE" value="Auto" />
|
<option name="DEBUGGER_TYPE" value="Auto" />
|
||||||
<Auto>
|
<Auto>
|
||||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
@ -22,6 +24,8 @@
|
||||||
<option name="WORKING_DIR" value="" />
|
<option name="WORKING_DIR" value="" />
|
||||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
</Auto>
|
</Auto>
|
||||||
<Hybrid>
|
<Hybrid>
|
||||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
@ -29,20 +33,27 @@
|
||||||
<option name="WORKING_DIR" value="" />
|
<option name="WORKING_DIR" value="" />
|
||||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
</Hybrid>
|
</Hybrid>
|
||||||
<Java />
|
<Java>
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Java>
|
||||||
<Native>
|
<Native>
|
||||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
<option name="SHOW_STATIC_VARS" value="true" />
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
<option name="WORKING_DIR" value="" />
|
<option name="WORKING_DIR" value="" />
|
||||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
</Native>
|
</Native>
|
||||||
<Profilers>
|
<Profilers>
|
||||||
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
||||||
<option name="STARTUP_PROFILING_ENABLED" value="false" />
|
<option name="STARTUP_PROFILING_ENABLED" value="false" />
|
||||||
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
|
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
|
||||||
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Sample Java Methods" />
|
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Callstack Sample" />
|
||||||
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
|
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
|
||||||
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
|
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
|
||||||
</Profilers>
|
</Profilers>
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
<option name="METHOD_NAME" value="" />
|
<option name="METHOD_NAME" value="" />
|
||||||
<option name="CLASS_NAME" value="" />
|
<option name="CLASS_NAME" value="" />
|
||||||
<option name="PACKAGE_NAME" value="" />
|
<option name="PACKAGE_NAME" value="" />
|
||||||
|
<option name="TEST_NAME_REGEX" value="" />
|
||||||
<option name="INSTRUMENTATION_RUNNER_CLASS" value="" />
|
<option name="INSTRUMENTATION_RUNNER_CLASS" value="" />
|
||||||
<option name="EXTRA_OPTIONS" value="" />
|
<option name="EXTRA_OPTIONS" value="" />
|
||||||
<option name="INCLUDE_GRADLE_EXTRA_OPTIONS" value="true" />
|
|
||||||
<option name="RETENTION_ENABLED" value="No" />
|
<option name="RETENTION_ENABLED" value="No" />
|
||||||
<option name="RETENTION_MAX_SNAPSHOTS" value="2" />
|
<option name="RETENTION_MAX_SNAPSHOTS" value="2" />
|
||||||
<option name="RETENTION_COMPRESS_SNAPSHOTS" value="false" />
|
<option name="RETENTION_COMPRESS_SNAPSHOTS" value="false" />
|
||||||
|
@ -16,6 +16,7 @@
|
||||||
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
|
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
|
||||||
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
||||||
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="2147483645" />
|
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="2147483645" />
|
||||||
|
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="locale-debug-48db7" />
|
||||||
<option name="DEBUGGER_TYPE" value="Auto" />
|
<option name="DEBUGGER_TYPE" value="Auto" />
|
||||||
<Auto>
|
<Auto>
|
||||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
@ -23,6 +24,8 @@
|
||||||
<option name="WORKING_DIR" value="" />
|
<option name="WORKING_DIR" value="" />
|
||||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
</Auto>
|
</Auto>
|
||||||
<Hybrid>
|
<Hybrid>
|
||||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
|
@ -30,14 +33,21 @@
|
||||||
<option name="WORKING_DIR" value="" />
|
<option name="WORKING_DIR" value="" />
|
||||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
</Hybrid>
|
</Hybrid>
|
||||||
<Java />
|
<Java>
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
|
</Java>
|
||||||
<Native>
|
<Native>
|
||||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
<option name="SHOW_STATIC_VARS" value="true" />
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
<option name="WORKING_DIR" value="" />
|
<option name="WORKING_DIR" value="" />
|
||||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
</Native>
|
</Native>
|
||||||
<Profilers>
|
<Profilers>
|
||||||
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
137
CHANGELOG.md
137
CHANGELOG.md
|
@ -1,25 +1,20 @@
|
||||||
Change Log
|
# Change Log
|
||||||
==========
|
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
- The SDK's `CompactBlockProcessor` switched from processing **all blocks in one run** mechanism to **batched blocks**
|
- Transparent fund balances are now displayed almost immediately
|
||||||
processing. This was necessary for the sync state's parallelization. Example of syncing of the latest
|
- Synchronization of shielded balances and transaction history is about 30% faster
|
||||||
100 blocks:
|
- Disk space usage is reduced by about 90%
|
||||||
- Previously: _Download 100 blocks -> Validate 100 blocks -> Scan 100 blocks -> SYNCED_
|
- `Synchronizer.status` has been simplified by combining `DOWNLOADING`, `VALIDATING`, and `SCANNING` states into a single `SYNCING` state.
|
||||||
- Now: _10x (Download 10 blocks -> Validate 10 blocks -> Scan 10 blocks) -> SYNCED_
|
- `Synchronizer.progress` now returns `Flow<PercentDecimal>` instead of `Flow<Int>`. PercentDecimal is a type-safe model. Use `PercentDecimal.toPercentage()` to get a number within 0-100% scale.
|
||||||
- `Synchronizer.progress` now returns `Flow<PercentDecimal>` instead of `Flow<Int>`. PercentDecimal is a type-safe
|
- `Synchronizer.clearedTransactions` has been renamed to `Synchronizer.transactions` and includes sent, received, and pending transactions. Synchronizer APIs for listing sent, received, and pending transactions have been removed. Clients can determine whether a transaction is sent, received, or pending by filtering the `TransactionOverview` objects returned by `Synchronizer.transactions`
|
||||||
model.
|
|
||||||
Use `PercentDecimal.toPercentage()` to get a number within 0-100% scale.
|
|
||||||
- `Synchronizer.status` now provides a new `SYNCING` state, which covers all three previous `DOWNLOADING`,
|
|
||||||
`VALIDATING`, and `SCANNING` states, which were eliminated in favor of `SYNCING` state.
|
|
||||||
|
|
||||||
## 1.17.0-beta01
|
|
||||||
- Synchronizer APIs for listing sent and received transactions have been removed.
|
|
||||||
- Synchronizer APIs for listing pending transactions have been removed, along with the `PendingTransaction` object.
|
|
||||||
- `Synchronizer.clearedTransactions` has been renamed to `Synchronizer.transactions` and includes sent, received, and pending transactions.
|
|
||||||
- `Synchronizer.send()` and `shieldFunds()` are now `suspend` functions with `Long` return values representing the ID of the newly created transaction. Errors are reported by thrown exceptions.
|
- `Synchronizer.send()` and `shieldFunds()` are now `suspend` functions with `Long` return values representing the ID of the newly created transaction. Errors are reported by thrown exceptions.
|
||||||
|
- `DerivationTool` is now an interface, rather than an `object`, which makes it easier to inject alternative implementations into tests. To adapt to the new API, replace calls to `DerivationTool.methodName()` with `DerivationTool.getInstance().methodName()`.
|
||||||
|
- `DerivationTool` methods are no longer suspending, which should make it easier to call them in various situations. Obtaining a `DerivationTool` instance via `DerivationTool.getInstance()` frontloads the need for a suspending call.
|
||||||
|
- `DerivationTool.deriveUnifiedFullViewingKeys()` no longer has a default argument for `numberOfAccounts`. Clients should now pass `DerivationTool.DEFAULT_NUMBER_OF_ACCOUNTS` as the value. Note that the SDK does not currently have proper support for multiple accounts.
|
||||||
|
- The SDK's internals for connecting with librustzcash have been refactored to a separate Gradle module `backend-lib` (and therefore a separate artifact) which is a transitive dependency of the Zcash Android SDK. SDK consumers that use Gradle dependency locks may notice this difference, but otherwise it should be mostly an invisible change.
|
||||||
|
|
||||||
## 1.16.0-beta01
|
## 1.16.0-beta01
|
||||||
|
(This version was only deployed as a snapshot and not released on Maven Central)
|
||||||
### Changed
|
### Changed
|
||||||
- The minimum supported version of Android is now API level 27.
|
- The minimum supported version of Android is now API level 27.
|
||||||
|
|
||||||
|
@ -27,7 +22,7 @@ processing. This was necessary for the sync state's parallelization. Example of
|
||||||
### Changed
|
### Changed
|
||||||
- A new package `sdk-incubator-lib` is now available as a public API. This package contains experimental APIs that may be promoted to the SDK in the future. The APIs in this package are not guaranteed to be stable, and may change at any time.
|
- A new package `sdk-incubator-lib` is now available as a public API. This package contains experimental APIs that may be promoted to the SDK in the future. The APIs in this package are not guaranteed to be stable, and may change at any time.
|
||||||
- `Synchronizer.refreshUtxos` now takes `Account` type as first parameter instead of transparent address of type
|
- `Synchronizer.refreshUtxos` now takes `Account` type as first parameter instead of transparent address of type
|
||||||
`String`, and thus it downloads all UTXOs for the given account addresses.
|
`String`, and thus it downloads all UTXOs for the given account addresses. The Account object provides a default `0` index Account with `Account.DEFAULT`.
|
||||||
|
|
||||||
## 1.14.0-beta01
|
## 1.14.0-beta01
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -41,6 +36,7 @@ processing. This was necessary for the sync state's parallelization. Example of
|
||||||
- The new networking module now provides a `LightWalletClient` for asynchronous calls.
|
- The new networking module now provides a `LightWalletClient` for asynchronous calls.
|
||||||
- Most unary calls respond with the new `Response` class and its subclasses. Streaming calls will be updated
|
- Most unary calls respond with the new `Response` class and its subclasses. Streaming calls will be updated
|
||||||
with the Response class later.
|
with the Response class later.
|
||||||
|
- SDK clients should avoid using generated GRPC objects, as these are an internal implementation detail and are in process of being removed from the public API. Any clients using GRPC objects will find these have been repackaged from `cash.z.wallet.sdk.rpc` to `cash.z.wallet.sdk.internal.rpc` to signal they are not a public API.
|
||||||
|
|
||||||
## 1.12.0-beta01
|
## 1.12.0-beta01
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -122,58 +118,48 @@ processing. This was necessary for the sync state's parallelization. Example of
|
||||||
- `DerivationTool.deriveUnifiedViewingKeys` (use `DerivationTool.deriveUnifiedFullViewingKey` instead)
|
- `DerivationTool.deriveUnifiedViewingKeys` (use `DerivationTool.deriveUnifiedFullViewingKey` instead)
|
||||||
- `DerivationTool.validateUnifiedViewingKey`
|
- `DerivationTool.validateUnifiedViewingKey`
|
||||||
|
|
||||||
Version 1.9.0-beta05
|
## Version 1.9.0-beta05
|
||||||
------------------------------------
|
|
||||||
- The minimum version of Android supported is now API 21
|
- The minimum version of Android supported is now API 21
|
||||||
- Fixed R8/ProGuard consumer rule, which eliminates a runtime crash for minified apps
|
- Fixed R8/ProGuard consumer rule, which eliminates a runtime crash for minified apps
|
||||||
|
|
||||||
Version 1.9.0-beta04
|
## Version 1.9.0-beta04
|
||||||
------------------------------------
|
|
||||||
- The SDK now stores sapling param files in `no_backup/co.electricoin.zcash` folder instead of the `cache/params`
|
- The SDK now stores sapling param files in `no_backup/co.electricoin.zcash` folder instead of the `cache/params`
|
||||||
folder. Besides that, `SaplingParamTool` also does validation of downloaded sapling param file hash and size.
|
folder. Besides that, `SaplingParamTool` also does validation of downloaded sapling param file hash and size.
|
||||||
**No action required from client app**.
|
**No action required from client app**.
|
||||||
|
|
||||||
Version 1.9.0-beta03
|
## Version 1.9.0-beta03
|
||||||
------------------------------------
|
|
||||||
- No changes; this release is a test of a new deployment process
|
- No changes; this release is a test of a new deployment process
|
||||||
|
|
||||||
Version 1.9.0-beta02
|
## Version 1.9.0-beta02
|
||||||
------------------------------------
|
|
||||||
- The SDK now stores database files in `no_backup/co.electricoin.zcash` folder instead of the `database` folder. **No action required from client app**.
|
- The SDK now stores database files in `no_backup/co.electricoin.zcash` folder instead of the `database` folder. **No action required from client app**.
|
||||||
|
|
||||||
Version 1.9.0-beta01
|
## Version 1.9.0-beta01
|
||||||
------------------------------------
|
|
||||||
- Split `ZcashNetwork` into `ZcashNetwork` and `LightWalletEndpoint` to decouple network and server configuration
|
- Split `ZcashNetwork` into `ZcashNetwork` and `LightWalletEndpoint` to decouple network and server configuration
|
||||||
- Gradle 7.5.1
|
- Gradle 7.5.1
|
||||||
- Updated checkpoints
|
- Updated checkpoints
|
||||||
|
|
||||||
Version 1.8.0-beta01
|
## Version 1.8.0-beta01
|
||||||
------------------------------------
|
|
||||||
- Enabled automated unit tests run on the CI server
|
- Enabled automated unit tests run on the CI server
|
||||||
- Added `BlockHeight` typesafe object to represent block heights
|
- Added `BlockHeight` typesafe object to represent block heights
|
||||||
- Significantly reduced memory usage, fixing potential OutOfMemoryError during block download
|
- Significantly reduced memory usage, fixing potential OutOfMemoryError during block download
|
||||||
- Kotlin 1.7.10
|
- Kotlin 1.7.10
|
||||||
- Updated checkpoints
|
- Updated checkpoints
|
||||||
|
|
||||||
Version 1.7.0-beta01
|
## Version 1.7.0-beta01
|
||||||
------------------------------------
|
|
||||||
- Added `Zatoshi` typesafe object to represent amounts.
|
- Added `Zatoshi` typesafe object to represent amounts.
|
||||||
- Kotlin 1.7.0
|
- Kotlin 1.7.0
|
||||||
|
|
||||||
Version 1.6.0-beta01
|
## Version 1.6.0-beta01
|
||||||
------------------------------------
|
|
||||||
- Updated checkpoints for Mainnet and Testnet
|
- Updated checkpoints for Mainnet and Testnet
|
||||||
- Fix: SDK can now be used on Intel x86_64 emulators
|
- Fix: SDK can now be used on Intel x86_64 emulators
|
||||||
- Prevent R8 warnings for apps consuming the SDK
|
- Prevent R8 warnings for apps consuming the SDK
|
||||||
|
|
||||||
Version 1.5.0-beta01
|
## Version 1.5.0-beta01
|
||||||
------------------------------------
|
|
||||||
- New: Transactions can be created after NU5 activation.
|
- New: Transactions can be created after NU5 activation.
|
||||||
- New: Support for receiving v5 transactions.
|
- New: Support for receiving v5 transactions.
|
||||||
- Known issues: The SDK will not run on Intel 64-bit API 31+ emulators. Workarounds include: testing on a physical device, using an older 32-bit API version Intel emulator, or using an ARM emulator.
|
- Known issues: The SDK will not run on Intel 64-bit API 31+ emulators. Workarounds include: testing on a physical device, using an older 32-bit API version Intel emulator, or using an ARM emulator.
|
||||||
|
|
||||||
Version 1.4.0-beta01
|
## Version 1.4.0-beta01
|
||||||
------------------------------------
|
|
||||||
- Main entrypoint to the SDK has changed. See [MIGRATIONS.md](MIGRATIONS.md)
|
- Main entrypoint to the SDK has changed. See [MIGRATIONS.md](MIGRATIONS.md)
|
||||||
- The minimum version of Android supported is now API 19
|
- The minimum version of Android supported is now API 19
|
||||||
- Updated checkpoints for Mainnet and Testnet
|
- Updated checkpoints for Mainnet and Testnet
|
||||||
|
@ -182,83 +168,68 @@ Version 1.4.0-beta01
|
||||||
- Updated dependencies, including Kotlin 1.6.21, Coroutines 1.6.1, GRPC 1.46.0, Okio 3.1.0, NDK 23
|
- Updated dependencies, including Kotlin 1.6.21, Coroutines 1.6.1, GRPC 1.46.0, Okio 3.1.0, NDK 23
|
||||||
- Known issues: The SDK will not run on Intel 64-bit API 31+ emulators. Workarounds include: testing on a physical device, using an older 32-bit API version Intel emulator, or using an ARM emulator.
|
- Known issues: The SDK will not run on Intel 64-bit API 31+ emulators. Workarounds include: testing on a physical device, using an older 32-bit API version Intel emulator, or using an ARM emulator.
|
||||||
|
|
||||||
Version 1.3.0-beta20
|
## Version 1.3.0-beta20
|
||||||
------------------------------------
|
|
||||||
- New: Updated checkpoints for Mainnet and Testnet
|
- New: Updated checkpoints for Mainnet and Testnet
|
||||||
|
|
||||||
Version 1.3.0-beta19
|
## Version 1.3.0-beta19
|
||||||
------------------------------------
|
|
||||||
- New: Updated checkpoints for Mainnet and Testnet
|
- New: Updated checkpoints for Mainnet and Testnet
|
||||||
- Fix: Repackaged internal classes to a new `internal` package name
|
- Fix: Repackaged internal classes to a new `internal` package name
|
||||||
- Fix: Testnet checkpoints have been corrected
|
- Fix: Testnet checkpoints have been corrected
|
||||||
- Updated dependencies
|
- Updated dependencies
|
||||||
|
|
||||||
Version 1.3.0-beta18
|
## Version 1.3.0-beta18
|
||||||
------------------------------------
|
|
||||||
- Fix: Corrected logic when calculating birthdates for wallets with zero received notes.
|
- Fix: Corrected logic when calculating birthdates for wallets with zero received notes.
|
||||||
|
|
||||||
Version 1.3.0-beta17
|
## Version 1.3.0-beta17
|
||||||
------------------------------------
|
|
||||||
- Fix: Autoshielding confirmation count error so funds are available after 10 confirmations.
|
- Fix: Autoshielding confirmation count error so funds are available after 10 confirmations.
|
||||||
- New: Allow developers to enable Rust logs.
|
- New: Allow developers to enable Rust logs.
|
||||||
- New: Accept GZIP compression from lightwalletd.
|
- New: Accept GZIP compression from lightwalletd.
|
||||||
- New: Reduce the UTXO retry time.
|
- New: Reduce the UTXO retry time.
|
||||||
|
|
||||||
Version 1.3.0-beta16
|
## Version 1.3.0-beta16
|
||||||
------------------------------------
|
|
||||||
- Fix: Gracefully handle failures while fetching UTXOs.
|
- Fix: Gracefully handle failures while fetching UTXOs.
|
||||||
- New: Expose StateFlows for balances.
|
- New: Expose StateFlows for balances.
|
||||||
- New: Make it easier to subscribe to transactions.
|
- New: Make it easier to subscribe to transactions.
|
||||||
- New: Cleanup default logs.
|
- New: Cleanup default logs.
|
||||||
- New: Convenience functions for WalletBalance objects.
|
- New: Convenience functions for WalletBalance objects.
|
||||||
|
|
||||||
Version 1.3.0-beta15
|
## Version 1.3.0-beta15
|
||||||
------------------------------------
|
|
||||||
- Fix: Increase reconnection attempts on failed app restart.
|
- Fix: Increase reconnection attempts on failed app restart.
|
||||||
- New: Updated checkpoints for testnet and mainnet.
|
- New: Updated checkpoints for testnet and mainnet.
|
||||||
|
|
||||||
Version 1.3.0-beta14
|
## Version 1.3.0-beta14
|
||||||
------------------------------------
|
|
||||||
- New: Add separate flows for sapling, orchard and tranparent balances.
|
- New: Add separate flows for sapling, orchard and tranparent balances.
|
||||||
- Fix: Continue troubleshooting and fixing server disconnects.
|
- Fix: Continue troubleshooting and fixing server disconnects.
|
||||||
- Updated dependencies.
|
- Updated dependencies.
|
||||||
|
|
||||||
Version 1.3.0-beta12
|
## Version 1.3.0-beta12
|
||||||
------------------------------------
|
|
||||||
- New: Expose network height as StateFlow.
|
- New: Expose network height as StateFlow.
|
||||||
- Fix: Reconnect to lightwalletd when a service exception occurs.
|
- Fix: Reconnect to lightwalletd when a service exception occurs.
|
||||||
|
|
||||||
Version 1.3.0-beta11
|
## Version 1.3.0-beta11
|
||||||
------------------------------------
|
|
||||||
- Fix: Remove unused flag that was breaking new wallet creation for some wallets.
|
- Fix: Remove unused flag that was breaking new wallet creation for some wallets.
|
||||||
|
|
||||||
Version 1.3.0-beta10
|
## Version 1.3.0-beta10
|
||||||
------------------------------------
|
|
||||||
- Fix: Make it safe to call the new prepare function more than once.
|
- Fix: Make it safe to call the new prepare function more than once.
|
||||||
|
|
||||||
Version 1.3.0-beta09
|
## Version 1.3.0-beta09
|
||||||
------------------------------------
|
|
||||||
- New: Add quick rewind feature, which makes it easy to rescan blocks after an upgrade.
|
- New: Add quick rewind feature, which makes it easy to rescan blocks after an upgrade.
|
||||||
- Fix: Repair complex data migration bug that caused crashes on upgrades.
|
- Fix: Repair complex data migration bug that caused crashes on upgrades.
|
||||||
|
|
||||||
Version 1.3.0-beta08
|
## Version 1.3.0-beta08
|
||||||
------------------------------------
|
|
||||||
- Fix: Disable librustzcash logs by default.
|
- Fix: Disable librustzcash logs by default.
|
||||||
|
|
||||||
Version 1.3.0-beta07
|
## Version 1.3.0-beta07
|
||||||
------------------------------------
|
|
||||||
- Fix: Address issues with key migration, allowing wallets to reset viewing keys, when needed.
|
- Fix: Address issues with key migration, allowing wallets to reset viewing keys, when needed.
|
||||||
|
|
||||||
Version 1.3.0-beta06
|
## Version 1.3.0-beta06
|
||||||
------------------------------------
|
|
||||||
- Fix: Repair publishing so that AARs work on Windows machines [issue #222].
|
- Fix: Repair publishing so that AARs work on Windows machines [issue #222].
|
||||||
- Fix: Incorrect BranchId on 32-bit devics [issue #224].
|
- Fix: Incorrect BranchId on 32-bit devics [issue #224].
|
||||||
- Fix: Rescan should not go beyond the wallet checkpoint.
|
- Fix: Rescan should not go beyond the wallet checkpoint.
|
||||||
- New: Drop Android Jetifier since it is no longer used.
|
- New: Drop Android Jetifier since it is no longer used.
|
||||||
- Updated checkpoints, improved tests (added Test Suites) and better error messages.
|
- Updated checkpoints, improved tests (added Test Suites) and better error messages.
|
||||||
|
|
||||||
Version 1.3.0-beta05
|
## Version 1.3.0-beta05
|
||||||
------------------------------------
|
|
||||||
- Major: Consolidate product flavors into one library for the SDK instead of two.
|
- Major: Consolidate product flavors into one library for the SDK instead of two.
|
||||||
- Major: Integrates with latest Librustzcash including full Data Access API support.
|
- Major: Integrates with latest Librustzcash including full Data Access API support.
|
||||||
- Major: Move off of JCenter and onto Maven Central.
|
- Major: Move off of JCenter and onto Maven Central.
|
||||||
|
@ -283,44 +254,36 @@ Version 1.3.0-beta05
|
||||||
- New: Derive sapling activation height from the active network.
|
- New: Derive sapling activation height from the active network.
|
||||||
- New: Latest checkpoints for mainnet and testnet.
|
- New: Latest checkpoints for mainnet and testnet.
|
||||||
|
|
||||||
Version 1.2.1-beta04
|
## Version 1.2.1-beta04
|
||||||
------------------------------------
|
|
||||||
- New: Updated to latest versions of grpc, grpc-okhttp and protoc
|
- New: Updated to latest versions of grpc, grpc-okhttp and protoc
|
||||||
- Fix: Addresses root issue of Android 11 crash on SSL sockets
|
- Fix: Addresses root issue of Android 11 crash on SSL sockets
|
||||||
|
|
||||||
Version 1.2.1-beta03
|
## Version 1.2.1-beta03
|
||||||
------------------------------------
|
|
||||||
- New: Implements ZIP-313, reducing the default fee from 10,000 to 1,000 zats.
|
- New: Implements ZIP-313, reducing the default fee from 10,000 to 1,000 zats.
|
||||||
- Fix: 80% reduction in build warnings from 90 -> 18 and improved docs [Credit: @herou].
|
- Fix: 80% reduction in build warnings from 90 -> 18 and improved docs [Credit: @herou].
|
||||||
|
|
||||||
Version 1.2.1-beta02
|
## Version 1.2.1-beta02
|
||||||
------------------------------------
|
|
||||||
- New: Improve birthday configuration and config functions.
|
- New: Improve birthday configuration and config functions.
|
||||||
- Fix: Broken layout in demo app transaction list.
|
- Fix: Broken layout in demo app transaction list.
|
||||||
|
|
||||||
Version 1.2.1-beta01
|
## Version 1.2.1-beta01
|
||||||
------------------------------------
|
|
||||||
- New: Added latest checkpoints for testnet and mainnet.
|
- New: Added latest checkpoints for testnet and mainnet.
|
||||||
- New: Added display name for Canopy.
|
- New: Added display name for Canopy.
|
||||||
- New: Update to the latest lightwalletd service definition.
|
- New: Update to the latest lightwalletd service definition.
|
||||||
- Fix: Convert Initializer.Builder to Initializer.Config to simplify the constructors.
|
- Fix: Convert Initializer.Builder to Initializer.Config to simplify the constructors.
|
||||||
|
|
||||||
Version 1.2.0-beta01
|
## Version 1.2.0-beta01
|
||||||
------------------------------------
|
|
||||||
- New: Added ability to erase initializer data.
|
- New: Added ability to erase initializer data.
|
||||||
- Fix: Updated to latest librustzcash, fixing send functionality on Canopy.
|
- Fix: Updated to latest librustzcash, fixing send functionality on Canopy.
|
||||||
|
|
||||||
Version 1.1.0-beta10
|
## Version 1.1.0-beta10
|
||||||
------------------------------------
|
|
||||||
- New: Modified visibility on a few things to facilitate partner integrations.
|
- New: Modified visibility on a few things to facilitate partner integrations.
|
||||||
|
|
||||||
Version 1.1.0-beta08
|
## Version 1.1.0-beta08
|
||||||
------------------------------------
|
|
||||||
- Fix: Publishing has been corrected by jcenter's support team.
|
- Fix: Publishing has been corrected by jcenter's support team.
|
||||||
- New: Minor improvement to initializer
|
- New: Minor improvement to initializer
|
||||||
|
|
||||||
Version 1.1.0-beta05
|
## Version 1.1.0-beta05
|
||||||
------------------------------------
|
|
||||||
- New: Synchronizer can now be started with just a viewing key.
|
- New: Synchronizer can now be started with just a viewing key.
|
||||||
- New: Initializer improvements.
|
- New: Initializer improvements.
|
||||||
- New: Added tool for loading checkpoints.
|
- New: Added tool for loading checkpoints.
|
||||||
|
@ -330,8 +293,7 @@ Version 1.1.0-beta05
|
||||||
- Fix: Broken testnet demo app.
|
- Fix: Broken testnet demo app.
|
||||||
- Fix: Publishing configuration.
|
- Fix: Publishing configuration.
|
||||||
|
|
||||||
Version 1.1.0-beta04
|
## Version 1.1.0-beta04
|
||||||
------------------------------------
|
|
||||||
- New: Add support for canopy on testnet.
|
- New: Add support for canopy on testnet.
|
||||||
- New: Change the default lightwalletd server.
|
- New: Change the default lightwalletd server.
|
||||||
- New: Add lightwalletd service for fetching t-addr transactions.
|
- New: Add lightwalletd service for fetching t-addr transactions.
|
||||||
|
@ -340,8 +302,7 @@ Version 1.1.0-beta04
|
||||||
- New: Added new checkpoints.
|
- New: Added new checkpoints.
|
||||||
- Fix: Minor enhancements.
|
- Fix: Minor enhancements.
|
||||||
|
|
||||||
Version 1.1.0-beta03
|
## Version 1.1.0-beta03
|
||||||
------------------------------------
|
|
||||||
- New: Add robust support for transaction cancellation.
|
- New: Add robust support for transaction cancellation.
|
||||||
- New: Update to latest version of librustzcash.
|
- New: Update to latest version of librustzcash.
|
||||||
- New: Expand test support.
|
- New: Expand test support.
|
||||||
|
|
|
@ -1,27 +1,7 @@
|
||||||
Troubleshooting Migrations
|
Troubleshooting Migrations
|
||||||
==========
|
==========
|
||||||
|
|
||||||
Migration to Version 1.17
|
Note: Going forward, migrations will be incorporated into the CHANGELOG.md.
|
||||||
---------------------------------
|
|
||||||
Synchronizer APIs for listing sent and received transactions have been removed. Clients should use `Synchronizer.transactions`, filtering on the field `TransactionOverview.isSentTransaction`.
|
|
||||||
|
|
||||||
Synchronizer APIs for pending transactions have been removed. Clients should use `Synchronizer.transactions`, filtering on the field `TransactionOverview.transactionState`
|
|
||||||
|
|
||||||
The Synchronizer APIs for sending transactions (`send()` and `shieldFunds()`) are now suspend functions that return `Long` which contains the ID of the newly created transaction. To monitor for changes to pending transactions, observe `Synchronizer.transactions`. If a failure occurs, `send()` and `shieldFunds()` throw exceptions.
|
|
||||||
|
|
||||||
Migration to Version 1.15
|
|
||||||
---------------------------------
|
|
||||||
The updated `Synchronizer.refreshUtxos` is now supposed to be called with `Account` parameter instead of `String` address parameter. The Account object provides a default `0` index Account with `Account.DEFAULT`.
|
|
||||||
|
|
||||||
Migration to Version 1.13
|
|
||||||
---------------------------------
|
|
||||||
Update usages of `z.cash.ecc.android.sdk.model.LightWalletEndpoint` to `co.electriccoin.lightwallet.client.model.LightWalletEndpoint`.
|
|
||||||
|
|
||||||
SDK clients should avoid using generated GRPC objects, as these are an internal implementation detail and are in process of being removed from the public API. Any clients using GRPC objects will find these have been repackaged from `cash.z.wallet.sdk.rpc` to `cash.z.wallet.sdk.internal.rpc` to signal they are not a public API.
|
|
||||||
|
|
||||||
Migration to Version 1.12
|
|
||||||
---------------------------------
|
|
||||||
`TransactionOverview`, `Transaction.Sent`, and `Transaction.Received` have been updated to reflect that `minedHeight` is nullable.
|
|
||||||
|
|
||||||
Migration to Version 1.11
|
Migration to Version 1.11
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
plugins {
|
||||||
|
id("com.android.library")
|
||||||
|
id("org.jetbrains.kotlin.android")
|
||||||
|
id("zcash-sdk.android-conventions")
|
||||||
|
|
||||||
|
id("org.jetbrains.dokka")
|
||||||
|
id("org.mozilla.rust-android-gradle.rust-android")
|
||||||
|
|
||||||
|
id("wtf.emulator.gradle")
|
||||||
|
id("zcash-sdk.emulator-wtf-conventions")
|
||||||
|
|
||||||
|
id("maven-publish")
|
||||||
|
id("signing")
|
||||||
|
id("zcash-sdk.publishing-conventions")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publishing information
|
||||||
|
|
||||||
|
val myVersion = project.property("LIBRARY_VERSION").toString()
|
||||||
|
val myArtifactId = "zcash-android-backend"
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
publications.withType<MavenPublication>().all {
|
||||||
|
artifactId = myArtifactId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "cash.z.ecc.android.backend"
|
||||||
|
|
||||||
|
useLibrary("android.test.runner")
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
consumerProguardFiles("proguard-consumer.txt")
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
getByName("debug").apply {
|
||||||
|
// test builds exceed the dex limit because they pull in large test libraries
|
||||||
|
isMinifyEnabled = false
|
||||||
|
}
|
||||||
|
getByName("release").apply {
|
||||||
|
isMinifyEnabled = project.property("IS_MINIFY_SDK_ENABLED").toString().toBoolean()
|
||||||
|
proguardFiles.addAll(
|
||||||
|
listOf(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
File("proguard-project.txt")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
create("benchmark") {
|
||||||
|
// We provide the extra benchmark build type just for benchmarking purposes
|
||||||
|
initWith(buildTypes.getByName("release"))
|
||||||
|
matchingFallbacks += listOf("release")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lint {
|
||||||
|
baseline = File("lint-baseline.xml")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cargo {
|
||||||
|
module = "."
|
||||||
|
libname = "zcashwalletsdk"
|
||||||
|
targets = listOf(
|
||||||
|
"arm",
|
||||||
|
"arm64",
|
||||||
|
"x86",
|
||||||
|
"x86_64"
|
||||||
|
)
|
||||||
|
val minSdkVersion = project.property("ANDROID_MIN_SDK_VERSION").toString().toInt()
|
||||||
|
apiLevels = mapOf(
|
||||||
|
"arm" to minSdkVersion,
|
||||||
|
"arm64" to minSdkVersion,
|
||||||
|
"x86" to minSdkVersion,
|
||||||
|
"x86_64" to minSdkVersion,
|
||||||
|
)
|
||||||
|
|
||||||
|
profile = "release"
|
||||||
|
prebuiltToolchains = true
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(projects.lightwalletClientLib)
|
||||||
|
|
||||||
|
implementation(libs.androidx.annotation)
|
||||||
|
|
||||||
|
// Kotlin
|
||||||
|
implementation(libs.kotlin.stdlib)
|
||||||
|
implementation(libs.kotlinx.coroutines.core)
|
||||||
|
implementation(libs.kotlinx.coroutines.android)
|
||||||
|
|
||||||
|
androidTestImplementation(libs.androidx.multidex)
|
||||||
|
androidTestImplementation(libs.androidx.test.runner)
|
||||||
|
androidTestImplementation(libs.androidx.test.junit)
|
||||||
|
androidTestImplementation(libs.androidx.test.core)
|
||||||
|
androidTestImplementation(libs.kotlin.test)
|
||||||
|
androidTestImplementation(libs.kotlinx.coroutines.test)
|
||||||
|
|
||||||
|
androidTestImplementation(libs.zcashwalletplgn)
|
||||||
|
androidTestImplementation(libs.bip39)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
/*
|
||||||
|
* The Mozilla Rust Gradle plugin caches the native build data under the "target" directory,
|
||||||
|
* which does not normally get deleted during a clean. The following task and dependency solves
|
||||||
|
* that.
|
||||||
|
*/
|
||||||
|
getByName<Delete>("clean").dependsOn(create<Delete>("cleanRustBuildOutput") {
|
||||||
|
delete("target")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
project.afterEvaluate {
|
||||||
|
val cargoTask = tasks.getByName("cargoBuild")
|
||||||
|
tasks.getByName("javaPreCompileDebug").dependsOn(cargoTask)
|
||||||
|
tasks.getByName("javaPreCompileRelease").dependsOn(cargoTask)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun MinimalExternalModuleDependency.asCoordinateString() =
|
||||||
|
"${module.group}:${module.name}:${versionConstraint.displayName}"
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<issues format="6" by="lint 7.4.0" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0)" variant="all" version="7.4.0">
|
||||||
|
|
||||||
|
</issues>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<lint>
|
||||||
|
|
||||||
|
</lint>
|
|
@ -0,0 +1,3 @@
|
||||||
|
-keepclasseswithmembernames,includedescriptorclasses class * {
|
||||||
|
native <methods>;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
# This improves obfuscation and moves non-public classes to their own namespace.
|
||||||
|
-repackageclasses 'cash.z.ecc.android.sdk.internal'
|
||||||
|
|
||||||
|
# This makes it easier to autocomplete methods in an IDE using this obfuscated library.
|
||||||
|
-keepparameternames
|
||||||
|
|
||||||
|
# The ProGuard manual recommends keeping these attributes for libraries.
|
||||||
|
-keepattributes EnclosingMethod,InnerClasses,Signature,Exceptions,*Annotation*
|
||||||
|
|
||||||
|
# Ensure that stacktraces are reversible.
|
||||||
|
-renamesourcefileattribute SourceFile
|
||||||
|
-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# Keep the public interface of the library.
|
||||||
|
-keep public class cash.z.ecc.android.sdk.internal.Backend { public protected *; }
|
||||||
|
-keep public class cash.z.ecc.android.sdk.internal.Derivation { public protected *; }
|
||||||
|
-keep public class cash.z.ecc.android.sdk.internal.jni.RustBackend { public protected *; }
|
||||||
|
-keep public class cash.z.ecc.android.sdk.internal.model.* { public protected *; }
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<!-- For code coverage -->
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
|
<application android:name="androidx.multidex.MultiDexApplication" />
|
||||||
|
</manifest>
|
|
@ -0,0 +1,26 @@
|
||||||
|
package cash.z.ecc.android.sdk.internal.jni
|
||||||
|
|
||||||
|
import cash.z.ecc.android.bip39.Mnemonics
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.test.assertContentEquals
|
||||||
|
|
||||||
|
class RustDerivationToolTest {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val SEED_PHRASE =
|
||||||
|
"kitchen renew wide common vague fold vacuum tilt amazing pear square gossip jewel month tree shock scan alpha just spot fluid toilet view dinner"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
fun create_spending_key_does_not_mutate_passed_bytes() = runTest {
|
||||||
|
val bytesOne = Mnemonics.MnemonicCode(SEED_PHRASE).toEntropy()
|
||||||
|
val bytesTwo = Mnemonics.MnemonicCode(SEED_PHRASE).toEntropy()
|
||||||
|
|
||||||
|
RustDerivationTool.new().deriveUnifiedSpendingKey(bytesOne, networkId = 1, accountIndex = 0)
|
||||||
|
|
||||||
|
assertContentEquals(bytesTwo, bytesOne)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
</manifest>
|
|
@ -1,9 +1,7 @@
|
||||||
package cash.z.ecc.android.sdk.jni
|
package cash.z.ecc.android.sdk.internal
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.internal.model.JniUnifiedSpendingKey
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contract defining the exposed capabilities of the Rust backend.
|
* Contract defining the exposed capabilities of the Rust backend.
|
||||||
|
@ -14,11 +12,9 @@ import java.io.File
|
||||||
// TODO [#920]: Tweak RustBackend public APIs to have void return values
|
// TODO [#920]: Tweak RustBackend public APIs to have void return values
|
||||||
// TODO [#920]: https://github.com/zcash/zcash-android-wallet-sdk/issues/920
|
// TODO [#920]: https://github.com/zcash/zcash-android-wallet-sdk/issues/920
|
||||||
@Suppress("TooManyFunctions")
|
@Suppress("TooManyFunctions")
|
||||||
internal interface Backend {
|
interface Backend {
|
||||||
|
|
||||||
val network: ZcashNetwork
|
val networkId: Int
|
||||||
|
|
||||||
val saplingParamDir: File
|
|
||||||
|
|
||||||
suspend fun initBlockMetaDb(): Int
|
suspend fun initBlockMetaDb(): Int
|
||||||
|
|
||||||
|
@ -53,7 +49,7 @@ internal interface Backend {
|
||||||
|
|
||||||
suspend fun initDataDb(seed: ByteArray?): Int
|
suspend fun initDataDb(seed: ByteArray?): Int
|
||||||
|
|
||||||
suspend fun createAccount(seed: ByteArray): UnifiedSpendingKeyJni
|
suspend fun createAccount(seed: ByteArray): JniUnifiedSpendingKey
|
||||||
|
|
||||||
fun isValidShieldedAddr(addr: String): Boolean
|
fun isValidShieldedAddr(addr: String): Boolean
|
||||||
|
|
||||||
|
@ -112,6 +108,6 @@ internal interface Backend {
|
||||||
index: Int,
|
index: Int,
|
||||||
script: ByteArray,
|
script: ByteArray,
|
||||||
value: Long,
|
value: Long,
|
||||||
height: BlockHeight
|
height: Long
|
||||||
): Boolean
|
): Boolean
|
||||||
}
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package cash.z.ecc.android.sdk.internal
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.JniUnifiedSpendingKey
|
||||||
|
|
||||||
|
interface Derivation {
|
||||||
|
fun deriveUnifiedAddress(
|
||||||
|
viewingKey: String,
|
||||||
|
networkId: Int
|
||||||
|
): String
|
||||||
|
|
||||||
|
fun deriveUnifiedAddress(
|
||||||
|
seed: ByteArray,
|
||||||
|
networkId: Int,
|
||||||
|
accountIndex: Int
|
||||||
|
): String
|
||||||
|
|
||||||
|
fun deriveUnifiedSpendingKey(
|
||||||
|
seed: ByteArray,
|
||||||
|
networkId: Int,
|
||||||
|
accountIndex: Int
|
||||||
|
): JniUnifiedSpendingKey
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a unified full viewing key.
|
||||||
|
*/
|
||||||
|
fun deriveUnifiedFullViewingKey(
|
||||||
|
usk: JniUnifiedSpendingKey,
|
||||||
|
networkId: Int
|
||||||
|
): String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param numberOfAccounts Use [DEFAULT_NUMBER_OF_ACCOUNTS] to derive a single key.
|
||||||
|
* @return an array of unified full viewing keys, one for each account.
|
||||||
|
*/
|
||||||
|
fun deriveUnifiedFullViewingKeys(
|
||||||
|
seed: ByteArray,
|
||||||
|
networkId: Int,
|
||||||
|
numberOfAccounts: Int
|
||||||
|
): Array<String>
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val DEFAULT_NUMBER_OF_ACCOUNTS = 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ internal object SdkExecutors {
|
||||||
val DATABASE_IO = Executors.newSingleThreadExecutor()
|
val DATABASE_IO = Executors.newSingleThreadExecutor()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal object SdkDispatchers {
|
object SdkDispatchers {
|
||||||
/**
|
/**
|
||||||
* Dispatcher used for database IO that's shared with the Rust native library.
|
* Dispatcher used for database IO that's shared with the Rust native library.
|
||||||
*/
|
*/
|
|
@ -9,15 +9,15 @@ import java.io.FileInputStream
|
||||||
import java.security.DigestInputStream
|
import java.security.DigestInputStream
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
|
|
||||||
internal suspend fun File.canWriteSuspend() = withContext(Dispatchers.IO) { canWrite() }
|
suspend fun File.canWriteSuspend() = withContext(Dispatchers.IO) { canWrite() }
|
||||||
|
|
||||||
suspend fun File.createNewFileSuspend() = withContext(Dispatchers.IO) { createNewFile() }
|
suspend fun File.createNewFileSuspend() = withContext(Dispatchers.IO) { createNewFile() }
|
||||||
|
|
||||||
internal suspend fun File.deleteSuspend() = withContext(Dispatchers.IO) { delete() }
|
suspend fun File.deleteSuspend() = withContext(Dispatchers.IO) { delete() }
|
||||||
|
|
||||||
suspend fun File.deleteRecursivelySuspend() = withContext(Dispatchers.IO) { deleteRecursively() }
|
suspend fun File.deleteRecursivelySuspend() = withContext(Dispatchers.IO) { deleteRecursively() }
|
||||||
|
|
||||||
internal suspend fun File.existsSuspend() = withContext(Dispatchers.IO) { exists() }
|
suspend fun File.existsSuspend() = withContext(Dispatchers.IO) { exists() }
|
||||||
|
|
||||||
suspend fun File.inputStreamSuspend(): FileInputStream = withContext(Dispatchers.IO) { inputStream() }
|
suspend fun File.inputStreamSuspend(): FileInputStream = withContext(Dispatchers.IO) { inputStream() }
|
||||||
|
|
||||||
|
@ -27,11 +27,11 @@ suspend fun File.listFilesSuspend(): Array<File>? = withContext(Dispatchers.IO)
|
||||||
|
|
||||||
suspend fun File.listSuspend(): Array<String>? = withContext(Dispatchers.IO) { list() }
|
suspend fun File.listSuspend(): Array<String>? = withContext(Dispatchers.IO) { list() }
|
||||||
|
|
||||||
internal suspend fun File.mkdirsSuspend() = withContext(Dispatchers.IO) { mkdirs() }
|
suspend fun File.mkdirsSuspend() = withContext(Dispatchers.IO) { mkdirs() }
|
||||||
|
|
||||||
suspend fun File.readBytesSuspend() = withContext(Dispatchers.IO) { readBytes() }
|
suspend fun File.readBytesSuspend() = withContext(Dispatchers.IO) { readBytes() }
|
||||||
|
|
||||||
internal suspend fun File.renameToSuspend(dest: File) = withContext(Dispatchers.IO) { renameTo(dest) }
|
suspend fun File.renameToSuspend(dest: File) = withContext(Dispatchers.IO) { renameTo(dest) }
|
||||||
|
|
||||||
suspend fun File.writeBytesSuspend(byteArray: ByteArray) = withContext(Dispatchers.IO) { writeBytes(byteArray) }
|
suspend fun File.writeBytesSuspend(byteArray: ByteArray) = withContext(Dispatchers.IO) { writeBytes(byteArray) }
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
package cash.z.ecc.android.sdk.jni
|
package cash.z.ecc.android.sdk.internal.jni
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.internal.Twig
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import kotlin.system.measureTimeMillis
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a native library once. This class is thread-safe.
|
* Loads a native library once. This class is thread-safe.
|
||||||
|
@ -39,14 +37,7 @@ internal class NativeLibraryLoader(private val libraryName: String) {
|
||||||
|
|
||||||
private suspend fun loadNativeLibrary() {
|
private suspend fun loadNativeLibrary() {
|
||||||
runCatching {
|
runCatching {
|
||||||
Twig.debug { "Loading native library $libraryName" }
|
|
||||||
|
|
||||||
val loadTimeMillis = measureTimeMillis {
|
|
||||||
loadLibrarySuspend(libraryName)
|
loadLibrarySuspend(libraryName)
|
||||||
}
|
|
||||||
|
|
||||||
Twig.debug { "Loading native library took $loadTimeMillis milliseconds" }
|
|
||||||
|
|
||||||
isLoaded.set(true)
|
isLoaded.set(true)
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
// Fail fast, because this is not a recoverable error
|
// Fail fast, because this is not a recoverable error
|
|
@ -1,13 +1,11 @@
|
||||||
package cash.z.ecc.android.sdk.jni
|
package cash.z.ecc.android.sdk.internal.jni
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.internal.SaplingParamTool
|
import cash.z.ecc.android.sdk.internal.Backend
|
||||||
import cash.z.ecc.android.sdk.internal.SdkDispatchers
|
import cash.z.ecc.android.sdk.internal.SdkDispatchers
|
||||||
import cash.z.ecc.android.sdk.internal.Twig
|
|
||||||
import cash.z.ecc.android.sdk.internal.ext.deleteRecursivelySuspend
|
import cash.z.ecc.android.sdk.internal.ext.deleteRecursivelySuspend
|
||||||
import cash.z.ecc.android.sdk.internal.ext.deleteSuspend
|
import cash.z.ecc.android.sdk.internal.ext.deleteSuspend
|
||||||
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.internal.model.JniUnifiedSpendingKey
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
@ -17,12 +15,12 @@ import java.io.File
|
||||||
* should be used such as Wallet.kt or CompactBlockProcessor.kt.
|
* should be used such as Wallet.kt or CompactBlockProcessor.kt.
|
||||||
*/
|
*/
|
||||||
@Suppress("TooManyFunctions")
|
@Suppress("TooManyFunctions")
|
||||||
internal class RustBackend private constructor(
|
class RustBackend private constructor(
|
||||||
override val network: ZcashNetwork,
|
override val networkId: Int,
|
||||||
val birthdayHeight: BlockHeight,
|
private val dataDbFile: File,
|
||||||
val dataDbFile: File,
|
private val fsBlockDbRoot: File,
|
||||||
val fsBlockDbRoot: File,
|
private val saplingSpendFile: File,
|
||||||
override val saplingParamDir: File
|
private val saplingOutputFile: File,
|
||||||
) : Backend {
|
) : Backend {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,16 +36,14 @@ internal class RustBackend private constructor(
|
||||||
var cacheClearResult = true
|
var cacheClearResult = true
|
||||||
var dataClearResult = true
|
var dataClearResult = true
|
||||||
if (clearCache) {
|
if (clearCache) {
|
||||||
Twig.debug { "Deleting the cache files..." }
|
|
||||||
fsBlockDbRoot.deleteRecursivelySuspend().also { result ->
|
fsBlockDbRoot.deleteRecursivelySuspend().also { result ->
|
||||||
Twig.debug { "Deletion of the cache files ${if (result) "succeeded" else "failed"}!" }
|
// Twig.debug { "Deletion of the cache files ${if (result) "succeeded" else "failed"}!" }
|
||||||
cacheClearResult = result
|
cacheClearResult = result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (clearDataDb) {
|
if (clearDataDb) {
|
||||||
Twig.debug { "Deleting the data database..." }
|
|
||||||
dataDbFile.deleteSuspend().also { result ->
|
dataDbFile.deleteSuspend().also { result ->
|
||||||
Twig.debug { "Deletion of the data database ${if (result) "succeeded" else "failed"}!" }
|
// Twig.debug { "Deletion of the data database ${if (result) "succeeded" else "failed"}!" }
|
||||||
dataClearResult = result
|
dataClearResult = result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,16 +64,16 @@ internal class RustBackend private constructor(
|
||||||
initDataDb(
|
initDataDb(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
seed,
|
seed,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun createAccount(seed: ByteArray): UnifiedSpendingKeyJni {
|
override suspend fun createAccount(seed: ByteArray): JniUnifiedSpendingKey {
|
||||||
return withContext(SdkDispatchers.DATABASE_IO) {
|
return withContext(SdkDispatchers.DATABASE_IO) {
|
||||||
createAccount(
|
createAccount(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
seed,
|
seed,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,7 +86,7 @@ internal class RustBackend private constructor(
|
||||||
initAccountsTableWithKeys(
|
initAccountsTableWithKeys(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
keys,
|
keys,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +104,7 @@ internal class RustBackend private constructor(
|
||||||
checkpointHash,
|
checkpointHash,
|
||||||
checkpointTime,
|
checkpointTime,
|
||||||
checkpointSaplingTree,
|
checkpointSaplingTree,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +114,7 @@ internal class RustBackend private constructor(
|
||||||
getCurrentAddress(
|
getCurrentAddress(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
account,
|
account,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +127,7 @@ internal class RustBackend private constructor(
|
||||||
listTransparentReceivers(
|
listTransparentReceivers(
|
||||||
dbDataPath = dataDbFile.absolutePath,
|
dbDataPath = dataDbFile.absolutePath,
|
||||||
account = account,
|
account = account,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
).asList()
|
).asList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,7 +137,7 @@ internal class RustBackend private constructor(
|
||||||
getBalance(
|
getBalance(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
account,
|
account,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +149,7 @@ internal class RustBackend private constructor(
|
||||||
getVerifiedBalance(
|
getVerifiedBalance(
|
||||||
dbDataPath = dataDbFile.absolutePath,
|
dbDataPath = dataDbFile.absolutePath,
|
||||||
account = account,
|
account = account,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +161,7 @@ internal class RustBackend private constructor(
|
||||||
getReceivedMemoAsUtf8(
|
getReceivedMemoAsUtf8(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
idNote,
|
idNote,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +170,7 @@ internal class RustBackend private constructor(
|
||||||
getSentMemoAsUtf8(
|
getSentMemoAsUtf8(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
idNote,
|
idNote,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +215,7 @@ internal class RustBackend private constructor(
|
||||||
dbCachePath = fsBlockDbRoot.absolutePath,
|
dbCachePath = fsBlockDbRoot.absolutePath,
|
||||||
dbDataPath = dataDbFile.absolutePath,
|
dbDataPath = dataDbFile.absolutePath,
|
||||||
limit = limit ?: -1,
|
limit = limit ?: -1,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
|
|
||||||
if (-1L == validationResult) {
|
if (-1L == validationResult) {
|
||||||
|
@ -234,7 +230,7 @@ internal class RustBackend private constructor(
|
||||||
getVerifiedTransparentBalance(
|
getVerifiedTransparentBalance(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
address,
|
address,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +239,7 @@ internal class RustBackend private constructor(
|
||||||
getTotalTransparentBalance(
|
getTotalTransparentBalance(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
address,
|
address,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +248,7 @@ internal class RustBackend private constructor(
|
||||||
getNearestRewindHeight(
|
getNearestRewindHeight(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
height,
|
height,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,7 +262,7 @@ internal class RustBackend private constructor(
|
||||||
rewindToHeight(
|
rewindToHeight(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
height,
|
height,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +272,7 @@ internal class RustBackend private constructor(
|
||||||
fsBlockDbRoot.absolutePath,
|
fsBlockDbRoot.absolutePath,
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
limit ?: -1,
|
limit ?: -1,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,7 +282,7 @@ internal class RustBackend private constructor(
|
||||||
decryptAndStoreTransaction(
|
decryptAndStoreTransaction(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
tx,
|
tx,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,9 +299,9 @@ internal class RustBackend private constructor(
|
||||||
to,
|
to,
|
||||||
value,
|
value,
|
||||||
memo ?: ByteArray(0),
|
memo ?: ByteArray(0),
|
||||||
File(saplingParamDir, SaplingParamTool.SPEND_PARAM_FILE_NAME).absolutePath,
|
spendParamsPath = saplingSpendFile.absolutePath,
|
||||||
File(saplingParamDir, SaplingParamTool.OUTPUT_PARAM_FILE_NAME).absolutePath,
|
outputParamsPath = saplingOutputFile.absolutePath,
|
||||||
networkId = network.id,
|
networkId = networkId,
|
||||||
useZip317Fees = IS_USE_ZIP_317_FEES
|
useZip317Fees = IS_USE_ZIP_317_FEES
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -315,15 +311,14 @@ internal class RustBackend private constructor(
|
||||||
unifiedSpendingKey: ByteArray,
|
unifiedSpendingKey: ByteArray,
|
||||||
memo: ByteArray?
|
memo: ByteArray?
|
||||||
): Long {
|
): Long {
|
||||||
Twig.debug { "TMP: shieldToAddress with db path: $dataDbFile, ${memo?.size}" }
|
|
||||||
return withContext(SdkDispatchers.DATABASE_IO) {
|
return withContext(SdkDispatchers.DATABASE_IO) {
|
||||||
shieldToAddress(
|
shieldToAddress(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
unifiedSpendingKey,
|
unifiedSpendingKey,
|
||||||
memo ?: ByteArray(0),
|
memo ?: ByteArray(0),
|
||||||
File(saplingParamDir, SaplingParamTool.SPEND_PARAM_FILE_NAME).absolutePath,
|
spendParamsPath = saplingSpendFile.absolutePath,
|
||||||
File(saplingParamDir, SaplingParamTool.OUTPUT_PARAM_FILE_NAME).absolutePath,
|
outputParamsPath = saplingOutputFile.absolutePath,
|
||||||
networkId = network.id,
|
networkId = networkId,
|
||||||
useZip317Fees = IS_USE_ZIP_317_FEES
|
useZip317Fees = IS_USE_ZIP_317_FEES
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -335,7 +330,7 @@ internal class RustBackend private constructor(
|
||||||
index: Int,
|
index: Int,
|
||||||
script: ByteArray,
|
script: ByteArray,
|
||||||
value: Long,
|
value: Long,
|
||||||
height: BlockHeight
|
height: Long
|
||||||
): Boolean = withContext(SdkDispatchers.DATABASE_IO) {
|
): Boolean = withContext(SdkDispatchers.DATABASE_IO) {
|
||||||
putUtxo(
|
putUtxo(
|
||||||
dataDbFile.absolutePath,
|
dataDbFile.absolutePath,
|
||||||
|
@ -344,22 +339,22 @@ internal class RustBackend private constructor(
|
||||||
index,
|
index,
|
||||||
script,
|
script,
|
||||||
value,
|
value,
|
||||||
height.value,
|
height,
|
||||||
networkId = network.id
|
networkId = networkId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isValidShieldedAddr(addr: String) =
|
override fun isValidShieldedAddr(addr: String) =
|
||||||
isValidShieldedAddress(addr, networkId = network.id)
|
isValidShieldedAddress(addr, networkId = networkId)
|
||||||
|
|
||||||
override fun isValidTransparentAddr(addr: String) =
|
override fun isValidTransparentAddr(addr: String) =
|
||||||
isValidTransparentAddress(addr, networkId = network.id)
|
isValidTransparentAddress(addr, networkId = networkId)
|
||||||
|
|
||||||
override fun isValidUnifiedAddr(addr: String) =
|
override fun isValidUnifiedAddr(addr: String) =
|
||||||
isValidUnifiedAddress(addr, networkId = network.id)
|
isValidUnifiedAddress(addr, networkId = networkId)
|
||||||
|
|
||||||
override fun getBranchIdForHeight(height: Long): Long =
|
override fun getBranchIdForHeight(height: Long): Long =
|
||||||
branchIdForHeight(height, networkId = network.id)
|
branchIdForHeight(height, networkId = networkId)
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * This is a proof-of-concept for doing Local RPC, where we are effectively using the JNI
|
// * This is a proof-of-concept for doing Local RPC, where we are effectively using the JNI
|
||||||
|
@ -400,21 +395,21 @@ internal class RustBackend private constructor(
|
||||||
* Loads the library and initializes path variables. Although it is best to only call this
|
* Loads the library and initializes path variables. Although it is best to only call this
|
||||||
* function once, it is idempotent.
|
* function once, it is idempotent.
|
||||||
*/
|
*/
|
||||||
suspend fun init(
|
suspend fun new(
|
||||||
fsBlockDbRoot: File,
|
fsBlockDbRoot: File,
|
||||||
dataDbFile: File,
|
dataDbFile: File,
|
||||||
saplingParamsDir: File,
|
saplingSpendFile: File,
|
||||||
zcashNetwork: ZcashNetwork,
|
saplingOutputFile: File,
|
||||||
birthdayHeight: BlockHeight
|
zcashNetworkId: Int,
|
||||||
): RustBackend {
|
): RustBackend {
|
||||||
loadLibrary()
|
loadLibrary()
|
||||||
|
|
||||||
return RustBackend(
|
return RustBackend(
|
||||||
zcashNetwork,
|
zcashNetworkId,
|
||||||
birthdayHeight,
|
|
||||||
dataDbFile = dataDbFile,
|
dataDbFile = dataDbFile,
|
||||||
fsBlockDbRoot = fsBlockDbRoot,
|
fsBlockDbRoot = fsBlockDbRoot,
|
||||||
saplingParamDir = saplingParamsDir
|
saplingSpendFile = saplingSpendFile,
|
||||||
|
saplingOutputFile = saplingOutputFile
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,7 +445,7 @@ internal class RustBackend private constructor(
|
||||||
): Boolean
|
): Boolean
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private external fun createAccount(dbDataPath: String, seed: ByteArray, networkId: Int): UnifiedSpendingKeyJni
|
private external fun createAccount(dbDataPath: String, seed: ByteArray, networkId: Int): JniUnifiedSpendingKey
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private external fun getCurrentAddress(
|
private external fun getCurrentAddress(
|
||||||
|
@ -468,7 +463,7 @@ internal class RustBackend private constructor(
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private external fun listTransparentReceivers(dbDataPath: String, account: Int, networkId: Int): Array<String>
|
private external fun listTransparentReceivers(dbDataPath: String, account: Int, networkId: Int): Array<String>
|
||||||
|
|
||||||
internal fun validateUnifiedSpendingKey(bytes: ByteArray) =
|
fun validateUnifiedSpendingKey(bytes: ByteArray) =
|
||||||
isValidSpendingKey(bytes)
|
isValidSpendingKey(bytes)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
|
@ -0,0 +1,78 @@
|
||||||
|
package cash.z.ecc.android.sdk.internal.jni
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.internal.Derivation
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.JniUnifiedSpendingKey
|
||||||
|
|
||||||
|
class RustDerivationTool private constructor() : Derivation {
|
||||||
|
|
||||||
|
override fun deriveUnifiedFullViewingKeys(
|
||||||
|
seed: ByteArray,
|
||||||
|
networkId: Int,
|
||||||
|
numberOfAccounts: Int
|
||||||
|
): Array<String> =
|
||||||
|
deriveUnifiedFullViewingKeysFromSeed(seed, numberOfAccounts, networkId = networkId)
|
||||||
|
|
||||||
|
override fun deriveUnifiedFullViewingKey(
|
||||||
|
usk: JniUnifiedSpendingKey,
|
||||||
|
networkId: Int
|
||||||
|
): String =
|
||||||
|
deriveUnifiedFullViewingKey(usk.bytes, networkId = networkId)
|
||||||
|
|
||||||
|
override fun deriveUnifiedSpendingKey(
|
||||||
|
seed: ByteArray,
|
||||||
|
networkId: Int,
|
||||||
|
accountIndex: Int
|
||||||
|
): JniUnifiedSpendingKey = deriveSpendingKey(seed, accountIndex, networkId = networkId)
|
||||||
|
|
||||||
|
override fun deriveUnifiedAddress(seed: ByteArray, networkId: Int, accountIndex: Int): String =
|
||||||
|
deriveUnifiedAddressFromSeed(seed, accountIndex = accountIndex, networkId = networkId)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a Unified Full Viewing Key string, return the associated Unified Address.
|
||||||
|
*
|
||||||
|
* @param viewingKey the viewing key to use for deriving the address. The viewing key is tied to
|
||||||
|
* a specific account so no account index is required.
|
||||||
|
*
|
||||||
|
* @return the address that corresponds to the viewing key.
|
||||||
|
*/
|
||||||
|
override fun deriveUnifiedAddress(
|
||||||
|
viewingKey: String,
|
||||||
|
networkId: Int
|
||||||
|
): String =
|
||||||
|
deriveUnifiedAddressFromViewingKey(viewingKey, networkId = networkId)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
suspend fun new(): Derivation {
|
||||||
|
RustBackend.loadLibrary()
|
||||||
|
|
||||||
|
return RustDerivationTool()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
private external fun deriveSpendingKey(
|
||||||
|
seed: ByteArray,
|
||||||
|
account: Int,
|
||||||
|
networkId: Int
|
||||||
|
): JniUnifiedSpendingKey
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
private external fun deriveUnifiedFullViewingKeysFromSeed(
|
||||||
|
seed: ByteArray,
|
||||||
|
numberOfAccounts: Int,
|
||||||
|
networkId: Int
|
||||||
|
): Array<String>
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
private external fun deriveUnifiedFullViewingKey(usk: ByteArray, networkId: Int): String
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
private external fun deriveUnifiedAddressFromSeed(
|
||||||
|
seed: ByteArray,
|
||||||
|
accountIndex: Int,
|
||||||
|
networkId: Int
|
||||||
|
): String
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
private external fun deriveUnifiedAddressFromViewingKey(key: String, networkId: Int): String
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,7 +37,7 @@ class JniBlockMeta(
|
||||||
companion object {
|
companion object {
|
||||||
private val UINT_RANGE = 0.toLong()..UInt.MAX_VALUE.toLong()
|
private val UINT_RANGE = 0.toLong()..UInt.MAX_VALUE.toLong()
|
||||||
|
|
||||||
internal fun new(block: CompactBlockUnsafe): JniBlockMeta {
|
fun new(block: CompactBlockUnsafe): JniBlockMeta {
|
||||||
return JniBlockMeta(
|
return JniBlockMeta(
|
||||||
height = block.height,
|
height = block.height,
|
||||||
hash = block.hash,
|
hash = block.hash,
|
|
@ -1,4 +1,4 @@
|
||||||
package cash.z.ecc.android.sdk.jni
|
package cash.z.ecc.android.sdk.internal.model
|
||||||
|
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import androidx.annotation.Keep
|
||||||
* export/import, or backup purposes.
|
* export/import, or backup purposes.
|
||||||
*/
|
*/
|
||||||
@Keep
|
@Keep
|
||||||
class UnifiedSpendingKeyJni(
|
class JniUnifiedSpendingKey(
|
||||||
val account: Int,
|
val account: Int,
|
||||||
/**
|
/**
|
||||||
* The binary encoding of the [ZIP 316](https://zips.z.cash/zip-0316) Unified Spending
|
* The binary encoding of the [ZIP 316](https://zips.z.cash/zip-0316) Unified Spending
|
||||||
|
@ -22,27 +22,17 @@ class UnifiedSpendingKeyJni(
|
||||||
* inherently unstable, and only intended to be passed between the SDK and the storage
|
* inherently unstable, and only intended to be passed between the SDK and the storage
|
||||||
* backend. Wallets **MUST NOT** allow this encoding to be exported or imported.
|
* backend. Wallets **MUST NOT** allow this encoding to be exported or imported.
|
||||||
*/
|
*/
|
||||||
private val bytes: ByteArray
|
val bytes: ByteArray
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
|
||||||
* The binary encoding of the [ZIP 316](https://zips.z.cash/zip-0316) Unified Spending
|
|
||||||
* Key for [account].
|
|
||||||
*
|
|
||||||
* This encoding **MUST NOT** be exposed to users. It is an internal encoding that is
|
|
||||||
* inherently unstable, and only intended to be passed between the SDK and the storage
|
|
||||||
* backend. Wallets **MUST NOT** allow this encoding to be exported or imported.
|
|
||||||
*/
|
|
||||||
fun copyBytes() = bytes.copyOf()
|
|
||||||
|
|
||||||
// Override to prevent leaking key to logs
|
// Override to prevent leaking key to logs
|
||||||
override fun toString() = "UnifiedSpendingKeyJni(account=$account)"
|
override fun toString() = "JniUnifiedSpendingKey(account=$account, bytes=***)"
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (javaClass != other?.javaClass) return false
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
other as UnifiedSpendingKeyJni
|
other as JniUnifiedSpendingKey
|
||||||
|
|
||||||
if (account != other.account) return false
|
if (account != other.account) return false
|
||||||
if (!bytes.contentEquals(other.bytes)) return false
|
if (!bytes.contentEquals(other.bytes)) return false
|
|
@ -95,7 +95,7 @@ fn block_db(env: &JNIEnv<'_>, fsblockdb_root: JString<'_>) -> Result<FsBlockDb,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initOnLoad(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_initOnLoad(
|
||||||
_env: JNIEnv<'_>,
|
_env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
) {
|
) {
|
||||||
|
@ -134,7 +134,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initOnLoad(
|
||||||
///
|
///
|
||||||
/// Returns 0 if successful, or -1 otherwise.
|
/// Returns 0 if successful, or -1 otherwise.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initBlockMetaDb(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_initBlockMetaDb(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
fsblockdb_root: JString<'_>,
|
fsblockdb_root: JString<'_>,
|
||||||
|
@ -160,7 +160,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initBlockMe
|
||||||
/// Returns 0 if successful, 1 if the seed must be provided in order to execute the requested
|
/// Returns 0 if successful, 1 if the seed must be provided in order to execute the requested
|
||||||
/// migrations, or -1 otherwise.
|
/// migrations, or -1 otherwise.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initDataDb(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_initDataDb(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -197,7 +197,7 @@ fn encode_usk(
|
||||||
let encoded = SecretVec::new(usk.to_bytes(Era::Orchard));
|
let encoded = SecretVec::new(usk.to_bytes(Era::Orchard));
|
||||||
let bytes = env.byte_array_from_slice(encoded.expose_secret())?;
|
let bytes = env.byte_array_from_slice(encoded.expose_secret())?;
|
||||||
let output = env.new_object(
|
let output = env.new_object(
|
||||||
"cash/z/ecc/android/sdk/jni/UnifiedSpendingKeyJni",
|
"cash/z/ecc/android/sdk/internal/model/JniUnifiedSpendingKey",
|
||||||
"(I[B)V",
|
"(I[B)V",
|
||||||
&[
|
&[
|
||||||
JValue::Int(u32::from(account) as i32),
|
JValue::Int(u32::from(account) as i32),
|
||||||
|
@ -241,7 +241,7 @@ fn decode_usk(env: &JNIEnv<'_>, usk: jbyteArray) -> Result<UnifiedSpendingKey, f
|
||||||
///
|
///
|
||||||
/// [ZIP 316]: https://zips.z.cash/zip-0316
|
/// [ZIP 316]: https://zips.z.cash/zip-0316
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createAccount(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_createAccount(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -268,7 +268,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createAccou
|
||||||
/// This should only be used in special cases for implementing wallet recovery; prefer
|
/// This should only be used in special cases for implementing wallet recovery; prefer
|
||||||
/// `RustBackend.createAccount` for normal account creation purposes.
|
/// `RustBackend.createAccount` for normal account creation purposes.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initAccountsTableWithKeys(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_initAccountsTableWithKeys(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -315,7 +315,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initAccount
|
||||||
/// of the [`UnifiedSpendingKey`] for the newly created account. The caller should store
|
/// of the [`UnifiedSpendingKey`] for the newly created account. The caller should store
|
||||||
/// the returned spending key in a secure fashion.
|
/// the returned spending key in a secure fashion.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveSpendingKey(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustDerivationTool_deriveSpendingKey(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
seed: jbyteArray,
|
seed: jbyteArray,
|
||||||
|
@ -340,7 +340,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveS
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveUnifiedFullViewingKeysFromSeed(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustDerivationTool_deriveUnifiedFullViewingKeysFromSeed(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
seed: jbyteArray,
|
seed: jbyteArray,
|
||||||
|
@ -379,7 +379,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveU
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveUnifiedAddressFromSeed(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustDerivationTool_deriveUnifiedAddressFromSeed(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
seed: jbyteArray,
|
seed: jbyteArray,
|
||||||
|
@ -413,7 +413,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveU
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveUnifiedAddressFromViewingKey(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustDerivationTool_deriveUnifiedAddressFromViewingKey(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
ufvk_string: JString<'_>,
|
ufvk_string: JString<'_>,
|
||||||
|
@ -445,7 +445,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveU
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveUnifiedFullViewingKey(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustDerivationTool_deriveUnifiedFullViewingKey(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
usk: jbyteArray,
|
usk: jbyteArray,
|
||||||
|
@ -467,7 +467,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveU
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initBlocksTable(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_initBlocksTable(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -509,7 +509,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initBlocksT
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getCurrentAddress(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getCurrentAddress(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -553,7 +553,7 @@ impl zcash_address::TryFromRawAddress for UnifiedAddressParser {
|
||||||
|
|
||||||
/// Returns the transparent receiver within the given Unified Address, if any.
|
/// Returns the transparent receiver within the given Unified Address, if any.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getTransparentReceiverForUnifiedAddress(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getTransparentReceiverForUnifiedAddress(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
ua: JString<'_>,
|
ua: JString<'_>,
|
||||||
|
@ -593,7 +593,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getTranspar
|
||||||
|
|
||||||
/// Returns the Sapling receiver within the given Unified Address, if any.
|
/// Returns the Sapling receiver within the given Unified Address, if any.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getSaplingReceiverForUnifiedAddress(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getSaplingReceiverForUnifiedAddress(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
ua: JString<'_>,
|
ua: JString<'_>,
|
||||||
|
@ -623,7 +623,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getSaplingR
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidSpendingKey(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_isValidSpendingKey(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
usk: jbyteArray,
|
usk: jbyteArray,
|
||||||
|
@ -636,7 +636,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidSpen
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidShieldedAddress(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_isValidShieldedAddress(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
addr: JString<'_>,
|
addr: JString<'_>,
|
||||||
|
@ -658,7 +658,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidShie
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidTransparentAddress(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_isValidTransparentAddress(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
addr: JString<'_>,
|
addr: JString<'_>,
|
||||||
|
@ -680,7 +680,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidTran
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidUnifiedAddress(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_isValidUnifiedAddress(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
addr: JString<'_>,
|
addr: JString<'_>,
|
||||||
|
@ -702,7 +702,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidUnif
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getBalance(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getBalance(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -740,7 +740,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getBalance(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getVerifiedTransparentBalance(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getVerifiedTransparentBalance(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -778,7 +778,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getVerified
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getTotalTransparentBalance(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getTotalTransparentBalance(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -820,7 +820,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getTotalTra
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getVerifiedBalance(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getVerifiedBalance(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -852,7 +852,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getVerified
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getReceivedMemoAsUtf8(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getReceivedMemoAsUtf8(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -879,7 +879,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getReceived
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getSentMemoAsUtf8(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getSentMemoAsUtf8(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -946,7 +946,7 @@ fn decode_blockmeta(env: &JNIEnv<'_>, obj: JObject<'_>) -> Result<BlockMeta, fai
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_writeBlockMetadata(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_writeBlockMetadata(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_cache: JString<'_>,
|
db_cache: JString<'_>,
|
||||||
|
@ -978,7 +978,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_writeBlockM
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getLatestHeight(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getLatestHeight(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
fsblockdb_root: JString<'_>,
|
fsblockdb_root: JString<'_>,
|
||||||
|
@ -1000,7 +1000,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getLatestHe
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_findBlockMetadata(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_findBlockMetadata(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
fsblockdb_root: JString<'_>,
|
fsblockdb_root: JString<'_>,
|
||||||
|
@ -1023,7 +1023,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_findBlockMe
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_rewindBlockMetadataToHeight(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_rewindBlockMetadataToHeight(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
fsblockdb_root: JString<'_>,
|
fsblockdb_root: JString<'_>,
|
||||||
|
@ -1046,7 +1046,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_rewindBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_validateCombinedChain(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_validateCombinedChain(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_cache: JString<'_>,
|
db_cache: JString<'_>,
|
||||||
|
@ -1084,7 +1084,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_validateCom
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getNearestRewindHeight(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getNearestRewindHeight(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -1120,7 +1120,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getNearestR
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_rewindToHeight(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_rewindToHeight(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -1143,7 +1143,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_rewindToHei
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_scanBlocks(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_scanBlocks(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_cache: JString<'_>,
|
db_cache: JString<'_>,
|
||||||
|
@ -1171,7 +1171,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_scanBlocks(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_putUtxo(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_putUtxo(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -1218,7 +1218,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_putUtxo(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_decryptAndStoreTransaction(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_decryptAndStoreTransaction(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -1271,7 +1271,7 @@ fn zip317_helper<Ctx, DbT, R>(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createToAddress(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_createToAddress(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -1363,7 +1363,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createToAdd
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_shieldToAddress(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_shieldToAddress(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
||||||
|
@ -1454,7 +1454,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_shieldToAdd
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_branchIdForHeight(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_branchIdForHeight(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
height: jlong,
|
height: jlong,
|
||||||
|
@ -1499,7 +1499,7 @@ fn parse_network(value: u32) -> Result<Network, failure::Error> {
|
||||||
/// - Call [`zcashlc_free_keys`] to free the memory associated with the returned pointer
|
/// - Call [`zcashlc_free_keys`] to free the memory associated with the returned pointer
|
||||||
/// when done using it.
|
/// when done using it.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_listTransparentReceivers(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_listTransparentReceivers(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
_: JClass<'_>,
|
_: JClass<'_>,
|
||||||
db_data: JString<'_>,
|
db_data: JString<'_>,
|
|
@ -58,7 +58,7 @@ class TestWallet(
|
||||||
private val context = InstrumentationRegistry.getInstrumentation().context
|
private val context = InstrumentationRegistry.getInstrumentation().context
|
||||||
private val seed: ByteArray = Mnemonics.MnemonicCode(seedPhrase).toSeed()
|
private val seed: ByteArray = Mnemonics.MnemonicCode(seedPhrase).toSeed()
|
||||||
private val shieldedSpendingKey =
|
private val shieldedSpendingKey =
|
||||||
runBlocking { DerivationTool.deriveUnifiedSpendingKey(seed, network = network, account) }
|
runBlocking { DerivationTool.getInstance().deriveUnifiedSpendingKey(seed, network = network, account) }
|
||||||
val synchronizer: SdkSynchronizer = Synchronizer.newBlocking(
|
val synchronizer: SdkSynchronizer = Synchronizer.newBlocking(
|
||||||
context,
|
context,
|
||||||
network,
|
network,
|
||||||
|
|
|
@ -178,7 +178,7 @@ class SampleCodeTest {
|
||||||
val amount = 0.123.convertZecToZatoshi()
|
val amount = 0.123.convertZecToZatoshi()
|
||||||
val address = "ztestsapling1tklsjr0wyw0d58f3p7wufvrj2cyfv6q6caumyueadq8qvqt8lda6v6tpx474rfru9y6u75u7qnw"
|
val address = "ztestsapling1tklsjr0wyw0d58f3p7wufvrj2cyfv6q6caumyueadq8qvqt8lda6v6tpx474rfru9y6u75u7qnw"
|
||||||
val memo = "Test Transaction"
|
val memo = "Test Transaction"
|
||||||
val spendingKey = DerivationTool.deriveUnifiedSpendingKey(seed, ZcashNetwork.Mainnet, Account.DEFAULT)
|
val spendingKey = DerivationTool.getInstance().deriveUnifiedSpendingKey(seed, ZcashNetwork.Mainnet, Account.DEFAULT)
|
||||||
synchronizer.sendToAddress(spendingKey, amount, address, memo)
|
synchronizer.sendToAddress(spendingKey, amount, address, memo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ internal fun ComposeActivity.Navigation() {
|
||||||
} else {
|
} else {
|
||||||
Transactions(
|
Transactions(
|
||||||
synchronizer = synchronizer,
|
synchronizer = synchronizer,
|
||||||
onBack = { navController.popBackStackJustOnce(SEND) }
|
onBack = { navController.popBackStackJustOnce(TRANSACTIONS) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ class GetAddressFragment : BaseDemoFragment<FragmentGetAddressBinding>() {
|
||||||
override fun onActionButtonClicked() {
|
override fun onActionButtonClicked() {
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
copyToClipboard(
|
copyToClipboard(
|
||||||
DerivationTool.deriveUnifiedAddress(
|
DerivationTool.getInstance().deriveUnifiedAddress(
|
||||||
viewingKey.encoding,
|
viewingKey.encoding,
|
||||||
ZcashNetwork.fromResources(requireApplicationContext())
|
ZcashNetwork.fromResources(requireApplicationContext())
|
||||||
),
|
),
|
||||||
|
|
|
@ -69,7 +69,7 @@ class GetBalanceFragment : BaseDemoFragment<FragmentGetBalanceBinding>() {
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
sharedViewModel.synchronizerFlow.value?.shieldFunds(
|
sharedViewModel.synchronizerFlow.value?.shieldFunds(
|
||||||
DerivationTool.deriveUnifiedSpendingKey(
|
DerivationTool.getInstance().deriveUnifiedSpendingKey(
|
||||||
seed,
|
seed,
|
||||||
network,
|
network,
|
||||||
Account.DEFAULT
|
Account.DEFAULT
|
||||||
|
|
|
@ -47,14 +47,14 @@ class GetPrivateKeyFragment : BaseDemoFragment<FragmentGetPrivateKeyBinding>() {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
val spendingKey = DerivationTool.deriveUnifiedSpendingKey(
|
val spendingKey = DerivationTool.getInstance().deriveUnifiedSpendingKey(
|
||||||
seed,
|
seed,
|
||||||
ZcashNetwork.fromResources(requireApplicationContext()),
|
ZcashNetwork.fromResources(requireApplicationContext()),
|
||||||
Account(5)
|
Account(5)
|
||||||
)
|
)
|
||||||
|
|
||||||
// derive the key that allows you to view but not spend transactions
|
// derive the key that allows you to view but not spend transactions
|
||||||
val viewingKey = DerivationTool.deriveUnifiedFullViewingKey(
|
val viewingKey = DerivationTool.getInstance().deriveUnifiedFullViewingKey(
|
||||||
spendingKey,
|
spendingKey,
|
||||||
ZcashNetwork.fromResources(requireApplicationContext())
|
ZcashNetwork.fromResources(requireApplicationContext())
|
||||||
)
|
)
|
||||||
|
@ -91,9 +91,10 @@ class GetPrivateKeyFragment : BaseDemoFragment<FragmentGetPrivateKeyBinding>() {
|
||||||
override fun onActionButtonClicked() {
|
override fun onActionButtonClicked() {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
copyToClipboard(
|
copyToClipboard(
|
||||||
DerivationTool.deriveUnifiedFullViewingKeys(
|
DerivationTool.getInstance().deriveUnifiedFullViewingKeys(
|
||||||
seed,
|
seed,
|
||||||
ZcashNetwork.fromResources(requireApplicationContext())
|
ZcashNetwork.fromResources(requireApplicationContext()),
|
||||||
|
DerivationTool.DEFAULT_NUMBER_OF_ACCOUNTS
|
||||||
).first().encoding,
|
).first().encoding,
|
||||||
"UnifiedFullViewingKey copied to clipboard!"
|
"UnifiedFullViewingKey copied to clipboard!"
|
||||||
)
|
)
|
||||||
|
|
|
@ -90,7 +90,7 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
|
||||||
val bip39Seed = withContext(Dispatchers.IO) {
|
val bip39Seed = withContext(Dispatchers.IO) {
|
||||||
Mnemonics.MnemonicCode(it.seedPhrase.joinToString()).toSeed()
|
Mnemonics.MnemonicCode(it.seedPhrase.joinToString()).toSeed()
|
||||||
}
|
}
|
||||||
DerivationTool.deriveUnifiedSpendingKey(
|
DerivationTool.getInstance().deriveUnifiedSpendingKey(
|
||||||
seed = bip39Seed,
|
seed = bip39Seed,
|
||||||
network = it.network,
|
network = it.network,
|
||||||
account = Account.DEFAULT
|
account = Account.DEFAULT
|
||||||
|
|
|
@ -10,6 +10,7 @@ Thankfully, the only thing an app developer has to be concerned with is the foll
|
||||||
# Modules
|
# Modules
|
||||||
The SDK is broken down into several logical components, implemented as Gradle modules. At a high level, the modularization is:
|
The SDK is broken down into several logical components, implemented as Gradle modules. At a high level, the modularization is:
|
||||||
|
|
||||||
|
* backend-lib — Native library interfaces. This is internal to the SDK.
|
||||||
* sdk-lib — Compiles all of the modules together for the SDK.
|
* sdk-lib — Compiles all of the modules together for the SDK.
|
||||||
* sdk-incubator-lib — Incubator for new APIs that may eventually be promoted to the SDK. Classes are packaged to match the SDK, so that moving them will not necessarily change the API. While SDK clients can use classes in sdk-incubator-lib, they should anticipate a greater amount of public API churn.
|
* sdk-incubator-lib — Incubator for new APIs that may eventually be promoted to the SDK. Classes are packaged to match the SDK, so that moving them will not necessarily change the API. While SDK clients can use classes in sdk-incubator-lib, they should anticipate a greater amount of public API churn.
|
||||||
* lightwallet-client-lib — Provides a set of Kotlin APIs for interacting with lightwalletd over the network.
|
* lightwallet-client-lib — Provides a set of Kotlin APIs for interacting with lightwalletd over the network.
|
||||||
|
@ -18,6 +19,7 @@ The SDK is broken down into several logical components, implemented as Gradle mo
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart TB;
|
flowchart TB;
|
||||||
|
backendLib[[backend-lib]] --> sdkLib[[sdk-lib]];
|
||||||
lightwalletClientLib[[lightwallet-client-lib]] --> sdkLib[[sdk-lib]];
|
lightwalletClientLib[[lightwallet-client-lib]] --> sdkLib[[sdk-lib]];
|
||||||
sdkLib[[sdk-lib]] --> demoApp[[demo-app]];
|
sdkLib[[sdk-lib]] --> demoApp[[demo-app]];
|
||||||
sdkLib[[sdk-lib]] --> sdkIncubatorLib[[sdk-incubator-lib]];
|
sdkLib[[sdk-lib]] --> sdkIncubatorLib[[sdk-incubator-lib]];
|
||||||
|
@ -28,9 +30,11 @@ The SDK is broken down into several logical components, implemented as Gradle mo
|
||||||
# Data model
|
# Data model
|
||||||
Before diving into some of the module specifics, it is helpful to provide some context on the data model representations as data flows between the different modules of this repository. There are multiple data representations, including:
|
Before diving into some of the module specifics, it is helpful to provide some context on the data model representations as data flows between the different modules of this repository. There are multiple data representations, including:
|
||||||
|
|
||||||
1. Network — The wire representation for calls to and from the Lightwalletd server. These are generated by `protoc` at compile time. These are not generally a public API.
|
1. Primitive — The JNI generally requires primitive values (e.g. `Int`, `Long`, `String`, `ByteArray`). These are not generally part of the public API.
|
||||||
2. Unsafe — The representation provided as the output from `lightwallet-client-lib`. These values are not necessarily validated, hence the smurf naming with the suffix `Unsafe`. These are not generally a public API for clients of the SDK.
|
2. JNI — Objects that may cross the JNI boundary. These are not generally part of the public API.
|
||||||
3. SDK — Objects exposed as a public API for clients of the SDK.
|
3. Network — The wire representation for calls to and from the Lightwalletd server. These are generated by `protoc` at compile time. These are not generally a public API.
|
||||||
|
4. Unsafe — The representation provided as the output from `lightwallet-client-lib`. These values are not necessarily validated, hence the smurf naming with the suffix `Unsafe`. These are not generally a public API for clients of the SDK.
|
||||||
|
5. SDK — Objects exposed as a public API for clients of the SDK.
|
||||||
|
|
||||||
# lightwallet-client-lib
|
# lightwallet-client-lib
|
||||||
This library is a work-in-progress.
|
This library is a work-in-progress.
|
||||||
|
|
|
@ -115,7 +115,8 @@ dependencies {
|
||||||
implementation(libs.kotlinx.coroutines.core)
|
implementation(libs.kotlinx.coroutines.core)
|
||||||
implementation(libs.kotlinx.coroutines.android)
|
implementation(libs.kotlinx.coroutines.android)
|
||||||
|
|
||||||
// TODO [#673]: Make `implementation` https://github.com/zcash/zcash-android-wallet-sdk/issues/673
|
// TODO [#1030]: Make sdk-lib gRPC objects free (and then make this `implementation`)
|
||||||
|
// TODO [#1030]: https://github.com/zcash/zcash-android-wallet-sdk/issues/1030
|
||||||
api(libs.bundles.grpc)
|
api(libs.bundles.grpc)
|
||||||
|
|
||||||
// Tests
|
// Tests
|
||||||
|
|
|
@ -1,48 +1,4 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<issues format="5" by="lint 4.2.1" client="gradle" variant="all" version="4.2.1">
|
<issues format="6" by="lint 7.4.0" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0)" variant="all" version="7.4.0">
|
||||||
|
|
||||||
<issue
|
|
||||||
id="DefaultLocale"
|
|
||||||
message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
|
||||||
errorLine1=" (t.message?.toLowerCase()?.contains(unlessContains.toLowerCase()) == true)"
|
|
||||||
errorLine2=" ~~~~~~~~~~~">
|
|
||||||
<location
|
|
||||||
file="src/main/java/cash/z/ecc/android/sdk/ext/Ext.kt"
|
|
||||||
line="29"
|
|
||||||
column="29"/>
|
|
||||||
</issue>
|
|
||||||
|
|
||||||
<issue
|
|
||||||
id="DefaultLocale"
|
|
||||||
message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
|
||||||
errorLine1=" (t.message?.toLowerCase()?.contains(unlessContains.toLowerCase()) == true)"
|
|
||||||
errorLine2=" ~~~~~~~~~~~">
|
|
||||||
<location
|
|
||||||
file="src/main/java/cash/z/ecc/android/sdk/ext/Ext.kt"
|
|
||||||
line="29"
|
|
||||||
column="68"/>
|
|
||||||
</issue>
|
|
||||||
|
|
||||||
<issue
|
|
||||||
id="DefaultLocale"
|
|
||||||
message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
|
||||||
errorLine1=" (t.message?.toLowerCase()?.contains(ifContains.toLowerCase()) == false)"
|
|
||||||
errorLine2=" ~~~~~~~~~~~">
|
|
||||||
<location
|
|
||||||
file="src/main/java/cash/z/ecc/android/sdk/ext/Ext.kt"
|
|
||||||
line="33"
|
|
||||||
column="33"/>
|
|
||||||
</issue>
|
|
||||||
|
|
||||||
<issue
|
|
||||||
id="DefaultLocale"
|
|
||||||
message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
|
||||||
errorLine1=" (t.message?.toLowerCase()?.contains(ifContains.toLowerCase()) == false)"
|
|
||||||
errorLine2=" ~~~~~~~~~~~">
|
|
||||||
<location
|
|
||||||
file="src/main/java/cash/z/ecc/android/sdk/ext/Ext.kt"
|
|
||||||
line="33"
|
|
||||||
column="68"/>
|
|
||||||
</issue>
|
|
||||||
|
|
||||||
</issues>
|
</issues>
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
-keepclasseswithmembernames,includedescriptorclasses class * {
|
|
||||||
native <methods>;
|
|
||||||
}
|
|
||||||
|
|
||||||
# https://github.com/grpc/grpc-java/blob/master/android/proguard-rules.txt
|
# https://github.com/grpc/grpc-java/blob/master/android/proguard-rules.txt
|
||||||
-keepclassmembers class io.grpc.okhttp.OkHttpChannelBuilder {
|
-keepclassmembers class io.grpc.okhttp.OkHttpChannelBuilder {
|
||||||
io.grpc.okhttp.OkHttpChannelBuilder forTarget(java.lang.String);
|
io.grpc.okhttp.OkHttpChannelBuilder forTarget(java.lang.String);
|
||||||
|
@ -10,6 +6,9 @@
|
||||||
io.grpc.okhttp.OkHttpChannelBuilder transportExecutor(java.util.concurrent.Executor);
|
io.grpc.okhttp.OkHttpChannelBuilder transportExecutor(java.util.concurrent.Executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# gRPC related - https://github.com/grpc/grpc-java/issues/6612
|
||||||
|
-keep class * extends com.google.protobuf.GeneratedMessageLite { *; }
|
||||||
|
|
||||||
# Prevent OKHttp from causing warnings for consumers of the SDK
|
# Prevent OKHttp from causing warnings for consumers of the SDK
|
||||||
-dontwarn org.bouncycastle.jsse.BCSSLParameters
|
-dontwarn org.bouncycastle.jsse.BCSSLParameters
|
||||||
-dontwarn org.bouncycastle.jsse.BCSSLSocket
|
-dontwarn org.bouncycastle.jsse.BCSSLSocket
|
||||||
|
|
|
@ -46,7 +46,7 @@ class CompactBlockUnsafe(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class CompactBlockOutputsCounts(
|
data class CompactBlockOutputsCounts(
|
||||||
val saplingOutputsCount: UInt,
|
val saplingOutputsCount: UInt,
|
||||||
val orchardActionsCount: UInt
|
val orchardActionsCount: UInt
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,7 +20,11 @@ sealed class WalletFixture {
|
||||||
seed: String = seedPhrase,
|
seed: String = seedPhrase,
|
||||||
network: ZcashNetwork,
|
network: ZcashNetwork,
|
||||||
account: Account = Account.DEFAULT
|
account: Account = Account.DEFAULT
|
||||||
) = DerivationTool.deriveUnifiedSpendingKey(Mnemonics.MnemonicCode(seed).toEntropy(), network, account)
|
) = DerivationTool.getInstance().deriveUnifiedSpendingKey(
|
||||||
|
Mnemonics.MnemonicCode(seed).toEntropy(),
|
||||||
|
network,
|
||||||
|
account
|
||||||
|
)
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
object Ben : WalletFixture() {
|
object Ben : WalletFixture() {
|
||||||
|
@ -34,9 +38,11 @@ sealed class WalletFixture {
|
||||||
ZcashNetwork.ID_TESTNET -> {
|
ZcashNetwork.ID_TESTNET -> {
|
||||||
BlockHeight.new(zcashNetwork, 2170000L)
|
BlockHeight.new(zcashNetwork, 2170000L)
|
||||||
}
|
}
|
||||||
|
|
||||||
ZcashNetwork.ID_MAINNET -> {
|
ZcashNetwork.ID_MAINNET -> {
|
||||||
BlockHeight.new(zcashNetwork, 1935000L)
|
BlockHeight.new(zcashNetwork, 1935000L)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> error("Unknown network $zcashNetwork")
|
else -> error("Unknown network $zcashNetwork")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +56,7 @@ sealed class WalletFixture {
|
||||||
transparent = "tmP3uLtGx5GPddkq8a6ddmXhqJJ3vy6tpTE"
|
transparent = "tmP3uLtGx5GPddkq8a6ddmXhqJJ3vy6tpTE"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ZcashNetwork.ID_MAINNET -> {
|
ZcashNetwork.ID_MAINNET -> {
|
||||||
Addresses(
|
Addresses(
|
||||||
unified =
|
unified =
|
||||||
|
@ -59,6 +66,7 @@ sealed class WalletFixture {
|
||||||
transparent = "t1JP7PHu72xHztsZiwH6cye4yvC9Prb3EvQ"
|
transparent = "t1JP7PHu72xHztsZiwH6cye4yvC9Prb3EvQ"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> error("Unknown network $zcashNetwork")
|
else -> error("Unknown network $zcashNetwork")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,9 +84,11 @@ sealed class WalletFixture {
|
||||||
ZcashNetwork.ID_TESTNET -> {
|
ZcashNetwork.ID_TESTNET -> {
|
||||||
BlockHeight.new(zcashNetwork, 2170000L)
|
BlockHeight.new(zcashNetwork, 2170000L)
|
||||||
}
|
}
|
||||||
|
|
||||||
ZcashNetwork.ID_MAINNET -> {
|
ZcashNetwork.ID_MAINNET -> {
|
||||||
BlockHeight.new(zcashNetwork, 1935000L)
|
BlockHeight.new(zcashNetwork, 1935000L)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> error("Unknown network $zcashNetwork")
|
else -> error("Unknown network $zcashNetwork")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +102,7 @@ sealed class WalletFixture {
|
||||||
transparent = "tmCxJG72RWN66xwPtNgu4iKHpyysGrc7rEg"
|
transparent = "tmCxJG72RWN66xwPtNgu4iKHpyysGrc7rEg"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ZcashNetwork.ID_MAINNET -> {
|
ZcashNetwork.ID_MAINNET -> {
|
||||||
Addresses(
|
Addresses(
|
||||||
unified =
|
unified =
|
||||||
|
@ -101,6 +112,7 @@ sealed class WalletFixture {
|
||||||
transparent = "t1duiEGg7b39nfQee3XaTY4f5McqfyJKhBi"
|
transparent = "t1duiEGg7b39nfQee3XaTY4f5McqfyJKhBi"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> error("Unknown network $zcashNetwork")
|
else -> error("Unknown network $zcashNetwork")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ plugins {
|
||||||
|
|
||||||
id("org.jetbrains.kotlin.plugin.allopen")
|
id("org.jetbrains.kotlin.plugin.allopen")
|
||||||
id("org.jetbrains.dokka")
|
id("org.jetbrains.dokka")
|
||||||
id("org.mozilla.rust-android-gradle.rust-android")
|
|
||||||
|
|
||||||
id("wtf.emulator.gradle")
|
id("wtf.emulator.gradle")
|
||||||
id("zcash-sdk.emulator-wtf-conventions")
|
id("zcash-sdk.emulator-wtf-conventions")
|
||||||
|
@ -84,28 +83,9 @@ tasks.dokkaHtml.configure {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cargo {
|
|
||||||
module = "."
|
|
||||||
libname = "zcashwalletsdk"
|
|
||||||
targets = listOf(
|
|
||||||
"arm",
|
|
||||||
"arm64",
|
|
||||||
"x86",
|
|
||||||
"x86_64"
|
|
||||||
)
|
|
||||||
apiLevels = mapOf(
|
|
||||||
"arm" to 16,
|
|
||||||
"arm64" to 21,
|
|
||||||
"x86" to 16,
|
|
||||||
"x86_64" to 21,
|
|
||||||
)
|
|
||||||
|
|
||||||
profile = "release"
|
|
||||||
prebuiltToolchains = true
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.lightwalletClientLib)
|
api(projects.lightwalletClientLib)
|
||||||
|
implementation(projects.backendLib)
|
||||||
|
|
||||||
implementation(libs.androidx.annotation)
|
implementation(libs.androidx.annotation)
|
||||||
implementation(libs.androidx.appcompat)
|
implementation(libs.androidx.appcompat)
|
||||||
|
@ -149,22 +129,5 @@ dependencies {
|
||||||
androidTestImplementation(libs.bip39)
|
androidTestImplementation(libs.bip39)
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
|
||||||
/*
|
|
||||||
* The Mozilla Rust Gradle plugin caches the native build data under the "target" directory,
|
|
||||||
* which does not normally get deleted during a clean. The following task and dependency solves
|
|
||||||
* that.
|
|
||||||
*/
|
|
||||||
getByName<Delete>("clean").dependsOn(create<Delete>("cleanRustBuildOutput") {
|
|
||||||
delete("target")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
project.afterEvaluate {
|
|
||||||
val cargoTask = tasks.getByName("cargoBuild")
|
|
||||||
tasks.getByName("javaPreCompileDebug").dependsOn(cargoTask)
|
|
||||||
tasks.getByName("javaPreCompileRelease").dependsOn(cargoTask)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun MinimalExternalModuleDependency.asCoordinateString() =
|
fun MinimalExternalModuleDependency.asCoordinateString() =
|
||||||
"${module.group}:${module.name}:${versionConstraint.displayName}"
|
"${module.group}:${module.name}:${versionConstraint.displayName}"
|
|
@ -1,48 +1,4 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<issues format="5" by="lint 4.2.1" client="gradle" variant="all" version="4.2.1">
|
<issues format="6" by="lint 7.4.0" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0)" variant="all" version="7.4.0">
|
||||||
|
|
||||||
<issue
|
|
||||||
id="DefaultLocale"
|
|
||||||
message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
|
||||||
errorLine1=" (t.message?.toLowerCase()?.contains(unlessContains.toLowerCase()) == true)"
|
|
||||||
errorLine2=" ~~~~~~~~~~~">
|
|
||||||
<location
|
|
||||||
file="src/main/java/cash/z/ecc/android/sdk/ext/Ext.kt"
|
|
||||||
line="29"
|
|
||||||
column="29"/>
|
|
||||||
</issue>
|
|
||||||
|
|
||||||
<issue
|
|
||||||
id="DefaultLocale"
|
|
||||||
message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
|
||||||
errorLine1=" (t.message?.toLowerCase()?.contains(unlessContains.toLowerCase()) == true)"
|
|
||||||
errorLine2=" ~~~~~~~~~~~">
|
|
||||||
<location
|
|
||||||
file="src/main/java/cash/z/ecc/android/sdk/ext/Ext.kt"
|
|
||||||
line="29"
|
|
||||||
column="68"/>
|
|
||||||
</issue>
|
|
||||||
|
|
||||||
<issue
|
|
||||||
id="DefaultLocale"
|
|
||||||
message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
|
||||||
errorLine1=" (t.message?.toLowerCase()?.contains(ifContains.toLowerCase()) == false)"
|
|
||||||
errorLine2=" ~~~~~~~~~~~">
|
|
||||||
<location
|
|
||||||
file="src/main/java/cash/z/ecc/android/sdk/ext/Ext.kt"
|
|
||||||
line="33"
|
|
||||||
column="33"/>
|
|
||||||
</issue>
|
|
||||||
|
|
||||||
<issue
|
|
||||||
id="DefaultLocale"
|
|
||||||
message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
|
||||||
errorLine1=" (t.message?.toLowerCase()?.contains(ifContains.toLowerCase()) == false)"
|
|
||||||
errorLine2=" ~~~~~~~~~~~">
|
|
||||||
<location
|
|
||||||
file="src/main/java/cash/z/ecc/android/sdk/ext/Ext.kt"
|
|
||||||
line="33"
|
|
||||||
column="68"/>
|
|
||||||
</issue>
|
|
||||||
|
|
||||||
</issues>
|
</issues>
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
-keepclasseswithmembernames,includedescriptorclasses class * {
|
|
||||||
native <methods>;
|
|
||||||
}
|
|
||||||
|
|
||||||
# https://github.com/grpc/grpc-java/blob/master/android/proguard-rules.txt
|
|
||||||
-keepclassmembers class io.grpc.okhttp.OkHttpChannelBuilder {
|
|
||||||
io.grpc.okhttp.OkHttpChannelBuilder forTarget(java.lang.String);
|
|
||||||
io.grpc.okhttp.OkHttpChannelBuilder scheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
|
|
||||||
io.grpc.okhttp.OkHttpChannelBuilder sslSocketFactory(javax.net.ssl.SSLSocketFactory);
|
|
||||||
io.grpc.okhttp.OkHttpChannelBuilder transportExecutor(java.util.concurrent.Executor);
|
|
||||||
}
|
|
||||||
# gRPC related - https://github.com/grpc/grpc-java/issues/6612
|
|
||||||
-keep class * extends com.google.protobuf.GeneratedMessageLite { *; }
|
|
||||||
|
|
||||||
# Prevent OKHttp from causing warnings for consumers of the SDK
|
|
||||||
-dontwarn org.bouncycastle.jsse.BCSSLParameters
|
|
||||||
-dontwarn org.bouncycastle.jsse.BCSSLSocket
|
|
||||||
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
|
|
||||||
-dontwarn org.conscrypt.Conscrypt
|
|
||||||
-dontwarn org.conscrypt.Conscrypt$Version
|
|
||||||
-dontwarn org.conscrypt.ConscryptHostnameVerifier
|
|
||||||
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
|
|
||||||
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
|
|
||||||
-dontwarn org.openjsse.net.ssl.OpenJSSE
|
|
|
@ -19,6 +19,5 @@
|
||||||
-keep public class cash.z.ecc.android.sdk.db.entity.* { public protected *; }
|
-keep public class cash.z.ecc.android.sdk.db.entity.* { public protected *; }
|
||||||
-keep public class cash.z.ecc.android.sdk.exception.* { public protected *; }
|
-keep public class cash.z.ecc.android.sdk.exception.* { public protected *; }
|
||||||
-keep public class cash.z.ecc.android.sdk.ext.* { public protected *; }
|
-keep public class cash.z.ecc.android.sdk.ext.* { public protected *; }
|
||||||
-keep public class cash.z.ecc.android.sdk.jni.* { public protected *; }
|
|
||||||
-keep public class cash.z.ecc.android.sdk.tool.* { public protected *; }
|
-keep public class cash.z.ecc.android.sdk.tool.* { public protected *; }
|
||||||
-keep public class cash.z.ecc.android.sdk.type.* { public protected *; }
|
-keep public class cash.z.ecc.android.sdk.type.* { public protected *; }
|
|
@ -1,8 +1,9 @@
|
||||||
package cash.z.ecc.android.sdk.db
|
package cash.z.ecc.android.sdk.db
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import cash.z.ecc.android.sdk.internal.db.DatabaseCoordinator
|
import cash.z.ecc.android.sdk.internal.db.DatabaseCoordinator
|
||||||
import cash.z.ecc.android.sdk.internal.ext.existsSuspend
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
import cash.z.ecc.android.sdk.test.getAppContext
|
import cash.z.ecc.android.sdk.test.getAppContext
|
||||||
import cash.z.ecc.fixture.DatabaseCacheFilesRootFixture
|
import cash.z.ecc.fixture.DatabaseCacheFilesRootFixture
|
||||||
import cash.z.ecc.fixture.DatabaseNameFixture
|
import cash.z.ecc.fixture.DatabaseNameFixture
|
||||||
|
@ -124,28 +125,28 @@ class DatabaseCoordinatorTest {
|
||||||
DatabaseNameFixture.newDbWal(name = DatabaseCoordinator.DB_DATA_NAME)
|
DatabaseNameFixture.newDbWal(name = DatabaseCoordinator.DB_DATA_NAME)
|
||||||
)
|
)
|
||||||
|
|
||||||
assertTrue(originalDbFile.existsSuspend())
|
assertTrue(originalDbFile.exists())
|
||||||
assertTrue(originalDbJournalFile.existsSuspend())
|
assertTrue(originalDbJournalFile.exists())
|
||||||
assertTrue(originalDbWalFile.existsSuspend())
|
assertTrue(originalDbWalFile.exists())
|
||||||
|
|
||||||
assertFalse(expectedDbFile.existsSuspend())
|
assertFalse(expectedDbFile.exists())
|
||||||
assertFalse(expectedDbJournalFile.existsSuspend())
|
assertFalse(expectedDbJournalFile.exists())
|
||||||
assertFalse(expectedDbWalFile.existsSuspend())
|
assertFalse(expectedDbWalFile.exists())
|
||||||
|
|
||||||
dbCoordinator.dataDbFile(
|
dbCoordinator.dataDbFile(
|
||||||
DatabaseNameFixture.TEST_DB_NETWORK,
|
DatabaseNameFixture.TEST_DB_NETWORK,
|
||||||
DatabaseNameFixture.TEST_DB_ALIAS
|
DatabaseNameFixture.TEST_DB_ALIAS
|
||||||
).also { resultFile ->
|
).also { resultFile ->
|
||||||
assertTrue(resultFile.existsSuspend())
|
assertTrue(resultFile.exists())
|
||||||
assertEquals(expectedDbFile.absolutePath, resultFile.absolutePath)
|
assertEquals(expectedDbFile.absolutePath, resultFile.absolutePath)
|
||||||
|
|
||||||
assertTrue(expectedDbFile.existsSuspend())
|
assertTrue(expectedDbFile.exists())
|
||||||
assertTrue(expectedDbJournalFile.existsSuspend())
|
assertTrue(expectedDbJournalFile.exists())
|
||||||
assertTrue(expectedDbWalFile.existsSuspend())
|
assertTrue(expectedDbWalFile.exists())
|
||||||
|
|
||||||
assertFalse(originalDbFile.existsSuspend())
|
assertFalse(originalDbFile.exists())
|
||||||
assertFalse(originalDbJournalFile.existsSuspend())
|
assertFalse(originalDbJournalFile.exists())
|
||||||
assertFalse(originalDbWalFile.existsSuspend())
|
assertFalse(originalDbWalFile.exists())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,14 +187,14 @@ class DatabaseCoordinatorTest {
|
||||||
fileName = DatabaseNameFixture.newDbWal(name = DatabaseCoordinator.DB_DATA_NAME)
|
fileName = DatabaseNameFixture.newDbWal(name = DatabaseCoordinator.DB_DATA_NAME)
|
||||||
)
|
)
|
||||||
|
|
||||||
assertTrue(dbFile.existsSuspend())
|
assertTrue(dbFile.exists())
|
||||||
assertTrue(dbJournalFile.existsSuspend())
|
assertTrue(dbJournalFile.exists())
|
||||||
assertTrue(dbWalFile.existsSuspend())
|
assertTrue(dbWalFile.exists())
|
||||||
|
|
||||||
dbCoordinator.deleteDatabases(DatabaseNameFixture.TEST_DB_NETWORK, DatabaseNameFixture.TEST_DB_ALIAS).also {
|
dbCoordinator.deleteDatabases(DatabaseNameFixture.TEST_DB_NETWORK, DatabaseNameFixture.TEST_DB_ALIAS).also {
|
||||||
assertFalse(dbFile.existsSuspend())
|
assertFalse(dbFile.exists())
|
||||||
assertFalse(dbJournalFile.existsSuspend())
|
assertFalse(dbJournalFile.exists())
|
||||||
assertFalse(dbWalFile.existsSuspend())
|
assertFalse(dbWalFile.exists())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,13 +277,13 @@ class DatabaseCoordinatorTest {
|
||||||
)
|
)
|
||||||
|
|
||||||
// check all files in place
|
// check all files in place
|
||||||
assertTrue(olderLegacyDbFile.existsSuspend())
|
assertTrue(olderLegacyDbFile.exists())
|
||||||
assertTrue(olderLegacyDbJournalFile.existsSuspend())
|
assertTrue(olderLegacyDbJournalFile.exists())
|
||||||
assertTrue(olderLegacyDbWalFile.existsSuspend())
|
assertTrue(olderLegacyDbWalFile.exists())
|
||||||
|
|
||||||
assertTrue(newerLegacyDbFile.existsSuspend())
|
assertTrue(newerLegacyDbFile.exists())
|
||||||
assertTrue(newerLegacyDbJournalFile.existsSuspend())
|
assertTrue(newerLegacyDbJournalFile.exists())
|
||||||
assertTrue(newerLegacyDbWalFile.existsSuspend())
|
assertTrue(newerLegacyDbWalFile.exists())
|
||||||
|
|
||||||
// once we access the latest file system blocks storage root directory, all the legacy database files should
|
// once we access the latest file system blocks storage root directory, all the legacy database files should
|
||||||
// be removed
|
// be removed
|
||||||
|
@ -290,13 +291,41 @@ class DatabaseCoordinatorTest {
|
||||||
network = DatabaseNameFixture.TEST_DB_NETWORK,
|
network = DatabaseNameFixture.TEST_DB_NETWORK,
|
||||||
alias = DatabaseNameFixture.TEST_DB_ALIAS
|
alias = DatabaseNameFixture.TEST_DB_ALIAS
|
||||||
).also {
|
).also {
|
||||||
assertFalse(olderLegacyDbFile.existsSuspend())
|
assertFalse(olderLegacyDbFile.exists())
|
||||||
assertFalse(olderLegacyDbJournalFile.existsSuspend())
|
assertFalse(olderLegacyDbJournalFile.exists())
|
||||||
assertFalse(olderLegacyDbWalFile.existsSuspend())
|
assertFalse(olderLegacyDbWalFile.exists())
|
||||||
|
|
||||||
assertFalse(newerLegacyDbFile.existsSuspend())
|
assertFalse(newerLegacyDbFile.exists())
|
||||||
assertFalse(newerLegacyDbJournalFile.existsSuspend())
|
assertFalse(newerLegacyDbJournalFile.exists())
|
||||||
assertFalse(newerLegacyDbWalFile.existsSuspend())
|
assertFalse(newerLegacyDbWalFile.exists())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@Test
|
||||||
|
@SmallTest
|
||||||
|
fun data_db_path() = runTest {
|
||||||
|
val coordinator = DatabaseCoordinator.getInstance(ApplicationProvider.getApplicationContext())
|
||||||
|
val dataDbFile = coordinator.dataDbFile(ZcashNetwork.Testnet, "TestWallet")
|
||||||
|
assertTrue(
|
||||||
|
"Invalid DataDB file",
|
||||||
|
dataDbFile.absolutePath.endsWith(
|
||||||
|
"no_backup/co.electricoin.zcash/TestWallet_testnet_${DatabaseCoordinator.DB_DATA_NAME}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@Test
|
||||||
|
@SmallTest
|
||||||
|
fun cache_path() = runTest {
|
||||||
|
val coordinator = DatabaseCoordinator.getInstance(ApplicationProvider.getApplicationContext())
|
||||||
|
val cache = coordinator.fsBlockDbRoot(ZcashNetwork.Testnet, "TestWallet")
|
||||||
|
assertTrue(
|
||||||
|
"Invalid CacheDB file",
|
||||||
|
cache.absolutePath.endsWith(
|
||||||
|
"no_backup/co.electricoin.zcash/TestWallet_testnet_${DatabaseCoordinator.DB_FS_BLOCK_DB_ROOT_NAME}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package cash.z.ecc.android.sdk.fixture
|
package cash.z.ecc.android.sdk.fixture
|
||||||
|
|
||||||
import cash.z.ecc.android.bip39.Mnemonics
|
import cash.z.ecc.android.bip39.Mnemonics
|
||||||
|
import cash.z.ecc.android.sdk.internal.deriveUnifiedSpendingKey
|
||||||
|
import cash.z.ecc.android.sdk.internal.jni.RustDerivationTool
|
||||||
import cash.z.ecc.android.sdk.model.Account
|
import cash.z.ecc.android.sdk.model.Account
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
import cash.z.ecc.android.sdk.tool.DerivationTool
|
|
||||||
|
|
||||||
object WalletFixture {
|
object WalletFixture {
|
||||||
val NETWORK = ZcashNetwork.Mainnet
|
val NETWORK = ZcashNetwork.Mainnet
|
||||||
|
@ -14,5 +15,5 @@ object WalletFixture {
|
||||||
seed: String = SEED_PHRASE,
|
seed: String = SEED_PHRASE,
|
||||||
network: ZcashNetwork = NETWORK,
|
network: ZcashNetwork = NETWORK,
|
||||||
account: Account = Account.DEFAULT
|
account: Account = Account.DEFAULT
|
||||||
) = DerivationTool.deriveUnifiedSpendingKey(Mnemonics.MnemonicCode(seed).toEntropy(), network, account)
|
) = RustDerivationTool.new().deriveUnifiedSpendingKey(Mnemonics.MnemonicCode(seed).toEntropy(), network, account)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
package cash.z.ecc.android.sdk.integration
|
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider
|
|
||||||
import androidx.test.filters.SmallTest
|
|
||||||
import cash.z.ecc.android.sdk.DefaultSynchronizerFactory
|
|
||||||
import cash.z.ecc.android.sdk.internal.SaplingParamTool
|
|
||||||
import cash.z.ecc.android.sdk.internal.db.DatabaseCoordinator
|
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
|
||||||
import cash.z.ecc.android.sdk.util.TestWallet
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import org.junit.Assert.assertTrue
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class SynchronizerFactoryTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@SmallTest
|
|
||||||
fun testFilePaths() {
|
|
||||||
val rustBackend = runBlocking {
|
|
||||||
val coordinator = DatabaseCoordinator.getInstance(ApplicationProvider.getApplicationContext())
|
|
||||||
DefaultSynchronizerFactory.defaultRustBackend(
|
|
||||||
ZcashNetwork.Testnet,
|
|
||||||
"TestWallet",
|
|
||||||
TestWallet.Backups.SAMPLE_WALLET.testnetBirthday,
|
|
||||||
SaplingParamTool.new(ApplicationProvider.getApplicationContext()),
|
|
||||||
coordinator
|
|
||||||
)
|
|
||||||
}
|
|
||||||
assertTrue(
|
|
||||||
"Invalid DataDB file",
|
|
||||||
rustBackend.dataDbFile.absolutePath.endsWith(
|
|
||||||
"no_backup/co.electricoin.zcash/TestWallet_testnet_${DatabaseCoordinator.DB_DATA_NAME}"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
assertTrue(
|
|
||||||
"Invalid CacheDB file",
|
|
||||||
rustBackend.fsBlockDbRoot.absolutePath.endsWith(
|
|
||||||
"no_backup/co.electricoin.zcash/TestWallet_testnet_${DatabaseCoordinator.DB_FS_BLOCK_DB_ROOT_NAME}"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
assertTrue(
|
|
||||||
"Invalid CacheDB params dir",
|
|
||||||
rustBackend.saplingParamDir.endsWith(
|
|
||||||
"no_backup/co.electricoin.zcash"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -101,7 +101,7 @@ class TestnetIntegrationTest : ScopedTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun sendFunds(): Boolean {
|
private suspend fun sendFunds(): Boolean {
|
||||||
val spendingKey = DerivationTool.deriveUnifiedSpendingKey(seed, synchronizer.network, Account.DEFAULT)
|
val spendingKey = DerivationTool.getInstance().deriveUnifiedSpendingKey(seed, synchronizer.network, Account.DEFAULT)
|
||||||
log("sending to address")
|
log("sending to address")
|
||||||
synchronizer.sendToAddress(
|
synchronizer.sendToAddress(
|
||||||
spendingKey,
|
spendingKey,
|
||||||
|
|
|
@ -2,6 +2,13 @@ package cash.z.ecc.android.sdk.internal
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.KEY_EPOCH_SECONDS
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.KEY_HASH
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.KEY_HEIGHT
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.KEY_TREE
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.KEY_VERSION
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.VERSION_1
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.from
|
||||||
import cash.z.ecc.fixture.CheckpointFixture
|
import cash.z.ecc.fixture.CheckpointFixture
|
||||||
import cash.z.ecc.fixture.toJson
|
import cash.z.ecc.fixture.toJson
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cash.z.ecc.android.sdk.internal
|
package cash.z.ecc.android.sdk.internal
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.filters.MediumTest
|
import androidx.test.filters.MediumTest
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import cash.z.ecc.android.sdk.exception.TransactionEncoderException
|
import cash.z.ecc.android.sdk.exception.TransactionEncoderException
|
||||||
|
@ -11,6 +12,7 @@ import cash.z.ecc.fixture.SaplingParamsFixture
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Assert
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
@ -168,4 +170,17 @@ class SaplingParamToolBasicTest {
|
||||||
saplingParamTool.ensureParams(SaplingParamToolFixture.PARAMS_DIRECTORY)
|
saplingParamTool.ensureParams(SaplingParamToolFixture.PARAMS_DIRECTORY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@Test
|
||||||
|
@SmallTest
|
||||||
|
fun sapling_params_path() = runTest {
|
||||||
|
val paramsDir = SaplingParamTool.new(ApplicationProvider.getApplicationContext()).properties.paramsDirectory
|
||||||
|
Assert.assertTrue(
|
||||||
|
"Invalid CacheDB params dir",
|
||||||
|
paramsDir.endsWith(
|
||||||
|
"no_backup/co.electricoin.zcash"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package cash.z.ecc.android.sdk.internal.storage.block
|
package cash.z.ecc.android.sdk.internal.storage.block
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.internal.Backend
|
||||||
import cash.z.ecc.android.sdk.internal.ext.deleteRecursivelySuspend
|
import cash.z.ecc.android.sdk.internal.ext.deleteRecursivelySuspend
|
||||||
import cash.z.ecc.android.sdk.internal.ext.existsSuspend
|
import cash.z.ecc.android.sdk.internal.ext.existsSuspend
|
||||||
import cash.z.ecc.android.sdk.internal.ext.listSuspend
|
import cash.z.ecc.android.sdk.internal.ext.listSuspend
|
||||||
import cash.z.ecc.android.sdk.internal.ext.mkdirsSuspend
|
import cash.z.ecc.android.sdk.internal.ext.mkdirsSuspend
|
||||||
import cash.z.ecc.android.sdk.jni.Backend
|
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
import cash.z.ecc.fixture.FakeRustBackendFixture
|
import cash.z.ecc.fixture.FakeRustBackendFixture
|
||||||
|
|
|
@ -2,6 +2,10 @@ package cash.z.ecc.android.sdk.jni
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.annotation.MaintainedTest
|
import cash.z.ecc.android.sdk.annotation.MaintainedTest
|
||||||
import cash.z.ecc.android.sdk.annotation.TestPurpose
|
import cash.z.ecc.android.sdk.annotation.TestPurpose
|
||||||
|
import cash.z.ecc.android.sdk.internal.Backend
|
||||||
|
import cash.z.ecc.android.sdk.internal.getBranchIdForHeight
|
||||||
|
import cash.z.ecc.android.sdk.internal.jni.RustBackend
|
||||||
|
import cash.z.ecc.android.sdk.internal.network
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
@ -47,21 +51,21 @@ class BranchIdTest internal constructor(
|
||||||
// However, due to quirks on certain devices, we created this test at the Android level,
|
// However, due to quirks on certain devices, we created this test at the Android level,
|
||||||
// as a sanity check
|
// as a sanity check
|
||||||
val testnetBackend = runBlocking {
|
val testnetBackend = runBlocking {
|
||||||
RustBackend.init(
|
RustBackend.new(
|
||||||
File(""),
|
File(""),
|
||||||
File(""),
|
File(""),
|
||||||
File(""),
|
File(""),
|
||||||
ZcashNetwork.Testnet,
|
File(""),
|
||||||
ZcashNetwork.Testnet.saplingActivationHeight
|
ZcashNetwork.Testnet.id,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val mainnetBackend = runBlocking {
|
val mainnetBackend = runBlocking {
|
||||||
RustBackend.init(
|
RustBackend.new(
|
||||||
File(""),
|
File(""),
|
||||||
File(""),
|
File(""),
|
||||||
File(""),
|
File(""),
|
||||||
ZcashNetwork.Mainnet,
|
File(""),
|
||||||
ZcashNetwork.Mainnet.saplingActivationHeight
|
ZcashNetwork.Mainnet.id,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return listOf(
|
return listOf(
|
||||||
|
|
|
@ -5,8 +5,11 @@ import cash.z.ecc.android.bip39.Mnemonics.MnemonicCode
|
||||||
import cash.z.ecc.android.bip39.toSeed
|
import cash.z.ecc.android.bip39.toSeed
|
||||||
import cash.z.ecc.android.sdk.annotation.MaintainedTest
|
import cash.z.ecc.android.sdk.annotation.MaintainedTest
|
||||||
import cash.z.ecc.android.sdk.annotation.TestPurpose
|
import cash.z.ecc.android.sdk.annotation.TestPurpose
|
||||||
|
import cash.z.ecc.android.sdk.internal.Derivation
|
||||||
|
import cash.z.ecc.android.sdk.internal.deriveUnifiedAddress
|
||||||
|
import cash.z.ecc.android.sdk.internal.deriveUnifiedFullViewingKeysTypesafe
|
||||||
|
import cash.z.ecc.android.sdk.internal.jni.RustDerivationTool
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
import cash.z.ecc.android.sdk.tool.DerivationTool
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.BeforeClass
|
import org.junit.BeforeClass
|
||||||
|
@ -21,10 +24,15 @@ class TransparentTest(val expected: Expected, val network: ZcashNetwork) {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun deriveUnifiedFullViewingKeysFromSeedTest() = runBlocking {
|
fun deriveUnifiedFullViewingKeysFromSeedTest() = runBlocking {
|
||||||
val ufvks = DerivationTool.deriveUnifiedFullViewingKeys(SEED, network = network)
|
val ufvks = RustDerivationTool.new().deriveUnifiedFullViewingKeysTypesafe(
|
||||||
|
SEED,
|
||||||
|
network = network,
|
||||||
|
numberOfAccounts =
|
||||||
|
Derivation.DEFAULT_NUMBER_OF_ACCOUNTS
|
||||||
|
)
|
||||||
assertEquals(1, ufvks.size)
|
assertEquals(1, ufvks.size)
|
||||||
val ufvk = ufvks.first()
|
val ufvk = ufvks.first()
|
||||||
assertEquals(expected.uAddr, DerivationTool.deriveUnifiedAddress(ufvk.encoding, network = network))
|
assertEquals(expected.uAddr, RustDerivationTool.new().deriveUnifiedAddress(ufvk.encoding, network = network))
|
||||||
// TODO: If we need this, change DerivationTool to derive from the UFVK instead of the public key.
|
// TODO: If we need this, change DerivationTool to derive from the UFVK instead of the public key.
|
||||||
// assertEquals(expected.tAddr, DerivationTool.deriveTransparentAddressFromPublicKey(ufvk.encoding,
|
// assertEquals(expected.tAddr, DerivationTool.deriveTransparentAddressFromPublicKey(ufvk.encoding,
|
||||||
// network = network))
|
// network = network))
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package cash.z.ecc.android.sdk.tool
|
|
||||||
|
|
||||||
import cash.z.ecc.android.bip39.Mnemonics
|
|
||||||
import cash.z.ecc.android.sdk.fixture.WalletFixture
|
|
||||||
import cash.z.ecc.android.sdk.model.Account
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import org.junit.Test
|
|
||||||
import kotlin.test.assertContentEquals
|
|
||||||
|
|
||||||
class DerivationToolTest {
|
|
||||||
@Test
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
fun create_spending_key_does_not_mutate_passed_bytes() = runTest {
|
|
||||||
val bytesOne = Mnemonics.MnemonicCode(WalletFixture.SEED_PHRASE).toEntropy()
|
|
||||||
val bytesTwo = Mnemonics.MnemonicCode(WalletFixture.SEED_PHRASE).toEntropy()
|
|
||||||
|
|
||||||
DerivationTool.deriveUnifiedSpendingKey(bytesOne, WalletFixture.NETWORK, Account.DEFAULT)
|
|
||||||
|
|
||||||
assertContentEquals(bytesTwo, bytesOne)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,10 @@
|
||||||
package cash.z.ecc.android.sdk.util
|
package cash.z.ecc.android.sdk.util
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.internal.deriveUnifiedAddress
|
||||||
|
import cash.z.ecc.android.sdk.internal.jni.RustDerivationTool
|
||||||
import cash.z.ecc.android.sdk.model.Account
|
import cash.z.ecc.android.sdk.model.Account
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
import cash.z.ecc.android.sdk.test.readFileLinesInFlow
|
import cash.z.ecc.android.sdk.test.readFileLinesInFlow
|
||||||
import cash.z.ecc.android.sdk.tool.DerivationTool
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
@ -31,7 +32,7 @@ class AddressGeneratorUtil {
|
||||||
.map { seedPhrase ->
|
.map { seedPhrase ->
|
||||||
mnemonics.toSeed(seedPhrase.toCharArray())
|
mnemonics.toSeed(seedPhrase.toCharArray())
|
||||||
}.map { seed ->
|
}.map { seed ->
|
||||||
DerivationTool.deriveUnifiedAddress(seed, ZcashNetwork.Mainnet, Account.DEFAULT)
|
RustDerivationTool.new().deriveUnifiedAddress(seed, ZcashNetwork.Mainnet, Account.DEFAULT)
|
||||||
}.collect { address ->
|
}.collect { address ->
|
||||||
println("xrxrx2\t$address")
|
println("xrxrx2\t$address")
|
||||||
assertTrue(address.startsWith("u1"))
|
assertTrue(address.startsWith("u1"))
|
||||||
|
|
|
@ -6,13 +6,14 @@ import cash.z.ecc.android.bip39.toSeed
|
||||||
import cash.z.ecc.android.sdk.SdkSynchronizer
|
import cash.z.ecc.android.sdk.SdkSynchronizer
|
||||||
import cash.z.ecc.android.sdk.Synchronizer
|
import cash.z.ecc.android.sdk.Synchronizer
|
||||||
import cash.z.ecc.android.sdk.internal.Twig
|
import cash.z.ecc.android.sdk.internal.Twig
|
||||||
|
import cash.z.ecc.android.sdk.internal.deriveUnifiedSpendingKey
|
||||||
|
import cash.z.ecc.android.sdk.internal.jni.RustDerivationTool
|
||||||
import cash.z.ecc.android.sdk.model.Account
|
import cash.z.ecc.android.sdk.model.Account
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.Testnet
|
import cash.z.ecc.android.sdk.model.Testnet
|
||||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
import cash.z.ecc.android.sdk.tool.DerivationTool
|
|
||||||
import co.electriccoin.lightwallet.client.model.LightWalletEndpoint
|
import co.electriccoin.lightwallet.client.model.LightWalletEndpoint
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
|
@ -58,7 +59,7 @@ class TestWallet(
|
||||||
private val context = InstrumentationRegistry.getInstrumentation().context
|
private val context = InstrumentationRegistry.getInstrumentation().context
|
||||||
private val seed: ByteArray = Mnemonics.MnemonicCode(seedPhrase).toSeed()
|
private val seed: ByteArray = Mnemonics.MnemonicCode(seedPhrase).toSeed()
|
||||||
private val spendingKey =
|
private val spendingKey =
|
||||||
runBlocking { DerivationTool.deriveUnifiedSpendingKey(seed, network = network, account) }
|
runBlocking { RustDerivationTool.new().deriveUnifiedSpendingKey(seed, network = network, account) }
|
||||||
val synchronizer: SdkSynchronizer = Synchronizer.newBlocking(
|
val synchronizer: SdkSynchronizer = Synchronizer.newBlocking(
|
||||||
context,
|
context,
|
||||||
network,
|
network,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package cash.z.ecc.fixture
|
package cash.z.ecc.fixture
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.internal.KEY_EPOCH_SECONDS
|
|
||||||
import cash.z.ecc.android.sdk.internal.KEY_HASH
|
|
||||||
import cash.z.ecc.android.sdk.internal.KEY_HEIGHT
|
|
||||||
import cash.z.ecc.android.sdk.internal.KEY_TREE
|
|
||||||
import cash.z.ecc.android.sdk.internal.KEY_VERSION
|
|
||||||
import cash.z.ecc.android.sdk.internal.VERSION_1
|
|
||||||
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.KEY_EPOCH_SECONDS
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.KEY_HASH
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.KEY_HEIGHT
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.KEY_TREE
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.KEY_VERSION
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.VERSION_1
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
package cash.z.ecc.fixture
|
package cash.z.ecc.fixture
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.internal.Backend
|
||||||
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
||||||
import cash.z.ecc.android.sdk.jni.Backend
|
import cash.z.ecc.android.sdk.internal.model.JniUnifiedSpendingKey
|
||||||
import cash.z.ecc.android.sdk.jni.UnifiedSpendingKeyJni
|
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
internal class FakeRustBackend(
|
internal class FakeRustBackend(
|
||||||
override val network: ZcashNetwork,
|
override val networkId: Int,
|
||||||
override val saplingParamDir: File,
|
|
||||||
val metadata: MutableList<JniBlockMeta>
|
val metadata: MutableList<JniBlockMeta>
|
||||||
) : Backend {
|
) : Backend {
|
||||||
|
|
||||||
|
@ -34,6 +30,17 @@ internal class FakeRustBackend(
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun putUtxo(
|
||||||
|
tAddress: String,
|
||||||
|
txId: ByteArray,
|
||||||
|
index: Int,
|
||||||
|
script: ByteArray,
|
||||||
|
value: Long,
|
||||||
|
height: Long
|
||||||
|
): Boolean {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun findBlockMetadata(height: Long): JniBlockMeta? {
|
override suspend fun findBlockMetadata(height: Long): JniBlockMeta? {
|
||||||
return metadata.findLast { it.height == height }
|
return metadata.findLast { it.height == height }
|
||||||
}
|
}
|
||||||
|
@ -78,7 +85,7 @@ internal class FakeRustBackend(
|
||||||
override suspend fun initDataDb(seed: ByteArray?): Int =
|
override suspend fun initDataDb(seed: ByteArray?): Int =
|
||||||
error("Intentionally not implemented in mocked FakeRustBackend implementation.")
|
error("Intentionally not implemented in mocked FakeRustBackend implementation.")
|
||||||
|
|
||||||
override suspend fun createAccount(seed: ByteArray): UnifiedSpendingKeyJni =
|
override suspend fun createAccount(seed: ByteArray): JniUnifiedSpendingKey =
|
||||||
error("Intentionally not implemented in mocked FakeRustBackend implementation.")
|
error("Intentionally not implemented in mocked FakeRustBackend implementation.")
|
||||||
|
|
||||||
override fun isValidShieldedAddr(addr: String): Boolean =
|
override fun isValidShieldedAddr(addr: String): Boolean =
|
||||||
|
@ -128,13 +135,4 @@ internal class FakeRustBackend(
|
||||||
|
|
||||||
override suspend fun scanBlocks(limit: Long?): Boolean =
|
override suspend fun scanBlocks(limit: Long?): Boolean =
|
||||||
error("Intentionally not implemented in mocked FakeRustBackend implementation.")
|
error("Intentionally not implemented in mocked FakeRustBackend implementation.")
|
||||||
|
|
||||||
override suspend fun putUtxo(
|
|
||||||
tAddress: String,
|
|
||||||
txId: ByteArray,
|
|
||||||
index: Int,
|
|
||||||
script: ByteArray,
|
|
||||||
value: Long,
|
|
||||||
height: BlockHeight
|
|
||||||
): Boolean = error("Intentionally not implemented in mocked FakeRustBackend implementation.")
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,20 +2,16 @@ package cash.z.ecc.fixture
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
internal class FakeRustBackendFixture {
|
internal class FakeRustBackendFixture {
|
||||||
|
|
||||||
private val DEFAULT_SAPLING_PARAM_DIR = File(DatabasePathFixture.new())
|
|
||||||
private val DEFAULT_NETWORK = ZcashNetwork.Testnet
|
private val DEFAULT_NETWORK = ZcashNetwork.Testnet
|
||||||
|
|
||||||
fun new(
|
fun new(
|
||||||
saplingParamDir: File = DEFAULT_SAPLING_PARAM_DIR,
|
|
||||||
network: ZcashNetwork = DEFAULT_NETWORK,
|
network: ZcashNetwork = DEFAULT_NETWORK,
|
||||||
metadata: MutableList<JniBlockMeta> = mutableListOf()
|
metadata: MutableList<JniBlockMeta> = mutableListOf()
|
||||||
) = FakeRustBackend(
|
) = FakeRustBackend(
|
||||||
saplingParamDir = saplingParamDir,
|
networkId = network.id,
|
||||||
network = network,
|
|
||||||
metadata = metadata
|
metadata = metadata
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,17 @@ import cash.z.ecc.android.sdk.exception.TransactionEncoderException
|
||||||
import cash.z.ecc.android.sdk.exception.TransactionSubmitException
|
import cash.z.ecc.android.sdk.exception.TransactionSubmitException
|
||||||
import cash.z.ecc.android.sdk.ext.ConsensusBranchId
|
import cash.z.ecc.android.sdk.ext.ConsensusBranchId
|
||||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||||
|
import cash.z.ecc.android.sdk.internal.Backend
|
||||||
import cash.z.ecc.android.sdk.internal.SaplingParamTool
|
import cash.z.ecc.android.sdk.internal.SaplingParamTool
|
||||||
import cash.z.ecc.android.sdk.internal.Twig
|
import cash.z.ecc.android.sdk.internal.Twig
|
||||||
import cash.z.ecc.android.sdk.internal.block.CompactBlockDownloader
|
import cash.z.ecc.android.sdk.internal.block.CompactBlockDownloader
|
||||||
import cash.z.ecc.android.sdk.internal.db.DatabaseCoordinator
|
import cash.z.ecc.android.sdk.internal.db.DatabaseCoordinator
|
||||||
import cash.z.ecc.android.sdk.internal.db.derived.DbDerivedDataRepository
|
import cash.z.ecc.android.sdk.internal.db.derived.DbDerivedDataRepository
|
||||||
import cash.z.ecc.android.sdk.internal.db.derived.DerivedDataDb
|
import cash.z.ecc.android.sdk.internal.db.derived.DerivedDataDb
|
||||||
|
import cash.z.ecc.android.sdk.internal.ext.isNullOrEmpty
|
||||||
import cash.z.ecc.android.sdk.internal.ext.toHexReversed
|
import cash.z.ecc.android.sdk.internal.ext.toHexReversed
|
||||||
import cash.z.ecc.android.sdk.internal.ext.tryNull
|
import cash.z.ecc.android.sdk.internal.ext.tryNull
|
||||||
import cash.z.ecc.android.sdk.internal.isNullOrEmpty
|
import cash.z.ecc.android.sdk.internal.jni.RustBackend
|
||||||
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
||||||
import cash.z.ecc.android.sdk.internal.repository.CompactBlockRepository
|
import cash.z.ecc.android.sdk.internal.repository.CompactBlockRepository
|
||||||
import cash.z.ecc.android.sdk.internal.repository.DerivedDataRepository
|
import cash.z.ecc.android.sdk.internal.repository.DerivedDataRepository
|
||||||
|
@ -34,7 +36,6 @@ import cash.z.ecc.android.sdk.internal.transaction.OutboundTransactionManager
|
||||||
import cash.z.ecc.android.sdk.internal.transaction.OutboundTransactionManagerImpl
|
import cash.z.ecc.android.sdk.internal.transaction.OutboundTransactionManagerImpl
|
||||||
import cash.z.ecc.android.sdk.internal.transaction.TransactionEncoder
|
import cash.z.ecc.android.sdk.internal.transaction.TransactionEncoder
|
||||||
import cash.z.ecc.android.sdk.internal.transaction.TransactionEncoderImpl
|
import cash.z.ecc.android.sdk.internal.transaction.TransactionEncoderImpl
|
||||||
import cash.z.ecc.android.sdk.jni.RustBackend
|
|
||||||
import cash.z.ecc.android.sdk.model.Account
|
import cash.z.ecc.android.sdk.model.Account
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||||
|
@ -69,6 +70,7 @@ import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.io.File
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
@ -92,7 +94,7 @@ class SdkSynchronizer private constructor(
|
||||||
private val storage: DerivedDataRepository,
|
private val storage: DerivedDataRepository,
|
||||||
private val txManager: OutboundTransactionManager,
|
private val txManager: OutboundTransactionManager,
|
||||||
val processor: CompactBlockProcessor,
|
val processor: CompactBlockProcessor,
|
||||||
private val rustBackend: RustBackend
|
private val backend: Backend
|
||||||
) : CloseableSynchronizer {
|
) : CloseableSynchronizer {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -116,7 +118,7 @@ class SdkSynchronizer private constructor(
|
||||||
repository: DerivedDataRepository,
|
repository: DerivedDataRepository,
|
||||||
txManager: OutboundTransactionManager,
|
txManager: OutboundTransactionManager,
|
||||||
processor: CompactBlockProcessor,
|
processor: CompactBlockProcessor,
|
||||||
rustBackend: RustBackend
|
backend: Backend
|
||||||
): CloseableSynchronizer {
|
): CloseableSynchronizer {
|
||||||
val synchronizerKey = SynchronizerKey(zcashNetwork, alias)
|
val synchronizerKey = SynchronizerKey(zcashNetwork, alias)
|
||||||
|
|
||||||
|
@ -128,7 +130,7 @@ class SdkSynchronizer private constructor(
|
||||||
repository,
|
repository,
|
||||||
txManager,
|
txManager,
|
||||||
processor,
|
processor,
|
||||||
rustBackend
|
backend
|
||||||
).apply {
|
).apply {
|
||||||
instances[synchronizerKey] = InstanceState.Active
|
instances[synchronizerKey] = InstanceState.Active
|
||||||
|
|
||||||
|
@ -311,10 +313,10 @@ class SdkSynchronizer private constructor(
|
||||||
return storage.getNoteIds(transactionOverview.id).map {
|
return storage.getNoteIds(transactionOverview.id).map {
|
||||||
when (transactionOverview.isSentTransaction) {
|
when (transactionOverview.isSentTransaction) {
|
||||||
true -> {
|
true -> {
|
||||||
rustBackend.getSentMemoAsUtf8(it)
|
backend.getSentMemoAsUtf8(it)
|
||||||
}
|
}
|
||||||
false -> {
|
false -> {
|
||||||
rustBackend.getReceivedMemoAsUtf8(it)
|
backend.getReceivedMemoAsUtf8(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.filterNotNull()
|
}.filterNotNull()
|
||||||
|
@ -405,7 +407,6 @@ class SdkSynchronizer private constructor(
|
||||||
lastScanTime = now
|
lastScanTime = now
|
||||||
SYNCED
|
SYNCED
|
||||||
}
|
}
|
||||||
|
|
||||||
is Stopped -> STOPPED
|
is Stopped -> STOPPED
|
||||||
is Disconnected -> DISCONNECTED
|
is Disconnected -> DISCONNECTED
|
||||||
is Syncing, Initialized -> SYNCING
|
is Syncing, Initialized -> SYNCING
|
||||||
|
@ -509,25 +510,25 @@ class SdkSynchronizer private constructor(
|
||||||
|
|
||||||
// Not ready to be a public API; internal for testing only
|
// Not ready to be a public API; internal for testing only
|
||||||
internal suspend fun createAccount(seed: ByteArray): UnifiedSpendingKey =
|
internal suspend fun createAccount(seed: ByteArray): UnifiedSpendingKey =
|
||||||
CompactBlockProcessor.createAccount(rustBackend, seed)
|
CompactBlockProcessor.createAccount(backend, seed)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current Unified Address for this account.
|
* Returns the current Unified Address for this account.
|
||||||
*/
|
*/
|
||||||
override suspend fun getUnifiedAddress(account: Account): String =
|
override suspend fun getUnifiedAddress(account: Account): String =
|
||||||
CompactBlockProcessor.getCurrentAddress(rustBackend, account)
|
CompactBlockProcessor.getCurrentAddress(backend, account)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the legacy Sapling address corresponding to the current Unified Address for this account.
|
* Returns the legacy Sapling address corresponding to the current Unified Address for this account.
|
||||||
*/
|
*/
|
||||||
override suspend fun getSaplingAddress(account: Account): String =
|
override suspend fun getSaplingAddress(account: Account): String =
|
||||||
CompactBlockProcessor.getLegacySaplingAddress(rustBackend, account)
|
CompactBlockProcessor.getLegacySaplingAddress(backend, account)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the legacy transparent address corresponding to the current Unified Address for this account.
|
* Returns the legacy transparent address corresponding to the current Unified Address for this account.
|
||||||
*/
|
*/
|
||||||
override suspend fun getTransparentAddress(account: Account): String =
|
override suspend fun getTransparentAddress(account: Account): String =
|
||||||
CompactBlockProcessor.getTransparentAddress(rustBackend, account)
|
CompactBlockProcessor.getTransparentAddress(backend, account)
|
||||||
|
|
||||||
@Throws(TransactionEncoderException::class, TransactionSubmitException::class)
|
@Throws(TransactionEncoderException::class, TransactionSubmitException::class)
|
||||||
override suspend fun sendToAddress(
|
override suspend fun sendToAddress(
|
||||||
|
@ -557,7 +558,7 @@ class SdkSynchronizer private constructor(
|
||||||
memo: String
|
memo: String
|
||||||
): Long {
|
): Long {
|
||||||
Twig.debug { "Initializing shielding transaction" }
|
Twig.debug { "Initializing shielding transaction" }
|
||||||
val tAddr = CompactBlockProcessor.getTransparentAddress(rustBackend, usk.account)
|
val tAddr = CompactBlockProcessor.getTransparentAddress(backend, usk.account)
|
||||||
val tBalance = processor.getUtxoCacheBalance(tAddr)
|
val tBalance = processor.getUtxoCacheBalance(tAddr)
|
||||||
|
|
||||||
val encodedTx = txManager.encode(
|
val encodedTx = txManager.encode(
|
||||||
|
@ -628,26 +629,26 @@ class SdkSynchronizer private constructor(
|
||||||
*/
|
*/
|
||||||
internal object DefaultSynchronizerFactory {
|
internal object DefaultSynchronizerFactory {
|
||||||
|
|
||||||
internal suspend fun defaultRustBackend(
|
internal suspend fun defaultBackend(
|
||||||
network: ZcashNetwork,
|
network: ZcashNetwork,
|
||||||
alias: String,
|
alias: String,
|
||||||
blockHeight: BlockHeight,
|
|
||||||
saplingParamTool: SaplingParamTool,
|
saplingParamTool: SaplingParamTool,
|
||||||
coordinator: DatabaseCoordinator
|
coordinator: DatabaseCoordinator
|
||||||
): RustBackend {
|
): Backend {
|
||||||
return RustBackend.init(
|
return RustBackend.new(
|
||||||
coordinator.fsBlockDbRoot(network, alias),
|
coordinator.fsBlockDbRoot(network, alias),
|
||||||
coordinator.dataDbFile(network, alias),
|
coordinator.dataDbFile(network, alias),
|
||||||
saplingParamTool.properties.paramsDirectory,
|
saplingOutputFile = saplingParamTool.outputParamsFile,
|
||||||
network,
|
saplingSpendFile = saplingParamTool.spendParamsFile,
|
||||||
blockHeight
|
zcashNetworkId = network.id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
internal suspend fun defaultDerivedDataRepository(
|
internal suspend fun defaultDerivedDataRepository(
|
||||||
context: Context,
|
context: Context,
|
||||||
rustBackend: RustBackend,
|
rustBackend: Backend,
|
||||||
|
databaseFile: File,
|
||||||
zcashNetwork: ZcashNetwork,
|
zcashNetwork: ZcashNetwork,
|
||||||
checkpoint: Checkpoint,
|
checkpoint: Checkpoint,
|
||||||
seed: ByteArray?,
|
seed: ByteArray?,
|
||||||
|
@ -657,6 +658,7 @@ internal object DefaultSynchronizerFactory {
|
||||||
DerivedDataDb.new(
|
DerivedDataDb.new(
|
||||||
context,
|
context,
|
||||||
rustBackend,
|
rustBackend,
|
||||||
|
databaseFile,
|
||||||
zcashNetwork,
|
zcashNetwork,
|
||||||
checkpoint,
|
checkpoint,
|
||||||
seed,
|
seed,
|
||||||
|
@ -664,19 +666,20 @@ internal object DefaultSynchronizerFactory {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
internal suspend fun defaultFileCompactBlockRepository(rustBackend: RustBackend): CompactBlockRepository =
|
internal suspend fun defaultCompactBlockRepository(blockCacheRoot: File, backend: Backend): CompactBlockRepository =
|
||||||
FileCompactBlockRepository.new(
|
FileCompactBlockRepository.new(
|
||||||
rustBackend
|
blockCacheRoot,
|
||||||
|
backend
|
||||||
)
|
)
|
||||||
|
|
||||||
fun defaultService(context: Context, lightWalletEndpoint: LightWalletEndpoint): LightWalletClient =
|
fun defaultService(context: Context, lightWalletEndpoint: LightWalletEndpoint): LightWalletClient =
|
||||||
LightWalletClient.new(context, lightWalletEndpoint)
|
LightWalletClient.new(context, lightWalletEndpoint)
|
||||||
|
|
||||||
internal fun defaultEncoder(
|
internal fun defaultEncoder(
|
||||||
rustBackend: RustBackend,
|
backend: Backend,
|
||||||
saplingParamTool: SaplingParamTool,
|
saplingParamTool: SaplingParamTool,
|
||||||
repository: DerivedDataRepository
|
repository: DerivedDataRepository
|
||||||
): TransactionEncoder = TransactionEncoderImpl(rustBackend, saplingParamTool, repository)
|
): TransactionEncoder = TransactionEncoderImpl(backend, saplingParamTool, repository)
|
||||||
|
|
||||||
fun defaultDownloader(
|
fun defaultDownloader(
|
||||||
service: LightWalletClient,
|
service: LightWalletClient,
|
||||||
|
@ -689,19 +692,20 @@ internal object DefaultSynchronizerFactory {
|
||||||
): OutboundTransactionManager {
|
): OutboundTransactionManager {
|
||||||
return OutboundTransactionManagerImpl.new(
|
return OutboundTransactionManagerImpl.new(
|
||||||
encoder,
|
encoder,
|
||||||
service,
|
service
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun defaultProcessor(
|
internal fun defaultProcessor(
|
||||||
rustBackend: RustBackend,
|
backend: Backend,
|
||||||
downloader: CompactBlockDownloader,
|
downloader: CompactBlockDownloader,
|
||||||
repository: DerivedDataRepository
|
repository: DerivedDataRepository,
|
||||||
|
birthdayHeight: BlockHeight
|
||||||
): CompactBlockProcessor = CompactBlockProcessor(
|
): CompactBlockProcessor = CompactBlockProcessor(
|
||||||
downloader,
|
downloader,
|
||||||
repository,
|
repository,
|
||||||
rustBackend,
|
backend,
|
||||||
rustBackend.birthdayHeight
|
birthdayHeight
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package cash.z.ecc.android.sdk
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
|
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
|
||||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||||
|
import cash.z.ecc.android.sdk.internal.Derivation
|
||||||
import cash.z.ecc.android.sdk.internal.SaplingParamTool
|
import cash.z.ecc.android.sdk.internal.SaplingParamTool
|
||||||
import cash.z.ecc.android.sdk.internal.db.DatabaseCoordinator
|
import cash.z.ecc.android.sdk.internal.db.DatabaseCoordinator
|
||||||
import cash.z.ecc.android.sdk.model.Account
|
import cash.z.ecc.android.sdk.model.Account
|
||||||
|
@ -412,7 +413,7 @@ interface Synchronizer {
|
||||||
* If customized initialization is required (e.g. for dependency injection or testing), see
|
* If customized initialization is required (e.g. for dependency injection or testing), see
|
||||||
* [DefaultSynchronizerFactory].
|
* [DefaultSynchronizerFactory].
|
||||||
*/
|
*/
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList", "LongMethod")
|
||||||
suspend fun new(
|
suspend fun new(
|
||||||
context: Context,
|
context: Context,
|
||||||
zcashNetwork: ZcashNetwork,
|
zcashNetwork: ZcashNetwork,
|
||||||
|
@ -437,29 +438,29 @@ interface Synchronizer {
|
||||||
// The pending transaction database no longer exists, so we can delete the file
|
// The pending transaction database no longer exists, so we can delete the file
|
||||||
coordinator.deletePendingTransactionDatabase(zcashNetwork, alias)
|
coordinator.deletePendingTransactionDatabase(zcashNetwork, alias)
|
||||||
|
|
||||||
val rustBackend = DefaultSynchronizerFactory.defaultRustBackend(
|
val backend = DefaultSynchronizerFactory.defaultBackend(
|
||||||
zcashNetwork,
|
zcashNetwork,
|
||||||
alias,
|
alias,
|
||||||
loadedCheckpoint.height,
|
|
||||||
saplingParamTool,
|
saplingParamTool,
|
||||||
coordinator
|
coordinator
|
||||||
)
|
)
|
||||||
|
|
||||||
val blockStore =
|
val blockStore =
|
||||||
DefaultSynchronizerFactory
|
DefaultSynchronizerFactory
|
||||||
.defaultFileCompactBlockRepository(rustBackend)
|
.defaultCompactBlockRepository(coordinator.fsBlockDbRoot(zcashNetwork, alias), backend)
|
||||||
|
|
||||||
val viewingKeys = seed?.let {
|
val viewingKeys = seed?.let {
|
||||||
DerivationTool.deriveUnifiedFullViewingKeys(
|
DerivationTool.getInstance().deriveUnifiedFullViewingKeys(
|
||||||
seed,
|
seed,
|
||||||
zcashNetwork,
|
zcashNetwork,
|
||||||
1
|
Derivation.DEFAULT_NUMBER_OF_ACCOUNTS
|
||||||
).toList()
|
).toList()
|
||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
|
|
||||||
val repository = DefaultSynchronizerFactory.defaultDerivedDataRepository(
|
val repository = DefaultSynchronizerFactory.defaultDerivedDataRepository(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
rustBackend,
|
backend,
|
||||||
|
coordinator.dataDbFile(zcashNetwork, alias),
|
||||||
zcashNetwork,
|
zcashNetwork,
|
||||||
loadedCheckpoint,
|
loadedCheckpoint,
|
||||||
seed,
|
seed,
|
||||||
|
@ -467,10 +468,19 @@ interface Synchronizer {
|
||||||
)
|
)
|
||||||
|
|
||||||
val service = DefaultSynchronizerFactory.defaultService(applicationContext, lightWalletEndpoint)
|
val service = DefaultSynchronizerFactory.defaultService(applicationContext, lightWalletEndpoint)
|
||||||
val encoder = DefaultSynchronizerFactory.defaultEncoder(rustBackend, saplingParamTool, repository)
|
val encoder = DefaultSynchronizerFactory.defaultEncoder(backend, saplingParamTool, repository)
|
||||||
val downloader = DefaultSynchronizerFactory.defaultDownloader(service, blockStore)
|
val downloader = DefaultSynchronizerFactory.defaultDownloader(service, blockStore)
|
||||||
val txManager = DefaultSynchronizerFactory.defaultTxManager(encoder, service)
|
val txManager = DefaultSynchronizerFactory.defaultTxManager(
|
||||||
val processor = DefaultSynchronizerFactory.defaultProcessor(rustBackend, downloader, repository)
|
encoder,
|
||||||
|
service
|
||||||
|
)
|
||||||
|
val processor = DefaultSynchronizerFactory.defaultProcessor(
|
||||||
|
backend,
|
||||||
|
downloader,
|
||||||
|
repository,
|
||||||
|
birthday
|
||||||
|
?: zcashNetwork.saplingActivationHeight
|
||||||
|
)
|
||||||
|
|
||||||
return SdkSynchronizer.new(
|
return SdkSynchronizer.new(
|
||||||
zcashNetwork,
|
zcashNetwork,
|
||||||
|
@ -478,7 +488,7 @@ interface Synchronizer {
|
||||||
repository,
|
repository,
|
||||||
txManager,
|
txManager,
|
||||||
processor,
|
processor,
|
||||||
rustBackend
|
backend
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,30 +14,31 @@ import cash.z.ecc.android.sdk.ext.BatchMetrics
|
||||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||||
import cash.z.ecc.android.sdk.ext.ZcashSdk.MAX_BACKOFF_INTERVAL
|
import cash.z.ecc.android.sdk.ext.ZcashSdk.MAX_BACKOFF_INTERVAL
|
||||||
import cash.z.ecc.android.sdk.ext.ZcashSdk.POLL_INTERVAL
|
import cash.z.ecc.android.sdk.ext.ZcashSdk.POLL_INTERVAL
|
||||||
|
import cash.z.ecc.android.sdk.internal.Backend
|
||||||
import cash.z.ecc.android.sdk.internal.Twig
|
import cash.z.ecc.android.sdk.internal.Twig
|
||||||
import cash.z.ecc.android.sdk.internal.block.CompactBlockDownloader
|
import cash.z.ecc.android.sdk.internal.block.CompactBlockDownloader
|
||||||
|
import cash.z.ecc.android.sdk.internal.createAccountAndGetSpendingKey
|
||||||
|
import cash.z.ecc.android.sdk.internal.ext.isNullOrEmpty
|
||||||
|
import cash.z.ecc.android.sdk.internal.ext.length
|
||||||
import cash.z.ecc.android.sdk.internal.ext.retryUpTo
|
import cash.z.ecc.android.sdk.internal.ext.retryUpTo
|
||||||
import cash.z.ecc.android.sdk.internal.ext.retryWithBackoff
|
import cash.z.ecc.android.sdk.internal.ext.retryWithBackoff
|
||||||
import cash.z.ecc.android.sdk.internal.ext.toHexReversed
|
import cash.z.ecc.android.sdk.internal.ext.toHexReversed
|
||||||
import cash.z.ecc.android.sdk.internal.isNullOrEmpty
|
import cash.z.ecc.android.sdk.internal.getBalance
|
||||||
import cash.z.ecc.android.sdk.internal.length
|
import cash.z.ecc.android.sdk.internal.getBranchIdForHeight
|
||||||
|
import cash.z.ecc.android.sdk.internal.getCurrentAddress
|
||||||
|
import cash.z.ecc.android.sdk.internal.getDownloadedUtxoBalance
|
||||||
|
import cash.z.ecc.android.sdk.internal.getNearestRewindHeight
|
||||||
|
import cash.z.ecc.android.sdk.internal.getVerifiedBalance
|
||||||
|
import cash.z.ecc.android.sdk.internal.listTransparentReceivers
|
||||||
import cash.z.ecc.android.sdk.internal.model.BlockBatch
|
import cash.z.ecc.android.sdk.internal.model.BlockBatch
|
||||||
import cash.z.ecc.android.sdk.internal.model.DbTransactionOverview
|
import cash.z.ecc.android.sdk.internal.model.DbTransactionOverview
|
||||||
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
||||||
import cash.z.ecc.android.sdk.internal.model.ext.from
|
import cash.z.ecc.android.sdk.internal.model.ext.from
|
||||||
import cash.z.ecc.android.sdk.internal.model.ext.toBlockHeight
|
import cash.z.ecc.android.sdk.internal.model.ext.toBlockHeight
|
||||||
|
import cash.z.ecc.android.sdk.internal.network
|
||||||
import cash.z.ecc.android.sdk.internal.repository.DerivedDataRepository
|
import cash.z.ecc.android.sdk.internal.repository.DerivedDataRepository
|
||||||
import cash.z.ecc.android.sdk.jni.Backend
|
import cash.z.ecc.android.sdk.internal.rewindToHeight
|
||||||
import cash.z.ecc.android.sdk.jni.createAccountAndGetSpendingKey
|
import cash.z.ecc.android.sdk.internal.validateCombinedChainOrErrorBlockHeight
|
||||||
import cash.z.ecc.android.sdk.jni.getBalance
|
|
||||||
import cash.z.ecc.android.sdk.jni.getBranchIdForHeight
|
|
||||||
import cash.z.ecc.android.sdk.jni.getCurrentAddress
|
|
||||||
import cash.z.ecc.android.sdk.jni.getDownloadedUtxoBalance
|
|
||||||
import cash.z.ecc.android.sdk.jni.getNearestRewindHeight
|
|
||||||
import cash.z.ecc.android.sdk.jni.getVerifiedBalance
|
|
||||||
import cash.z.ecc.android.sdk.jni.listTransparentReceivers
|
|
||||||
import cash.z.ecc.android.sdk.jni.rewindToHeight
|
|
||||||
import cash.z.ecc.android.sdk.jni.validateCombinedChainOrErrorBlockHeight
|
|
||||||
import cash.z.ecc.android.sdk.model.Account
|
import cash.z.ecc.android.sdk.model.Account
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||||
|
@ -80,7 +81,7 @@ import kotlin.time.Duration.Companion.days
|
||||||
* @property downloader the component responsible for downloading compact blocks and persisting them
|
* @property downloader the component responsible for downloading compact blocks and persisting them
|
||||||
* locally for processing.
|
* locally for processing.
|
||||||
* @property repository the repository holding transaction information.
|
* @property repository the repository holding transaction information.
|
||||||
* @property rustBackend the librustzcash functionality available and exposed to the SDK.
|
* @property backend the librustzcash functionality available and exposed to the SDK.
|
||||||
* @param minimumHeight the lowest height that we could care about. This is mostly used during
|
* @param minimumHeight the lowest height that we could care about. This is mostly used during
|
||||||
* reorgs as a backstop to make sure we do not rewind beyond sapling activation. It also is factored
|
* reorgs as a backstop to make sure we do not rewind beyond sapling activation. It also is factored
|
||||||
* in when considering initial range to download. In most cases, this should be the birthday height
|
* in when considering initial range to download. In most cases, this should be the birthday height
|
||||||
|
@ -91,8 +92,8 @@ import kotlin.time.Duration.Companion.days
|
||||||
class CompactBlockProcessor internal constructor(
|
class CompactBlockProcessor internal constructor(
|
||||||
val downloader: CompactBlockDownloader,
|
val downloader: CompactBlockDownloader,
|
||||||
private val repository: DerivedDataRepository,
|
private val repository: DerivedDataRepository,
|
||||||
private val rustBackend: Backend,
|
private val backend: Backend,
|
||||||
minimumHeight: BlockHeight = rustBackend.network.saplingActivationHeight
|
minimumHeight: BlockHeight
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Callback for any non-trivial errors that occur while processing compact blocks.
|
* Callback for any non-trivial errors that occur while processing compact blocks.
|
||||||
|
@ -130,9 +131,15 @@ class CompactBlockProcessor internal constructor(
|
||||||
var onScanMetricCompleteListener: ((BatchMetrics, Boolean) -> Unit)? = null
|
var onScanMetricCompleteListener: ((BatchMetrics, Boolean) -> Unit)? = null
|
||||||
|
|
||||||
private val consecutiveChainErrors = AtomicInteger(0)
|
private val consecutiveChainErrors = AtomicInteger(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The zcash network that is being processed. Either Testnet or Mainnet.
|
||||||
|
*/
|
||||||
|
val network = backend.network
|
||||||
|
|
||||||
private val lowerBoundHeight: BlockHeight = BlockHeight(
|
private val lowerBoundHeight: BlockHeight = BlockHeight(
|
||||||
max(
|
max(
|
||||||
rustBackend.network.saplingActivationHeight.value,
|
network.saplingActivationHeight.value,
|
||||||
minimumHeight.value - MAX_REORG_SIZE
|
minimumHeight.value - MAX_REORG_SIZE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -152,11 +159,6 @@ class CompactBlockProcessor internal constructor(
|
||||||
*/
|
*/
|
||||||
private val _birthdayHeight = MutableStateFlow(lowerBoundHeight)
|
private val _birthdayHeight = MutableStateFlow(lowerBoundHeight)
|
||||||
|
|
||||||
/**
|
|
||||||
* The zcash network that is being processed. Either Testnet or Mainnet.
|
|
||||||
*/
|
|
||||||
val network = rustBackend.network
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The flow of state values so that a wallet can monitor the state of this class without needing
|
* The flow of state values so that a wallet can monitor the state of this class without needing
|
||||||
* to poll.
|
* to poll.
|
||||||
|
@ -357,7 +359,7 @@ class CompactBlockProcessor internal constructor(
|
||||||
// Sync
|
// Sync
|
||||||
var syncResult: BlockProcessingResult = BlockProcessingResult.Success
|
var syncResult: BlockProcessingResult = BlockProcessingResult.Success
|
||||||
syncNewBlocks(
|
syncNewBlocks(
|
||||||
backend = rustBackend,
|
backend = backend,
|
||||||
downloader = downloader,
|
downloader = downloader,
|
||||||
repository = repository,
|
repository = repository,
|
||||||
network = network,
|
network = network,
|
||||||
|
@ -508,7 +510,7 @@ class CompactBlockProcessor internal constructor(
|
||||||
is Response.Success -> {
|
is Response.Success -> {
|
||||||
runCatching {
|
runCatching {
|
||||||
Twig.debug { "decrypting and storing transaction (id:$id block:$minedHeight)" }
|
Twig.debug { "decrypting and storing transaction (id:$id block:$minedHeight)" }
|
||||||
rustBackend.decryptAndStoreTransaction(response.result.data)
|
backend.decryptAndStoreTransaction(response.result.data)
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
Twig.debug { "DONE: enhancing transaction (id:$id block:$minedHeight)" }
|
Twig.debug { "DONE: enhancing transaction (id:$id block:$minedHeight)" }
|
||||||
}.onFailure { error ->
|
}.onFailure { error ->
|
||||||
|
@ -548,9 +550,9 @@ class CompactBlockProcessor internal constructor(
|
||||||
} else {
|
} else {
|
||||||
val clientBranch = "%x".format(
|
val clientBranch = "%x".format(
|
||||||
Locale.ROOT,
|
Locale.ROOT,
|
||||||
rustBackend.getBranchIdForHeight(serverBlockHeight)
|
backend.getBranchIdForHeight(serverBlockHeight)
|
||||||
)
|
)
|
||||||
val network = rustBackend.network.networkName
|
val network = backend.network.networkName
|
||||||
|
|
||||||
if (!clientBranch.equals(info.consensusBranchId, true)) {
|
if (!clientBranch.equals(info.consensusBranchId, true)) {
|
||||||
MismatchedNetwork(
|
MismatchedNetwork(
|
||||||
|
@ -610,7 +612,7 @@ class CompactBlockProcessor internal constructor(
|
||||||
@Suppress("TooGenericExceptionCaught")
|
@Suppress("TooGenericExceptionCaught")
|
||||||
try {
|
try {
|
||||||
retryUpTo(3) {
|
retryUpTo(3) {
|
||||||
val tAddresses = rustBackend.listTransparentReceivers(account)
|
val tAddresses = backend.listTransparentReceivers(account)
|
||||||
|
|
||||||
downloader.lightWalletClient.fetchUtxos(
|
downloader.lightWalletClient.fetchUtxos(
|
||||||
tAddresses,
|
tAddresses,
|
||||||
|
@ -689,13 +691,13 @@ class CompactBlockProcessor internal constructor(
|
||||||
// TODO [#920]: Tweak RustBackend public APIs to have void return values.
|
// TODO [#920]: Tweak RustBackend public APIs to have void return values.
|
||||||
// TODO [#920]: Thus, we don't need to check the boolean result of this call until fixed.
|
// TODO [#920]: Thus, we don't need to check the boolean result of this call until fixed.
|
||||||
// TODO [#920]: https://github.com/zcash/zcash-android-wallet-sdk/issues/920
|
// TODO [#920]: https://github.com/zcash/zcash-android-wallet-sdk/issues/920
|
||||||
rustBackend.putUtxo(
|
backend.putUtxo(
|
||||||
utxo.address,
|
utxo.address,
|
||||||
utxo.txid,
|
utxo.txid,
|
||||||
utxo.index,
|
utxo.index,
|
||||||
utxo.script,
|
utxo.script,
|
||||||
utxo.valueZat,
|
utxo.valueZat,
|
||||||
BlockHeight(utxo.height)
|
utxo.height
|
||||||
)
|
)
|
||||||
true
|
true
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
|
@ -1071,7 +1073,7 @@ class CompactBlockProcessor internal constructor(
|
||||||
// tricky: subtract one because we delete ABOVE this block
|
// tricky: subtract one because we delete ABOVE this block
|
||||||
// This could create an invalid height if if height was saplingActivationHeight
|
// This could create an invalid height if if height was saplingActivationHeight
|
||||||
val rewindHeight = BlockHeight(height.value - 1)
|
val rewindHeight = BlockHeight(height.value - 1)
|
||||||
rustBackend.getNearestRewindHeight(rewindHeight)
|
backend.getNearestRewindHeight(rewindHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1109,10 +1111,10 @@ class CompactBlockProcessor internal constructor(
|
||||||
|
|
||||||
if (null == lastSyncedHeight && targetHeight < lastLocalBlock) {
|
if (null == lastSyncedHeight && targetHeight < lastLocalBlock) {
|
||||||
Twig.debug { "Rewinding because targetHeight is less than lastLocalBlock." }
|
Twig.debug { "Rewinding because targetHeight is less than lastLocalBlock." }
|
||||||
rustBackend.rewindToHeight(targetHeight)
|
backend.rewindToHeight(targetHeight)
|
||||||
} else if (null != lastSyncedHeight && targetHeight < lastSyncedHeight) {
|
} else if (null != lastSyncedHeight && targetHeight < lastSyncedHeight) {
|
||||||
Twig.debug { "Rewinding because targetHeight is less than lastSyncedHeight." }
|
Twig.debug { "Rewinding because targetHeight is less than lastSyncedHeight." }
|
||||||
rustBackend.rewindToHeight(targetHeight)
|
backend.rewindToHeight(targetHeight)
|
||||||
} else {
|
} else {
|
||||||
Twig.debug {
|
Twig.debug {
|
||||||
"Not rewinding dataDb because the last synced height is $lastSyncedHeight and the" +
|
"Not rewinding dataDb because the last synced height is $lastSyncedHeight and the" +
|
||||||
|
@ -1265,7 +1267,7 @@ class CompactBlockProcessor internal constructor(
|
||||||
}
|
}
|
||||||
return buildList<BlockHeight> {
|
return buildList<BlockHeight> {
|
||||||
add(lowerBoundHeight)
|
add(lowerBoundHeight)
|
||||||
add(rustBackend.network.saplingActivationHeight)
|
add(backend.network.saplingActivationHeight)
|
||||||
oldestTransactionHeight?.let { add(it) }
|
oldestTransactionHeight?.let { add(it) }
|
||||||
}.maxOf { it }
|
}.maxOf { it }
|
||||||
}
|
}
|
||||||
|
@ -1280,9 +1282,9 @@ class CompactBlockProcessor internal constructor(
|
||||||
suspend fun getBalanceInfo(account: Account): WalletBalance {
|
suspend fun getBalanceInfo(account: Account): WalletBalance {
|
||||||
@Suppress("TooGenericExceptionCaught")
|
@Suppress("TooGenericExceptionCaught")
|
||||||
return try {
|
return try {
|
||||||
val balanceTotal = rustBackend.getBalance(account)
|
val balanceTotal = backend.getBalance(account)
|
||||||
Twig.debug { "found total balance: $balanceTotal" }
|
Twig.debug { "found total balance: $balanceTotal" }
|
||||||
val balanceAvailable = rustBackend.getVerifiedBalance(account)
|
val balanceAvailable = backend.getVerifiedBalance(account)
|
||||||
Twig.debug { "found available balance: $balanceAvailable" }
|
Twig.debug { "found available balance: $balanceAvailable" }
|
||||||
WalletBalance(balanceTotal, balanceAvailable)
|
WalletBalance(balanceTotal, balanceAvailable)
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
|
@ -1292,7 +1294,7 @@ class CompactBlockProcessor internal constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getUtxoCacheBalance(address: String): WalletBalance =
|
suspend fun getUtxoCacheBalance(address: String): WalletBalance =
|
||||||
rustBackend.getDownloadedUtxoBalance(address)
|
backend.getDownloadedUtxoBalance(address)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transmits the given state for this processor.
|
* Transmits the given state for this processor.
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
@file:Suppress("TooManyFunctions")
|
@file:Suppress("TooManyFunctions")
|
||||||
|
|
||||||
package cash.z.ecc.android.sdk.jni
|
package cash.z.ecc.android.sdk.internal
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.internal.SdkDispatchers
|
|
||||||
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
||||||
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
||||||
import cash.z.ecc.android.sdk.model.Account
|
import cash.z.ecc.android.sdk.model.Account
|
||||||
|
@ -11,9 +10,13 @@ import cash.z.ecc.android.sdk.model.UnifiedFullViewingKey
|
||||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||||
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
import cash.z.ecc.android.sdk.tool.DerivationTool
|
import cash.z.ecc.android.sdk.tool.DerivationTool
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
internal val Backend.network: ZcashNetwork
|
||||||
|
get() = ZcashNetwork.from(networkId)
|
||||||
|
|
||||||
internal suspend fun Backend.initAccountsTable(vararg keys: UnifiedFullViewingKey): Boolean {
|
internal suspend fun Backend.initAccountsTable(vararg keys: UnifiedFullViewingKey): Boolean {
|
||||||
val ufvks = Array(keys.size) { keys[it].encoding }
|
val ufvks = Array(keys.size) { keys[it].encoding }
|
||||||
|
|
||||||
|
@ -21,14 +24,11 @@ internal suspend fun Backend.initAccountsTable(vararg keys: UnifiedFullViewingKe
|
||||||
return initAccountsTable(*ufvks)
|
return initAccountsTable(*ufvks)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal suspend fun Backend.initAccountsTable(
|
internal suspend fun Backend.initAccountsTableTypesafe(
|
||||||
seed: ByteArray,
|
seed: ByteArray,
|
||||||
numberOfAccounts: Int
|
numberOfAccounts: Int
|
||||||
): Array<UnifiedFullViewingKey> {
|
): List<UnifiedFullViewingKey> {
|
||||||
return DerivationTool.deriveUnifiedFullViewingKeys(seed, network, numberOfAccounts).apply {
|
return DerivationTool.getInstance().deriveUnifiedFullViewingKeys(seed, network, numberOfAccounts)
|
||||||
@Suppress("SpreadOperator")
|
|
||||||
initAccountsTable(*this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal suspend fun Backend.initBlocksTable(checkpoint: Checkpoint): Boolean = initBlocksTable(
|
internal suspend fun Backend.initBlocksTable(checkpoint: Checkpoint): Boolean = initBlocksTable(
|
||||||
|
@ -80,7 +80,7 @@ internal suspend fun Backend.getVerifiedBalance(account: Account): Zatoshi = Zat
|
||||||
)
|
)
|
||||||
|
|
||||||
internal suspend fun Backend.getNearestRewindHeight(height: BlockHeight): BlockHeight = BlockHeight.new(
|
internal suspend fun Backend.getNearestRewindHeight(height: BlockHeight): BlockHeight = BlockHeight.new(
|
||||||
network,
|
ZcashNetwork.from(networkId),
|
||||||
getNearestRewindHeight(height.value)
|
getNearestRewindHeight(height.value)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ internal suspend fun Backend.rewindToHeight(height: BlockHeight): Boolean = rewi
|
||||||
|
|
||||||
internal suspend fun Backend.getLatestBlockHeight(): BlockHeight? = getLatestHeight()?.let {
|
internal suspend fun Backend.getLatestBlockHeight(): BlockHeight? = getLatestHeight()?.let {
|
||||||
BlockHeight.new(
|
BlockHeight.new(
|
||||||
network,
|
ZcashNetwork.from(networkId),
|
||||||
it
|
it
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ internal suspend fun Backend.rewindBlockMetadataToHeight(height: BlockHeight) =
|
||||||
internal suspend fun Backend.validateCombinedChainOrErrorBlockHeight(limit: Long?): BlockHeight? =
|
internal suspend fun Backend.validateCombinedChainOrErrorBlockHeight(limit: Long?): BlockHeight? =
|
||||||
validateCombinedChainOrErrorHeight(limit)?.let {
|
validateCombinedChainOrErrorHeight(limit)?.let {
|
||||||
BlockHeight.new(
|
BlockHeight.new(
|
||||||
network,
|
ZcashNetwork.from(networkId),
|
||||||
it
|
it
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -124,3 +124,20 @@ internal suspend fun Backend.getDownloadedUtxoBalance(address: String): WalletBa
|
||||||
}
|
}
|
||||||
return WalletBalance(Zatoshi(total), Zatoshi(verified))
|
return WalletBalance(Zatoshi(total), Zatoshi(verified))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
|
internal suspend fun Backend.putUtxo(
|
||||||
|
tAddress: String,
|
||||||
|
txId: ByteArray,
|
||||||
|
index: Int,
|
||||||
|
script: ByteArray,
|
||||||
|
value: Long,
|
||||||
|
height: BlockHeight
|
||||||
|
): Boolean = putUtxo(
|
||||||
|
tAddress,
|
||||||
|
txId,
|
||||||
|
index,
|
||||||
|
script,
|
||||||
|
value,
|
||||||
|
height.value
|
||||||
|
)
|
|
@ -0,0 +1,44 @@
|
||||||
|
package cash.z.ecc.android.sdk.internal
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.JniUnifiedSpendingKey
|
||||||
|
import cash.z.ecc.android.sdk.model.Account
|
||||||
|
import cash.z.ecc.android.sdk.model.UnifiedFullViewingKey
|
||||||
|
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||||
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
|
|
||||||
|
fun Derivation.deriveUnifiedAddress(
|
||||||
|
seed: ByteArray,
|
||||||
|
network: ZcashNetwork,
|
||||||
|
account: Account
|
||||||
|
): String = deriveUnifiedAddress(seed, network.id, account.value)
|
||||||
|
|
||||||
|
fun Derivation.deriveUnifiedAddress(
|
||||||
|
viewingKey: String,
|
||||||
|
network: ZcashNetwork,
|
||||||
|
): String = deriveUnifiedAddress(viewingKey, network.id)
|
||||||
|
|
||||||
|
fun Derivation.deriveUnifiedSpendingKey(
|
||||||
|
seed: ByteArray,
|
||||||
|
network: ZcashNetwork,
|
||||||
|
account: Account
|
||||||
|
): UnifiedSpendingKey = UnifiedSpendingKey(deriveUnifiedSpendingKey(seed, network.id, account.value))
|
||||||
|
|
||||||
|
fun Derivation.deriveUnifiedFullViewingKey(
|
||||||
|
usk: UnifiedSpendingKey,
|
||||||
|
network: ZcashNetwork
|
||||||
|
): UnifiedFullViewingKey = UnifiedFullViewingKey(
|
||||||
|
deriveUnifiedFullViewingKey(
|
||||||
|
JniUnifiedSpendingKey(
|
||||||
|
usk.account.value,
|
||||||
|
usk.copyBytes()
|
||||||
|
),
|
||||||
|
network.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
fun Derivation.deriveUnifiedFullViewingKeysTypesafe(
|
||||||
|
seed: ByteArray,
|
||||||
|
network: ZcashNetwork,
|
||||||
|
numberOfAccounts: Int
|
||||||
|
): List<UnifiedFullViewingKey> =
|
||||||
|
deriveUnifiedFullViewingKeys(seed, network.id, numberOfAccounts).map { UnifiedFullViewingKey(it) }
|
|
@ -21,6 +21,13 @@ import java.nio.channels.Channels
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
internal class SaplingParamTool(val properties: SaplingParamToolProperties) {
|
internal class SaplingParamTool(val properties: SaplingParamToolProperties) {
|
||||||
|
|
||||||
|
val spendParamsFile: File
|
||||||
|
get() = File(properties.paramsDirectory, SPEND_PARAM_FILE_NAME)
|
||||||
|
|
||||||
|
val outputParamsFile: File
|
||||||
|
get() = File(properties.paramsDirectory, OUTPUT_PARAM_FILE_NAME)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
* Maximum file size for the sapling spend params - 50MB
|
* Maximum file size for the sapling spend params - 50MB
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
package cash.z.ecc.android.sdk.internal
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple implementation of Simple moving average.
|
|
||||||
*/
|
|
||||||
class Sma(val window: Int = 3) {
|
|
||||||
private val values = Array(window) { 0.0 }
|
|
||||||
var average = 0.0
|
|
||||||
private set
|
|
||||||
|
|
||||||
var count: Int = 0
|
|
||||||
var index: Int = 0
|
|
||||||
|
|
||||||
fun add(value: Number) = add(value.toDouble())
|
|
||||||
|
|
||||||
fun add(value: Double): Double {
|
|
||||||
when {
|
|
||||||
// full window
|
|
||||||
count == window -> {
|
|
||||||
index = (index + 1) % window
|
|
||||||
average += ((value - values[index]) / count.toFloat())
|
|
||||||
values[index] = value
|
|
||||||
}
|
|
||||||
// partially-filled window
|
|
||||||
count != 0 -> {
|
|
||||||
index = (index + 1) % window
|
|
||||||
average = ((value + count.toFloat() * average) / (count + 1).toFloat())
|
|
||||||
values[index] = value
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
// empty window
|
|
||||||
else -> {
|
|
||||||
// simply assign given value as current average:
|
|
||||||
average = value
|
|
||||||
values[0] = value
|
|
||||||
count = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return average
|
|
||||||
}
|
|
||||||
|
|
||||||
fun format(places: Int = 0) = "%.${places}f".format(average)
|
|
||||||
}
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package cash.z.ecc.android.sdk.internal
|
||||||
|
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements a coroutines-friendly lazy singleton pattern with an input argument.
|
||||||
|
*
|
||||||
|
* This class is thread-safe.
|
||||||
|
*/
|
||||||
|
internal class SuspendingLazy<in Input, out Output>(private val deferredCreator: suspend ((Input) -> Output)) {
|
||||||
|
private var singletonInstance: Output? = null
|
||||||
|
|
||||||
|
private val mutex = Mutex()
|
||||||
|
|
||||||
|
suspend fun getInstance(input: Input): Output {
|
||||||
|
mutex.withLock {
|
||||||
|
singletonInstance?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
val newInstance = deferredCreator(input)
|
||||||
|
singletonInstance = newInstance
|
||||||
|
|
||||||
|
return newInstance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package cash.z.ecc.android.sdk.jni
|
package cash.z.ecc.android.sdk.internal
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
||||||
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
||||||
|
@ -16,7 +16,7 @@ internal interface TypesafeBackend {
|
||||||
suspend fun initAccountsTable(
|
suspend fun initAccountsTable(
|
||||||
seed: ByteArray,
|
seed: ByteArray,
|
||||||
numberOfAccounts: Int
|
numberOfAccounts: Int
|
||||||
): Array<UnifiedFullViewingKey>
|
): List<UnifiedFullViewingKey>
|
||||||
|
|
||||||
suspend fun initBlocksTable(checkpoint: Checkpoint): Boolean
|
suspend fun initBlocksTable(checkpoint: Checkpoint): Boolean
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package cash.z.ecc.android.sdk.jni
|
package cash.z.ecc.android.sdk.internal
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
||||||
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
||||||
|
@ -8,6 +8,7 @@ import cash.z.ecc.android.sdk.model.UnifiedFullViewingKey
|
||||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||||
|
|
||||||
|
// This class is currently unused, although the goal is to swap out usages of BackendExt for this throughout the SDK.
|
||||||
@Suppress("TooManyFunctions")
|
@Suppress("TooManyFunctions")
|
||||||
internal class TypesafeBackendImpl(private val backend: Backend) : TypesafeBackend {
|
internal class TypesafeBackendImpl(private val backend: Backend) : TypesafeBackend {
|
||||||
override suspend fun initAccountsTable(vararg keys: UnifiedFullViewingKey): Boolean =
|
override suspend fun initAccountsTable(vararg keys: UnifiedFullViewingKey): Boolean =
|
||||||
|
@ -16,7 +17,7 @@ internal class TypesafeBackendImpl(private val backend: Backend) : TypesafeBacke
|
||||||
override suspend fun initAccountsTable(
|
override suspend fun initAccountsTable(
|
||||||
seed: ByteArray,
|
seed: ByteArray,
|
||||||
numberOfAccounts: Int
|
numberOfAccounts: Int
|
||||||
): Array<UnifiedFullViewingKey> = backend.initAccountsTable(seed, numberOfAccounts)
|
): List<UnifiedFullViewingKey> = backend.initAccountsTableTypesafe(seed, numberOfAccounts)
|
||||||
|
|
||||||
override suspend fun initBlocksTable(checkpoint: Checkpoint): Boolean = backend.initBlocksTable(checkpoint)
|
override suspend fun initBlocksTable(checkpoint: Checkpoint): Boolean = backend.initBlocksTable(checkpoint)
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package cash.z.ecc.android.sdk.internal
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.model.Account
|
||||||
|
import cash.z.ecc.android.sdk.model.UnifiedFullViewingKey
|
||||||
|
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||||
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
|
import cash.z.ecc.android.sdk.tool.DerivationTool
|
||||||
|
|
||||||
|
internal class TypesafeDerivationToolImpl(private val derivation: Derivation) : DerivationTool {
|
||||||
|
|
||||||
|
override suspend fun deriveUnifiedFullViewingKeys(
|
||||||
|
seed: ByteArray,
|
||||||
|
network: ZcashNetwork,
|
||||||
|
numberOfAccounts: Int
|
||||||
|
): List<UnifiedFullViewingKey> = derivation.deriveUnifiedFullViewingKeysTypesafe(seed, network, numberOfAccounts)
|
||||||
|
|
||||||
|
override suspend fun deriveUnifiedFullViewingKey(
|
||||||
|
usk: UnifiedSpendingKey,
|
||||||
|
network: ZcashNetwork
|
||||||
|
): UnifiedFullViewingKey = derivation.deriveUnifiedFullViewingKey(usk, network)
|
||||||
|
|
||||||
|
override suspend fun deriveUnifiedSpendingKey(
|
||||||
|
seed: ByteArray,
|
||||||
|
network: ZcashNetwork,
|
||||||
|
account: Account
|
||||||
|
): UnifiedSpendingKey = derivation.deriveUnifiedSpendingKey(seed, network, account)
|
||||||
|
|
||||||
|
override suspend fun deriveUnifiedAddress(
|
||||||
|
seed: ByteArray,
|
||||||
|
network: ZcashNetwork,
|
||||||
|
account: Account
|
||||||
|
): String = derivation.deriveUnifiedAddress(seed, network, account)
|
||||||
|
|
||||||
|
override suspend fun deriveUnifiedAddress(
|
||||||
|
viewingKey: String,
|
||||||
|
network: ZcashNetwork,
|
||||||
|
): String = derivation.deriveUnifiedAddress(viewingKey, network)
|
||||||
|
}
|
|
@ -2,17 +2,18 @@ package cash.z.ecc.android.sdk.internal.db.derived
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
import cash.z.ecc.android.sdk.internal.Backend
|
||||||
import cash.z.ecc.android.sdk.internal.NoBackupContextWrapper
|
import cash.z.ecc.android.sdk.internal.NoBackupContextWrapper
|
||||||
import cash.z.ecc.android.sdk.internal.db.ReadOnlySupportSqliteOpenHelper
|
import cash.z.ecc.android.sdk.internal.db.ReadOnlySupportSqliteOpenHelper
|
||||||
import cash.z.ecc.android.sdk.internal.ext.tryWarn
|
import cash.z.ecc.android.sdk.internal.ext.tryWarn
|
||||||
|
import cash.z.ecc.android.sdk.internal.initAccountsTable
|
||||||
|
import cash.z.ecc.android.sdk.internal.initBlocksTable
|
||||||
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
||||||
import cash.z.ecc.android.sdk.jni.RustBackend
|
|
||||||
import cash.z.ecc.android.sdk.jni.initAccountsTable
|
|
||||||
import cash.z.ecc.android.sdk.jni.initBlocksTable
|
|
||||||
import cash.z.ecc.android.sdk.model.UnifiedFullViewingKey
|
import cash.z.ecc.android.sdk.model.UnifiedFullViewingKey
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
internal class DerivedDataDb private constructor(
|
internal class DerivedDataDb private constructor(
|
||||||
zcashNetwork: ZcashNetwork,
|
zcashNetwork: ZcashNetwork,
|
||||||
|
@ -42,13 +43,14 @@ internal class DerivedDataDb private constructor(
|
||||||
@Suppress("LongParameterList", "SpreadOperator")
|
@Suppress("LongParameterList", "SpreadOperator")
|
||||||
suspend fun new(
|
suspend fun new(
|
||||||
context: Context,
|
context: Context,
|
||||||
rustBackend: RustBackend,
|
backend: Backend,
|
||||||
|
databaseFile: File,
|
||||||
zcashNetwork: ZcashNetwork,
|
zcashNetwork: ZcashNetwork,
|
||||||
checkpoint: Checkpoint,
|
checkpoint: Checkpoint,
|
||||||
seed: ByteArray?,
|
seed: ByteArray?,
|
||||||
viewingKeys: List<UnifiedFullViewingKey>
|
viewingKeys: List<UnifiedFullViewingKey>
|
||||||
): DerivedDataDb {
|
): DerivedDataDb {
|
||||||
rustBackend.initDataDb(seed)
|
backend.initDataDb(seed)
|
||||||
|
|
||||||
// TODO [#681]: consider converting these to typed exceptions in the welding layer
|
// TODO [#681]: consider converting these to typed exceptions in the welding layer
|
||||||
// TODO [#681]: https://github.com/zcash/zcash-android-wallet-sdk/issues/681
|
// TODO [#681]: https://github.com/zcash/zcash-android-wallet-sdk/issues/681
|
||||||
|
@ -56,22 +58,22 @@ internal class DerivedDataDb private constructor(
|
||||||
"Did not initialize the blocks table. It probably was already initialized.",
|
"Did not initialize the blocks table. It probably was already initialized.",
|
||||||
ifContains = "table is not empty"
|
ifContains = "table is not empty"
|
||||||
) {
|
) {
|
||||||
rustBackend.initBlocksTable(checkpoint)
|
backend.initBlocksTable(checkpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
tryWarn(
|
tryWarn(
|
||||||
"Did not initialize the accounts table. It probably was already initialized.",
|
"Did not initialize the accounts table. It probably was already initialized.",
|
||||||
ifContains = "table is not empty"
|
ifContains = "table is not empty"
|
||||||
) {
|
) {
|
||||||
rustBackend.initAccountsTable(*viewingKeys.toTypedArray())
|
backend.initAccountsTable(*viewingKeys.toTypedArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
val database = ReadOnlySupportSqliteOpenHelper.openExistingDatabaseAsReadOnly(
|
val database = ReadOnlySupportSqliteOpenHelper.openExistingDatabaseAsReadOnly(
|
||||||
NoBackupContextWrapper(
|
NoBackupContextWrapper(
|
||||||
context,
|
context,
|
||||||
rustBackend.dataDbFile.parentFile!!
|
databaseFile.parentFile!!
|
||||||
),
|
),
|
||||||
rustBackend.dataDbFile,
|
databaseFile,
|
||||||
DATABASE_VERSION
|
DATABASE_VERSION
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package cash.z.ecc.android.sdk.internal
|
package cash.z.ecc.android.sdk.internal.ext
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package cash.z.ecc.android.sdk.internal.model
|
||||||
|
|
||||||
|
import cash.z.wallet.sdk.internal.rpc.CompactFormats
|
||||||
|
import co.electriccoin.lightwallet.client.model.CompactBlockUnsafe
|
||||||
|
|
||||||
|
internal fun JniBlockMeta.Companion.new(
|
||||||
|
block: CompactFormats.CompactBlock,
|
||||||
|
outputs: CompactBlockUnsafe.CompactBlockOutputsCounts
|
||||||
|
): JniBlockMeta {
|
||||||
|
return JniBlockMeta(
|
||||||
|
height = block.height,
|
||||||
|
hash = block.hash.toByteArray(),
|
||||||
|
time = block.time.toLong(),
|
||||||
|
saplingOutputsCount = outputs.saplingOutputsCount.toLong(),
|
||||||
|
orchardOutputsCount = outputs.orchardActionsCount.toLong()
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package cash.z.ecc.android.sdk.internal
|
package cash.z.ecc.android.sdk.internal.model.ext
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
|
@ -1,6 +1,7 @@
|
||||||
package cash.z.ecc.android.sdk.internal.storage.block
|
package cash.z.ecc.android.sdk.internal.storage.block
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import cash.z.ecc.android.sdk.internal.Backend
|
||||||
import cash.z.ecc.android.sdk.internal.Twig
|
import cash.z.ecc.android.sdk.internal.Twig
|
||||||
import cash.z.ecc.android.sdk.internal.ext.createNewFileSuspend
|
import cash.z.ecc.android.sdk.internal.ext.createNewFileSuspend
|
||||||
import cash.z.ecc.android.sdk.internal.ext.deleteRecursivelySuspend
|
import cash.z.ecc.android.sdk.internal.ext.deleteRecursivelySuspend
|
||||||
|
@ -12,13 +13,11 @@ import cash.z.ecc.android.sdk.internal.ext.mkdirsSuspend
|
||||||
import cash.z.ecc.android.sdk.internal.ext.renameToSuspend
|
import cash.z.ecc.android.sdk.internal.ext.renameToSuspend
|
||||||
import cash.z.ecc.android.sdk.internal.ext.toHexReversed
|
import cash.z.ecc.android.sdk.internal.ext.toHexReversed
|
||||||
import cash.z.ecc.android.sdk.internal.ext.writeBytesSuspend
|
import cash.z.ecc.android.sdk.internal.ext.writeBytesSuspend
|
||||||
|
import cash.z.ecc.android.sdk.internal.findBlockMetadata
|
||||||
|
import cash.z.ecc.android.sdk.internal.getLatestBlockHeight
|
||||||
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
||||||
import cash.z.ecc.android.sdk.internal.repository.CompactBlockRepository
|
import cash.z.ecc.android.sdk.internal.repository.CompactBlockRepository
|
||||||
import cash.z.ecc.android.sdk.jni.Backend
|
import cash.z.ecc.android.sdk.internal.rewindBlockMetadataToHeight
|
||||||
import cash.z.ecc.android.sdk.jni.RustBackend
|
|
||||||
import cash.z.ecc.android.sdk.jni.findBlockMetadata
|
|
||||||
import cash.z.ecc.android.sdk.jni.getLatestBlockHeight
|
|
||||||
import cash.z.ecc.android.sdk.jni.rewindBlockMetadataToHeight
|
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import co.electriccoin.lightwallet.client.model.CompactBlockUnsafe
|
import co.electriccoin.lightwallet.client.model.CompactBlockUnsafe
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
@ -26,12 +25,12 @@ import java.io.File
|
||||||
|
|
||||||
internal class FileCompactBlockRepository(
|
internal class FileCompactBlockRepository(
|
||||||
private val blocksDirectory: File,
|
private val blocksDirectory: File,
|
||||||
private val rustBackend: Backend
|
private val backend: Backend
|
||||||
) : CompactBlockRepository {
|
) : CompactBlockRepository {
|
||||||
|
|
||||||
override suspend fun getLatestHeight() = rustBackend.getLatestBlockHeight()
|
override suspend fun getLatestHeight() = backend.getLatestBlockHeight()
|
||||||
|
|
||||||
override suspend fun findCompactBlock(height: BlockHeight) = rustBackend.findBlockMetadata(height)
|
override suspend fun findCompactBlock(height: BlockHeight) = backend.findBlockMetadata(height)
|
||||||
|
|
||||||
override suspend fun write(blocks: Flow<CompactBlockUnsafe>): List<JniBlockMeta> {
|
override suspend fun write(blocks: Flow<CompactBlockUnsafe>): List<JniBlockMeta> {
|
||||||
val processingBlocks = mutableListOf<JniBlockMeta>()
|
val processingBlocks = mutableListOf<JniBlockMeta>()
|
||||||
|
@ -66,11 +65,11 @@ internal class FileCompactBlockRepository(
|
||||||
* Write block metadata to storage when the buffer is full or when we reached the current range end.
|
* Write block metadata to storage when the buffer is full or when we reached the current range end.
|
||||||
*/
|
*/
|
||||||
private suspend fun writeAndClearBuffer(metaDataBuffer: MutableList<JniBlockMeta>) {
|
private suspend fun writeAndClearBuffer(metaDataBuffer: MutableList<JniBlockMeta>) {
|
||||||
rustBackend.writeBlockMetadata(metaDataBuffer)
|
backend.writeBlockMetadata(metaDataBuffer)
|
||||||
metaDataBuffer.clear()
|
metaDataBuffer.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun rewindTo(height: BlockHeight) = rustBackend.rewindBlockMetadataToHeight(height)
|
override suspend fun rewindTo(height: BlockHeight) = backend.rewindBlockMetadataToHeight(height)
|
||||||
|
|
||||||
override suspend fun deleteAllCompactBlockFiles(): Boolean {
|
override suspend fun deleteAllCompactBlockFiles(): Boolean {
|
||||||
Twig.verbose { "Deleting all blocks from directory ${blocksDirectory.path}" }
|
Twig.verbose { "Deleting all blocks from directory ${blocksDirectory.path}" }
|
||||||
|
@ -129,13 +128,16 @@ internal class FileCompactBlockRepository(
|
||||||
*/
|
*/
|
||||||
const val BLOCKS_METADATA_BUFFER_SIZE = 10
|
const val BLOCKS_METADATA_BUFFER_SIZE = 10
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param blockCacheRoot The root directory for the compact block cache (contains the database and a
|
||||||
|
* subdirectory for the blocks).
|
||||||
|
*/
|
||||||
suspend fun new(
|
suspend fun new(
|
||||||
rustBackend: RustBackend
|
blockCacheRoot: File,
|
||||||
|
rustBackend: Backend
|
||||||
): FileCompactBlockRepository {
|
): FileCompactBlockRepository {
|
||||||
Twig.debug { "${rustBackend.fsBlockDbRoot.absolutePath} \n ${rustBackend.dataDbFile.absolutePath}" }
|
|
||||||
|
|
||||||
// create and check cache directories
|
// create and check cache directories
|
||||||
val blocksDirectory = File(rustBackend.fsBlockDbRoot, BLOCKS_DOWNLOAD_DIRECTORY).also {
|
val blocksDirectory = File(blockCacheRoot, BLOCKS_DOWNLOAD_DIRECTORY).also {
|
||||||
it.mkdirsSuspend()
|
it.mkdirsSuspend()
|
||||||
}
|
}
|
||||||
if (!blocksDirectory.existsSuspend()) {
|
if (!blocksDirectory.existsSuspend()) {
|
||||||
|
|
|
@ -2,14 +2,15 @@ package cash.z.ecc.android.sdk.internal.transaction
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.exception.TransactionEncoderException
|
import cash.z.ecc.android.sdk.exception.TransactionEncoderException
|
||||||
import cash.z.ecc.android.sdk.ext.masked
|
import cash.z.ecc.android.sdk.ext.masked
|
||||||
|
import cash.z.ecc.android.sdk.internal.Backend
|
||||||
import cash.z.ecc.android.sdk.internal.SaplingParamTool
|
import cash.z.ecc.android.sdk.internal.SaplingParamTool
|
||||||
import cash.z.ecc.android.sdk.internal.Twig
|
import cash.z.ecc.android.sdk.internal.Twig
|
||||||
|
import cash.z.ecc.android.sdk.internal.createToAddress
|
||||||
|
import cash.z.ecc.android.sdk.internal.getBranchIdForHeight
|
||||||
import cash.z.ecc.android.sdk.internal.model.EncodedTransaction
|
import cash.z.ecc.android.sdk.internal.model.EncodedTransaction
|
||||||
|
import cash.z.ecc.android.sdk.internal.network
|
||||||
import cash.z.ecc.android.sdk.internal.repository.DerivedDataRepository
|
import cash.z.ecc.android.sdk.internal.repository.DerivedDataRepository
|
||||||
import cash.z.ecc.android.sdk.jni.Backend
|
import cash.z.ecc.android.sdk.internal.shieldToAddress
|
||||||
import cash.z.ecc.android.sdk.jni.createToAddress
|
|
||||||
import cash.z.ecc.android.sdk.jni.getBranchIdForHeight
|
|
||||||
import cash.z.ecc.android.sdk.jni.shieldToAddress
|
|
||||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||||
|
@ -19,7 +20,7 @@ import cash.z.ecc.android.sdk.model.Zatoshi
|
||||||
* behaving like a stateless API so that callers can request [createTransaction] and receive a
|
* behaving like a stateless API so that callers can request [createTransaction] and receive a
|
||||||
* result, even though there are intermediate database interactions.
|
* result, even though there are intermediate database interactions.
|
||||||
*
|
*
|
||||||
* @property backend the instance of RustBackendWelding to use for creating and validating.
|
* @property rustBackend the instance of RustBackendWelding to use for creating and validating.
|
||||||
* @property repository the repository that stores information about the transactions being created
|
* @property repository the repository that stores information about the transactions being created
|
||||||
* such as the raw bytes and raw txId.
|
* such as the raw bytes and raw txId.
|
||||||
*/
|
*/
|
||||||
|
@ -132,7 +133,7 @@ internal class TransactionEncoderImpl(
|
||||||
|
|
||||||
@Suppress("TooGenericExceptionCaught")
|
@Suppress("TooGenericExceptionCaught")
|
||||||
return try {
|
return try {
|
||||||
saplingParamTool.ensureParams(backend.saplingParamDir)
|
saplingParamTool.ensureParams(saplingParamTool.properties.paramsDirectory)
|
||||||
Twig.debug { "params exist! attempting to send..." }
|
Twig.debug { "params exist! attempting to send..." }
|
||||||
backend.createToAddress(
|
backend.createToAddress(
|
||||||
usk,
|
usk,
|
||||||
|
@ -154,7 +155,7 @@ internal class TransactionEncoderImpl(
|
||||||
): Long {
|
): Long {
|
||||||
@Suppress("TooGenericExceptionCaught")
|
@Suppress("TooGenericExceptionCaught")
|
||||||
return try {
|
return try {
|
||||||
saplingParamTool.ensureParams(backend.saplingParamDir)
|
saplingParamTool.ensureParams(saplingParamTool.properties.paramsDirectory)
|
||||||
Twig.debug { "params exist! attempting to shield..." }
|
Twig.debug { "params exist! attempting to shield..." }
|
||||||
backend.shieldToAddress(
|
backend.shieldToAddress(
|
||||||
usk,
|
usk,
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
package cash.z.ecc.android.sdk.jni
|
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.model.Account
|
|
||||||
import cash.z.ecc.android.sdk.model.UnifiedFullViewingKey
|
|
||||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
|
||||||
|
|
||||||
// Implemented by `DerivationTool`
|
|
||||||
interface Derivation {
|
|
||||||
suspend fun deriveUnifiedAddress(
|
|
||||||
viewingKey: String,
|
|
||||||
network: ZcashNetwork
|
|
||||||
): String
|
|
||||||
|
|
||||||
suspend fun deriveUnifiedAddress(
|
|
||||||
seed: ByteArray,
|
|
||||||
network: ZcashNetwork,
|
|
||||||
account: Account
|
|
||||||
): String
|
|
||||||
|
|
||||||
suspend fun deriveUnifiedSpendingKey(
|
|
||||||
seed: ByteArray,
|
|
||||||
network: ZcashNetwork,
|
|
||||||
account: Account
|
|
||||||
): UnifiedSpendingKey
|
|
||||||
|
|
||||||
suspend fun deriveUnifiedFullViewingKey(
|
|
||||||
usk: UnifiedSpendingKey,
|
|
||||||
network: ZcashNetwork
|
|
||||||
): UnifiedFullViewingKey
|
|
||||||
|
|
||||||
suspend fun deriveUnifiedFullViewingKeys(
|
|
||||||
seed: ByteArray,
|
|
||||||
network: ZcashNetwork,
|
|
||||||
numberOfAccounts: Int = 1
|
|
||||||
): Array<UnifiedFullViewingKey>
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
package cash.z.ecc.android.sdk.model
|
package cash.z.ecc.android.sdk.model
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.jni.RustBackend
|
import cash.z.ecc.android.sdk.internal.jni.RustBackend
|
||||||
import cash.z.ecc.android.sdk.jni.UnifiedSpendingKeyJni
|
import cash.z.ecc.android.sdk.internal.model.JniUnifiedSpendingKey
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [ZIP 316](https://zips.z.cash/zip-0316) Unified Spending Key.
|
* A [ZIP 316](https://zips.z.cash/zip-0316) Unified Spending Key.
|
||||||
|
@ -26,9 +26,9 @@ class UnifiedSpendingKey private constructor(
|
||||||
private val bytes: FirstClassByteArray
|
private val bytes: FirstClassByteArray
|
||||||
) {
|
) {
|
||||||
|
|
||||||
internal constructor(uskJni: UnifiedSpendingKeyJni) : this(
|
internal constructor(uskJni: JniUnifiedSpendingKey) : this(
|
||||||
Account(uskJni.account),
|
Account(uskJni.account),
|
||||||
FirstClassByteArray(uskJni.copyBytes())
|
FirstClassByteArray(uskJni.bytes.copyOf())
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,9 +75,7 @@ class UnifiedSpendingKey private constructor(
|
||||||
val bytesCopy = bytes.copyOf()
|
val bytesCopy = bytes.copyOf()
|
||||||
RustBackend.loadLibrary()
|
RustBackend.loadLibrary()
|
||||||
return runCatching {
|
return runCatching {
|
||||||
// We can ignore the Boolean returned from this, because if an error
|
require(RustBackend.validateUnifiedSpendingKey(bytesCopy))
|
||||||
// occurs the Rust side will throw.
|
|
||||||
RustBackend.validateUnifiedSpendingKey(bytesCopy)
|
|
||||||
UnifiedSpendingKey(account, FirstClassByteArray(bytesCopy))
|
UnifiedSpendingKey(account, FirstClassByteArray(bytesCopy))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ import android.content.Context
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import cash.z.ecc.android.sdk.exception.BirthdayException
|
import cash.z.ecc.android.sdk.exception.BirthdayException
|
||||||
import cash.z.ecc.android.sdk.internal.Twig
|
import cash.z.ecc.android.sdk.internal.Twig
|
||||||
import cash.z.ecc.android.sdk.internal.from
|
|
||||||
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ext.from
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
package cash.z.ecc.android.sdk.tool
|
package cash.z.ecc.android.sdk.tool
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.jni.Derivation
|
import cash.z.ecc.android.sdk.internal.Derivation
|
||||||
import cash.z.ecc.android.sdk.jni.RustBackend
|
import cash.z.ecc.android.sdk.internal.SuspendingLazy
|
||||||
import cash.z.ecc.android.sdk.jni.UnifiedSpendingKeyJni
|
import cash.z.ecc.android.sdk.internal.TypesafeDerivationToolImpl
|
||||||
|
import cash.z.ecc.android.sdk.internal.jni.RustDerivationTool
|
||||||
import cash.z.ecc.android.sdk.model.Account
|
import cash.z.ecc.android.sdk.model.Account
|
||||||
import cash.z.ecc.android.sdk.model.UnifiedFullViewingKey
|
import cash.z.ecc.android.sdk.model.UnifiedFullViewingKey
|
||||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
|
|
||||||
@Suppress("TooManyFunctions")
|
interface DerivationTool {
|
||||||
object DerivationTool : Derivation {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a seed and a number of accounts, return the associated Unified Full Viewing Keys.
|
* Given a seed and a number of accounts, return the associated Unified Full Viewing Keys.
|
||||||
|
@ -20,16 +20,11 @@ object DerivationTool : Derivation {
|
||||||
*
|
*
|
||||||
* @return the UFVKs derived from the seed, encoded as Strings.
|
* @return the UFVKs derived from the seed, encoded as Strings.
|
||||||
*/
|
*/
|
||||||
override suspend fun deriveUnifiedFullViewingKeys(
|
suspend fun deriveUnifiedFullViewingKeys(
|
||||||
seed: ByteArray,
|
seed: ByteArray,
|
||||||
network: ZcashNetwork,
|
network: ZcashNetwork,
|
||||||
numberOfAccounts: Int
|
numberOfAccounts: Int
|
||||||
): Array<UnifiedFullViewingKey> =
|
): List<UnifiedFullViewingKey>
|
||||||
withRustBackendLoaded {
|
|
||||||
deriveUnifiedFullViewingKeysFromSeed(seed, numberOfAccounts, networkId = network.id).map {
|
|
||||||
UnifiedFullViewingKey(it)
|
|
||||||
}.toTypedArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a unified spending key, return the associated unified full viewing key.
|
* Given a unified spending key, return the associated unified full viewing key.
|
||||||
|
@ -38,14 +33,10 @@ object DerivationTool : Derivation {
|
||||||
*
|
*
|
||||||
* @return a unified full viewing key.
|
* @return a unified full viewing key.
|
||||||
*/
|
*/
|
||||||
override suspend fun deriveUnifiedFullViewingKey(
|
suspend fun deriveUnifiedFullViewingKey(
|
||||||
usk: UnifiedSpendingKey,
|
usk: UnifiedSpendingKey,
|
||||||
network: ZcashNetwork
|
network: ZcashNetwork
|
||||||
): UnifiedFullViewingKey = withRustBackendLoaded {
|
): UnifiedFullViewingKey
|
||||||
UnifiedFullViewingKey(
|
|
||||||
deriveUnifiedFullViewingKey(usk.copyBytes(), networkId = network.id)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives and returns a unified spending key from the given seed for the given account ID.
|
* Derives and returns a unified spending key from the given seed for the given account ID.
|
||||||
|
@ -59,26 +50,21 @@ object DerivationTool : Derivation {
|
||||||
*
|
*
|
||||||
* @return the unified spending key for the account.
|
* @return the unified spending key for the account.
|
||||||
*/
|
*/
|
||||||
override suspend fun deriveUnifiedSpendingKey(
|
suspend fun deriveUnifiedSpendingKey(
|
||||||
seed: ByteArray,
|
seed: ByteArray,
|
||||||
network: ZcashNetwork,
|
network: ZcashNetwork,
|
||||||
account: Account
|
account: Account
|
||||||
): UnifiedSpendingKey = withRustBackendLoaded {
|
): UnifiedSpendingKey
|
||||||
UnifiedSpendingKey(deriveSpendingKey(seed, account.value, networkId = network.id))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a seed and account index, return the associated Unified Address.
|
* Given a seed and account index, return the associated Unified Address.
|
||||||
*
|
*
|
||||||
* @param seed the seed from which to derive the address.
|
* @param seed the seed from which to derive the address.
|
||||||
* @param accountIndex the index of the account to use for deriving the address.
|
* @param account the index of the account to use for deriving the address.
|
||||||
*
|
*
|
||||||
* @return the address that corresponds to the seed and account index.
|
* @return the address that corresponds to the seed and account index.
|
||||||
*/
|
*/
|
||||||
override suspend fun deriveUnifiedAddress(seed: ByteArray, network: ZcashNetwork, account: Account): String =
|
suspend fun deriveUnifiedAddress(seed: ByteArray, network: ZcashNetwork, account: Account): String
|
||||||
withRustBackendLoaded {
|
|
||||||
deriveUnifiedAddressFromSeed(seed, account.value, networkId = network.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a Unified Full Viewing Key string, return the associated Unified Address.
|
* Given a Unified Full Viewing Key string, return the associated Unified Address.
|
||||||
|
@ -88,56 +74,17 @@ object DerivationTool : Derivation {
|
||||||
*
|
*
|
||||||
* @return the address that corresponds to the viewing key.
|
* @return the address that corresponds to the viewing key.
|
||||||
*/
|
*/
|
||||||
override suspend fun deriveUnifiedAddress(
|
suspend fun deriveUnifiedAddress(
|
||||||
viewingKey: String,
|
viewingKey: String,
|
||||||
network: ZcashNetwork
|
network: ZcashNetwork
|
||||||
): String = withRustBackendLoaded {
|
|
||||||
deriveUnifiedAddressFromViewingKey(viewingKey, networkId = network.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
fun validateUnifiedFullViewingKey(viewingKey: UnifiedFullViewingKey, networkId: Int = ZcashNetwork.Mainnet.id) {
|
|
||||||
// TODO [#654] https://github.com/zcash/zcash-android-wallet-sdk/issues/654
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper function to ensure that the Rust libraries are loaded before any code in this
|
|
||||||
* class attempts to interact with it, indirectly, by invoking JNI functions. It would be
|
|
||||||
* nice to have an annotation like @UsesSystemLibrary for this
|
|
||||||
*/
|
|
||||||
private suspend fun <T> withRustBackendLoaded(block: () -> T): T {
|
|
||||||
RustBackend.loadLibrary()
|
|
||||||
return block()
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// JNI functions
|
|
||||||
//
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
private external fun deriveSpendingKey(
|
|
||||||
seed: ByteArray,
|
|
||||||
account: Int,
|
|
||||||
networkId: Int
|
|
||||||
): UnifiedSpendingKeyJni
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
private external fun deriveUnifiedFullViewingKeysFromSeed(
|
|
||||||
seed: ByteArray,
|
|
||||||
numberOfAccounts: Int,
|
|
||||||
networkId: Int
|
|
||||||
): Array<String>
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
private external fun deriveUnifiedFullViewingKey(usk: ByteArray, networkId: Int): String
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
private external fun deriveUnifiedAddressFromSeed(
|
|
||||||
seed: ByteArray,
|
|
||||||
accountIndex: Int,
|
|
||||||
networkId: Int
|
|
||||||
): String
|
): String
|
||||||
|
|
||||||
@JvmStatic
|
companion object {
|
||||||
private external fun deriveUnifiedAddressFromViewingKey(key: String, networkId: Int): String
|
const val DEFAULT_NUMBER_OF_ACCOUNTS = Derivation.DEFAULT_NUMBER_OF_ACCOUNTS
|
||||||
|
|
||||||
|
private val instance = SuspendingLazy<Unit, DerivationTool> {
|
||||||
|
TypesafeDerivationToolImpl(RustDerivationTool.new())
|
||||||
|
}
|
||||||
|
suspend fun getInstance() = instance.getInstance(Unit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
task unregistered {
|
|
||||||
println "configuring unregistered"
|
|
||||||
doLast {
|
|
||||||
println 'unregistered'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("pb") {
|
|
||||||
println "configuring pb"
|
|
||||||
doLast {
|
|
||||||
println 'preBuild'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tasks.register("generateJni") {
|
|
||||||
println "configuring generateJni"
|
|
||||||
doLast {
|
|
||||||
println 'jni'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tasks.register("copyA") {
|
|
||||||
dependsOn generateJni
|
|
||||||
println "configuring copyA"
|
|
||||||
doLast {
|
|
||||||
println 'copyA'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tasks.register("copyB") {
|
|
||||||
dependsOn generateJni
|
|
||||||
println "configuring copyB"
|
|
||||||
doLast {
|
|
||||||
println 'copyB'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tasks.register("copyC") {
|
|
||||||
dependsOn generateJni
|
|
||||||
println "configuring copyC"
|
|
||||||
doLast {
|
|
||||||
println 'copyC'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task copyAll {
|
|
||||||
dependsOn copyA, copyB, copyC
|
|
||||||
}
|
|
||||||
|
|
||||||
pb.dependsOn copyAll
|
|
|
@ -269,6 +269,7 @@ rootProject.name = "zcash-android-sdk"
|
||||||
|
|
||||||
includeBuild("build-conventions")
|
includeBuild("build-conventions")
|
||||||
|
|
||||||
|
include("backend-lib")
|
||||||
include("darkside-test-lib")
|
include("darkside-test-lib")
|
||||||
include("demo-app")
|
include("demo-app")
|
||||||
include("demo-app-benchmark-test")
|
include("demo-app-benchmark-test")
|
||||||
|
|
Loading…
Reference in New Issue