Expose the rest of `WalletSummary` across the FFI
This commit is contained in:
parent
9eeb5ba04c
commit
1f19360ca3
|
@ -6,8 +6,14 @@ import androidx.annotation.Keep
|
|||
* Serves as cross layer (Kotlin, Rust) communication class.
|
||||
*
|
||||
* @param account the account ID
|
||||
* @param saplingTotalBalance The total account balance in the Sapling pool, including unconfirmed funds.
|
||||
* @param saplingTotalBalance The total account balance in the Sapling pool,
|
||||
* including unconfirmed funds.
|
||||
* @param saplingVerifiedBalance The verified account balance in the Sapling pool.
|
||||
* @param orchardTotalBalance The total account balance in the Orchard pool,
|
||||
* including unconfirmed funds.
|
||||
* @param orchardVerifiedBalance The verified account balance in the Orchard pool.
|
||||
* @param unshieldedBalance The total account balance in the transparent pool,
|
||||
* including unconfirmed funds, that must be shielded before use.
|
||||
* @throws IllegalArgumentException if the values are inconsistent.
|
||||
*/
|
||||
@Keep
|
||||
|
@ -15,11 +21,18 @@ class JniAccountBalance(
|
|||
val account: Int,
|
||||
val saplingTotalBalance: Long,
|
||||
val saplingVerifiedBalance: Long,
|
||||
val orchardTotalBalance: Long,
|
||||
val orchardVerifiedBalance: Long,
|
||||
val unshieldedBalance: Long,
|
||||
) {
|
||||
init {
|
||||
require(saplingTotalBalance >= saplingVerifiedBalance) {
|
||||
"Total Sapling balance $saplingTotalBalance must not be " +
|
||||
"less than verified Sapling balance $saplingVerifiedBalance."
|
||||
}
|
||||
require(orchardTotalBalance >= orchardVerifiedBalance) {
|
||||
"Total Orchard balance $orchardTotalBalance must not be " +
|
||||
"less than verified Orchard balance $orchardVerifiedBalance."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
package cash.z.ecc.android.sdk.internal.model
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import cash.z.ecc.android.sdk.internal.ext.isInUIntRange
|
||||
|
||||
/**
|
||||
* Serves as cross layer (Kotlin, Rust) communication class.
|
||||
*
|
||||
* @param accountBalances the balances of the wallet accounts
|
||||
* @param chainTipHeight the wallet's view of the current chain tip
|
||||
* @param fullyScannedHeight the height below which all blocks have been scanned
|
||||
* by the wallet, ignoring blocks below the wallet birthday.
|
||||
* @param progressNumerator the numerator of the progress ratio
|
||||
* @param progressDenominator the denominator of the progress ratio
|
||||
* @param nextSaplingSubtreeIndex the Sapling subtree index that should start
|
||||
* the next range of subtree roots passed to `Backend.putSaplingSubtreeRoots`.
|
||||
* @throws IllegalArgumentException unless (progressNumerator is nonnegative,
|
||||
* progressDenominator is positive, and the represented ratio is in the
|
||||
* range 0.0 to 1.0 inclusive).
|
||||
|
@ -15,10 +21,19 @@ import androidx.annotation.Keep
|
|||
@Keep
|
||||
class JniWalletSummary(
|
||||
val accountBalances: Array<JniAccountBalance>,
|
||||
val chainTipHeight: Long,
|
||||
val fullyScannedHeight: Long,
|
||||
val progressNumerator: Long,
|
||||
val progressDenominator: Long
|
||||
val progressDenominator: Long,
|
||||
val nextSaplingSubtreeIndex: Long,
|
||||
) {
|
||||
init {
|
||||
require(chainTipHeight.isInUIntRange()) {
|
||||
"Height $chainTipHeight is outside of allowed UInt range"
|
||||
}
|
||||
require(fullyScannedHeight.isInUIntRange()) {
|
||||
"Height $fullyScannedHeight is outside of allowed UInt range"
|
||||
}
|
||||
require(progressNumerator >= 0L) {
|
||||
"Numerator $progressNumerator is outside of allowed range [0, Long.MAX_VALUE]"
|
||||
}
|
||||
|
@ -31,5 +46,8 @@ class JniWalletSummary(
|
|||
require(progressNumerator.toFloat().div(progressDenominator) <= 1f) {
|
||||
"Result of ${progressNumerator.toFloat()}/$progressDenominator is outside of allowed range"
|
||||
}
|
||||
require(nextSaplingSubtreeIndex >= 0L) {
|
||||
"Numerator $nextSaplingSubtreeIndex is outside of allowed range [0, Long.MAX_VALUE]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1117,13 +1117,21 @@ fn encode_account_balance<'a>(
|
|||
let sapling_total_balance = Amount::from(balance.sapling_balance().total());
|
||||
let sapling_verified_balance = Amount::from(balance.sapling_balance().spendable_value());
|
||||
|
||||
let orchard_total_balance = Amount::from(balance.orchard_balance().total());
|
||||
let orchard_verified_balance = Amount::from(balance.orchard_balance().spendable_value());
|
||||
|
||||
let unshielded = Amount::from(balance.unshielded());
|
||||
|
||||
env.new_object(
|
||||
JNI_ACCOUNT_BALANCE,
|
||||
"(IJJ)V",
|
||||
"(IJJJJJ)V",
|
||||
&[
|
||||
JValue::Int(u32::from(*account) as i32),
|
||||
JValue::Long(sapling_total_balance.into()),
|
||||
JValue::Long(sapling_verified_balance.into()),
|
||||
JValue::Long(orchard_total_balance.into()),
|
||||
JValue::Long(orchard_verified_balance.into()),
|
||||
JValue::Long(unshielded.into()),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
@ -1153,11 +1161,14 @@ fn encode_wallet_summary<'a>(
|
|||
|
||||
env.new_object(
|
||||
"cash/z/ecc/android/sdk/internal/model/JniWalletSummary",
|
||||
&format!("([L{};JJ)V", JNI_ACCOUNT_BALANCE),
|
||||
&format!("([L{};JJJJJ)V", JNI_ACCOUNT_BALANCE),
|
||||
&[
|
||||
(&account_balances).into(),
|
||||
JValue::Long(i64::from(u32::from(summary.chain_tip_height()))),
|
||||
JValue::Long(i64::from(u32::from(summary.fully_scanned_height()))),
|
||||
JValue::Long(progress_numerator as i64),
|
||||
JValue::Long(progress_denominator as i64),
|
||||
JValue::Long(summary.next_sapling_subtree_index() as i64),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -6,14 +6,24 @@ object JniAccountBalanceFixture {
|
|||
const val ACCOUNT_ID: Int = 0
|
||||
const val SAPLING_TOTAL_BALANCE: Long = 0L
|
||||
const val SAPLING_VERIFIED_BALANCE: Long = 0L
|
||||
const val ORCHARD_TOTAL_BALANCE: Long = 0L
|
||||
const val ORCHARD_VERIFIED_BALANCE: Long = 0L
|
||||
const val UNSHIELDED_BALANCE: Long = 0L
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
fun new(
|
||||
account: Int = ACCOUNT_ID,
|
||||
saplingTotalBalance: Long = SAPLING_TOTAL_BALANCE,
|
||||
saplingVerifiedBalance: Long = SAPLING_VERIFIED_BALANCE,
|
||||
orchardTotalBalance: Long = ORCHARD_TOTAL_BALANCE,
|
||||
orchardVerifiedBalance: Long = ORCHARD_VERIFIED_BALANCE,
|
||||
unshieldedBalance: Long = UNSHIELDED_BALANCE,
|
||||
) = JniAccountBalance(
|
||||
account = account,
|
||||
saplingTotalBalance = saplingTotalBalance,
|
||||
saplingVerifiedBalance = saplingVerifiedBalance
|
||||
saplingVerifiedBalance = saplingVerifiedBalance,
|
||||
orchardTotalBalance = orchardTotalBalance,
|
||||
orchardVerifiedBalance = orchardVerifiedBalance,
|
||||
unshieldedBalance = unshieldedBalance
|
||||
)
|
||||
}
|
||||
|
|
|
@ -7,23 +7,43 @@ import kotlin.test.assertIs
|
|||
|
||||
class JniWalletSummaryTest {
|
||||
@Test
|
||||
fun both_attribute_within_constraints() {
|
||||
fun all_attribute_within_constraints() {
|
||||
val instance =
|
||||
JniWalletSummary(
|
||||
accountBalances = arrayOf(JniAccountBalanceFixture.new()),
|
||||
chainTipHeight = 0,
|
||||
fullyScannedHeight = 0,
|
||||
progressNumerator = 1L,
|
||||
progressDenominator = 100L
|
||||
progressDenominator = 100L,
|
||||
nextSaplingSubtreeIndex = 0
|
||||
)
|
||||
assertIs<JniWalletSummary>(instance)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun height_not_in_constraints() {
|
||||
assertFailsWith(IllegalArgumentException::class) {
|
||||
JniWalletSummary(
|
||||
accountBalances = arrayOf(JniAccountBalanceFixture.new()),
|
||||
chainTipHeight = -1,
|
||||
fullyScannedHeight = 0,
|
||||
progressNumerator = 1L,
|
||||
progressDenominator = 100L,
|
||||
nextSaplingSubtreeIndex = 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun numerator_attribute_not_in_constraints() {
|
||||
assertFailsWith(IllegalArgumentException::class) {
|
||||
JniWalletSummary(
|
||||
accountBalances = arrayOf(JniAccountBalanceFixture.new()),
|
||||
chainTipHeight = 0,
|
||||
fullyScannedHeight = 0,
|
||||
progressNumerator = -1L,
|
||||
progressDenominator = 100L
|
||||
progressDenominator = 100L,
|
||||
nextSaplingSubtreeIndex = 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -33,8 +53,11 @@ class JniWalletSummaryTest {
|
|||
assertFailsWith(IllegalArgumentException::class) {
|
||||
JniWalletSummary(
|
||||
accountBalances = arrayOf(JniAccountBalanceFixture.new()),
|
||||
chainTipHeight = 0,
|
||||
fullyScannedHeight = 0,
|
||||
progressNumerator = 1L,
|
||||
progressDenominator = 0L
|
||||
progressDenominator = 0L,
|
||||
nextSaplingSubtreeIndex = 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -44,8 +67,25 @@ class JniWalletSummaryTest {
|
|||
assertFailsWith(IllegalArgumentException::class) {
|
||||
JniWalletSummary(
|
||||
accountBalances = arrayOf(JniAccountBalanceFixture.new()),
|
||||
chainTipHeight = 0,
|
||||
fullyScannedHeight = 0,
|
||||
progressNumerator = 100L,
|
||||
progressDenominator = 1L
|
||||
progressDenominator = 1L,
|
||||
nextSaplingSubtreeIndex = 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun subtree_index_not_in_constraints() {
|
||||
assertFailsWith(IllegalArgumentException::class) {
|
||||
JniWalletSummary(
|
||||
accountBalances = arrayOf(JniAccountBalanceFixture.new()),
|
||||
chainTipHeight = 0,
|
||||
fullyScannedHeight = 0,
|
||||
progressNumerator = 1L,
|
||||
progressDenominator = 100L,
|
||||
nextSaplingSubtreeIndex = -1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package cash.z.ecc.android.sdk.internal.model
|
||||
|
||||
import cash.z.ecc.android.sdk.model.Account
|
||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
|
||||
internal data class WalletSummary(
|
||||
val accountBalances: Map<Account, AccountBalance>,
|
||||
val scanProgress: ScanProgress
|
||||
val chainTipHeight: BlockHeight,
|
||||
val fullyScannedHeight: BlockHeight,
|
||||
val scanProgress: ScanProgress,
|
||||
val nextSaplingSubtreeIndex: Long
|
||||
) {
|
||||
companion object {
|
||||
fun new(jni: JniWalletSummary): WalletSummary {
|
||||
|
@ -13,7 +17,10 @@ internal data class WalletSummary(
|
|||
jni.accountBalances.associateBy({ Account(it.account) }, {
|
||||
AccountBalance.new(it)
|
||||
}),
|
||||
scanProgress = ScanProgress.new(jni)
|
||||
chainTipHeight = BlockHeight(jni.chainTipHeight),
|
||||
fullyScannedHeight = BlockHeight(jni.fullyScannedHeight),
|
||||
scanProgress = ScanProgress.new(jni),
|
||||
nextSaplingSubtreeIndex = jni.nextSaplingSubtreeIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue