Bundle sapling params in APK instead of downloading from remote servers
- Add sapling-spend.params and sapling-output.params to sdk-lib assets - Rewrite SaplingParamTool to copy params from bundled assets instead of HTTP download - Remove OkHttp dependency from SaplingParamTool - Initialize SaplingParamTool with app context from Initializer
This commit is contained in:
BIN
sdk-lib/src/main/assets/params/sapling-output.params
Normal file
BIN
sdk-lib/src/main/assets/params/sapling-output.params
Normal file
Binary file not shown.
BIN
sdk-lib/src/main/assets/params/sapling-spend.params
Normal file
BIN
sdk-lib/src/main/assets/params/sapling-spend.params
Normal file
Binary file not shown.
@@ -3,6 +3,7 @@ package cash.z.ecc.android.sdk
|
||||
import android.content.Context
|
||||
import cash.z.ecc.android.sdk.exception.InitializerException
|
||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||
import cash.z.ecc.android.sdk.internal.SaplingParamTool
|
||||
import cash.z.ecc.android.sdk.internal.SdkDispatchers
|
||||
import cash.z.ecc.android.sdk.internal.ext.getCacheDirSuspend
|
||||
import cash.z.ecc.android.sdk.internal.ext.getDatabasePathSuspend
|
||||
@@ -319,6 +320,7 @@ class Initializer private constructor(
|
||||
config: Config
|
||||
): Initializer {
|
||||
config.validate()
|
||||
SaplingParamTool.init(context)
|
||||
|
||||
val loadedCheckpoint = run {
|
||||
val height = config.birthdayHeight
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
package cash.z.ecc.android.sdk.internal
|
||||
|
||||
import android.content.Context
|
||||
import cash.z.ecc.android.sdk.exception.TransactionEncoderException
|
||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okio.buffer
|
||||
import okio.sink
|
||||
import java.io.File
|
||||
|
||||
class SaplingParamTool {
|
||||
|
||||
companion object {
|
||||
|
||||
private var appContext: Context? = null
|
||||
|
||||
/**
|
||||
* Checks the given directory for the output and spending params and calls [fetchParams] if
|
||||
* they're missing.
|
||||
* Initialize with application context so params can be copied from bundled assets.
|
||||
*/
|
||||
fun init(context: Context) {
|
||||
appContext = context.applicationContext
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given directory for the output and spending params and copies them from
|
||||
* bundled assets if they're missing.
|
||||
*
|
||||
* @param destinationDir the directory where the params should be stored.
|
||||
*/
|
||||
@@ -32,64 +39,44 @@ class SaplingParamTool {
|
||||
}
|
||||
if (hadError) {
|
||||
try {
|
||||
Bush.trunk.twigTask("attempting to download missing params") {
|
||||
fetchParams(destinationDir)
|
||||
Bush.trunk.twigTask("copying bundled sapling params") {
|
||||
copyBundledParams(destinationDir)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
twig("failed to fetch params due to: $e")
|
||||
twig("failed to copy bundled params due to: $e")
|
||||
throw TransactionEncoderException.MissingParamsException
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download and store the params into the given directory.
|
||||
* Copy the sapling params from bundled assets into the given directory.
|
||||
*
|
||||
* @param destinationDir the directory where the params will be stored. It's assumed that we
|
||||
* have write access to this directory. Typically, this should be the app's cache directory
|
||||
* because it is not harmful if these files are cleared by the user since they are downloaded
|
||||
* on-demand.
|
||||
* @param destinationDir the directory where the params will be stored.
|
||||
*/
|
||||
suspend fun fetchParams(destinationDir: String) {
|
||||
val client = createHttpClient()
|
||||
var failureMessage = ""
|
||||
private suspend fun copyBundledParams(destinationDir: String) {
|
||||
val context = appContext
|
||||
?: throw IllegalStateException("SaplingParamTool not initialized. Call init(context) first.")
|
||||
|
||||
arrayOf(
|
||||
ZcashSdk.SPEND_PARAM_FILE_NAME,
|
||||
ZcashSdk.OUTPUT_PARAM_FILE_NAME
|
||||
).forEach { paramFileName ->
|
||||
val url = "${ZcashSdk.CLOUD_PARAM_DIR_URL.random()}/$paramFileName"
|
||||
twig("Downloading Sapling params from ${url}...")
|
||||
val request = Request.Builder().url(url).build()
|
||||
val response = withContext(Dispatchers.IO) { client.newCall(request).execute() }
|
||||
if (response.isSuccessful) {
|
||||
twig("fetch succeeded", -1)
|
||||
val file = File(destinationDir, paramFileName)
|
||||
if (file.parentFile?.existsSuspend() == true) {
|
||||
twig("directory exists!", -1)
|
||||
} else {
|
||||
twig("directory did not exist attempting to make it")
|
||||
file.parentFile?.mkdirsSuspend()
|
||||
val destFile = File(destinationDir, paramFileName)
|
||||
if (!destFile.existsSuspend()) {
|
||||
if (destFile.parentFile?.existsSuspend() != true) {
|
||||
destFile.parentFile?.mkdirsSuspend()
|
||||
}
|
||||
withContext(Dispatchers.IO) {
|
||||
response.body?.let { body ->
|
||||
body.source().use { source ->
|
||||
file.sink().buffer().use { sink ->
|
||||
twig("writing to $file")
|
||||
sink.writeAll(source)
|
||||
}
|
||||
context.assets.open("params/$paramFileName").use { input ->
|
||||
destFile.outputStream().use { output ->
|
||||
twig("copying bundled $paramFileName to $destFile")
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
failureMessage += "Error while fetching $paramFileName : $response\n"
|
||||
twig(failureMessage)
|
||||
}
|
||||
|
||||
twig("fetch succeeded, done writing $paramFileName")
|
||||
}
|
||||
if (failureMessage.isNotEmpty()) throw TransactionEncoderException.FetchParamsException(
|
||||
failureMessage
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun clear(destinationDir: String) {
|
||||
@@ -119,19 +106,6 @@ class SaplingParamTool {
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
/**
|
||||
* Http client is only used for downloading sapling spend and output params data, which are
|
||||
* necessary for the wallet to scan blocks.
|
||||
*
|
||||
* @return an http client suitable for downloading params data.
|
||||
*/
|
||||
private fun createHttpClient(): OkHttpClient {
|
||||
// TODO: add logging and timeouts
|
||||
return OkHttpClient()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user