-
Notifications
You must be signed in to change notification settings - Fork 56
feat(kotlin-sdk): expose core_wallet_set_gap_limit to Kotlin (migrated-wallet address-window heal) #4377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
bfoss765
wants to merge
3
commits into
v4.2-dev
Choose a base branch
from
feat/kotlin-sdk-gap-limit-jni
base: v4.2-dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+212
−0
Open
feat(kotlin-sdk): expose core_wallet_set_gap_limit to Kotlin (migrated-wallet address-window heal) #4377
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
121 changes: 121 additions & 0 deletions
121
.../androidTest/kotlin/org/dashfoundation/dashsdk/wallet/CoreWalletSetGapLimitBindingTest.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| package org.dashfoundation.dashsdk.wallet | ||
|
|
||
| import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
| import org.dashfoundation.dashsdk.errors.DashSdkError | ||
| import org.dashfoundation.dashsdk.ffi.DashSDKException | ||
| import org.dashfoundation.dashsdk.ffi.NativeLoader | ||
| import org.dashfoundation.dashsdk.ffi.WalletManagerNative | ||
| import org.junit.Assert.assertEquals | ||
| import org.junit.Assert.assertThrows | ||
| import org.junit.Assert.assertTrue | ||
| import org.junit.Test | ||
| import org.junit.runner.RunWith | ||
|
|
||
| /** | ||
| * Binding-level coverage for the `coreWalletSetGapLimit` JNI export — the | ||
| * same no-wallet discipline as [CoreTxBuilderOpReturnBindingTest]: prove the | ||
| * Kotlin external declaration, the generated JNI symbol, and the parameter | ||
| * descriptor stay in lockstep (a naming/signature mismatch surfaces here as | ||
| * `UnsatisfiedLinkError`, not in production), and pin each trampoline | ||
| * validation branch to the exception it throws. No network, no wallet, no | ||
| * funds. | ||
| * | ||
| * Two rejection layers are asserted apart: | ||
| * - the JNI trampoline's own parameter validation throws | ||
| * [DashSDKException] with RAW code 1 (the rs-sdk-ffi InvalidParameter | ||
| * code) and a branch-naming message, BEFORE any FFI call; | ||
| * - a well-formed call with a dead handle crosses into | ||
| * `core_wallet_set_gap_limit`, whose storage miss comes back translated | ||
| * into the platform-wallet code range | ||
| * (>= [DashSdkError.PLATFORM_WALLET_CODE_OFFSET]) — proof the JNI | ||
| * validations passed and execution reached the underlying FFI's | ||
| * invalid-handle path. | ||
| * | ||
| * The branch-naming message assertions double as parameter-order pins: the | ||
| * three ints share one JNI descriptor slot type, so a swapped argument | ||
| * order in either declaration would misroute a probe into the wrong | ||
| * validation branch and fail the message check. | ||
| */ | ||
| @RunWith(AndroidJUnit4::class) | ||
| class CoreWalletSetGapLimitBindingTest { | ||
|
|
||
| private fun callExpectingThrow( | ||
| handle: Long, | ||
| accountType: Int, | ||
| accountIndex: Int, | ||
| gapLimit: Int, | ||
| ): DashSDKException { | ||
| NativeLoader.ensureLoaded() | ||
| return assertThrows(DashSDKException::class.java) { | ||
| WalletManagerNative.coreWalletSetGapLimit(handle, accountType, accountIndex, gapLimit) | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| fun allSpendableAggregateIsRejectedBeforeTheFfi() { | ||
| // 3 = AllSpendable: it pools several accounts and has no address | ||
| // pool of its own, so the trampoline rejects it up front rather | ||
| // than letting the per-account FFI fail opaquely. | ||
| val e = callExpectingThrow(0L, accountType = 3, accountIndex = 0, gapLimit = 100) | ||
| assertEquals("JNI-side parameter rejection carries raw code 1", 1, e.code) | ||
| assertTrue( | ||
| "the rejection must name the accountType branch, got: ${e.message}", | ||
| e.message.orEmpty().contains("accountType"), | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun unknownAccountTypeIsRejectedBeforeTheFfi() { | ||
| // Outside the mapped range entirely — the mapping's `None` arm | ||
| // shares the AllSpendable rejection. | ||
| val e = callExpectingThrow(0L, accountType = 42, accountIndex = 0, gapLimit = 100) | ||
| assertEquals(1, e.code) | ||
| assertTrue( | ||
| "the rejection must name the accountType branch, got: ${e.message}", | ||
| e.message.orEmpty().contains("accountType"), | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun negativeAccountIndexIsRejectedBeforeTheFfi() { | ||
| val e = callExpectingThrow(0L, accountType = 0, accountIndex = -1, gapLimit = 100) | ||
| assertEquals(1, e.code) | ||
| assertTrue( | ||
| "the rejection must name the accountIndex branch, got: ${e.message}", | ||
| e.message.orEmpty().contains("accountIndex"), | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun nonPositiveGapLimitIsRejectedBeforeTheFfi() { | ||
| // 0 would freeze the address frontier and a negative jint would | ||
| // otherwise bit-cast to a huge u32 — both stop at the boundary. | ||
| for (gap in intArrayOf(0, -1)) { | ||
| val e = callExpectingThrow(0L, accountType = 0, accountIndex = 0, gapLimit = gap) | ||
| assertEquals("gapLimit $gap", 1, e.code) | ||
| assertTrue( | ||
| "the rejection must name the gapLimit branch for $gap, got: ${e.message}", | ||
| e.message.orEmpty().contains("gapLimit"), | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| fun concreteAccountTypesReachTheFfiInvalidHandlePath() { | ||
| // 0 BIP44, 1 BIP32, 2 CoinJoin — every concrete arm of the | ||
| // trampoline's account-type mapping must pass validation and cross | ||
| // into `core_wallet_set_gap_limit`, where handle 0 can never be a | ||
| // live core wallet. The FFI's miss comes back translated into the | ||
| // platform-wallet code range — NOT the trampoline's raw code 1 — | ||
| // which proves the call left the JNI layer and the concrete arms | ||
| // are wired through. | ||
| for (accountType in intArrayOf(0, 1, 2)) { | ||
| val e = callExpectingThrow(0L, accountType, accountIndex = 0, gapLimit = 100) | ||
| assertTrue( | ||
| "type $accountType must fail inside the FFI (translated code >= " + | ||
| "${DashSdkError.PLATFORM_WALLET_CODE_OFFSET}), got ${e.code}: ${e.message}", | ||
| e.code >= DashSdkError.PLATFORM_WALLET_CODE_OFFSET, | ||
| ) | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Suggestion: Add an instrumented binding test for the new JNI export
No repository test invokes
coreWalletSetGapLimit, so the Kotlin external declaration, generated JNI symbol, parameter descriptor, and the new validation branches can regress without detection.cargo check -p rs-unified-sdk-jniverifies only the Rust side and cannot detect a Kotlin/JNI naming or signature mismatch that would produceUnsatisfiedLinkErroron Android. The existing Android instrumented suite already uses invalid handles to pin JNI bindings without requiring a funded wallet; add equivalent coverage that loads the native library, verifies that account type3, a negative account index, and a non-positive gap limit are rejected as invalid parameters, then calls a concrete account type with handle0and verifies that execution reaches the underlying FFI's invalid-handle path.source: ['codex']
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added in 25000de — CoreWalletSetGapLimitBindingTest (androidTest, mirrors the existing CoreTxBuilderOpReturnBindingTest no-wallet pattern): five cases pin the validation branches (AllSpendable and unknown account types, negative accountIndex, gapLimit 0/-1) to raw code 1 with branch-naming message assertions that double as int-parameter-order pins, and each concrete account type with a dead handle must surface an FFI-translated code >= PLATFORM_WALLET_CODE_OFFSET — proving execution crossed the JNI symbol into core_wallet_set_gap_limit rather than dying in the trampoline. Compiles green (:sdk:compileDebugAndroidTestKotlin); rides the next instrumented device run since the only prebuilt local .so predates the export.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved in this update — Add an instrumented binding test for the new JNI export no longer present.
Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.