Skip to content
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

Integrate transaction status queue for transparent history #1559

Merged
merged 17 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions backend-lib/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions backend-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ crate-type = ["staticlib", "cdylib"]
[patch.crates-io]
incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "337f59179eda51261e9ddfc6b18e8fb84ea277c9" }
shardtree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "337f59179eda51261e9ddfc6b18e8fb84ea277c9" }
zcash_address = { git = "https://github.com/zcash/librustzcash.git", rev = "7f7b685b99132505a0fe4ba588f329e3516e9669" }
zcash_client_backend = { git = "https://github.com/zcash/librustzcash.git", rev = "7f7b685b99132505a0fe4ba588f329e3516e9669" }
zcash_client_sqlite = { git = "https://github.com/zcash/librustzcash.git", rev = "7f7b685b99132505a0fe4ba588f329e3516e9669" }
zcash_encoding = { git = "https://github.com/zcash/librustzcash.git", rev = "7f7b685b99132505a0fe4ba588f329e3516e9669" }
zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "7f7b685b99132505a0fe4ba588f329e3516e9669" }
zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "7f7b685b99132505a0fe4ba588f329e3516e9669" }
zcash_protocol = { git = "https://github.com/zcash/librustzcash.git", rev = "7f7b685b99132505a0fe4ba588f329e3516e9669" }
zcash_address = { git = "https://github.com/zcash/librustzcash.git", rev = "05887be9622fbc68ff901b05e04321627618d3bf" }
zcash_client_backend = { git = "https://github.com/zcash/librustzcash.git", rev = "05887be9622fbc68ff901b05e04321627618d3bf" }
zcash_client_sqlite = { git = "https://github.com/zcash/librustzcash.git", rev = "05887be9622fbc68ff901b05e04321627618d3bf" }
zcash_encoding = { git = "https://github.com/zcash/librustzcash.git", rev = "05887be9622fbc68ff901b05e04321627618d3bf" }
zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "05887be9622fbc68ff901b05e04321627618d3bf" }
zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "05887be9622fbc68ff901b05e04321627618d3bf" }
zcash_protocol = { git = "https://github.com/zcash/librustzcash.git", rev = "05887be9622fbc68ff901b05e04321627618d3bf" }
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,14 @@ interface Backend {
unifiedSpendingKey: ByteArray
): List<ByteArray>

suspend fun decryptAndStoreTransaction(tx: ByteArray)
/**
* @throws RuntimeException as a common indicator of the operation failure
*/
@Throws(RuntimeException::class)
suspend fun decryptAndStoreTransaction(
tx: ByteArray,
minedHeight: Long?
)

