2019-01-02 21:31:12 -08:00
|
|
|
package cash.z.wallet.sdk.data
|
|
|
|
|
|
|
|
import android.content.Context
|
|
|
|
import androidx.room.Room
|
|
|
|
import androidx.room.RoomDatabase
|
|
|
|
import cash.z.wallet.sdk.dao.CompactBlockDao
|
|
|
|
import cash.z.wallet.sdk.db.CompactBlockDb
|
|
|
|
import cash.z.wallet.sdk.ext.debug
|
|
|
|
import cash.z.wallet.sdk.jni.JniConverter
|
|
|
|
import kotlinx.coroutines.*
|
|
|
|
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
|
|
|
|
import kotlinx.coroutines.channels.ReceiveChannel
|
2019-01-15 18:07:25 -08:00
|
|
|
import cash.z.wallet.sdk.rpc.CompactFormats
|
2019-01-02 21:31:12 -08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Downloads compact blocks to the database and then scans them for transactions
|
|
|
|
*/
|
2019-01-13 07:37:23 -08:00
|
|
|
class Synchronizer(val applicationContext: Context, val scope: CoroutineScope, val birthday: Long = 373070L) {
|
2019-01-02 21:31:12 -08:00
|
|
|
|
|
|
|
// TODO: convert to CompactBlockSource that just has a stream and then have the downloader operate on the stream
|
2019-01-13 07:37:23 -08:00
|
|
|
private val downloader = CompactBlockDownloader("10.0.2.2", 9067)
|
|
|
|
private val savedBlockChannel = ConflatedBroadcastChannel<CompactFormats.CompactBlock>()
|
2019-01-02 21:31:12 -08:00
|
|
|
private lateinit var cacheDao: CompactBlockDao
|
|
|
|
private lateinit var cacheDb: CompactBlockDb
|
|
|
|
private lateinit var saveJob: Job
|
|
|
|
private lateinit var scanJob: Job
|
2019-01-13 07:37:23 -08:00
|
|
|
fun blocks(): ReceiveChannel<CompactFormats.CompactBlock> = savedBlockChannel.openSubscription()
|
2019-01-02 21:31:12 -08:00
|
|
|
|
|
|
|
fun start() {
|
|
|
|
createDb()
|
2019-01-13 07:37:23 -08:00
|
|
|
downloader.start(scope, birthday)
|
2019-01-02 21:31:12 -08:00
|
|
|
saveJob = saveBlocks()
|
|
|
|
scanJob = scanBlocks()
|
|
|
|
}
|
|
|
|
|
|
|
|
fun stop() {
|
|
|
|
scanJob.cancel()
|
|
|
|
saveJob.cancel()
|
|
|
|
downloader.stop()
|
|
|
|
cacheDb.close()
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun createDb() {
|
|
|
|
// TODO: inject the db and dao
|
|
|
|
cacheDb = Room.databaseBuilder(
|
|
|
|
applicationContext,
|
|
|
|
CompactBlockDb::class.java,
|
|
|
|
CACHEDB_NAME
|
|
|
|
)
|
|
|
|
.setJournalMode(RoomDatabase.JournalMode.TRUNCATE)
|
|
|
|
.fallbackToDestructiveMigration()
|
|
|
|
.build()
|
|
|
|
.apply { cacheDao = complactBlockDao() }
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun saveBlocks(): Job = scope.launch {
|
2019-01-13 07:37:23 -08:00
|
|
|
// val downloadedBlockChannel = downloader.blocks()
|
|
|
|
// while (isActive) {
|
|
|
|
// try {
|
|
|
|
// val nextBlock = downloadedBlockChannel.receive()
|
|
|
|
// cacheDao.insert(cash.z.wallet.sdk.vo.CompactBlock(nextBlock.height.toInt(), nextBlock.toByteArray()))
|
|
|
|
// async {
|
|
|
|
// savedBlockChannel.send(Result.success(nextBlock))
|
|
|
|
// debug("stored block at height: ${nextBlock.height}")
|
|
|
|
// }
|
|
|
|
// } catch (t: Throwable) {
|
|
|
|
// debug("failed to store block due to $t")
|
|
|
|
// async {
|
|
|
|
// savedBlockChannel.send(Result.failure(t))
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// }
|
2019-01-02 21:31:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun scanBlocks(): Job = scope.launch {
|
|
|
|
val savedBlocks = blocks()
|
|
|
|
val converter = JniConverter()
|
|
|
|
converter.initLogs()
|
|
|
|
ScanResultDbCreator.create(applicationContext)
|
|
|
|
while (isActive) {
|
|
|
|
try {
|
|
|
|
debug("scanning blocks from $birthday onward...")
|
2019-01-13 07:37:23 -08:00
|
|
|
val nextBlock = savedBlocks.receive()
|
2019-01-02 21:31:12 -08:00
|
|
|
debug("...scanner observed a block (${nextBlock.height}) without crashing!")
|
|
|
|
delay(5000L)
|
|
|
|
val result = converter.scanBlocks(
|
|
|
|
applicationContext.getDatabasePath(CACHEDB_NAME).absolutePath,
|
|
|
|
applicationContext.getDatabasePath(ScanResultDbCreator.DB_NAME).absolutePath,
|
|
|
|
"dummyseed".toByteArray(),
|
|
|
|
birthday.toInt()
|
|
|
|
)
|
|
|
|
debug("scan complete")
|
|
|
|
} catch (t: Throwable) {
|
|
|
|
debug("error while scanning blocks: $t")
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
const val CACHEDB_NAME = "DownloadedCompactBlocks.db"
|
|
|
|
}
|
|
|
|
}
|