115 lines
4.3 KiB
Kotlin
115 lines
4.3 KiB
Kotlin
package cash.z.ecc.android.sdk.internal.block
|
|
|
|
import cash.z.ecc.android.sdk.internal.ext.retryUpTo
|
|
import cash.z.ecc.android.sdk.internal.model.from
|
|
import cash.z.ecc.android.sdk.internal.repository.CompactBlockRepository
|
|
import cash.z.ecc.android.sdk.internal.twig
|
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
|
import co.electriccoin.lightwallet.client.BlockingLightWalletClient
|
|
import co.electriccoin.lightwallet.client.model.BlockHeightUnsafe
|
|
import co.electriccoin.lightwallet.client.model.LightWalletEndpointInfoUnsafe
|
|
import co.electriccoin.lightwallet.client.model.Response
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.Dispatchers.IO
|
|
import kotlinx.coroutines.withContext
|
|
|
|
/**
|
|
* Serves as a source of compact blocks received from the light wallet server. Once started, it will use the given
|
|
* lightWallet client to request all the appropriate blocks and compact block store to persist them. By delegating to
|
|
* these dependencies, the downloader remains agnostic to the particular implementation of how to retrieve and store
|
|
* data; although, by default the SDK uses gRPC and SQL.
|
|
*
|
|
* @property lightWalletClient the client used for requesting compact blocks
|
|
* @property compactBlockStore responsible for persisting the compact blocks that are received
|
|
*/
|
|
open class CompactBlockDownloader private constructor(val compactBlockRepository: CompactBlockRepository) {
|
|
|
|
lateinit var lightWalletClient: BlockingLightWalletClient
|
|
private set
|
|
|
|
constructor(
|
|
lightWalletClient: BlockingLightWalletClient,
|
|
compactBlockRepository: CompactBlockRepository
|
|
) : this(compactBlockRepository) {
|
|
this.lightWalletClient = lightWalletClient
|
|
}
|
|
|
|
/**
|
|
* Requests the given range of blocks from the lightWalletClient and then persists them to the
|
|
* compactBlockStore.
|
|
*
|
|
* @param heightRange the inclusive range of heights to request. For example 10..20 would
|
|
* request 11 blocks (including block 10 and block 20).
|
|
*
|
|
* @return the number of blocks that were returned in the results from the lightWalletClient.
|
|
*/
|
|
suspend fun downloadBlockRange(heightRange: ClosedRange<BlockHeight>): Int = withContext(IO) {
|
|
val result = lightWalletClient.getBlockRange(
|
|
BlockHeightUnsafe.from(heightRange.start)..BlockHeightUnsafe.from(heightRange.endInclusive)
|
|
)
|
|
compactBlockRepository.write(result)
|
|
}
|
|
|
|
/**
|
|
* Rewind the storage to the given height, usually to handle reorgs. Deletes all blocks above
|
|
* the given height.
|
|
*
|
|
* @param height the height to which the data will rewind.
|
|
*/
|
|
suspend fun rewindToHeight(height: BlockHeight) =
|
|
// TODO [#685]: cancel anything in flight
|
|
// TODO [#685]: https://github.com/zcash/zcash-android-wallet-sdk/issues/685
|
|
compactBlockRepository.rewindTo(height)
|
|
|
|
/**
|
|
* Return the latest block height known by the lightWalletClient.
|
|
*
|
|
* @return the latest block height.
|
|
*/
|
|
suspend fun getLatestBlockHeight() =
|
|
lightWalletClient.getLatestBlockHeight()
|
|
|
|
/**
|
|
* Return the latest block height that has been persisted into the [CompactBlockRepository].
|
|
*
|
|
* @return the latest block height that has been persisted.
|
|
*/
|
|
suspend fun getLastDownloadedHeight() =
|
|
compactBlockRepository.getLatestHeight()
|
|
|
|
suspend fun getServerInfo(): LightWalletEndpointInfoUnsafe? = withContext(IO) {
|
|
retryUpTo(GET_SERVER_INFO_RETRIES) {
|
|
when (val response = lightWalletClient.getServerInfo()) {
|
|
is Response.Success -> return@withContext response.result
|
|
else -> {
|
|
lightWalletClient.reconnect()
|
|
twig("WARNING: reconnecting to server in response to failure (retry #${it + 1})")
|
|
}
|
|
}
|
|
}
|
|
|
|
null
|
|
}
|
|
|
|
/**
|
|
* Stop this downloader and cleanup any resources being used.
|
|
*/
|
|
suspend fun stop() {
|
|
withContext(Dispatchers.IO) {
|
|
lightWalletClient.shutdown()
|
|
}
|
|
compactBlockRepository.close()
|
|
}
|
|
|
|
/**
|
|
* Fetch the details of a known transaction.
|
|
*
|
|
* @return the full transaction info.
|
|
*/
|
|
fun fetchTransaction(txId: ByteArray) = lightWalletClient.fetchTransaction(txId)
|
|
|
|
companion object {
|
|
private const val GET_SERVER_INFO_RETRIES = 6
|
|
}
|
|
}
|