/**
* Sets up the internal structure of the data database.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,14 +295,17 @@ class RustBackend private constructor(
}
}

override suspend fun decryptAndStoreTransaction(tx: ByteArray) =
withContext(SdkDispatchers.DATABASE_IO) {
decryptAndStoreTransaction(
dataDbFile.absolutePath,
tx,
networkId = networkId
)
}
override suspend fun decryptAndStoreTransaction(
tx: ByteArray,
minedHeight: Long?
) = withContext(SdkDispatchers.DATABASE_IO) {
decryptAndStoreTransaction(
dataDbFile.absolutePath,
tx,
minedHeight = minedHeight ?: -1,
networkId = networkId
)
}

override suspend fun proposeTransfer(
account: Int,
Expand Down Expand Up @@ -616,6 +619,7 @@ class RustBackend private constructor(
private external fun decryptAndStoreTransaction(
dbDataPath: String,
tx: ByteArray,
minedHeight: Long,
networkId: Int
)

Expand Down
10 changes: 7 additions & 3 deletions backend-lib/src/main/rust/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_createAcc
let account = db_data.get_account(account_id)?.expect("just created");
let account_index = match account.source() {
AccountSource::Derived { account_index, .. } => account_index,
AccountSource::Imported => unreachable!("just created"),
AccountSource::Imported { .. } => unreachable!("just created"),
};

Ok(encode_usk(env, account_index, usk)?.into_raw())
Expand Down Expand Up @@ -1327,7 +1327,9 @@ fn encode_wallet_summary<'a, P: Parameters>(
.source()
{
AccountSource::Derived { account_index, .. } => account_index,
AccountSource::Imported => unreachable!("Imported accounts are unimplemented"),
AccountSource::Imported { .. } => {
unreachable!("Imported accounts are unimplemented")
}
};
Ok::<_, anyhow::Error>((account_index, balance))
})
Expand Down Expand Up @@ -1556,6 +1558,7 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_decryptAn
_: JClass<'local>,
db_data: JString<'local>,
tx: JByteArray<'local>,
mined_height: jlong,
network_id: jint,
) -> jboolean {
let res = catch_unwind(&mut env, |env| {
Expand All @@ -1570,8 +1573,9 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_decryptAn
// - v5 and above transactions ignore the argument, and parse the correct value
// from their encoding.
let tx = Transaction::read(&tx_bytes[..], BranchId::Sapling)?;
let mined_height = BlockHeight::try_from(mined_height).ok();

match decrypt_and_store_transaction(&network, &mut db_data, &tx) {
match decrypt_and_store_transaction(&network, &mut db_data, &tx, mined_height) {
Ok(()) => Ok(JNI_TRUE),
Err(e) => Err(anyhow!("Error while decrypting transaction: {}", e)),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,36 @@ import cash.z.wallet.sdk.internal.rpc.Service.RawTransaction
*
* It is marked as "unsafe" because it is not guaranteed to be valid.
*/
class RawTransactionUnsafe(val height: BlockHeightUnsafe, val data: ByteArray) {
sealed class RawTransactionUnsafe(open val data: ByteArray) {
/**
* The transaction was found in a block mined in the current main chain.
*/
class MainChain(override val data: ByteArray, val height: BlockHeightUnsafe) : RawTransactionUnsafe(data)

/**
* The transaction was found in the mempool, and can potentially be mined in the
* current main chain.
*/
@Suppress("SpellCheckingInspection")
class Mempool(override val data: ByteArray) : RawTransactionUnsafe(data)

/**
* The transaction was found in an orphaned block.
*
* In particular, it was not found in the current main chain or the mempool, which
* means that the transaction is likely conflicted with the main chain (e.g. it may
* double-spend funds spent in the main chain, or it may have expired).
*/
class OrphanedBlock(override val data: ByteArray) : RawTransactionUnsafe(data)

companion object {
fun new(rawTransaction: RawTransaction) =
RawTransactionUnsafe(
BlockHeightUnsafe(rawTransaction.height),
rawTransaction.data.toByteArray()
)
fun new(rawTransaction: RawTransaction): RawTransactionUnsafe {
val data = rawTransaction.data.toByteArray();
return when (rawTransaction.height) {
-1L -> OrphanedBlock(data)
0L -> Mempool(data)
else -> MainChain(data, BlockHeightUnsafe(rawTransaction.height))
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,10 @@ internal class FakeRustBackend(
TODO("Not yet implemented")
}

override suspend fun decryptAndStoreTransaction(tx: ByteArray) =
error("Intentionally not implemented in mocked FakeRustBackend implementation.")
override suspend fun decryptAndStoreTransaction(
tx: ByteArray,
minedHeight: Long?
) = error("Intentionally not implemented in mocked FakeRustBackend implementation.")

override suspend fun initDataDb(seed: ByteArray?): Int =
error("Intentionally not implemented in mocked FakeRustBackend implementation.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import cash.z.ecc.android.sdk.model.Zatoshi
import cash.z.ecc.android.sdk.model.ZcashNetwork
import co.electriccoin.lightwallet.client.model.BlockHeightUnsafe
import co.electriccoin.lightwallet.client.model.GetAddressUtxosReplyUnsafe
import co.electriccoin.lightwallet.client.model.RawTransactionUnsafe
import co.electriccoin.lightwallet.client.model.Response
import co.electriccoin.lightwallet.client.model.ShieldedProtocolEnum
import co.electriccoin.lightwallet.client.model.SubtreeRootUnsafe
Expand Down Expand Up @@ -1574,7 +1575,8 @@ class CompactBlockProcessor internal constructor(
range = currentEnhancingRange,
repository = repository,
backend = backend,
downloader = downloader
downloader = downloader,
network = network
).collect { enhancingResult ->
Twig.info { "Enhancing result: $enhancingResult" }
resultState =
Expand Down Expand Up @@ -1838,7 +1840,8 @@ class CompactBlockProcessor internal constructor(
range: ClosedRange<BlockHeight>,
repository: DerivedDataRepository,
backend: TypesafeBackend,
downloader: CompactBlockDownloader
downloader: CompactBlockDownloader,
network: ZcashNetwork
): Flow<SyncingResult> =
flow {
Twig.debug { "Enhancing transaction details for blocks $range" }
Expand All @@ -1856,7 +1859,7 @@ class CompactBlockProcessor internal constructor(
}

newTxs.filter { it.minedHeight != null }.onEach { newTransaction ->
val trEnhanceResult = enhanceTransaction(newTransaction, backend, downloader)
val trEnhanceResult = enhanceTransaction(newTransaction, backend, downloader, network)
if (trEnhanceResult is SyncingResult.EnhanceFailed) {
Twig.error { "Encountered transaction enhancing error: ${trEnhanceResult.exception}" }
emit(trEnhanceResult)
Expand All @@ -1872,7 +1875,8 @@ class CompactBlockProcessor internal constructor(
private suspend fun enhanceTransaction(
transaction: DbTransactionOverview,
backend: TypesafeBackend,
downloader: CompactBlockDownloader
downloader: CompactBlockDownloader,
network: ZcashNetwork
): SyncingResult {
Twig.debug {
"Starting enhancing transaction (txid:${transaction.txIdString()} block:${transaction
Expand All @@ -1895,7 +1899,8 @@ class CompactBlockProcessor internal constructor(
transactionId = transaction.txIdString(),
rawTransactionId = transaction.rawId.byteArray,
minedHeight = transaction.minedHeight,
downloader = downloader
downloader = downloader,
network = network
)

// Decrypting and storing transaction is run just once, since we consider it more stable
Expand All @@ -1904,8 +1909,8 @@ class CompactBlockProcessor internal constructor(
"(txid:${transaction.txIdString()} block:${transaction.minedHeight})"
}
decryptTransaction(
transactionData = transactionData,
minedHeight = transaction.minedHeight,
transactionData = transactionData.first,
minedHeight = transactionData.second,
backend = backend
)

Expand All @@ -1931,10 +1936,11 @@ class CompactBlockProcessor internal constructor(
transactionId: String,
rawTransactionId: ByteArray,
minedHeight: BlockHeight,
downloader: CompactBlockDownloader
): ByteArray {
downloader: CompactBlockDownloader,
network: ZcashNetwork
): Pair<ByteArray, BlockHeight?> {
val traceScope = TraceScope("CompactBlockProcessor.fetchTransaction")
var transactionDataResult: ByteArray? = null
var transactionDataResult: Pair<ByteArray, BlockHeight?>? = null
retryUpToAndThrow(TRANSACTION_FETCH_RETRIES) { failedAttempts ->
if (failedAttempts == 0) {
Twig.debug { "Starting to fetch transaction (txid:$transactionId, block:$minedHeight)" }
Expand All @@ -1946,7 +1952,15 @@ class CompactBlockProcessor internal constructor(
}
when (val response = downloader.fetchTransaction(rawTransactionId)) {
is Response.Success -> {
transactionDataResult = response.result.data
val currentMinedHeight = when (response.result) {
is RawTransactionUnsafe.MainChain -> runCatching {
HonzaR marked this conversation as resolved.
Show resolved Hide resolved
(response.result as RawTransactionUnsafe.MainChain).height.toBlockHeight(
network
)
}.getOrNull()
else -> null
}
transactionDataResult = Pair(response.result.data, currentMinedHeight)
}
is Response.Failure -> {
throw EnhanceTxDownloadError(minedHeight, response.toThrowable())
Expand All @@ -1961,12 +1975,12 @@ class CompactBlockProcessor internal constructor(
@Throws(EnhanceTxDecryptError::class)
private suspend fun decryptTransaction(
transactionData: ByteArray,
minedHeight: BlockHeight,
minedHeight: BlockHeight?,
backend: TypesafeBackend,
) {
val traceScope = TraceScope("CompactBlockProcessor.decryptTransaction")
runCatching {
backend.decryptAndStoreTransaction(transactionData)
backend.decryptAndStoreTransaction(transactionData, minedHeight)
}.onFailure {
traceScope.end()
throw EnhanceTxDecryptError(minedHeight, it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ sealed class CompactBlockProcessorException(message: String, cause: Throwable? =

open class EnhanceTransactionError(
message: String,
val height: BlockHeight,
val height: BlockHeight?,
cause: Throwable
) : CompactBlockProcessorException(message, cause) {
class EnhanceTxDownloadError(
Expand All @@ -111,7 +111,7 @@ sealed class CompactBlockProcessorException(message: String, cause: Throwable? =
)

class EnhanceTxDecryptError(
height: BlockHeight,
height: BlockHeight?,
cause: Throwable
) : EnhanceTransactionError(
"Error while attempting to decrypt and store a transaction to enhance",
Expand Down
Loading
Loading