New: Functionality to refresh UTXOs and updated taddr support.
This commit is contained in:
parent
591df083b5
commit
39972d8e43
116
publish.gradle
116
publish.gradle
|
@ -1,116 +0,0 @@
|
|||
import cash.z.ecc.android.Deps
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Publishing
|
||||
/////////////////////////////////////////
|
||||
|
||||
group = Deps.group
|
||||
version = Deps.versionName
|
||||
|
||||
// Create the pom configuration:
|
||||
def pomConfig = {
|
||||
licenses {
|
||||
license {
|
||||
name "MIT-style"
|
||||
url "http://opensource.org/licenses/MIT"
|
||||
distribution "repo"
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id "gmale"
|
||||
name "Kevin Gorham"
|
||||
email "kevin.gorham@z.cash"
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
url Deps.githubUrl
|
||||
}
|
||||
}
|
||||
|
||||
// Jar containing Kotlin sources
|
||||
task sourcesJar(type: Jar) {
|
||||
archiveClassifier = 'sources'
|
||||
from kotlin.sourceSets.main.kotlin.srcDirs
|
||||
}
|
||||
|
||||
// Jar containing docs
|
||||
task docsJar(type: Jar) {
|
||||
archiveClassifier = "javadoc"
|
||||
group = JavaBasePlugin.DOCUMENTATION_GROUP
|
||||
dependsOn dokka
|
||||
from dokka
|
||||
}
|
||||
|
||||
def activePublication = Deps.publishingTarget
|
||||
publishing {
|
||||
publications {
|
||||
android.libraryVariants.all { variant ->
|
||||
if (variant.name != activePublication.variant) return
|
||||
|
||||
Production(MavenPublication) {
|
||||
artifact variant.outputs[0].packageLibrary // the AAR
|
||||
artifact sourcesJar
|
||||
artifact docsJar
|
||||
groupId Deps.group
|
||||
artifactId activePublication.artifactId
|
||||
version Deps.versionName
|
||||
|
||||
pom.withXml {
|
||||
def root = asNode()
|
||||
root.appendNode('description', Deps.description)
|
||||
root.appendNode('name', activePublication.artifactId)
|
||||
root.appendNode('url', )
|
||||
root.children().last() + pomConfig
|
||||
|
||||
// AAR-specific: we must explicitly add dependencies for an AAR
|
||||
def depsNode = root["dependencies"][0] ?: root.appendNode("dependencies")
|
||||
def addDep = {
|
||||
if (it.group == null) return // Avoid empty dependency nodes
|
||||
def dependencyNode = depsNode.appendNode('dependency')
|
||||
dependencyNode.appendNode('groupId', it.group)
|
||||
dependencyNode.appendNode('artifactId', it.name)
|
||||
dependencyNode.appendNode('version', it.version)
|
||||
if (it.hasProperty('type')) {
|
||||
dependencyNode.appendNode('type', it.type)
|
||||
}
|
||||
if (it.hasProperty('scope')) {
|
||||
dependencyNode.appendNode('scope', it.scope)
|
||||
}
|
||||
if (it.hasProperty('optional') && it.optional) {
|
||||
dependencyNode.appendNode('optional', 'true')
|
||||
}
|
||||
}
|
||||
// run the 'addDep' closure over each dependency
|
||||
configurations.implementation.allDependencies.each addDep
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bintray {
|
||||
user = project.findProperty('bintrayUser') ?: System.getenv('BINTRAY_USER')
|
||||
key = project.findProperty('bintrayApiKey') ?: System.getenv('BINTRAY_API_KEY')
|
||||
publications = ['Production']
|
||||
override = true
|
||||
pkg {
|
||||
repo = 'android'
|
||||
name = activePublication.artifactId
|
||||
description = Deps.description
|
||||
publish = true
|
||||
publicDownloadNumbers = true
|
||||
userOrg = 'ecc-mobile'
|
||||
labels = ['aar', 'native', 'android', 'zcash', 'ecc', 'sdk', 'kotlin', 'mobile', 'electric coin company', 'open source', 'crypto', 'cryptocurrency', 'cryptography', 'privacy']
|
||||
licenses = ['MIT']
|
||||
vcsUrl = Deps.githubUrl
|
||||
dryRun = Deps.publishingDryRun
|
||||
version {
|
||||
name = Deps.versionName
|
||||
desc = Deps.description
|
||||
released = new Date()
|
||||
vcsTag = this.version
|
||||
}
|
||||
}
|
||||
}
|
|
@ -330,6 +330,11 @@ class SdkSynchronizer internal constructor(
|
|||
// Private API
|
||||
//
|
||||
|
||||
suspend fun refreshUtxos() {
|
||||
twig("refreshing utxos")
|
||||
refreshUtxos(getTransparentAddress())
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the latest balance, based on the blocks that have been scanned and transmit this
|
||||
* information into the flow of [balances].
|
||||
|
@ -566,9 +571,7 @@ class SdkSynchronizer internal constructor(
|
|||
|
||||
override suspend fun getShieldedAddress(accountId: Int): String = processor.getShieldedAddress(accountId)
|
||||
|
||||
override suspend fun getTransparentAddress(seed: ByteArray, accountId: Int, index: Int): String {
|
||||
return DerivationTool.deriveTransparentAddress(seed, accountId, index)
|
||||
}
|
||||
override suspend fun getTransparentAddress(accountId: Int): String = processor.getTransparentAddress(accountId)
|
||||
|
||||
override fun sendToAddress(
|
||||
spendingKey: String,
|
||||
|
@ -593,6 +596,8 @@ class SdkSynchronizer internal constructor(
|
|||
}
|
||||
}
|
||||
}.flatMapLatest {
|
||||
// switch this flow over to monitoring the database for transactions
|
||||
// so we emit the placeholder TX above, then watch the database for all further updates
|
||||
twig("Monitoring pending transaction (id: ${it.id}) for updates...")
|
||||
txManager.monitorById(it.id)
|
||||
}.distinctUntilChanged()
|
||||
|
@ -626,9 +631,8 @@ class SdkSynchronizer internal constructor(
|
|||
txManager.monitorById(it.id)
|
||||
}.distinctUntilChanged()
|
||||
|
||||
override suspend fun refreshUtxos(address: String, sinceHeight: Int): Int {
|
||||
// TODO: we need to think about how we restrict this to only our taddr
|
||||
return processor.downloadUtxos(address, sinceHeight)
|
||||
override suspend fun refreshUtxos(address: String, startHeight: Int): Int {
|
||||
return processor.refreshUtxos(address, startHeight)
|
||||
}
|
||||
|
||||
override suspend fun getTransparentBalance(tAddr: String): WalletBalance {
|
||||
|
|
|
@ -152,16 +152,14 @@ interface Synchronizer {
|
|||
suspend fun getShieldedAddress(accountId: Int = 0): String
|
||||
|
||||
/**
|
||||
* Gets the transparent address for the given account and index.
|
||||
* Gets the transparent address for the given account.
|
||||
*
|
||||
* @param accountId the optional accountId whose address is of interest. By default, the first
|
||||
* account is used.
|
||||
* @param index the optional index whose address is of interest. By default, the first index is
|
||||
* used.
|
||||
*
|
||||
* @return the address for the given account and index.
|
||||
* @return the address for the given account.
|
||||
*/
|
||||
suspend fun getTransparentAddress(seed: ByteArray, accountId: Int = 0, index: Int = 0): String
|
||||
suspend fun getTransparentAddress(accountId: Int = 0): String
|
||||
|
||||
/**
|
||||
* Sends zatoshi.
|
||||
|
@ -270,7 +268,7 @@ interface Synchronizer {
|
|||
errorHandler: (Throwable) -> Unit = { throw it }
|
||||
)
|
||||
|
||||
suspend fun refreshUtxos(tAddr: String, sinceHeight: Int): Int
|
||||
suspend fun refreshUtxos(tAddr: String, sinceHeight: Int = ZcashSdk.SAPLING_ACTIVATION_HEIGHT): Int
|
||||
|
||||
/**
|
||||
* Returns the balance that the wallet knows about. This should be called after [refreshUtxos].
|
||||
|
|
|
@ -386,7 +386,6 @@ class CompactBlockProcessor(
|
|||
}
|
||||
}
|
||||
|
||||
internal suspend fun downloadUtxos(tAddress: String, startHeight: Int): Int = withContext(IO) {
|
||||
private suspend fun updateBirthdayHeight() {
|
||||
try {
|
||||
val betterBirthday = calculateBirthdayHeight()
|
||||
|
@ -399,9 +398,13 @@ class CompactBlockProcessor(
|
|||
}
|
||||
}
|
||||
|
||||
internal suspend fun refreshUtxos(tAddress: String, startHeight: Int): Int = withContext(IO) {
|
||||
var skipped = 0
|
||||
twig("Downloading utxos starting at height $startHeight")
|
||||
// todo test what happens when this call fails
|
||||
downloader.lightWalletService.fetchUtxos(tAddress, startHeight).let { result ->
|
||||
twig("Clearing utxos above height ${startHeight - 1}")
|
||||
rustBackend.clearUtxos(tAddress, startHeight - 1)
|
||||
twig("Downloading utxos starting at height $startHeight")
|
||||
result.forEach { utxo: Service.GetAddressUtxosReply ->
|
||||
twig("Found UTXO at height ${utxo.height.toInt()}")
|
||||
try {
|
||||
|
@ -570,7 +573,7 @@ class CompactBlockProcessor(
|
|||
determineLowerBound(errorHeight).let { lowerBound ->
|
||||
twig("handling chain error at $errorHeight by rewinding to block $lowerBound")
|
||||
onChainErrorListener?.invoke(errorHeight, lowerBound)
|
||||
rewindToHeight(lowerBound)
|
||||
rewindToHeight(lowerBound, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -579,21 +582,24 @@ class CompactBlockProcessor(
|
|||
* blocks. Otherwise, the cached blocks will be used in the rescan, which in most cases, is fine.
|
||||
*/
|
||||
suspend fun rewindToHeight(height: Int, alsoClearBlockCache: Boolean = false) = withContext(IO) {
|
||||
val lastHeight = currentInfo.lastScannedHeight
|
||||
twig("Rewinding from $lastHeight to height: $height")
|
||||
val lastScannedHeight = currentInfo.lastScannedHeight
|
||||
twig("Rewinding from $lastScannedHeight to height: $height")
|
||||
// TODO: think about how we might pause all processing during a rewind
|
||||
if (height < lastHeight) {
|
||||
if (height < lastScannedHeight) {
|
||||
rustBackend.rewindToHeight(height)
|
||||
val range = (height + 1)..lastHeight
|
||||
if (alsoClearBlockCache) {
|
||||
twig("Rewound blocks will download in the next scheduled scan")
|
||||
downloader.rewindToHeight(height)
|
||||
// communicate that the wallet is no longer synced because it might remain this way for 20+ seconds because we only download on 20s time boundaries so we can't trigger any immediate action
|
||||
setState(Downloading)
|
||||
} else {
|
||||
twig("Revalidating blocks that were rewound")
|
||||
if (validateAndScanNewBlocks(range) == ERROR_CODE_NONE) enhanceTransactionDetails(range)
|
||||
}
|
||||
} else {
|
||||
twig("not rewinding dataDb because the last scanned height is $lastScannedHeight which is less than the target height of $height")
|
||||
}
|
||||
|
||||
if (alsoClearBlockCache) {
|
||||
twig("Also clearing block cache back to $height. These rewound blocks will download in the next scheduled scan")
|
||||
downloader.rewindToHeight(height)
|
||||
// communicate that the wallet is no longer synced because it might remain this way for 20+ seconds because we only download on 20s time boundaries so we can't trigger any immediate action
|
||||
setState(Downloading)
|
||||
} else {
|
||||
val range = (height + 1)..lastScannedHeight
|
||||
twig("We kept the cache blocks in place so we don't need to wait for the next scheduled download to rescan. Instead we will rescan and validate blocks ${range.first}..${range.last}")
|
||||
if (validateAndScanNewBlocks(range) == ERROR_CODE_NONE) enhanceTransactionDetails(range)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -700,8 +706,12 @@ class CompactBlockProcessor(
|
|||
*
|
||||
* @return the address of this wallet.
|
||||
*/
|
||||
suspend fun getShieldedAddress(accountId: Int) = withContext(IO) {
|
||||
rustBackend.getShieldedAddress(accountId)
|
||||
suspend fun getShieldedAddress(accountId: Int = 0) = withContext(IO) {
|
||||
repository.getAccount(accountId)!!.rawShieldedAddress
|
||||
}
|
||||
|
||||
suspend fun getTransparentAddress(accountId: Int = 0) = withContext(IO) {
|
||||
repository.getAccount(accountId)!!.rawTransparentAddress
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -41,4 +41,15 @@ data class WalletBirthday(
|
|||
data class UnifiedViewingKey(
|
||||
val extfvk: String = "",
|
||||
val extpub: String = ""
|
||||
)
|
||||
)
|
||||
|
||||
data class UnifiedAddressAccount(
|
||||
val accountId: Int = -1,
|
||||
override val rawShieldedAddress: String = "",
|
||||
override val rawTransparentAddress: String = ""
|
||||
) : UnifiedAddress
|
||||
|
||||
interface UnifiedAddress {
|
||||
val rawShieldedAddress: String
|
||||
val rawTransparentAddress: String
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue