diff --git a/.editorconfig b/.editorconfig index 93957cf20..559ee7e0e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,5 +9,8 @@ trim_trailing_whitespace = true insert_final_newline = true end_of_line = lf -# ktlint -disabled_rules = no-wildcard-imports, import-ordering, max-line-length, no-unused-imports +ktlint_standard_no-wildcard-imports = disabled +ktlint_standard_trailing-comma-on-call-site = disabled +ktlint_standard_trailing-comma-on-declaration-site = disabled +ktlint_standard_import-ordering = disabled +ktlint_function_naming_ignore_when_annotated_with = Composable diff --git a/.github/workflows/apk_main.yml b/.github/workflows/apk_main.yml index f569958b5..5b6984209 100644 --- a/.github/workflows/apk_main.yml +++ b/.github/workflows/apk_main.yml @@ -15,9 +15,10 @@ jobs: - uses: ./.github/actions/checkout_submodules - name: Setup Java - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: - java-version: 11 + distribution: 'zulu' + java-version: '17' - name: Build release APK run: | diff --git a/.github/workflows/apk_pr.yml b/.github/workflows/apk_pr.yml index 643254c7f..50f4061c3 100644 --- a/.github/workflows/apk_pr.yml +++ b/.github/workflows/apk_pr.yml @@ -18,9 +18,10 @@ jobs: - uses: ./.github/actions/checkout_submodules - name: Setup Java - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: - java-version: 11 + distribution: 'zulu' + java-version: '17' - name: Build release APK run: | diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9e1666b0a..d86675c17 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,8 @@ on: jobs: test: name: Run Tests - runs-on: ubuntu-latest + # TODO: Ubuntu currently broken. + runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v2 @@ -16,12 +17,20 @@ jobs: - uses: ./.github/actions/checkout_submodules - name: Setup Java - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: - java-version: 11 + distribution: 'zulu' + java-version: '17' + + # TODO: This is currently broken due to SqlDelight. + # - name: Run check + # run: bash ./gradlew check - name: Run tests - run: bash ./gradlew check + run: bash ./gradlew test + + - name: Run lint + run: bash ./gradlew ktlintCheck - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 diff --git a/README.md b/README.md index 58c8ae25a..33cfa6b9f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# TrustChain Super App [![Build Status](https://github.com/Tribler/trustchain-superapp/workflows/build/badge.svg)](https://github.com/Tribler/trustchain-superapp/actions) +# TrustChain Super App +[![Build Status](https://github.com/Tribler/trustchain-superapp/workflows/build/badge.svg)](https://github.com/Tribler/trustchain-superapp/actions) [![ktlint](https://img.shields.io/badge/ktlint%20code--style-%E2%9D%A4-FF4081)](https://pinterest.github.io/ktlint/) This repository contains a collection of Android apps built on top of [IPv8](https://github.com/MattSkala/kotlin-ipv8) (our P2P networking stack) and [TrustChain](https://github.com/Tribler/kotlin-ipv8/blob/master/doc/TrustChainCommunity.md) (a scalable, distributed, pair-wise ledger). All applications are built into a single APK, following the concept of [super apps](https://home.kpmg/xx/en/home/insights/2019/06/super-app-or-super-disruption.html) – an emerging trend that allows to provide an ecosystem for multiple services within a single all-in-one app experience. @@ -134,6 +135,7 @@ Run unit tests: ``` ./gradlew test ``` +*Note: Currently tests fail on Linux, but pass on Windows and Mac. This is due to the tests relying on a native jlibtorrent binary, of which the linux version cannot be bundled with android builds. We are working on a solution to this problem.* Run instrumented tests: ``` @@ -142,7 +144,7 @@ Run instrumented tests: ## Code style -[Ktlint](https://ktlint.github.io/) is used to enforce a consistent code style across the whole project. +[Ktlint](https://ktlint.github.io/) is used to enforce a consistent code style across the whole project. It is recommended to install the [ktlint plugin](https://plugins.jetbrains.com/plugin/15057-ktlint) for your IDE to get real-time feedback. Check code style: ``` diff --git a/app/build.gradle b/app/build.gradle index 75524eee5..46b1543a7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,5 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' apply plugin: 'androidx.navigation.safeargs' apply plugin: 'org.jlleitschuh.gradle.ktlint' apply plugin: 'com.google.gms.google-services' @@ -27,6 +26,7 @@ ktlint { android = true outputToConsole = true ignoreFailures = false + verbose = true } // Generate a version code from git commit count @@ -36,12 +36,11 @@ static def generateVersionCode() { android { - compileSdkVersion 33 - defaultConfig { applicationId "nl.tudelft.trustchain" - minSdkVersion 24 - targetSdkVersion 33 + minSdkVersion 26 + compileSdk 34 + targetSdkVersion 34 versionCode generateVersionCode() versionName "0.3.3" @@ -59,6 +58,8 @@ android { sourceSets { main { + // TODO: Find a way to exclude linux .so + // TODO: Reintroduce the jlibtorrent library for linux. jniLibs.srcDirs = ['../common/libs'] } } @@ -69,17 +70,19 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' signingConfig signingConfigs.release } + debug { + applicationIdSuffix ".debug" + versionNameSuffix "-debug" + } } - // To inline the bytecode built with JVM target 1.8 into - // bytecode that is being built with JVM target 1.6. (e.g. navArgs) compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_17.toString() } buildFeatures { @@ -91,7 +94,6 @@ android { } } - ndkVersion '21.4.7075529' namespace 'nl.tudelft.trustchain.app' } @@ -189,7 +191,7 @@ dependencies { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { kotlinOptions.freeCompilerArgs += [ - "-opt-in=kotlin.Experimental,kotlin.ExperimentalUnsignedTypes", - "-opt-in=kotlin.RequiresOptIn" + "-opt-in=kotlin.ExperimentalUnsignedTypes", + "-opt-in=kotlin.RequiresOptIn" ] } diff --git a/app/src/debug/google-services.json b/app/src/debug/google-services.json new file mode 100644 index 000000000..dba66bd94 --- /dev/null +++ b/app/src/debug/google-services.json @@ -0,0 +1,40 @@ +{ + "project_info": { + "project_number": "327016605343", + "firebase_url": "https://trustchain-superapp.firebaseio.com", + "project_id": "trustchain-superapp", + "storage_bucket": "trustchain-superapp.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:327016605343:android:3055eb92f8bea31f5ae4aa", + "android_client_info": { + "package_name": "nl.tudelft.trustchain.debug" + } + }, + "oauth_client": [ + { + "client_id": "327016605343-rkvebn5hatrighvkr3ea8gn0br7d7f9d.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyAUq3-O12VR884jokteVn14yiXDeckIxAQ" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "327016605343-rkvebn5hatrighvkr3ea8gn0br7d7f9d.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 031c05c58..fbc9b0f6c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,6 +14,12 @@ + + + + @@ -80,7 +86,7 @@ android:theme="@style/Theme.PeerChat" /> @@ -130,7 +136,8 @@ + android:exported="false" + android:foregroundServiceType="dataSync" /> , private val firstRun: Boolean = false ) { - val preferredApps: List get() = apps.filter { it.isPreferred } var apps: Set @@ -26,12 +25,13 @@ class AppLoader( setPreferredAppList(DEFAULT_APPS) } else { val pApps = getPreferredAppList() - apps = AppDefinition.values().map { app -> - DashboardItem( - app, - isPreferred = pApps.contains(app.appName) - ) - }.toSet() + apps = + AppDefinition.values().map { app -> + DashboardItem( + app, + isPreferred = pApps.contains(app.appName) + ) + }.toSet() } } } @@ -49,10 +49,11 @@ class AppLoader( } private suspend fun getPreferredAppList(): Set { - val preferredApps: Flow> = dataStore.data - .map { preferences -> - preferences[PREFERRED_APPS] ?: emptySet() - } + val preferredApps: Flow> = + dataStore.data + .map { preferences -> + preferences[PREFERRED_APPS] ?: emptySet() + } preferredApps.first().let { return it } @@ -69,12 +70,13 @@ class AppLoader( companion object { val PREFERRED_APPS = stringSetPreferencesKey("preferred_apps") - val DEFAULT_APPS = setOf( - AppDefinition.CURRENCY_II.appName, - AppDefinition.VALUETRANSFER.appName, - AppDefinition.MUSIC_DAO.appName, - AppDefinition.EUROTOKEN.appName, - AppDefinition.FREEDOM_OF_COMPUTING.appName - ) + val DEFAULT_APPS = + setOf( + AppDefinition.CURRENCY_II.appName, + AppDefinition.VALUETRANSFER.appName, + AppDefinition.MUSIC_DAO.appName, + AppDefinition.EUROTOKEN.appName, + AppDefinition.FREEDOM_OF_COMPUTING.appName + ) } } diff --git a/app/src/main/java/nl/tudelft/trustchain/app/TrustChainApplication.kt b/app/src/main/java/nl/tudelft/trustchain/app/TrustChainApplication.kt index ea4a19357..126eab19d 100644 --- a/app/src/main/java/nl/tudelft/trustchain/app/TrustChainApplication.kt +++ b/app/src/main/java/nl/tudelft/trustchain/app/TrustChainApplication.kt @@ -5,7 +5,6 @@ import android.bluetooth.BluetoothManager import android.content.Context import android.os.Build import android.util.Log -import androidx.annotation.RequiresApi import androidx.core.content.getSystemService import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences @@ -13,8 +12,8 @@ import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.preferencesDataStore import androidx.preference.PreferenceManager -import com.squareup.sqldelight.android.AndroidSqliteDriver -import com.squareup.sqldelight.db.SqlDriver +import app.cash.sqldelight.db.SqlDriver +import app.cash.sqldelight.driver.android.AndroidSqliteDriver import dagger.hilt.android.HiltAndroidApp import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope @@ -53,7 +52,7 @@ import nl.tudelft.ipv8.peerdiscovery.strategy.RandomWalk import nl.tudelft.ipv8.sqldelight.Database import nl.tudelft.ipv8.util.hexToBytes import nl.tudelft.ipv8.util.toHex -import nl.tudelft.trustchain.FOC.community.FOCCommunity +import nl.tudelft.trustchain.foc.community.FOCCommunity import nl.tudelft.trustchain.app.service.TrustChainService import nl.tudelft.trustchain.common.DemoCommunity import nl.tudelft.trustchain.common.MarketCommunity @@ -76,45 +75,45 @@ val Context.dataStore: DataStore by preferencesDataStore(name = "se @ExperimentalUnsignedTypes @HiltAndroidApp class TrustChainApplication : Application() { - var isFirstRun: Boolean = false lateinit var appLoader: AppLoader - @RequiresApi(Build.VERSION_CODES.M) - override fun onCreate() = runBlocking { - super.onCreate() - launch { - isFirstRun = checkFirstRun() - appLoader = AppLoader(dataStore, isFirstRun) - } - defaultCryptoProvider = AndroidCryptoProvider + override fun onCreate() = + runBlocking { + super.onCreate() + launch { + isFirstRun = checkFirstRun() + appLoader = AppLoader(dataStore, isFirstRun) + } + defaultCryptoProvider = AndroidCryptoProvider - // Only start IPv8 here if we are on Android 11 or below. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { - initIPv8() + // Only start IPv8 here if we are on Android 11 or below. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + initIPv8() + } } - } - @RequiresApi(Build.VERSION_CODES.M) fun initIPv8() { - val config = IPv8Configuration( - overlays = listOf( - createDiscoveryCommunity(), - createTrustChainCommunity(), - createPeerChatCommunity(), - createEuroTokenCommunity(), - createTFTPCommunity(), - createDemoCommunity(), - createWalletCommunity(), - createMarketCommunity(), - createCoinCommunity(), - createDaoCommunity(), - createMusicCommunity(), - createIdentityCommunity(), - createFOCCommunity(), - ), - walkerInterval = 5.0 - ) + val config = + IPv8Configuration( + overlays = + listOf( + createDiscoveryCommunity(), + createTrustChainCommunity(), + createPeerChatCommunity(), + createEuroTokenCommunity(), + createTFTPCommunity(), + createDemoCommunity(), + createWalletCommunity(), + createMarketCommunity(), + createCoinCommunity(), + createDaoCommunity(), + createMusicCommunity(), + createIdentityCommunity(), + createFOCCommunity(), + ), + walkerInterval = 5.0 + ) IPv8Android.Factory(this) .setConfiguration(config) @@ -227,12 +226,17 @@ class TrustChainApplication : Application() { val periodicSimilarity = PeriodicSimilarity.Factory() val nsd = NetworkServiceDiscovery.Factory(getSystemService()!!) - val bluetoothManager = getSystemService() - ?: throw IllegalStateException("BluetoothManager not available") - val strategies = mutableListOf( - randomWalk, randomChurn, periodicSimilarity, nsd - ) - if (bluetoothManager.adapter != null && Build.VERSION.SDK_INT >= 24) { + val bluetoothManager = + getSystemService() + ?: throw IllegalStateException("BluetoothManager not available") + val strategies = + mutableListOf( + randomWalk, + randomChurn, + periodicSimilarity, + nsd + ) + if (bluetoothManager.adapter != null) { val ble = BluetoothLeDiscovery.Factory() strategies += ble } @@ -382,13 +386,15 @@ class TrustChainApplication : Application() { } private suspend fun checkFirstRun(): Boolean { - val key = booleanPreferencesKey( - FIRST_RUN - ) - val preferredApps: Flow = dataStore.data - .map { preferences -> - preferences[key] ?: true - } + val key = + booleanPreferencesKey( + FIRST_RUN + ) + val preferredApps: Flow = + dataStore.data + .map { preferences -> + preferences[key] ?: true + } val firstRun = preferredApps.first() diff --git a/app/src/main/java/nl/tudelft/trustchain/app/service/TrustChainService.kt b/app/src/main/java/nl/tudelft/trustchain/app/service/TrustChainService.kt index dd4af6e29..bceee139b 100644 --- a/app/src/main/java/nl/tudelft/trustchain/app/service/TrustChainService.kt +++ b/app/src/main/java/nl/tudelft/trustchain/app/service/TrustChainService.kt @@ -2,25 +2,20 @@ package nl.tudelft.trustchain.app.service import android.app.PendingIntent import android.content.Intent -import android.os.Build import androidx.core.app.NotificationCompat import androidx.core.app.TaskStackBuilder -import androidx.annotation.RequiresApi import nl.tudelft.ipv8.android.service.IPv8Service import nl.tudelft.trustchain.app.R import nl.tudelft.trustchain.app.ui.dashboard.DashboardActivity -@RequiresApi(Build.VERSION_CODES.M) class TrustChainService : IPv8Service() { override fun createNotification(): NotificationCompat.Builder { val trustChainDashboardIntent = Intent(this, DashboardActivity::class.java) - val flags = when { - Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - else -> PendingIntent.FLAG_UPDATE_CURRENT - } - val pendingIntent = TaskStackBuilder.create(this) - .addNextIntentWithParentStack(trustChainDashboardIntent) - .getPendingIntent(0, flags) + val flags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + val pendingIntent = + TaskStackBuilder.create(this) + .addNextIntentWithParentStack(trustChainDashboardIntent) + .getPendingIntent(0, flags) return NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_CONNECTION) .setContentTitle("IPv8") diff --git a/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardActivity.kt b/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardActivity.kt index 33de16945..f0bab6d73 100644 --- a/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardActivity.kt +++ b/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardActivity.kt @@ -7,7 +7,6 @@ import android.net.Uri import android.os.Build import android.os.Bundle import android.provider.Settings -import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.GridLayoutManager import com.mattskala.itemadapter.ItemAdapter @@ -17,19 +16,11 @@ import nl.tudelft.trustchain.app.TrustChainApplication import nl.tudelft.trustchain.app.databinding.ActivityDashboardBinding import nl.tudelft.trustchain.common.util.viewBinding -@RequiresApi(Build.VERSION_CODES.M) class DashboardActivity : AppCompatActivity() { private val binding by viewBinding(ActivityDashboardBinding::inflate) private val adapter = ItemAdapter() - private val BLUETOOTH_PERMISSIONS_REQUEST_CODE = 200 - private val SETTINGS_INTENT_CODE = 1000 - - private val BLUETOOTH_PERMISSIONS_SCAN = "android.permission.BLUETOOTH_SCAN" - private val BLUETOOTH_PERMISSIONS_CONNECT = "android.permission.BLUETOOTH_CONNECT" - private val BLUETOOTH_PERMISSIONS_ADVERTISE = "android.permission.BLUETOOTH_ADVERTISE" - override fun onResume() { super.onResume() adapter.updateItems((application as TrustChainApplication).appLoader.preferredApps) @@ -75,19 +66,19 @@ class DashboardActivity : AppCompatActivity() { } private fun hasBluetoothPermissions(): Boolean { - return checkSelfPermission(BLUETOOTH_PERMISSIONS_ADVERTISE) == PackageManager.PERMISSION_GRANTED && - checkSelfPermission(BLUETOOTH_PERMISSIONS_CONNECT) == PackageManager.PERMISSION_GRANTED && - checkSelfPermission(BLUETOOTH_PERMISSIONS_SCAN) == PackageManager.PERMISSION_GRANTED + return checkSelfPermission(Companion.BLUETOOTH_PERMISSIONS_ADVERTISE) == PackageManager.PERMISSION_GRANTED && + checkSelfPermission(Companion.BLUETOOTH_PERMISSIONS_CONNECT) == PackageManager.PERMISSION_GRANTED && + checkSelfPermission(Companion.BLUETOOTH_PERMISSIONS_SCAN) == PackageManager.PERMISSION_GRANTED } private fun requestBluetoothPermissions() { requestPermissions( arrayOf( - BLUETOOTH_PERMISSIONS_ADVERTISE, - BLUETOOTH_PERMISSIONS_CONNECT, - BLUETOOTH_PERMISSIONS_SCAN + Companion.BLUETOOTH_PERMISSIONS_ADVERTISE, + Companion.BLUETOOTH_PERMISSIONS_CONNECT, + Companion.BLUETOOTH_PERMISSIONS_SCAN ), - BLUETOOTH_PERMISSIONS_REQUEST_CODE + Companion.BLUETOOTH_PERMISSIONS_REQUEST_CODE ) } @@ -97,7 +88,7 @@ class DashboardActivity : AppCompatActivity() { grantResults: IntArray ) { when (requestCode) { - BLUETOOTH_PERMISSIONS_REQUEST_CODE -> { + Companion.BLUETOOTH_PERMISSIONS_REQUEST_CODE -> { if (hasBluetoothPermissions()) { (application as TrustChainApplication).initIPv8() } else { @@ -109,9 +100,13 @@ class DashboardActivity : AppCompatActivity() { } @Suppress("DEPRECATION") - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + override fun onActivityResult( + requestCode: Int, + resultCode: Int, + data: Intent? + ) { when (requestCode) { - SETTINGS_INTENT_CODE -> { + Companion.SETTINGS_INTENT_CODE -> { if (hasBluetoothPermissions()) { (application as TrustChainApplication).initIPv8() } else { @@ -138,11 +133,19 @@ class DashboardActivity : AppCompatActivity() { val uri: Uri = Uri.fromParts("package", packageName, null) intent.data = uri @Suppress("DEPRECATION") // TODO: Fix deprecation issue. - startActivityForResult(intent, SETTINGS_INTENT_CODE) + startActivityForResult(intent, Companion.SETTINGS_INTENT_CODE) } }.create() } .show() .setCanceledOnTouchOutside(false) } + + companion object { + private const val BLUETOOTH_PERMISSIONS_REQUEST_CODE = 200 + private const val SETTINGS_INTENT_CODE = 1000 + private const val BLUETOOTH_PERMISSIONS_SCAN = "android.permission.BLUETOOTH_SCAN" + private const val BLUETOOTH_PERMISSIONS_CONNECT = "android.permission.BLUETOOTH_CONNECT" + private const val BLUETOOTH_PERMISSIONS_ADVERTISE = "android.permission.BLUETOOTH_ADVERTISE" + } } diff --git a/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardItemRenderer.kt b/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardItemRenderer.kt index c078c9d3f..34d853791 100644 --- a/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardItemRenderer.kt +++ b/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardItemRenderer.kt @@ -8,10 +8,13 @@ import nl.tudelft.trustchain.app.databinding.ItemDashboardBinding class DashboardItemRenderer( private val onItemClick: (DashboardItem) -> Unit ) : BindingItemRenderer( - DashboardItem::class.java, - ItemDashboardBinding::inflate -) { - override fun bindView(item: DashboardItem, binding: ItemDashboardBinding) { + DashboardItem::class.java, + ItemDashboardBinding::inflate + ) { + override fun bindView( + item: DashboardItem, + binding: ItemDashboardBinding + ) { val context = binding.root.context val color = ResourcesCompat.getColor(context.resources, item.app.color, null) binding.imgIcon.setImageResource(item.app.icon) diff --git a/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardSelectorActivity.kt b/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardSelectorActivity.kt index 6ef0fc234..24521be3e 100644 --- a/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardSelectorActivity.kt +++ b/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardSelectorActivity.kt @@ -13,27 +13,28 @@ class DashboardSelectorActivity : AppCompatActivity() { private val binding by viewBinding(FragmentDashboardSelectorBinding::inflate) private val adapter = ItemAdapter() - override fun onCreate(savedInstanceState: Bundle?) = runBlocking { - super.onCreate(savedInstanceState) - title = "Projects" + override fun onCreate(savedInstanceState: Bundle?) = + runBlocking { + super.onCreate(savedInstanceState) + title = "Projects" - adapter.registerRenderer( - DashboardSelectorRenderer { item, isChecked -> - runBlocking { - if (isChecked) { - (application as TrustChainApplication).appLoader.setPreferredApp(item.app.appName) - } else { - (application as TrustChainApplication).appLoader.removePreferredApp(item.app.appName) + adapter.registerRenderer( + DashboardSelectorRenderer { item, isChecked -> + runBlocking { + if (isChecked) { + (application as TrustChainApplication).appLoader.setPreferredApp(item.app.appName) + } else { + (application as TrustChainApplication).appLoader.removePreferredApp(item.app.appName) + } } } - } - ) + ) - setContentView(binding.root) - val layoutManager = GridLayoutManager(baseContext, 3) - binding.recyclerView.layoutManager = layoutManager - binding.recyclerView.adapter = adapter + setContentView(binding.root) + val layoutManager = GridLayoutManager(baseContext, 3) + binding.recyclerView.layoutManager = layoutManager + binding.recyclerView.adapter = adapter - adapter.updateItems((application as TrustChainApplication).appLoader.apps.toList()) - } + adapter.updateItems((application as TrustChainApplication).appLoader.apps.toList()) + } } diff --git a/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardSelectorRenderer.kt b/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardSelectorRenderer.kt index a9cc09009..9427555e2 100644 --- a/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardSelectorRenderer.kt +++ b/app/src/main/java/nl/tudelft/trustchain/app/ui/dashboard/DashboardSelectorRenderer.kt @@ -8,10 +8,13 @@ import nl.tudelft.trustchain.app.databinding.ItemSelectorBinding class DashboardSelectorRenderer( private val onItemClick: (DashboardItem, Boolean) -> Unit ) : BindingItemRenderer( - DashboardItem::class.java, - ItemSelectorBinding::inflate -) { - override fun bindView(item: DashboardItem, binding: ItemSelectorBinding) { + DashboardItem::class.java, + ItemSelectorBinding::inflate + ) { + override fun bindView( + item: DashboardItem, + binding: ItemSelectorBinding + ) { val context = binding.root.context val color = ResourcesCompat.getColor(context.resources, item.app.color, null) binding.imgIcon.setImageResource(item.app.icon) diff --git a/build.gradle b/build.gradle index e85726cf9..011904995 100644 --- a/build.gradle +++ b/build.gradle @@ -1,18 +1,19 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.7.10' - ext.ktlint_version = '0.44.0' + ext.kotlin_version = '1.9.22' ext.coroutines_version = '1.6.4' - ext.ktlint_gradle_version = '11.0.0' - ext.sqldelight_version = '1.5.2' + ext.ktlint_version = '1.1.1' + ext.ktlint_gradle_version = '12.1.0' + ext.sqldelight_version = '2.0.1' ext.nav_version = '2.5.3' ext.fragment_version = '1.5.4' ext.lifecycle_version = "2.5.1" - ext.jlibtorrent_version = '1.2.17.0' + ext.jlibtorrent_version = '1.2.19.0' ext.dokka_version = "0.10.1" - ext.hilt_ver = '2.44.2' - ext.room_version = '2.4.0' + ext.hilt_ver = '2.50' + ext.room_version = '2.6.1' + ext.mockk_version = '1.13.9' repositories { google() jcenter() @@ -21,10 +22,10 @@ buildscript { maven { url 'https://jitpack.io' } } dependencies { - classpath 'com.android.tools.build:gradle:7.3.1' + classpath 'com.android.tools.build:gradle:8.2.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jlleitschuh.gradle:ktlint-gradle:$ktlint_gradle_version" - classpath "com.squareup.sqldelight:gradle-plugin:$sqldelight_version" + classpath "app.cash.sqldelight:gradle-plugin:$sqldelight_version" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" classpath 'com.google.gms:google-services:4.3.14' diff --git a/common-bitcoin/build.gradle b/common-bitcoin/build.gradle index 5f3ba4910..92ed14c58 100644 --- a/common-bitcoin/build.gradle +++ b/common-bitcoin/build.gradle @@ -1,14 +1,22 @@ plugins { id 'com.android.library' id 'org.jetbrains.kotlin.android' + id 'org.jlleitschuh.gradle.ktlint' } -android { - compileSdkVersion 33 +ktlint { + version = "$ktlint_version" + android = true + outputToConsole = true + ignoreFailures = false + verbose = true +} +android { defaultConfig { - minSdkVersion 24 - targetSdkVersion 33 + minSdkVersion 26 + compileSdk 34 + targetSdkVersion 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -22,11 +30,11 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = JavaVersion.VERSION_17.toString() allWarningsAsErrors = true } namespace 'com.example.common.bitcoin' diff --git a/common-bitcoin/src/main/java/nl/tudelft/trustchain/common/bitcoin/BitcoinMultiSigWallet.kt b/common-bitcoin/src/main/java/nl/tudelft/trustchain/common/bitcoin/BitcoinMultiSigWallet.kt index fce497a9b..2e66db9c3 100644 --- a/common-bitcoin/src/main/java/nl/tudelft/trustchain/common/bitcoin/BitcoinMultiSigWallet.kt +++ b/common-bitcoin/src/main/java/nl/tudelft/trustchain/common/bitcoin/BitcoinMultiSigWallet.kt @@ -31,7 +31,10 @@ class BitcoinMultiSigWallet( return transaction } - fun startWithdraw(value: Coin, receiveAddress: Address): Transaction { + fun startWithdraw( + value: Coin, + receiveAddress: Address + ): Transaction { val transaction = Transaction(params) val relayValue = Coin.valueOf(1000) @@ -60,7 +63,10 @@ class BitcoinMultiSigWallet( return transaction } - fun endWithdraw(transaction: Transaction, signatures: List): Transaction { + fun endWithdraw( + transaction: Transaction, + signatures: List + ): Transaction { for (transactionInput in transaction.inputs) { transactionInput.scriptSig = ScriptBuilder.createMultiSigInputScript(signatures) } @@ -71,7 +77,8 @@ class BitcoinMultiSigWallet( fun hash(transaction: Transaction): List { val transactionHashes = mutableListOf() transaction.inputs.forEachIndexed { index, _ -> - val transactionHash = transaction.hashForSignature(index, outputScript, Transaction.SigHash.ALL, false) + val transactionHash = + transaction.hashForSignature(index, outputScript, Transaction.SigHash.ALL, false) transactionHashes.add(transactionHash) } return transactionHashes diff --git a/common-ethereum/build.gradle b/common-ethereum/build.gradle index c3d960889..af09a5029 100644 --- a/common-ethereum/build.gradle +++ b/common-ethereum/build.gradle @@ -1,20 +1,22 @@ plugins { id 'com.android.library' id 'org.jetbrains.kotlin.android' + id 'org.jlleitschuh.gradle.ktlint' } -android { - compileSdkVersion 33 - - sourceSets { - main { - jniLibs.srcDirs = ['../common/libs'] - } - } +ktlint { + version = "$ktlint_version" + android = true + outputToConsole = true + ignoreFailures = false + verbose = true +} +android { defaultConfig { - minSdkVersion 24 - targetSdkVersion 33 + minSdkVersion 26 + compileSdk 34 + targetSdkVersion 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -34,15 +36,21 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } + kotlinOptions { - jvmTarget = '1.8' + jvmTarget = JavaVersion.VERSION_17.toString() allWarningsAsErrors = true } + namespace 'nl.tudelft.trustchain.common.ethereum' + buildFeatures { + buildConfig true + } } dependencies { diff --git a/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumGethMultiSigWallet.kt b/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumGethMultiSigWallet.kt index c8a175e03..31459a3b5 100644 --- a/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumGethMultiSigWallet.kt +++ b/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumGethMultiSigWallet.kt @@ -1,7 +1,6 @@ package nl.tudelft.trustchain.common.ethereum import kotlinx.coroutines.delay -import nl.tudelft.trustchain.common.ethereum.BuildConfig import nl.tudelft.trustchain.common.ethereum.contracts.geth.MultiSigWallet import org.ethereum.geth.* @@ -38,8 +37,16 @@ class EthereumGethMultiSigWallet(gethWallet: EthereumGethWallet) { return gethNode.peersInfo.size() > 0L } - class MySigner(private val account: Account?, private val keyStore: KeyStore?, private val password: String?, private val chainId: BigInt?) : Signer { - override fun sign(address: Address?, transaction: Transaction?): Transaction { + class MySigner( + private val account: Account?, + private val keyStore: KeyStore?, + private val password: String?, + private val chainId: BigInt? + ) : Signer { + override fun sign( + address: Address?, + transaction: Transaction? + ): Transaction { return keyStore!!.signTxPassphrase(account, password, transaction, chainId) } } diff --git a/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumGethWallet.kt b/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumGethWallet.kt index 12bdc8a5a..5433e1dec 100644 --- a/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumGethWallet.kt +++ b/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumGethWallet.kt @@ -2,7 +2,13 @@ package nl.tudelft.trustchain.common.ethereum import org.ethereum.geth.* -class EthereumGethWallet(val nodeConfig: NodeConfig, keyFile: String, nodeDirectory: String, keyStoreDirectory: String, val password: String) { +class EthereumGethWallet( + val nodeConfig: NodeConfig, + keyFile: String, + nodeDirectory: String, + keyStoreDirectory: String, + val password: String +) { val context: Context = Geth.newContext() val node: Node val keyStore: KeyStore @@ -13,11 +19,12 @@ class EthereumGethWallet(val nodeConfig: NodeConfig, keyFile: String, nodeDirect node.start() // Initialize the keystore. - keyStore = KeyStore( - keyStoreDirectory, - Geth.LightScryptN, - Geth.LightScryptP - ) + keyStore = + KeyStore( + keyStoreDirectory, + Geth.LightScryptN, + Geth.LightScryptP + ) // Remove all existing accounts. for (i in keyStore.accounts.size() - 1 downTo 0) { @@ -37,15 +44,25 @@ class EthereumGethWallet(val nodeConfig: NodeConfig, keyFile: String, nodeDirect return node.ethereumClient.getBalanceAt(context, getAddress(), -1) } - fun sendTo(address: Address, amount: BigInt) { - val transaction = Transaction( - node.ethereumClient.getPendingNonceAt(context, getAddress()), // Nonce. - address, // Receive address. - amount, // Amount. - 10000000, // Gas limit. - BigInt(1), // Gas price. - ByteArray(0) - ) // Data. + fun sendTo( + address: Address, + amount: BigInt + ) { + val transaction = + // Data. + Transaction( + // Nonce. + node.ethereumClient.getPendingNonceAt(context, getAddress()), + // Receive address. + address, + // Amount. + amount, + // Gas limit. + 10000000, + BigInt(1), + // Gas price. + ByteArray(0) + ) val signedTransaction = sign(transaction) send(signedTransaction) } diff --git a/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumWalletService.kt b/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumWalletService.kt index 9cbe31631..7b5d820f3 100644 --- a/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumWalletService.kt +++ b/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumWalletService.kt @@ -11,9 +11,7 @@ import java.math.BigInteger import java.security.SecureRandom class EthereumWalletService { - companion object { - private var globalWeb3jWallet: EthereumWeb3jWallet? = null private var lastDir: File? = null @@ -50,12 +48,13 @@ class EthereumWalletService { ) // Create wallet - globalWeb3jWallet = EthereumWeb3jWallet( - web3j, - context.cacheDir, - getWalletKeys(context), - getWalletPassword(context) - ) + globalWeb3jWallet = + EthereumWeb3jWallet( + web3j, + context.cacheDir, + getWalletKeys(context), + getWalletPassword(context) + ) return globalWeb3jWallet!! } @@ -65,7 +64,7 @@ class EthereumWalletService { private const val SHARED_PREF_KEY_PUBLIC_KEY = "web3j_wallet_public_key" private fun getWalletPassword(context: Context): String { - val preferences = context.getSharedPreferences("web3j_wallet", Context.MODE_PRIVATE); + val preferences = context.getSharedPreferences("web3j_wallet", Context.MODE_PRIVATE) var password = preferences.getString(SHARED_PREF_KEY_WALLET_PASSWORD, null) if (password == null) { @@ -84,7 +83,7 @@ class EthereumWalletService { } private fun getWalletKeys(context: Context): ECKeyPair { - val preferences = context.getSharedPreferences("web3j_wallet", Context.MODE_PRIVATE); + val preferences = context.getSharedPreferences("web3j_wallet", Context.MODE_PRIVATE) val privateKey = preferences.getString(SHARED_PREF_KEY_PRIVATE_KEY, null) val publicKey = preferences.getString(SHARED_PREF_KEY_PUBLIC_KEY, null) @@ -106,7 +105,5 @@ class EthereumWalletService { ECKeyPair(BigInteger(privateKey), BigInteger(publicKey)) } } - } - } diff --git a/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumWeb3jMultiSigWallet.kt b/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumWeb3jMultiSigWallet.kt index 0426b35d7..6444167bf 100644 --- a/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumWeb3jMultiSigWallet.kt +++ b/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumWeb3jMultiSigWallet.kt @@ -6,7 +6,11 @@ import org.web3j.protocol.core.DefaultBlockParameter import org.web3j.tx.gas.StaticGasProvider import java.math.BigInteger -class EthereumWeb3jMultiSigWallet(val web3j: Web3j, val address: String, wallet: EthereumWeb3jWallet) { +class EthereumWeb3jMultiSigWallet( + val web3j: Web3j, + val address: String, + wallet: EthereumWeb3jWallet +) { var credentials = wallet.credentials var contractGasProvider = StaticGasProvider(BigInteger.valueOf(4), BigInteger.valueOf(8000000)) private var contractBound: Boolean = false @@ -18,12 +22,20 @@ class EthereumWeb3jMultiSigWallet(val web3j: Web3j, val address: String, wallet: suspend fun balance(): BigInteger { ensureContractBound() - return web3j.ethGetBalance(boundMultiSigWallet.contractAddress, DefaultBlockParameter.valueOf("latest")).sendAsync().get().balance + return web3j.ethGetBalance( + boundMultiSigWallet.contractAddress, + DefaultBlockParameter.valueOf("latest") + ).sendAsync().get().balance } - suspend fun withdraw(destination: String, value: BigInteger): String { + suspend fun withdraw( + destination: String, + value: BigInteger + ): String { if (value > balance()) return "" - val receipt = boundMultiSigWallet.submitTransaction(destination, value, byteArrayOf()).sendAsync().get() + val receipt = + boundMultiSigWallet.submitTransaction(destination, value, byteArrayOf()).sendAsync() + .get() return receipt.transactionHash } diff --git a/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumWeb3jWallet.kt b/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumWeb3jWallet.kt index 6a3720b91..485316f0e 100644 --- a/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumWeb3jWallet.kt +++ b/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/EthereumWeb3jWallet.kt @@ -14,7 +14,6 @@ class EthereumWeb3jWallet( keyPair: ECKeyPair, password: String ) { - val credentials: Credentials init { @@ -28,30 +27,38 @@ class EthereumWeb3jWallet( } fun balance(): BigInteger { - return web3j.ethGetBalance(credentials.address, DefaultBlockParameter.valueOf("latest")).sendAsync().get().balance + return web3j.ethGetBalance(credentials.address, DefaultBlockParameter.valueOf("latest")) + .sendAsync().get().balance } fun nonce(): BigInteger { - val ethGetTransactionCount = web3j.ethGetTransactionCount( - address(), DefaultBlockParameterName.LATEST - ).sendAsync().get() + val ethGetTransactionCount = + web3j.ethGetTransactionCount( + address(), + DefaultBlockParameterName.LATEST + ).sendAsync().get() return ethGetTransactionCount.transactionCount } - fun send(receiveAddress: String, value: BigInteger) { - val rawTransaction = RawTransaction.createEtherTransaction( - nonce(), - BigInteger.valueOf(4), - BigInteger.valueOf(8000000), - receiveAddress, - value - ) - val signedMessage = Numeric.toHexString( - TransactionEncoder.signMessage( - rawTransaction, - credentials + fun send( + receiveAddress: String, + value: BigInteger + ) { + val rawTransaction = + RawTransaction.createEtherTransaction( + nonce(), + BigInteger.valueOf(4), + BigInteger.valueOf(8000000), + receiveAddress, + value + ) + val signedMessage = + Numeric.toHexString( + TransactionEncoder.signMessage( + rawTransaction, + credentials + ) ) - ) web3j.ethSendRawTransaction(signedMessage).sendAsync().get() } } diff --git a/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/utils/WalletPasswordUtils.kt b/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/utils/WalletPasswordUtils.kt index c325d02d9..bb25da460 100644 --- a/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/utils/WalletPasswordUtils.kt +++ b/common-ethereum/src/main/java/nl/tudelft/trustchain/common/ethereum/utils/WalletPasswordUtils.kt @@ -5,7 +5,8 @@ import java.util.* private const val PASSWORD_LENGTH = 31 private val PASSWORD_CHAR_POOL: List = ('a'..'z') + ('A'..'Z') + ('0'..'9') + '!' -fun generateWalletPassword(random: Random) = (1..PASSWORD_LENGTH) - .map { random.nextInt(PASSWORD_CHAR_POOL.size) } - .map(PASSWORD_CHAR_POOL::get) - .joinToString("") +fun generateWalletPassword(random: Random) = + (1..PASSWORD_LENGTH) + .map { random.nextInt(PASSWORD_CHAR_POOL.size) } + .map(PASSWORD_CHAR_POOL::get) + .joinToString("") diff --git a/common-ethereum/src/test/java/nl/tudelft/trustchain/common/ethereum/WalletPasswordUtilsTest.kt b/common-ethereum/src/test/java/nl/tudelft/trustchain/common/ethereum/WalletPasswordUtilsTest.kt index 1c28f1012..c446edcd4 100644 --- a/common-ethereum/src/test/java/nl/tudelft/trustchain/common/ethereum/WalletPasswordUtilsTest.kt +++ b/common-ethereum/src/test/java/nl/tudelft/trustchain/common/ethereum/WalletPasswordUtilsTest.kt @@ -4,10 +4,9 @@ import nl.tudelft.trustchain.common.ethereum.utils.generateWalletPassword import org.junit.Test import java.security.SecureRandom -private const val PASSWORD_REGEX = "[a-zA-Z0-9!]+"; +private const val PASSWORD_REGEX = "[a-zA-Z0-9!]+" class WalletPasswordUtilsTest { - @Test fun generatedWalletPassword_isCorrect() { // given @@ -19,5 +18,4 @@ class WalletPasswordUtilsTest { // then assert(password.matches(Regex(PASSWORD_REGEX))) } - } diff --git a/common/build.gradle b/common/build.gradle index 24c3e2cc2..70c91471d 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,7 +1,6 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' -apply plugin: 'com.squareup.sqldelight' +apply plugin: 'app.cash.sqldelight' apply plugin: 'org.jlleitschuh.gradle.ktlint' ktlint { @@ -9,22 +8,24 @@ ktlint { android = true outputToConsole = true ignoreFailures = false + verbose = true } sqldelight { - Database { - packageName = "nl.tudelft.common.sqldelight" - sourceFolders = ["sqldelight"] - schemaOutputDirectory = file("src/main/sqldelight/databases") + databases { + Database { + packageName = "nl.tudelft.common.sqldelight" + srcDirs = files(['src/main/sqldelight']) + schemaOutputDirectory = file("src/main/sqldelight/databases") + } } } android { - compileSdkVersion 33 - defaultConfig { - minSdkVersion 24 - targetSdkVersion 33 + minSdkVersion 26 + compileSdk 34 + targetSdkVersion 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles 'consumer-rules.pro' @@ -53,16 +54,17 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_17.toString() allWarningsAsErrors = true } buildFeatures { viewBinding = true + buildConfig true } testOptions { @@ -124,15 +126,16 @@ dependencies { implementation files('libs/jlibtorrent-android-arm-' + jlibtorrent_version + '.jar') implementation files('libs/jlibtorrent-android-x86-' + jlibtorrent_version + '.jar') implementation files('libs/jlibtorrent-android-x86_64-' + jlibtorrent_version + '.jar') + implementation 'androidx.databinding:viewbinding:8.2.2' // Testing testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.3' - testImplementation "io.mockk:mockk:1.9.3" + testImplementation "io.mockk:mockk:$mockk_version" testImplementation 'org.json:json:20190722' - testImplementation "com.squareup.sqldelight:sqlite-driver:$sqldelight_version" + testImplementation "app.cash.sqldelight:sqlite-driver:$sqldelight_version" testImplementation "com.goterl:lazysodium-java:5.1.4" annotationProcessor "androidx.room:room-compiler:$room_version" } diff --git a/common/libs/jlibtorrent-1.2.17.0.jar b/common/libs/jlibtorrent-1.2.17.0.jar deleted file mode 100644 index 8a7a01f4d..000000000 Binary files a/common/libs/jlibtorrent-1.2.17.0.jar and /dev/null differ diff --git a/common/libs/jlibtorrent-1.2.19.0.dll b/common/libs/jlibtorrent-1.2.19.0.dll new file mode 100755 index 000000000..ae1230fa1 Binary files /dev/null and b/common/libs/jlibtorrent-1.2.19.0.dll differ diff --git a/common/libs/jlibtorrent-1.2.19.0.jar b/common/libs/jlibtorrent-1.2.19.0.jar new file mode 100644 index 000000000..54b1176c2 Binary files /dev/null and b/common/libs/jlibtorrent-1.2.19.0.jar differ diff --git a/common/libs/jlibtorrent-android-arm-1.2.17.0.jar b/common/libs/jlibtorrent-android-arm-1.2.17.0.jar deleted file mode 100644 index b0f0b3457..000000000 Binary files a/common/libs/jlibtorrent-android-arm-1.2.17.0.jar and /dev/null differ diff --git a/common/libs/jlibtorrent-android-arm-1.2.19.0.jar b/common/libs/jlibtorrent-android-arm-1.2.19.0.jar new file mode 100644 index 000000000..fa78f5328 Binary files /dev/null and b/common/libs/jlibtorrent-android-arm-1.2.19.0.jar differ diff --git a/common/libs/jlibtorrent-android-arm64-1.2.17.0.jar b/common/libs/jlibtorrent-android-arm64-1.2.17.0.jar deleted file mode 100644 index a1a402e2a..000000000 Binary files a/common/libs/jlibtorrent-android-arm64-1.2.17.0.jar and /dev/null differ diff --git a/common/libs/jlibtorrent-android-arm64-1.2.19.0.jar b/common/libs/jlibtorrent-android-arm64-1.2.19.0.jar new file mode 100644 index 000000000..e7f4b62b3 Binary files /dev/null and b/common/libs/jlibtorrent-android-arm64-1.2.19.0.jar differ diff --git a/common/libs/jlibtorrent-android-x86-1.2.17.0.jar b/common/libs/jlibtorrent-android-x86-1.2.17.0.jar deleted file mode 100644 index ea6db28db..000000000 Binary files a/common/libs/jlibtorrent-android-x86-1.2.17.0.jar and /dev/null differ diff --git a/common/libs/jlibtorrent-android-x86-1.2.19.0.jar b/common/libs/jlibtorrent-android-x86-1.2.19.0.jar new file mode 100644 index 000000000..477f74fb8 Binary files /dev/null and b/common/libs/jlibtorrent-android-x86-1.2.19.0.jar differ diff --git a/common/libs/jlibtorrent-android-x86_64-1.2.17.0.jar b/common/libs/jlibtorrent-android-x86_64-1.2.17.0.jar deleted file mode 100644 index 3475c76e6..000000000 Binary files a/common/libs/jlibtorrent-android-x86_64-1.2.17.0.jar and /dev/null differ diff --git a/common/libs/jlibtorrent-android-x86_64-1.2.19.0.jar b/common/libs/jlibtorrent-android-x86_64-1.2.19.0.jar new file mode 100644 index 000000000..9298d343a Binary files /dev/null and b/common/libs/jlibtorrent-android-x86_64-1.2.19.0.jar differ diff --git a/common/libs/jlibtorrent-linux-1.2.17.0.jar b/common/libs/jlibtorrent-linux-1.2.17.0.jar deleted file mode 100644 index 89397c3d1..000000000 Binary files a/common/libs/jlibtorrent-linux-1.2.17.0.jar and /dev/null differ diff --git a/common/libs/jlibtorrent-linux-1.2.19.0.jar b/common/libs/jlibtorrent-linux-1.2.19.0.jar new file mode 100644 index 000000000..ba220cd5f Binary files /dev/null and b/common/libs/jlibtorrent-linux-1.2.19.0.jar differ diff --git a/common/libs/jlibtorrent-macosx-arm64-1.2.19.0.jar b/common/libs/jlibtorrent-macosx-arm64-1.2.19.0.jar new file mode 100644 index 000000000..34dbfd5cf Binary files /dev/null and b/common/libs/jlibtorrent-macosx-arm64-1.2.19.0.jar differ diff --git a/common/libs/jlibtorrent-macosx-x86_64-1.2.19.0.jar b/common/libs/jlibtorrent-macosx-x86_64-1.2.19.0.jar new file mode 100644 index 000000000..63bb6b668 Binary files /dev/null and b/common/libs/jlibtorrent-macosx-x86_64-1.2.19.0.jar differ diff --git a/common/libs/jlibtorrent-windows-1.2.19.0.jar b/common/libs/jlibtorrent-windows-1.2.19.0.jar new file mode 100644 index 000000000..ee470259c Binary files /dev/null and b/common/libs/jlibtorrent-windows-1.2.19.0.jar differ diff --git a/common/libs/libjlibtorrent-1.2.17.0.so b/common/libs/libjlibtorrent-1.2.17.0.so deleted file mode 100755 index 4b8abb0cb..000000000 Binary files a/common/libs/libjlibtorrent-1.2.17.0.so and /dev/null differ diff --git a/common/libs/libjlibtorrent.arm64.dylib b/common/libs/libjlibtorrent.arm64.dylib index 4314790d9..42b01a059 100755 Binary files a/common/libs/libjlibtorrent.arm64.dylib and b/common/libs/libjlibtorrent.arm64.dylib differ diff --git a/common/libs/libjlibtorrent.x86_64.dylib b/common/libs/libjlibtorrent.x86_64.dylib new file mode 100755 index 000000000..63c70ebbd Binary files /dev/null and b/common/libs/libjlibtorrent.x86_64.dylib differ diff --git a/common/src/main/java/nl/tudelft/trustchain/common/DemoCommunity.kt b/common/src/main/java/nl/tudelft/trustchain/common/DemoCommunity.kt index 68cdc2669..9b077a8b3 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/DemoCommunity.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/DemoCommunity.kt @@ -1,7 +1,6 @@ package nl.tudelft.trustchain.common -import kotlinx.coroutines.ObsoleteCoroutinesApi -import kotlinx.coroutines.channels.BroadcastChannel +import kotlinx.coroutines.flow.MutableSharedFlow import nl.tudelft.ipv8.Community import nl.tudelft.ipv8.IPv4Address import nl.tudelft.ipv8.Peer @@ -11,7 +10,7 @@ import nl.tudelft.ipv8.messaging.Address import nl.tudelft.ipv8.messaging.Packet import nl.tudelft.ipv8.messaging.payload.IntroductionResponsePayload import nl.tudelft.ipv8.messaging.payload.PuncturePayload -import java.util.* +import java.util.Date class DemoCommunity : Community() { override val serviceId = "02313685c1912a141279f8248fc8db5899c5df5a" @@ -20,8 +19,7 @@ class DemoCommunity : Community() { val lastTrackerResponses = mutableMapOf() - @OptIn(ObsoleteCoroutinesApi::class) - val punctureChannel = BroadcastChannel>(10000) + val punctureChannel = MutableSharedFlow>(0, 10000) // Retrieve the trustchain community private fun getTrustChainCommunity(): TrustChainCommunity { @@ -35,7 +33,10 @@ class DemoCommunity : Community() { discoveredAddressesContacted[address] = Date() } - override fun onIntroductionResponse(peer: Peer, payload: IntroductionResponsePayload) { + override fun onIntroductionResponse( + peer: Peer, + payload: IntroductionResponsePayload + ) { super.onIntroductionResponse(peer, payload) if (peer.address in DEFAULT_ADDRESSES) { @@ -47,7 +48,10 @@ class DemoCommunity : Community() { const val PUNCTURE_TEST = 251 } - fun sendPuncture(address: IPv4Address, id: Int) { + fun sendPuncture( + address: IPv4Address, + id: Int + ) { val payload = PuncturePayload(myEstimatedLan, myEstimatedWan, id) val packet = serializePacket(MessageId.PUNCTURE_TEST, payload, sign = false) endpoint.send(address, packet) @@ -58,9 +62,8 @@ class DemoCommunity : Community() { messageHandlers[MessageId.PUNCTURE_TEST] = ::onPunctureTest } - @OptIn(ObsoleteCoroutinesApi::class) private fun onPunctureTest(packet: Packet) { val payload = packet.getPayload(PuncturePayload.Deserializer) - punctureChannel.trySend(Pair(packet.source, payload)).isSuccess + punctureChannel.tryEmit(Pair(packet.source, payload)) } } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/MarketCommunity.kt b/common/src/main/java/nl/tudelft/trustchain/common/MarketCommunity.kt index 65e0650de..4b5f17380 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/MarketCommunity.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/MarketCommunity.kt @@ -30,7 +30,10 @@ class MarketCommunity : Community() { discoveredAddressesContacted[address] = Date() } - override fun onIntroductionResponse(peer: Peer, payload: IntroductionResponsePayload) { + override fun onIntroductionResponse( + peer: Peer, + payload: IntroductionResponsePayload + ) { super.onIntroductionResponse(peer, payload) if (peer.address in DEFAULT_ADDRESSES) { @@ -50,17 +53,24 @@ class MarketCommunity : Community() { notifyListeners(payload) Log.d( "MarketCommunity", - "Received packet:{${payload.primaryCurrency}, ${payload.secondaryCurrency}, ${payload.amount}, ${payload.price}, ${payload.type}}" + "Received packet:{${payload.primaryCurrency}, ${payload.secondaryCurrency}," + + " ${payload.amount}, ${payload.price}, ${payload.type}}" ) } - fun addListener(type: TradePayload.Type?, listener: (TradePayload) -> Unit) { + fun addListener( + type: TradePayload.Type?, + listener: (TradePayload) -> Unit + ) { val listeners = listenersMap[type] ?: mutableListOf() listeners.add(listener) listenersMap[type] = listeners } - fun removeListener(type: TradePayload.Type?, listener: (TradePayload) -> Unit) { + fun removeListener( + type: TradePayload.Type?, + listener: (TradePayload) -> Unit + ) { listenersMap[type]?.remove(listener) } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/bitcoin/WalletService.kt b/common/src/main/java/nl/tudelft/trustchain/common/bitcoin/WalletService.kt index d3c963f40..559b14dca 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/bitcoin/WalletService.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/bitcoin/WalletService.kt @@ -13,7 +13,6 @@ import java.io.File import java.net.InetAddress class WalletService { - companion object { private lateinit var globalWallet: WalletAppKit private val walletStore: MutableMap = mutableMapOf() @@ -40,22 +39,24 @@ class WalletService { * Creates a personal wallet and saves it continuously in the given file. If an app-kit has already * started, this function looks up the running app-kit. */ - fun createPersonalWallet(dir: File): WalletAppKit = - createWallet(dir, "personal") + fun createPersonalWallet(dir: File): WalletAppKit = createWallet(dir, "personal") /** * Creates a wallet with the given name and saves it continuously in the given file. If an app-kit * has already started, this function looks up the running app-kit and waits for it to be surely * running. */ - fun createWallet(dir: File, name: String): WalletAppKit { + fun createWallet( + dir: File, + name: String + ): WalletAppKit { // If a wallet app-kit was already stored and not terminated, retrieve it. if (walletStore.containsKey(name) && !setOf( - Service.State.TERMINATED, - Service.State.STOPPING, - Service.State.FAILED - ).contains(walletStore[name]?.state()) + Service.State.TERMINATED, + Service.State.STOPPING, + Service.State.FAILED + ).contains(walletStore[name]?.state()) ) { walletStore[name]!!.awaitRunning() @@ -63,20 +64,21 @@ class WalletService { } // Create an app-kit with testing bitcoins if empty. - val app = object : WalletAppKit(params, dir, name + "test") { - override fun onSetupCompleted() { - if (wallet().keyChainGroupSize < 1) { - wallet().importKey(ECKey()) - } - - if (wallet().balance.isZero) { - val address = wallet().issuedReceiveAddresses.first().toString() - println("Address:$address") - // TODO: Fix the faucet - // URL("${BuildConfig.BITCOIN_FAUCET}?id=$address").readBytes() + val app = + object : WalletAppKit(params, dir, name + "test") { + override fun onSetupCompleted() { + if (wallet().keyChainGroupSize < 1) { + wallet().importKey(ECKey()) + } + + if (wallet().balance.isZero) { + val address = wallet().issuedReceiveAddresses.first().toString() + println("Address:$address") + // TODO: Fix the faucet + // URL("${BuildConfig.BITCOIN_FAUCET}?id=$address").readBytes() + } } } - } app.setPeerNodes( PeerAddress( @@ -100,14 +102,17 @@ class WalletService { /** * Initializes the bitcoin side of the liquidity pool */ - fun initializePool(transactionRepository: TransactionRepository, publicKey: PublicKey) { - + fun initializePool( + transactionRepository: TransactionRepository, + publicKey: PublicKey + ) { // TODO: Look into different listeners, this event is called before the transfer is verified, not sure if this will be an issue globalWallet.wallet().addCoinsReceivedEventListener { wallet, tx, _, _ -> - val transaction = mapOf( - "bitcoin_tx" to tx!!.txId.toString(), - "amount" to tx.getValueSentToMe(wallet).toFriendlyString() - ) + val transaction = + mapOf( + "bitcoin_tx" to tx!!.txId.toString(), + "amount" to tx.getValueSentToMe(wallet).toFriendlyString() + ) Log.d("bitcoin_received", "Bitcoins received making a note on my chain") transactionRepository.trustChainCommunity.createProposalBlock( "bitcoin_transfer", diff --git a/common/src/main/java/nl/tudelft/trustchain/common/contacts/Contact.kt b/common/src/main/java/nl/tudelft/trustchain/common/contacts/Contact.kt index ccc5e5775..8aa0232ab 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/contacts/Contact.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/contacts/Contact.kt @@ -38,7 +38,10 @@ data class Contact( const val PUBLIC_KEY = "public_key" const val NAME = "name" - override fun deserialize(buffer: ByteArray, offset: Int): Pair { + override fun deserialize( + buffer: ByteArray, + offset: Int + ): Pair { val offsetBuffer = buffer.copyOfRange(0, buffer.size) val json = JSONObject(offsetBuffer.decodeToString()) val name = json.getString(NAME) diff --git a/common/src/main/java/nl/tudelft/trustchain/common/contacts/ContactStore.kt b/common/src/main/java/nl/tudelft/trustchain/common/contacts/ContactStore.kt index 1d800254c..88352ee6c 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/contacts/ContactStore.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/contacts/ContactStore.kt @@ -1,10 +1,11 @@ package nl.tudelft.trustchain.common.contacts import android.content.Context -import com.squareup.sqldelight.android.AndroidSqliteDriver -import com.squareup.sqldelight.runtime.coroutines.asFlow -import com.squareup.sqldelight.runtime.coroutines.mapToList -import com.squareup.sqldelight.runtime.coroutines.mapToOneOrNull +import app.cash.sqldelight.coroutines.asFlow +import app.cash.sqldelight.coroutines.mapToList +import app.cash.sqldelight.coroutines.mapToOneOrNull +import app.cash.sqldelight.driver.android.AndroidSqliteDriver +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import nl.tudelft.common.sqldelight.Database import nl.tudelft.ipv8.keyvault.PublicKey @@ -14,11 +15,17 @@ class ContactStore(context: Context) { private val driver = AndroidSqliteDriver(Database.Schema, context, "common.db") private val database = Database(driver) - fun addContact(publicKey: PublicKey, name: String) { + fun addContact( + publicKey: PublicKey, + name: String + ) { database.dbContactQueries.addContact(name, publicKey.keyToBin()) } - fun updateContact(publicKey: PublicKey, name: String) { + fun updateContact( + publicKey: PublicKey, + name: String + ) { database.dbContactQueries.addContact(name, publicKey.keyToBin()) } @@ -30,7 +37,9 @@ class ContactStore(context: Context) { contact.name, defaultCryptoProvider.keyFromPublicBin(contact.public_key) ) - } else null + } else { + null + } } fun getContactFromPublickey(publicKey: PublicKey): Flow { @@ -39,14 +48,14 @@ class ContactStore(context: Context) { name, defaultCryptoProvider.keyFromPublicBin(public_key) ) - }.asFlow().mapToOneOrNull() + }.asFlow().mapToOneOrNull(Dispatchers.IO) } fun getContacts(): Flow> { return database.dbContactQueries.getAll { name, public_key -> val publicKey = defaultCryptoProvider.keyFromPublicBin(public_key) Contact(name, publicKey) - }.asFlow().mapToList() + }.asFlow().mapToList(Dispatchers.IO) } fun deleteContact(contact: Contact) { @@ -55,6 +64,7 @@ class ContactStore(context: Context) { companion object { private lateinit var instance: ContactStore + fun getInstance(context: Context): ContactStore { if (!Companion::instance.isInitialized) { instance = ContactStore(context) diff --git a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/GatewayStore.kt b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/GatewayStore.kt index a2bd2b680..9da4986e8 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/GatewayStore.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/GatewayStore.kt @@ -1,7 +1,7 @@ package nl.tudelft.trustchain.common.eurotoken import android.content.Context -import com.squareup.sqldelight.android.AndroidSqliteDriver +import app.cash.sqldelight.driver.android.AndroidSqliteDriver import nl.tudelft.common.sqldelight.Database import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider @@ -74,7 +74,9 @@ open class GatewayStore(val database: Database) { gateway.port, gateway.preferred == 1L ) - } else null + } else { + null + } } fun getGatewayFromPublicKey(publicKey: PublicKey): Gateway? { @@ -88,7 +90,9 @@ open class GatewayStore(val database: Database) { gateway.port, gateway.preferred == 1L ) - } else null + } else { + null + } } fun getGateways(): List { @@ -104,6 +108,7 @@ open class GatewayStore(val database: Database) { companion object { private lateinit var instance: GatewayStore + fun getInstance(context: Context): GatewayStore { if (!Companion::instance.isInitialized) { instance = SqlGatewayStore(context) diff --git a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/Transaction.kt b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/Transaction.kt index acb403987..e1646bac4 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/Transaction.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/Transaction.kt @@ -13,7 +13,6 @@ data class Transaction( val outgoing: Boolean, val timestamp: Date ) { - override fun equals(other: Any?): Boolean { return other is Transaction && other.block == block diff --git a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/TransactionRepository.kt b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/TransactionRepository.kt index 788044a70..cd7bc32d8 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/TransactionRepository.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/TransactionRepository.kt @@ -60,14 +60,25 @@ class TransactionRepository( @OptIn(ExperimentalUnsignedTypes::class) fun crawlForLinked(block: TrustChainBlock): TrustChainBlock? { - val range = LongRange( - block.sequenceNumber.toLong(), - block.sequenceNumber.toLong() - ) - val peer = trustChainCommunity.getPeers().find { it.publicKey.keyToBin().contentEquals(block.publicKey) } - ?: Peer(defaultCryptoProvider.keyFromPublicBin(block.linkPublicKey)) + val range = + LongRange( + block.sequenceNumber.toLong(), + block.sequenceNumber.toLong() + ) + val peer = + trustChainCommunity.getPeers() + .find { it.publicKey.keyToBin().contentEquals(block.publicKey) } + ?: Peer(defaultCryptoProvider.keyFromPublicBin(block.linkPublicKey)) // Should only be run when receiving blocks, not when sending - val blocks = runBlocking { trustChainCommunity.sendCrawlRequest(peer, block.publicKey, range, forHalfBlock = block) } + val blocks = + runBlocking { + trustChainCommunity.sendCrawlRequest( + peer, + block.publicKey, + range, + forHalfBlock = block + ) + } if (blocks.isEmpty()) return null // No connection partial previous return blocks.find { // linked block it.publicKey.contentEquals(block.linkPublicKey) && @@ -75,7 +86,10 @@ class TransactionRepository( } ?: block // no linked block exists } - fun ensureCheckpointLinks(block: TrustChainBlock, database: TrustChainStore) { + fun ensureCheckpointLinks( + block: TrustChainBlock, + database: TrustChainStore + ) { if (block.publicKey.contentEquals(trustChainCommunity.myPeer.publicKey.keyToBin())) return // no need to crawl own chain val blockBefore = database.getBlockWithHash(block.previousHash) if (BLOCK_TYPE_CHECKPOINT == block.type && block.isProposal) { @@ -83,8 +97,9 @@ class TransactionRepository( if (database.getLinked(block) != null) { // verified return } else { // gateway verification is missing - val linked = crawlForLinked(block) // try to crawl for it - ?: return // peer didnt repond, TODO: Store this detail to make verification work better + val linked = + crawlForLinked(block) // try to crawl for it + ?: return // peer didnt repond, TODO: Store this detail to make verification work better if (linked == block) { // No linked block exists in peer, so they sent the transaction based on a different checkpoint ensureCheckpointLinks(blockBefore ?: return, database) // check next } else { @@ -96,7 +111,10 @@ class TransactionRepository( } } - fun getVerifiedBalanceForBlock(block: TrustChainBlock?, database: TrustChainStore): Long? { + fun getVerifiedBalanceForBlock( + block: TrustChainBlock?, + database: TrustChainStore + ): Long? { if (block == null) { Log.d("getVerifiedBalanceForBl", "Found null block!") return null @@ -118,7 +136,10 @@ class TransactionRepository( return (block.transaction[KEY_BALANCE] as Long) } else { Log.d("EuroTokenBlock", "Validation, checkpoint missing acceptance") - return getVerifiedBalanceForBlock(database.getBlockWithHash(block.previousHash), database) + return getVerifiedBalanceForBlock( + database.getBlockWithHash(block.previousHash), + database + ) } } else if (listOf( BLOCK_TYPE_TRANSFER, @@ -157,18 +178,23 @@ class TransactionRepository( } } - fun getBalanceForBlock(block: TrustChainBlock?, database: TrustChainStore): Long? { + fun getBalanceForBlock( + block: TrustChainBlock?, + database: TrustChainStore + ): Long? { if (block == null) { Log.d("getBalanceForBlock", "Found null block!") return null } // Missing block Log.d("getBalanceForBlock", "Found block with ID: ${block.blockId}") - if (!EUROTOKEN_TYPES.contains(block.type)) return getBalanceForBlock( - database.getBlockWithHash( - block.previousHash - ), - database - ) + if (!EUROTOKEN_TYPES.contains(block.type)) { + return getBalanceForBlock( + database.getBlockWithHash( + block.previousHash + ), + database + ) + } return if ( // block contains balance (base case) ( listOf( @@ -177,7 +203,7 @@ class TransactionRepository( BLOCK_TYPE_CHECKPOINT, BLOCK_TYPE_ROLLBACK ).contains(block.type) && block.isProposal - ) + ) ) { (block.transaction[KEY_BALANCE] as Long) } else if (listOf( @@ -187,7 +213,7 @@ class TransactionRepository( ) { // block is receiving money add it and recurse if (block.isGenesis) { - return INITIAL_BALANCE + (block.transaction[KEY_AMOUNT] as BigInteger).toLong() + return initialBalance + (block.transaction[KEY_AMOUNT] as BigInteger).toLong() } getBalanceForBlock(database.getBlockWithHash(block.previousHash), database)?.plus( (block.transaction[KEY_AMOUNT] as BigInteger).toLong() @@ -202,11 +228,12 @@ class TransactionRepository( Log.d("PEERDISCOVERY", "${trustChainCommunity.getPeers()}") val myPublicKey = IPv8Android.getInstance().myPeer.publicKey.keyToBin() val latestBlock = trustChainCommunity.database.getLatest(myPublicKey) - if (latestBlock == null) { + val myVerifiedBalance = + getVerifiedBalanceForBlock(latestBlock, trustChainCommunity.database) + if (latestBlock == null || myVerifiedBalance == null) { Log.d("getMyVerifiedBalance", "no latest block, defaulting to initial balance") - return INITIAL_BALANCE + return initialBalance } - val myVerifiedBalance = getVerifiedBalanceForBlock(latestBlock, trustChainCommunity.database)!! Log.d("getMyVerifiedBalance", "balance = $myVerifiedBalance") return myVerifiedBalance } @@ -216,7 +243,7 @@ class TransactionRepository( val latestBlock = trustChainCommunity.database.getLatest(myPublicKey) if (latestBlock == null) { Log.d("getMyBalance", "no latest block, defaulting to initial balance") - return INITIAL_BALANCE + return initialBalance } Log.d("getMyBalance", "latest block found") val myBalance = getBalanceForBlock(latestBlock, trustChainCommunity.database)!! @@ -224,7 +251,10 @@ class TransactionRepository( return myBalance } - fun sendTransferProposal(recipient: ByteArray, amount: Long): Boolean { + fun sendTransferProposal( + recipient: ByteArray, + amount: Long + ): Boolean { Log.d("sendTransferProposal", "sending amount: $amount") if (getMyBalance() - amount < 0) { return false @@ -235,18 +265,23 @@ class TransactionRepository( return true } - fun sendTransferProposalSync(recipient: ByteArray, amount: Long): TrustChainBlock? { + fun sendTransferProposalSync( + recipient: ByteArray, + amount: Long + ): TrustChainBlock? { Log.d("sendTransferProposalSyn", "sending amount: $amount") if (getMyBalance() - amount < 0) { return null } - val transaction = mapOf( - KEY_AMOUNT to BigInteger.valueOf(amount), - KEY_BALANCE to (BigInteger.valueOf(getMyBalance() - amount).toLong()) - ) + val transaction = + mapOf( + KEY_AMOUNT to BigInteger.valueOf(amount), + KEY_BALANCE to (BigInteger.valueOf(getMyBalance() - amount).toLong()) + ) return trustChainCommunity.createProposalBlock( - BLOCK_TYPE_TRANSFER, transaction, + BLOCK_TYPE_TRANSFER, + transaction, recipient ) } @@ -258,18 +293,24 @@ class TransactionRepository( val balance = getVerifiedBalanceForBlock(block, database) ?: return ValidationResult.PartialPrevious if (balance < 0) { - val blockBefore = database.getBlockWithHash(block.previousHash) ?: return ValidationResult.PartialPrevious + val blockBefore = + database.getBlockWithHash(block.previousHash) + ?: return ValidationResult.PartialPrevious if (lastCheckpointIsEmpty(blockBefore, database)) { // IF INVALID IS RETURNED WE WONT CRAWL FOR LINKED BLOCKS return ValidationResult.PartialPrevious } - val errorMsg = "Insufficient balance ($balance) for amount (${getBalanceChangeForBlock(block)})" + val errorMsg = + "Insufficient balance ($balance) for amount (${getBalanceChangeForBlock(block)})" return ValidationResult.Invalid(listOf(errorMsg)) } return ValidationResult.Valid } - fun verifyListedBalance(block: TrustChainBlock, database: TrustChainStore): ValidationResult { + fun verifyListedBalance( + block: TrustChainBlock, + database: TrustChainStore + ): ValidationResult { if (!block.transaction.containsKey(KEY_BALANCE)) return ValidationResult.Invalid(listOf("Missing balance")) if (block.isGenesis) { if (block.transaction.containsKey(KEY_AMOUNT)) { @@ -308,16 +349,22 @@ class TransactionRepository( /** * Sends a proposal block to join a liquidity pool with the hashes of a bitcoin and eurotoken transaction */ - fun sendJoinProposal(recipient: ByteArray, btcHash: String, euroHash: String): TrustChainBlock? { + fun sendJoinProposal( + recipient: ByteArray, + btcHash: String, + euroHash: String + ): TrustChainBlock? { if (btcHash == euroHash) { Log.d("LiquidityPool", "This is a bullsh*t check to make the app build") } - val transaction = mapOf( - "btcHash" to btcHash, - "euroHash" to euroHash - ) + val transaction = + mapOf( + "btcHash" to btcHash, + "euroHash" to euroHash + ) return trustChainCommunity.createProposalBlock( - BLOCK_TYPE_JOIN, transaction, + BLOCK_TYPE_JOIN, + transaction, recipient ) } @@ -332,33 +379,41 @@ class TransactionRepository( direction: String, receiveAddress: String ): TrustChainBlock? { - val transaction = mapOf( - "hash" to hash, - "receive" to receiveAddress, - "direction" to direction - ) + val transaction = + mapOf( + "hash" to hash, + "receive" to receiveAddress, + "direction" to direction + ) return trustChainCommunity.createProposalBlock( - BLOCK_TYPE_TRADE, transaction, + BLOCK_TYPE_TRADE, + transaction, recipient ) } fun sendCheckpointProposal(peer: Peer): TrustChainBlock { Log.w("EuroTokenBlockCheck", "Creating check...") - val transaction = mapOf( - KEY_BALANCE to BigInteger.valueOf(getMyBalance()).toLong() - ) - val block = trustChainCommunity.createProposalBlock( - BLOCK_TYPE_CHECKPOINT, transaction, - peer.publicKey.keyToBin() - ) + val transaction = + mapOf( + KEY_BALANCE to BigInteger.valueOf(getMyBalance()).toLong() + ) + val block = + trustChainCommunity.createProposalBlock( + BLOCK_TYPE_CHECKPOINT, + transaction, + peer.publicKey.keyToBin() + ) scope.launch { trustChainCommunity.sendBlock(block, peer) } return block } - fun attemptRollback(peer: Peer?, blockHash: ByteArray) { + fun attemptRollback( + peer: Peer?, + blockHash: ByteArray + ) { if (peer != null && peer.publicKey != getGatewayPeer()?.publicKey) { Log.w("EuroTokenBlockRollback", "Not a valid gateway") return @@ -373,16 +428,18 @@ class TransactionRepository( return } val amount = rolledBackBlock.transaction[KEY_AMOUNT] as BigInteger - val transaction = mapOf( - KEY_TRANSACTION_HASH to blockHash.toHex(), - KEY_AMOUNT to amount, - KEY_BALANCE to (BigInteger.valueOf(getMyBalance() - amount.toLong()).toLong()) - ) + val transaction = + mapOf( + KEY_TRANSACTION_HASH to blockHash.toHex(), + KEY_AMOUNT to amount, + KEY_BALANCE to (BigInteger.valueOf(getMyBalance() - amount.toLong()).toLong()) + ) @Suppress("CAST_NEVER_SUCCEEDS") Log.d("EuroTokenBlockRollback", (transaction[KEY_BALANCE] as Long).toString()) scope.launch { trustChainCommunity.createProposalBlock( - BLOCK_TYPE_ROLLBACK, transaction, + BLOCK_TYPE_ROLLBACK, + transaction, rolledBackBlock.publicKey ) } @@ -399,15 +456,18 @@ class TransactionRepository( return null } - val transaction = mapOf( - KEY_IBAN to iban, - KEY_AMOUNT to BigInteger.valueOf(amount), - KEY_BALANCE to (BigInteger.valueOf(getMyBalance() - amount).toLong()) - ) - val block = trustChainCommunity.createProposalBlock( - BLOCK_TYPE_DESTROY, transaction, - peer.publicKey.keyToBin() - ) + val transaction = + mapOf( + KEY_IBAN to iban, + KEY_AMOUNT to BigInteger.valueOf(amount), + KEY_BALANCE to (BigInteger.valueOf(getMyBalance() - amount).toLong()) + ) + val block = + trustChainCommunity.createProposalBlock( + BLOCK_TYPE_DESTROY, + transaction, + peer.publicKey.keyToBin() + ) trustChainCommunity.sendBlock(block, peer) return block @@ -429,15 +489,18 @@ class TransactionRepository( return null } - val transaction = mapOf( - KEY_PAYMENT_ID to paymentId, - KEY_AMOUNT to BigInteger.valueOf(amount), - KEY_BALANCE to (BigInteger.valueOf(getMyBalance() - amount).toLong()) - ) - val block = trustChainCommunity.createProposalBlock( - BLOCK_TYPE_DESTROY, transaction, - recipient - ) + val transaction = + mapOf( + KEY_PAYMENT_ID to paymentId, + KEY_AMOUNT to BigInteger.valueOf(amount), + KEY_BALANCE to (BigInteger.valueOf(getMyBalance() - amount).toLong()) + ) + val block = + trustChainCommunity.createProposalBlock( + BLOCK_TYPE_DESTROY, + transaction, + recipient + ) trustChainCommunity.sendBlock(block, peer) return block @@ -455,7 +518,9 @@ class TransactionRepository( defaultCryptoProvider.keyFromPublicBin(block.linkPublicKey), if (block.transaction.containsKey(KEY_AMOUNT)) { (block.transaction[KEY_AMOUNT] as BigInteger).toLong() - } else 0L, + } else { + 0L + }, block.type, getBalanceChangeForBlock(block) < 0, block.timestamp @@ -463,14 +528,20 @@ class TransactionRepository( } } - fun getLatestBlockOfType(trustchain: TrustChainHelper, allowedTypes: List): TrustChainBlock { + fun getLatestBlockOfType( + trustchain: TrustChainHelper, + allowedTypes: List + ): TrustChainBlock { return trustchain.getChainByUser(trustchain.getMyPublicKey()) .first { block: TrustChainBlock -> allowedTypes.contains(block.type) } } - fun getTransactionsBetweenMeAndOther(other: PublicKey, trustchain: TrustChainHelper): List { + fun getTransactionsBetweenMeAndOther( + other: PublicKey, + trustchain: TrustChainHelper + ): List { return trustchain.getChainByUser(trustchain.getMyPublicKey()) .asSequence() .filter { block -> @@ -484,7 +555,9 @@ class TransactionRepository( defaultCryptoProvider.keyFromPublicBin(block.linkPublicKey), if (block.transaction.containsKey(KEY_AMOUNT)) { (block.transaction[KEY_AMOUNT] as BigInteger).toLong() - } else 0L, + } else { + 0L + }, block.type, getBalanceChangeForBlock(block) < 0, block.timestamp @@ -511,10 +584,15 @@ class TransactionRepository( val hasLinkedBlock = linkedBlock != null val outgoing = getBalanceChangeForBlock(block) < 0 - val outgoingTransaction = outgoing && hasLinkedBlock && block.type == BLOCK_TYPE_TRANSFER - val incomingTransaction = !outgoing && block.type == BLOCK_TYPE_TRANSFER && (blocks.find { it.blockId == block.linkedBlockId } != null) - val buyFromExchange = !outgoing && block.type == BLOCK_TYPE_CREATE && !block.isAgreement - val sellToExchange = outgoing && block.type == BLOCK_TYPE_DESTROY && !block.isAgreement + val outgoingTransaction = + outgoing && hasLinkedBlock && block.type == BLOCK_TYPE_TRANSFER + val incomingTransaction = + !outgoing && block.type == BLOCK_TYPE_TRANSFER && + (blocks.find { it.blockId == block.linkedBlockId } != null) + val buyFromExchange = + !outgoing && block.type == BLOCK_TYPE_CREATE && !block.isAgreement + val sellToExchange = + outgoing && block.type == BLOCK_TYPE_DESTROY && !block.isAgreement buyFromExchange || sellToExchange || outgoingTransaction || incomingTransaction } @@ -527,7 +605,9 @@ class TransactionRepository( defaultCryptoProvider.keyFromPublicBin(block.linkPublicKey), if (block.transaction.containsKey(KEY_AMOUNT)) { (block.transaction[KEY_AMOUNT] as BigInteger).toLong() - } else 0L, + } else { + 0L + }, block.type, getBalanceChangeForBlock(block) < 0, block.timestamp @@ -550,7 +630,11 @@ class TransactionRepository( if (BLOCK_TYPE_CHECKPOINT == block.type && block.isProposal) { return database.getLinked(block) == null // Checkpoint acceptance is missing and should be crawled to prove validity } else { - val blockBefore = database.getBlockWithHash(block.previousHash) ?: return true // null will not actually happen, but true will result in PartialPrevious + val blockBefore = + database.getBlockWithHash( + block.previousHash + ) + ?: return true // null will not actually happen, but true will result in PartialPrevious return lastCheckpointIsEmpty(blockBefore, database) } } @@ -558,18 +642,25 @@ class TransactionRepository( /** * Checks the chain for the hashes specified in the join proposal */ - private fun verifyJoinTransactions(btcHash: String, euroHash: String, euroAddress: ByteArray): ValidationResult { + private fun verifyJoinTransactions( + btcHash: String, + euroHash: String, + euroAddress: ByteArray + ): ValidationResult { val myKey = IPv8Android.getInstance().myPeer.publicKey.keyToBin() - var latestBlock = trustChainCommunity.database.getLatest(myKey) ?: return ValidationResult.Invalid( - listOf("Empty Chain") - ) + var latestBlock = + trustChainCommunity.database.getLatest(myKey) ?: return ValidationResult.Invalid( + listOf("Empty Chain") + ) var btcConfirmed = false var euroConfirmed = false // Traverse the chain while the corresponding btc/euro transfer blocks are not found while (!euroConfirmed || !btcConfirmed) { // For eurotoken blocks check the linked block for the correct hash if (latestBlock.type.equals(BLOCK_TYPE_TRANSFER)) { - if (trustChainCommunity.database.getLinked(latestBlock)?.calculateHash()?.toHex().equals(euroHash)) { + if (trustChainCommunity.database.getLinked(latestBlock)?.calculateHash()?.toHex() + .equals(euroHash) + ) { if (!latestBlock.linkPublicKey.toHex().equals(euroAddress.toHex())) { return ValidationResult.Invalid( listOf("Not your Eurotoken transaction!") @@ -605,14 +696,21 @@ class TransactionRepository( * The hash belongs to a transaction of the opposing currency of direction. * I.e. if direction is eurotoken, you are looking for a bitcoin transaction. */ - private fun verifyTradeTransactions(hash: String, direction: String, euroAddress: ByteArray): ValidationResult { + private fun verifyTradeTransactions( + hash: String, + direction: String, + euroAddress: ByteArray + ): ValidationResult { val myKey = IPv8Android.getInstance().myPeer.publicKey.keyToBin() - var latestBlock = trustChainCommunity.database.getLatest(myKey) ?: return ValidationResult.Invalid( - listOf("Empty Chain") - ) + var latestBlock = + trustChainCommunity.database.getLatest(myKey) ?: return ValidationResult.Invalid( + listOf("Empty Chain") + ) while (true) { if (direction.equals("bitcoin") && latestBlock.type.equals(BLOCK_TYPE_TRANSFER)) { - if (trustChainCommunity.database.getLinked(latestBlock)?.calculateHash()?.toHex().equals(hash)) { + if (trustChainCommunity.database.getLinked(latestBlock)?.calculateHash()?.toHex() + .equals(hash) + ) { if (!latestBlock.linkPublicKey.toHex().equals(euroAddress.toHex())) { return ValidationResult.Invalid( listOf("Not your Eurotoken transaction!") @@ -669,7 +767,10 @@ class TransactionRepository( if (block.isAgreement && block.publicKey.contentEquals(trustChainCommunity.myPeer.publicKey.keyToBin())) { verifyBalance() } - Log.d("EuroTokenBlock", "${block.type} onBlockReceived: ${block.blockId} ${block.transaction}") + Log.d( + "EuroTokenBlock", + "${block.type} onBlockReceived: ${block.blockId} ${block.transaction}" + ) } } ) @@ -688,12 +789,28 @@ class TransactionRepository( if (block.publicKey.toHex() == mykey.toHex() && block.isProposal) return ValidationResult.Valid if (block.isProposal) { - Log.d("RecvProp", "Received Proposal Block!" + "from : " + block.publicKey.toHex() + " our key : " + mykey.toHex()) + Log.d( + "RecvProp", + "Received Proposal Block!" + "from : " + block.publicKey.toHex() + " our key : " + mykey.toHex() + ) - if (!block.transaction.containsKey("btcHash") || !block.transaction.containsKey("euroHash")) return ValidationResult.Invalid( - listOf("Missing hashes") + if (!block.transaction.containsKey("btcHash") || + !block.transaction.containsKey( + "euroHash" + ) + ) { + return ValidationResult.Invalid( + listOf("Missing hashes") + ) + } + Log.d( + "EuroTokenBlockJoin", + "Received join request with hashes\nBTC: ${ + block.transaction.get( + "btcHash" + ) + }\nEuro: ${block.transaction.get("euroHash")}" ) - Log.d("EuroTokenBlockJoin", "Received join request with hashes\nBTC: ${block.transaction.get("btcHash")}\nEuro: ${block.transaction.get("euroHash")}") // Check if hashes are valid by searching in own chain return verifyJoinTransactions( block.transaction.get("btcHash") as String, @@ -701,23 +818,33 @@ class TransactionRepository( block.publicKey ) } else { - Log.d("AgreementProp", "Received Agreement Block!" + "from : " + block.publicKey.toHex() + " our key : " + mykey.toHex()) + Log.d( + "AgreementProp", + "Received Agreement Block!" + "from : " + block.publicKey.toHex() + " our key : " + mykey.toHex() + ) if (database.getLinked(block)?.transaction?.equals(block.transaction) != true) { return ValidationResult.Invalid( listOf( "Linked transaction doesn't match (${block.transaction}, ${ - database.getLinked( - block - )?.transaction ?: "MISSING" + database.getLinked( + block + )?.transaction ?: "MISSING" })" ) ) } } - if (block.isProposal) - Log.d("RecvProp", "Received Proposal Block!" + "from : " + block.publicKey.toHex() + " our key : " + mykey.toHex()) - else - Log.d("AgreementProp", "Received Agreement Block!" + "from : " + block.publicKey.toHex() + " our key : " + mykey.toHex()) + if (block.isProposal) { + Log.d( + "RecvProp", + "Received Proposal Block!" + "from : " + block.publicKey.toHex() + " our key : " + mykey.toHex() + ) + } else { + Log.d( + "AgreementProp", + "Received Agreement Block!" + "from : " + block.publicKey.toHex() + " our key : " + mykey.toHex() + ) + } return ValidationResult.Valid } @@ -748,7 +875,10 @@ class TransactionRepository( if (block.isAgreement && block.publicKey.contentEquals(trustChainCommunity.myPeer.publicKey.keyToBin())) { verifyBalance() } - Log.d("EuroTokenBlock", "${block.type} onBlockReceived: ${block.blockId} ${block.transaction}") + Log.d( + "EuroTokenBlock", + "${block.type} onBlockReceived: ${block.blockId} ${block.transaction}" + ) } } ) @@ -767,30 +897,54 @@ class TransactionRepository( if (block.isProposal) { // Check if hash is valid for the corresponding direction - val result = verifyTradeTransactions(block.transaction.get("hash") as String, block.transaction.get("direction") as String, euroAddress = block.publicKey) + val result = + verifyTradeTransactions( + block.transaction.get("hash") as String, + block.transaction.get("direction") as String, + euroAddress = block.publicKey + ) if (result != ValidationResult.Valid) { return result } Log.d("Trade", "Valid trade") // It is valid, so we need to send some funds back if ((block.transaction.get("direction") as String).equals("bitcoin")) { - Log.d("TradeBitcoin", "Sending bitcoins back to some address: ${block.transaction.get("receive") as String}") + Log.d( + "TradeBitcoin", + "Sending bitcoins back to some address: ${block.transaction.get("receive") as String}" + ) val wallet = WalletService.getGlobalWallet().wallet() - val sendRequest = SendRequest.to(Address.fromString(WalletService.params, block.transaction.get("receive") as String), Coin.valueOf(10000000)) + val sendRequest = + SendRequest.to( + Address.fromString( + WalletService.params, + block.transaction.get("receive") as String + ), + Coin.valueOf(10000000) + ) wallet.sendCoins(sendRequest) } else if ((block.transaction.get("direction") as String).equals("eurotoken")) { - Log.d("TradeEurotoken", "Sending eurotokens back to some address: ${block.transaction.get("receive") as String}") - sendTransferProposal((block.transaction.get("receive") as String).hexToBytes(), 0) + Log.d( + "TradeEurotoken", + "Sending eurotokens back to some address: ${block.transaction.get("receive") as String}" + ) + sendTransferProposal( + (block.transaction.get("receive") as String).hexToBytes(), + 0 + ) } } else { - Log.d("AgreementProp", "Received Agreement Block!" + "from : " + block.publicKey.toHex() + " our key : " + mykey.toHex()) + Log.d( + "AgreementProp", + "Received Agreement Block!" + "from : " + block.publicKey.toHex() + " our key : " + mykey.toHex() + ) if (database.getLinked(block)?.transaction?.equals(block.transaction) != true) { return ValidationResult.Invalid( listOf( "Linked transaction doesn't match (${block.transaction}, ${ - database.getLinked( - block - )?.transaction ?: "MISSING" + database.getLinked( + block + )?.transaction ?: "MISSING" })" ) ) @@ -821,7 +975,10 @@ class TransactionRepository( BLOCK_TYPE_JOIN, object : BlockListener { override fun onBlockReceived(block: TrustChainBlock) { - Log.d("EuroTokenBlockJoin", "${block.type} onBlockReceived: ${block.blockId} ${block.transaction}") + Log.d( + "EuroTokenBlockJoin", + "${block.type} onBlockReceived: ${block.blockId} ${block.transaction}" + ) } } ) @@ -840,30 +997,54 @@ class TransactionRepository( if (block.isProposal) { // Check if hash is valid for the corresponding direction - val result = verifyTradeTransactions(block.transaction.get("hash") as String, block.transaction.get("direction") as String, euroAddress = block.publicKey) + val result = + verifyTradeTransactions( + block.transaction.get("hash") as String, + block.transaction.get("direction") as String, + euroAddress = block.publicKey + ) if (result != ValidationResult.Valid) { return result } Log.d("Trade", "Valid trade") // It is valid, so we need to send some funds back if ((block.transaction.get("direction") as String).equals("bitcoin")) { - Log.d("TradeBitcoin", "Sending bitcoins back to some address: ${block.transaction.get("receive") as String}") + Log.d( + "TradeBitcoin", + "Sending bitcoins back to some address: ${block.transaction.get("receive") as String}" + ) val wallet = WalletService.getGlobalWallet().wallet() - val sendRequest = SendRequest.to(Address.fromString(WalletService.params, block.transaction.get("receive") as String), Coin.valueOf(10000000)) + val sendRequest = + SendRequest.to( + Address.fromString( + WalletService.params, + block.transaction.get("receive") as String + ), + Coin.valueOf(10000000) + ) wallet.sendCoins(sendRequest) } else if ((block.transaction.get("direction") as String).equals("eurotoken")) { - Log.d("TradeEurotoken", "Sending eurotokens back to some address: ${block.transaction.get("receive") as String}") - sendTransferProposal((block.transaction.get("receive") as String).hexToBytes(), 100) + Log.d( + "TradeEurotoken", + "Sending eurotokens back to some address: ${block.transaction.get("receive") as String}" + ) + sendTransferProposal( + (block.transaction.get("receive") as String).hexToBytes(), + 100 + ) } } else { - Log.d("AgreementProp", "Received Agreement Block!" + "from : " + block.publicKey.toHex() + " our key : " + mykey.toHex()) + Log.d( + "AgreementProp", + "Received Agreement Block!" + "from : " + block.publicKey.toHex() + " our key : " + mykey.toHex() + ) if (database.getLinked(block)?.transaction?.equals(block.transaction) != true) { return ValidationResult.Invalid( listOf( "Linked transaction doesn't match (${block.transaction}, ${ - database.getLinked( - block - )?.transaction ?: "MISSING" + database.getLinked( + block + )?.transaction ?: "MISSING" })" ) ) @@ -1048,8 +1229,9 @@ class TransactionRepository( // } fun prettyAmount(amount: Long): String { - return "€" + (amount / 100).toString() + "," + (abs(amount) % 100).toString() - .padStart(2, '0') + return "€" + (amount / 100).toString() + "," + + (abs(amount) % 100).toString() + .padStart(2, '0') } const val BLOCK_TYPE_TRANSFER = "eurotoken_transfer" @@ -1060,15 +1242,17 @@ class TransactionRepository( const val BLOCK_TYPE_JOIN = "eurotoken_join" const val BLOCK_TYPE_TRADE = "eurotoken_trade" - val EUROTOKEN_TYPES = listOf( - BLOCK_TYPE_TRANSFER, - BLOCK_TYPE_CREATE, - BLOCK_TYPE_DESTROY, - BLOCK_TYPE_CHECKPOINT, - BLOCK_TYPE_ROLLBACK, - BLOCK_TYPE_JOIN, - BLOCK_TYPE_TRADE - ) + @Suppress("ktlint:standard:property-naming") + val EUROTOKEN_TYPES = + listOf( + BLOCK_TYPE_TRANSFER, + BLOCK_TYPE_CREATE, + BLOCK_TYPE_DESTROY, + BLOCK_TYPE_CHECKPOINT, + BLOCK_TYPE_ROLLBACK, + BLOCK_TYPE_JOIN, + BLOCK_TYPE_TRADE + ) const val KEY_AMOUNT = "amount" const val KEY_BALANCE = "balance" @@ -1076,6 +1260,6 @@ class TransactionRepository( const val KEY_PAYMENT_ID = "payment_id" const val KEY_IBAN = "iban" - var INITIAL_BALANCE: Long = 0 + var initialBalance: Long = 0 } } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/utils.kt b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/Utils.kt similarity index 84% rename from common/src/main/java/nl/tudelft/trustchain/common/eurotoken/utils.kt rename to common/src/main/java/nl/tudelft/trustchain/common/eurotoken/Utils.kt index 4985b5856..f8eb162a1 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/utils.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/Utils.kt @@ -6,7 +6,10 @@ import nl.tudelft.ipv8.attestation.trustchain.store.TrustChainStore import nl.tudelft.ipv8.attestation.trustchain.validation.ValidationResult import java.math.BigInteger -fun verifyGatewayIdentity(publicKey: ByteArray, gatewayStore: GatewayStore): ValidationResult { +fun verifyGatewayIdentity( + publicKey: ByteArray, + gatewayStore: GatewayStore +): ValidationResult { if (gatewayStore.getGatewayFromPublicKey(publicKey) != null) { return ValidationResult.Valid } @@ -33,11 +36,15 @@ fun getVerifiedBalanceChangeForBlock(block: TrustChainBlock?): Long { } } -fun getVerifiedBalanceForBlock(block: TrustChainBlock, database: TrustChainStore): Long? { +fun getVerifiedBalanceForBlock( + block: TrustChainBlock, + database: TrustChainStore +): Long? { Log.w("getVerifiedBalanceForBl", "Block with ID: ${block.blockId}") if (block.isGenesis) { - val blockBalance = block.transaction[TransactionRepository.KEY_BALANCE] - ?: return getVerifiedBalanceChangeForBlock(block) + val blockBalance = + block.transaction[TransactionRepository.KEY_BALANCE] + ?: return getVerifiedBalanceChangeForBlock(block) return blockBalance as Long } if (block.type == TransactionRepository.BLOCK_TYPE_CHECKPOINT && block.isProposal) { @@ -55,12 +62,17 @@ fun getVerifiedBalanceForBlock(block: TrustChainBlock, database: TrustChainStore } } -fun getBalanceForBlock(block: TrustChainBlock, database: TrustChainStore): Long? { +fun getBalanceForBlock( + block: TrustChainBlock, + database: TrustChainStore +): Long? { if (TransactionRepository.EUROTOKEN_TYPES.contains(block.type)) { - if (block.isProposal && block.transaction[TransactionRepository.KEY_BALANCE] != null) + if (block.isProposal && block.transaction[TransactionRepository.KEY_BALANCE] != null) { return (block.transaction[TransactionRepository.KEY_BALANCE] as Long) - if (block.isGenesis) + } + if (block.isGenesis) { return getBalanceChangeForBlock(block) + } } val blockBefore = database.getBlockWithHash(block.previousHash) ?: return null val balanceBefore = getBalanceForBlock(blockBefore, database) ?: return null diff --git a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenBaseValidator.kt b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenBaseValidator.kt index 5bbcd8731..1f17ccc31 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenBaseValidator.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenBaseValidator.kt @@ -11,10 +11,12 @@ import nl.tudelft.trustchain.common.eurotoken.getBalanceChangeForBlock import nl.tudelft.trustchain.common.eurotoken.getBalanceForBlock import nl.tudelft.trustchain.common.eurotoken.getVerifiedBalanceForBlock -@OptIn(ExperimentalUnsignedTypes::class) -open class EuroTokenBaseValidator(val transactionRepository: TransactionRepository) : TransactionValidator { - - private fun getBlockBeforeOrRaise(block: TrustChainBlock, database: TrustChainStore): TrustChainBlock? { +open class EuroTokenBaseValidator(val transactionRepository: TransactionRepository) : + TransactionValidator { + private fun getBlockBeforeOrRaise( + block: TrustChainBlock, + database: TrustChainStore + ): TrustChainBlock? { if (block.isGenesis) { return null } @@ -23,21 +25,35 @@ open class EuroTokenBaseValidator(val transactionRepository: TransactionReposito ?: throw PartialPrevious("Missing previous block") } - private fun verifyListedBalance(block: TrustChainBlock, database: TrustChainStore) { + private fun verifyListedBalance( + block: TrustChainBlock, + database: TrustChainStore + ) { assertBalanceExists(block) val blockBefore = getBlockBeforeOrRaise(block, database) - val balanceBefore = if (blockBefore != null) getBalanceForBlock(blockBefore, database) - else TransactionRepository.INITIAL_BALANCE + val balanceBefore = + if (blockBefore != null) { + getBalanceForBlock(blockBefore, database) + } else { + TransactionRepository.initialBalance + } balanceBefore ?: throw PartialPrevious("Missing previous block") Log.w("verifyListedBalance", "Current balance: $balanceBefore") val balanceChange = getBalanceChangeForBlock(block) Log.w("verifyListedBalance", "Attempted change in balance: $balanceChange") if ((block.transaction[TransactionRepository.KEY_BALANCE] as Long) < 0L) { - throw InsufficientBalance("block balance (${block.sequenceNumber}): ${block.transaction[TransactionRepository.KEY_BALANCE]} is negative") + throw InsufficientBalance( + "block balance (${block.sequenceNumber}): " + + "${block.transaction[TransactionRepository.KEY_BALANCE]} is negative" + ) } if (block.transaction[TransactionRepository.KEY_BALANCE] != balanceBefore + balanceChange) { Log.w("EuroTokenBlock", "Invalid balance") - throw InvalidBalance("block balance (${block.sequenceNumber}): ${block.transaction[TransactionRepository.KEY_BALANCE]} does not match calculated balance: $balanceBefore + $balanceChange ") + throw InvalidBalance( + "block balance (${block.sequenceNumber}): " + + "${block.transaction[TransactionRepository.KEY_BALANCE]} " + + "does not match calculated balance: $balanceBefore + $balanceChange " + ) } return // Valid } @@ -48,7 +64,10 @@ open class EuroTokenBaseValidator(val transactionRepository: TransactionReposito } } - private fun getUnlinkedCheckpointBlockRanges(block: TrustChainBlock, database: TrustChainStore): List { + private fun getUnlinkedCheckpointBlockRanges( + block: TrustChainBlock, + database: TrustChainStore + ): List { val blockBefore = getBlockBeforeOrRaise(block, database) ?: return listOf() if (blockBefore.type == TransactionRepository.BLOCK_TYPE_CHECKPOINT) { if (database.getLinked(blockBefore) != null) { @@ -56,15 +75,32 @@ open class EuroTokenBaseValidator(val transactionRepository: TransactionReposito return listOf() } else { // Found un-validated valid checkpoint, add to range and recurse - return getUnlinkedCheckpointBlockRanges(blockBefore, database) + listOf(BlockRange(blockBefore.publicKey, LongRange(blockBefore.sequenceNumber.toLong(), blockBefore.sequenceNumber.toLong()))) + return getUnlinkedCheckpointBlockRanges( + blockBefore, + database + ) + + listOf( + BlockRange( + blockBefore.publicKey, + LongRange( + blockBefore.sequenceNumber.toLong(), + blockBefore.sequenceNumber.toLong() + ) + ) + ) } } else { return getUnlinkedCheckpointBlockRanges(blockBefore, database) } } - private fun verifyBalanceAvailable(block: TrustChainBlock, database: TrustChainStore) { - val balance = getVerifiedBalanceForBlock(block, database) ?: throw PartialPrevious("Missing previous blocks") + private fun verifyBalanceAvailable( + block: TrustChainBlock, + database: TrustChainStore + ) { + val balance = + getVerifiedBalanceForBlock(block, database) + ?: throw PartialPrevious("Missing previous blocks") if (balance < 0) { // the validated balance is not enough, but it could be the case we're missing some // checkpoint links @@ -75,9 +111,9 @@ open class EuroTokenBaseValidator(val transactionRepository: TransactionReposito } else { // last checkpoint is full, spendable balance is invalid throw InsufficientValidatedBalance( "Insufficient balance ($balance) for amount (${ - getBalanceChangeForBlock( - block - ) + getBalanceChangeForBlock( + block + ) })" ) } @@ -85,16 +121,25 @@ open class EuroTokenBaseValidator(val transactionRepository: TransactionReposito return // Valid } - open fun validateEuroTokenProposal(block: TrustChainBlock, database: TrustChainStore) { + open fun validateEuroTokenProposal( + block: TrustChainBlock, + database: TrustChainStore + ) { verifyListedBalance(block, database) verifyBalanceAvailable(block, database) } - open fun validateEuroTokenAcceptance(block: TrustChainBlock, database: TrustChainStore) { + open fun validateEuroTokenAcceptance( + block: TrustChainBlock, + database: TrustChainStore + ) { // Most validations in the checkpoints } - fun validateEuroToken(block: TrustChainBlock, database: TrustChainStore) { + fun validateEuroToken( + block: TrustChainBlock, + database: TrustChainStore + ) { if (block.isProposal) { validateEuroTokenProposal(block, database) } else { @@ -102,11 +147,14 @@ open class EuroTokenBaseValidator(val transactionRepository: TransactionReposito } } - override fun validate(block: TrustChainBlock, database: TrustChainStore): ValidationResult { + override fun validate( + block: TrustChainBlock, + database: TrustChainStore + ): ValidationResult { try { validateEuroToken(block, database) } catch (e: Invalid) { - return ValidationResult.Invalid(listOf(e.TYPE, e.message ?: "")) + return ValidationResult.Invalid(listOf(e.type, e.message ?: "")) } catch (e: PartialPrevious) { return ValidationResult.PartialPrevious } catch (e: MissingBlocks) { @@ -116,34 +164,34 @@ open class EuroTokenBaseValidator(val transactionRepository: TransactionReposito } abstract class ValidationResultException(message: String) : Exception(message) { - abstract val TYPE: String + abstract val type: String } class PartialPrevious(message: String) : ValidationResultException(message) { - override val TYPE: String = "PartialPrevious" + override val type: String = "PartialPrevious" } abstract class Invalid(message: String) : ValidationResultException(message) class MissingBalance(message: String) : Invalid(message) { - override val TYPE: String = "MissingBalance" + override val type: String = "MissingBalance" } class InsufficientBalance(message: String) : Invalid(message) { - override val TYPE: String = "InsufficientBalance" + override val type: String = "InsufficientBalance" } class InsufficientValidatedBalance(message: String) : Invalid(message) { - override val TYPE: String = "InsufficientValidatedBalanceBalance" + override val type: String = "InsufficientValidatedBalanceBalance" } class InvalidBalance(message: String) : Invalid(message) { - override val TYPE: String = "InvalidBalance" + override val type: String = "InvalidBalance" } class MissingBlocks(val blockRanges: List) : ValidationResultException( "MissingBlocks (" + blockRanges.joinToString(", ") + ")" ) { - override val TYPE: String = "MissingBlocks" + override val type: String = "MissingBlocks" } } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCheckpointValidator.kt b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCheckpointValidator.kt index e9b3ceed6..19956504e 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCheckpointValidator.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCheckpointValidator.kt @@ -6,7 +6,10 @@ import nl.tudelft.trustchain.common.eurotoken.TransactionRepository import nl.tudelft.trustchain.common.eurotoken.verifyGatewayIdentity class EuroTokenCheckpointValidator(transactionRepository: TransactionRepository) : EuroTokenBaseValidator(transactionRepository) { - override fun validateEuroTokenProposal(block: TrustChainBlock, database: TrustChainStore) { + override fun validateEuroTokenProposal( + block: TrustChainBlock, + database: TrustChainStore + ) { assertBalanceExists(block) // Don't validate balances (this would crawl for previous), we check for this later verifyGatewayIdentity(block.linkPublicKey, transactionRepository.gatewayStore) diff --git a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCreationValidator.kt b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCreationValidator.kt index 5d4ccc574..8f18b4084 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCreationValidator.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCreationValidator.kt @@ -7,7 +7,10 @@ import nl.tudelft.trustchain.common.eurotoken.TransactionRepository import nl.tudelft.trustchain.common.eurotoken.verifyGatewayIdentity class EuroTokenCreationValidator(transactionRepository: TransactionRepository) : EuroTokenBaseValidator(transactionRepository) { - override fun validateEuroTokenProposal(block: TrustChainBlock, database: TrustChainStore) { + override fun validateEuroTokenProposal( + block: TrustChainBlock, + database: TrustChainStore + ) { if (!block.transaction.containsKey(TransactionRepository.KEY_AMOUNT)) { throw MissingAmount("Missing amount") } @@ -15,7 +18,8 @@ class EuroTokenCreationValidator(transactionRepository: TransactionRepository) : verifyGatewayIdentity(block.publicKey, transactionRepository.gatewayStore) return // Valid } + class MissingAmount(message: String) : Invalid(message) { - override val TYPE: String = "MissingAmount" + override val type: String = "MissingAmount" } } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenDestructionValidator.kt b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenDestructionValidator.kt index 573ea7f3e..297a1c4ad 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenDestructionValidator.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenDestructionValidator.kt @@ -5,7 +5,10 @@ import nl.tudelft.ipv8.attestation.trustchain.store.TrustChainStore import nl.tudelft.trustchain.common.eurotoken.TransactionRepository class EuroTokenDestructionValidator(transactionRepository: TransactionRepository) : EuroTokenBaseValidator(transactionRepository) { - override fun validateEuroTokenProposal(block: TrustChainBlock, database: TrustChainStore) { + override fun validateEuroTokenProposal( + block: TrustChainBlock, + database: TrustChainStore + ) { if (!block.transaction.containsKey(TransactionRepository.KEY_AMOUNT)) { throw MissingAmount("Missing amount") } @@ -17,10 +20,12 @@ class EuroTokenDestructionValidator(transactionRepository: TransactionRepository super.validateEuroTokenProposal(block, database) return // Valid } + class MissingAmount(message: String) : Invalid(message) { - override val TYPE: String = "MissingAmount" + override val type: String = "MissingAmount" } + class MissingPaymentIDorIBAN(message: String) : Invalid(message) { - override val TYPE: String = "MissingPaymentIDorIBAN" + override val type: String = "MissingPaymentIDorIBAN" } } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenRollBackValidator.kt b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenRollBackValidator.kt index d3b03bddc..31251c28f 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenRollBackValidator.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenRollBackValidator.kt @@ -6,7 +6,10 @@ import nl.tudelft.ipv8.util.hexToBytes import nl.tudelft.trustchain.common.eurotoken.TransactionRepository class EuroTokenRollBackValidator(transactionRepository: TransactionRepository) : EuroTokenBaseValidator(transactionRepository) { - override fun validateEuroTokenProposal(block: TrustChainBlock, database: TrustChainStore) { + override fun validateEuroTokenProposal( + block: TrustChainBlock, + database: TrustChainStore + ) { if (!block.transaction.containsKey(TransactionRepository.KEY_AMOUNT)) { throw MissingAmount("Missing amount") } @@ -14,22 +17,24 @@ class EuroTokenRollBackValidator(transactionRepository: TransactionRepository) : throw MissingTransactionHash("Missing transaction hash") } super.validateEuroTokenProposal(block, database) - val rolled_back = database.getBlockWithHash((block.transaction[TransactionRepository.KEY_TRANSACTION_HASH] as String).hexToBytes()) - ?: return - if (rolled_back.transaction["amount"] != block.transaction["amount"]) { + val rolledBack = + database.getBlockWithHash((block.transaction[TransactionRepository.KEY_TRANSACTION_HASH] as String).hexToBytes()) + ?: return + if (rolledBack.transaction["amount"] != block.transaction["amount"]) { throw InvalidTransaction("associated transaction amount does not match") } return // Valid } + class MissingAmount(message: String) : Invalid(message) { - override val TYPE: String = "MissingAmount" + override val type: String = "MissingAmount" } class MissingTransactionHash(message: String) : Invalid(message) { - override val TYPE: String = "MissingTransactionHash" + override val type: String = "MissingTransactionHash" } class InvalidTransaction(message: String) : Invalid(message) { - override val TYPE: String = "InvalidTransaction" + override val type: String = "InvalidTransaction" } } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenTransferValidator.kt b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenTransferValidator.kt index 980ae869d..33cb34ccd 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenTransferValidator.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenTransferValidator.kt @@ -5,7 +5,10 @@ import nl.tudelft.ipv8.attestation.trustchain.store.TrustChainStore import nl.tudelft.trustchain.common.eurotoken.TransactionRepository class EuroTokenTransferValidator(transactionRepository: TransactionRepository) : EuroTokenBaseValidator(transactionRepository) { - override fun validateEuroTokenProposal(block: TrustChainBlock, database: TrustChainStore) { + override fun validateEuroTokenProposal( + block: TrustChainBlock, + database: TrustChainStore + ) { if (!block.transaction.containsKey(TransactionRepository.KEY_AMOUNT)) { throw MissingAmount("Missing amount") } @@ -14,6 +17,6 @@ class EuroTokenTransferValidator(transactionRepository: TransactionRepository) : } class MissingAmount(message: String) : Invalid(message) { - override val TYPE: String = "MissingAmount" + override val type: String = "MissingAmount" } } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/freedomOfComputing/AppPayload.kt b/common/src/main/java/nl/tudelft/trustchain/common/freedomOfComputing/AppPayload.kt index 60ddfb9cb..45c9b1fd6 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/freedomOfComputing/AppPayload.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/freedomOfComputing/AppPayload.kt @@ -17,7 +17,10 @@ class AppPayload( } companion object Deserializer : Deserializable { - override fun deserialize(buffer: ByteArray, offset: Int): Pair { + override fun deserialize( + buffer: ByteArray, + offset: Int + ): Pair { var localOffset = offset val (appTorrentInfoHash, hashSize) = deserializeVarLen(buffer, localOffset) localOffset += hashSize diff --git a/common/src/main/java/nl/tudelft/trustchain/common/freedomOfComputing/AppRequestPayload.kt b/common/src/main/java/nl/tudelft/trustchain/common/freedomOfComputing/AppRequestPayload.kt index aa65d7ebf..58c8bc2ec 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/freedomOfComputing/AppRequestPayload.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/freedomOfComputing/AppRequestPayload.kt @@ -7,7 +7,8 @@ import nl.tudelft.ipv8.messaging.serializeVarLen data class AppRequestPayload( val appTorrentInfoHash: String, - val uuid: String // Created because EVA doesn't allow retransmits + // Created because EVA doesn't allow retransmits + val uuid: String ) : Serializable { override fun serialize(): ByteArray { return serializeVarLen(appTorrentInfoHash.toByteArray()) + @@ -15,7 +16,10 @@ data class AppRequestPayload( } companion object Deserializer : Deserializable { - override fun deserialize(buffer: ByteArray, offset: Int): Pair { + override fun deserialize( + buffer: ByteArray, + offset: Int + ): Pair { var localOffset = offset val (appTorrentInfoHash, idSize) = deserializeVarLen(buffer, localOffset) localOffset += idSize diff --git a/common/src/main/java/nl/tudelft/trustchain/common/messaging/TradePayload.kt b/common/src/main/java/nl/tudelft/trustchain/common/messaging/TradePayload.kt index a307bb424..f216d714c 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/messaging/TradePayload.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/messaging/TradePayload.kt @@ -40,16 +40,20 @@ class TradePayload( } companion object Deserializer : Deserializable { - override fun deserialize(buffer: ByteArray, offset: Int): Pair { + override fun deserialize( + buffer: ByteArray, + offset: Int + ): Pair { var localOffset = 0 val (publicKey, publicKeySize) = deserializeVarLen(buffer, offset + localOffset) localOffset += publicKeySize val (askCurrency, askCurrencySize) = deserializeVarLen(buffer, offset + localOffset) localOffset += askCurrencySize - val (paymentCurrency, paymentCurrencySize) = deserializeVarLen( - buffer, - offset + localOffset - ) + val (paymentCurrency, paymentCurrencySize) = + deserializeVarLen( + buffer, + offset + localOffset + ) localOffset += paymentCurrencySize val (amount, amountSize) = deserializeVarLen(buffer, offset + localOffset) localOffset += amountSize @@ -57,14 +61,15 @@ class TradePayload( localOffset += priceSize val (type, typeSize) = deserializeVarLen(buffer, offset + localOffset) localOffset += typeSize - val payload = TradePayload( - publicKey, - Currency.valueOf(askCurrency.toString(Charsets.UTF_8)), - Currency.valueOf(paymentCurrency.toString(Charsets.UTF_8)), - amount.toString(Charsets.UTF_8).toDouble(), - price.toString(Charsets.UTF_8).toDouble(), - Type.valueOf(type.toString(Charsets.UTF_8)) - ) + val payload = + TradePayload( + publicKey, + Currency.valueOf(askCurrency.toString(Charsets.UTF_8)), + Currency.valueOf(paymentCurrency.toString(Charsets.UTF_8)), + amount.toString(Charsets.UTF_8).toDouble(), + price.toString(Charsets.UTF_8).toDouble(), + Type.valueOf(type.toString(Charsets.UTF_8)) + ) return Pair(payload, localOffset) } } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/ui/BaseFragment.kt b/common/src/main/java/nl/tudelft/trustchain/common/ui/BaseFragment.kt index 621dc2f82..a14a947b3 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/ui/BaseFragment.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/ui/BaseFragment.kt @@ -9,7 +9,9 @@ import nl.tudelft.trustchain.common.DemoCommunity import nl.tudelft.trustchain.common.MarketCommunity import nl.tudelft.trustchain.common.util.TrustChainHelper -abstract class BaseFragment(@LayoutRes contentLayoutId: Int = 0) : Fragment(contentLayoutId) { +abstract class BaseFragment( + @LayoutRes contentLayoutId: Int = 0 +) : Fragment(contentLayoutId) { protected val trustchain: TrustChainHelper by lazy { TrustChainHelper(getTrustChainCommunity()) } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/ui/VotesFragmentHelper.kt b/common/src/main/java/nl/tudelft/trustchain/common/ui/VotesFragmentHelper.kt index 993ee2d8b..b05e34628 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/ui/VotesFragmentHelper.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/ui/VotesFragmentHelper.kt @@ -6,27 +6,26 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.BaseAdapter -import android.widget.ListView -import android.widget.TextView import androidx.fragment.app.Fragment import androidx.viewpager2.adapter.FragmentStateAdapter -import nl.tudelft.trustchain.common.R +import nl.tudelft.trustchain.common.databinding.FragmentVotesEntryBinding +import nl.tudelft.trustchain.common.databinding.FragmentVotesTabBinding /** * The adapter for showing the tab fragments in the voting fragment */ class TabsAdapter(fragment: Fragment, private val voters: Array>) : FragmentStateAdapter(fragment) { - override fun getItemCount(): Int = 3 override fun createFragment(position: Int): Fragment { // Return a NEW fragment instance in createFragment(int) val fragment = TabFragment() - fragment.arguments = Bundle().apply { - putInt("tabPosition", position) - putStringArrayList("voters", voters[position]) - } + fragment.arguments = + Bundle().apply { + putInt("tabPosition", position) + putStringArrayList("voters", voters[position]) + } return fragment } } @@ -35,6 +34,9 @@ class TabsAdapter(fragment: Fragment, private val voters: Array(R.id.votes) - votesAdapter = VotesAdapter( - view.context, - requireArguments().getStringArrayList("voters")!! - ) + val votesList = binding.votes + votesAdapter = + VotesAdapter( + view.context, + requireArguments().getStringArrayList("voters")!! + ) votesList.adapter = votesAdapter } } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } } /** @@ -68,7 +79,6 @@ class VotesAdapter( private val context: Context, private val voters: ArrayList ) : BaseAdapter() { - override fun getCount(): Int { return voters.size } @@ -81,11 +91,19 @@ class VotesAdapter( return position.toLong() } - override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { - val view = - LayoutInflater.from(context).inflate(R.layout.fragment_votes_entry, parent, false) - - view.findViewById(R.id.voter_name).text = voters[position] + override fun getView( + position: Int, + convertView: View?, + parent: ViewGroup? + ): View { + val binding = + if (convertView != null) { + FragmentVotesEntryBinding.bind(convertView) + } else { + FragmentVotesEntryBinding.inflate(LayoutInflater.from(context)) + } + val view = binding.root + binding.voterName.text = voters[position] return view } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/util/ActivityViewBindingDelegate.kt b/common/src/main/java/nl/tudelft/trustchain/common/util/ActivityViewBindingDelegate.kt index 126ffc044..cb5163752 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/util/ActivityViewBindingDelegate.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/util/ActivityViewBindingDelegate.kt @@ -7,8 +7,7 @@ import androidx.viewbinding.ViewBinding /** * @url https://medium.com/@Zhuinden/simple-one-liner-viewbinding-in-fragments-and-activities-with-kotlin-961430c6c07c */ -inline fun AppCompatActivity.viewBinding( - crossinline bindingInflater: (LayoutInflater) -> T -) = lazy(LazyThreadSafetyMode.NONE) { - bindingInflater.invoke(layoutInflater) -} +inline fun AppCompatActivity.viewBinding(crossinline bindingInflater: (LayoutInflater) -> T) = + lazy(LazyThreadSafetyMode.NONE) { + bindingInflater.invoke(layoutInflater) + } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/util/ColorUtils.kt b/common/src/main/java/nl/tudelft/trustchain/common/util/ColorUtils.kt index 3e8ff7db7..aeb1d8b6a 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/util/ColorUtils.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/util/ColorUtils.kt @@ -7,7 +7,10 @@ import kotlin.math.abs /** * Get color based on hash. */ -fun getColorByHash(context: Context, hash: String): Int { +fun getColorByHash( + context: Context, + hash: String +): Int { val colors = context.resources.getIntArray(R.array.colorsChain) val number = abs(hash.hashCode() % colors.size) return colors[number] diff --git a/common/src/main/java/nl/tudelft/trustchain/common/util/FragmentIntentIntegrator.kt b/common/src/main/java/nl/tudelft/trustchain/common/util/FragmentIntentIntegrator.kt index e0b1d24ca..aea9ae00c 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/util/FragmentIntentIntegrator.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/util/FragmentIntentIntegrator.kt @@ -11,7 +11,10 @@ import com.google.zxing.integration.android.IntentIntegrator */ class FragmentIntentIntegrator(private val fragment: Fragment) : IntentIntegrator(fragment.activity) { - override fun startActivityForResult(intent: Intent, code: Int) { + override fun startActivityForResult( + intent: Intent, + code: Int + ) { fragment.startActivityForResult(intent, code) } } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/util/FragmentViewBindingDelegate.kt b/common/src/main/java/nl/tudelft/trustchain/common/util/FragmentViewBindingDelegate.kt index fd8aea260..bc4619f07 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/util/FragmentViewBindingDelegate.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/util/FragmentViewBindingDelegate.kt @@ -16,25 +16,31 @@ class FragmentViewBindingDelegate( val fragment: Fragment, val viewBindingFactory: (View) -> T ) : ReadOnlyProperty { + @Suppress("ktlint:standard:property-naming") // False positive private var _binding: T? = null init { - fragment.lifecycle.addObserver(object : DefaultLifecycleObserver { - override fun onCreate(owner: LifecycleOwner) { - @Suppress("COMPATIBILITY_WARNING") - // TODO: Replace observe. - fragment.viewLifecycleOwnerLiveData.observe(fragment) { viewLifecycleOwner -> - viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver { - override fun onDestroy(owner: LifecycleOwner) { - _binding = null - } - }) + fragment.lifecycle.addObserver( + object : DefaultLifecycleObserver { + override fun onCreate(owner: LifecycleOwner) { + fragment.viewLifecycleOwnerLiveData.observe(fragment) { viewLifecycleOwner -> + viewLifecycleOwner.lifecycle.addObserver( + object : DefaultLifecycleObserver { + override fun onDestroy(owner: LifecycleOwner) { + _binding = null + } + } + ) + } } } - }) + ) } - override fun getValue(thisRef: Fragment, property: KProperty<*>): T { + override fun getValue( + thisRef: Fragment, + property: KProperty<*> + ): T { val binding = _binding if (binding != null) { return binding @@ -49,6 +55,4 @@ class FragmentViewBindingDelegate( } } -fun Fragment.viewBinding( - viewBindingFactory: (View) -> T -) = FragmentViewBindingDelegate(this, viewBindingFactory) +fun Fragment.viewBinding(viewBindingFactory: (View) -> T) = FragmentViewBindingDelegate(this, viewBindingFactory) diff --git a/common/src/main/java/nl/tudelft/trustchain/common/util/QRCodeUtils.kt b/common/src/main/java/nl/tudelft/trustchain/common/util/QRCodeUtils.kt index bf37554d7..c0ca1185b 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/util/QRCodeUtils.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/util/QRCodeUtils.kt @@ -20,17 +20,21 @@ import nl.tudelft.trustchain.common.ui.QRCodeActivityPortrait * Helper class for creating */ class QRCodeUtils(private val context: Context) { - /** * Start the QR scanner, which if successful, calls onActivityResult() on the fragment */ - fun startQRScanner(fragment: Fragment, promptText: String? = null, vertical: Boolean = false) { + fun startQRScanner( + fragment: Fragment, + promptText: String? = null, + vertical: Boolean = false + ) { run { - val integrator = FragmentIntentIntegrator(fragment) - .setPrompt(promptText ?: "Scan QR Code") - .setOrientationLocked(false) - .setBeepEnabled(true) - .setCameraId(0) + val integrator = + FragmentIntentIntegrator(fragment) + .setPrompt(promptText ?: "Scan QR Code") + .setOrientationLocked(false) + .setBeepEnabled(true) + .setCameraId(0) if (vertical) { integrator.captureActivity = QRCodeActivityPortrait::class.java } @@ -38,7 +42,11 @@ class QRCodeUtils(private val context: Context) { } } - fun parseActivityResult(requestCode: Int, resultCode: Int, data: Intent?): String? { + fun parseActivityResult( + requestCode: Int, + resultCode: Int, + data: Intent? + ): String? { return IntentIntegrator.parseActivityResult(requestCode, resultCode, data)?.contents } @@ -48,7 +56,7 @@ class QRCodeUtils(private val context: Context) { */ fun createQR( text: String, - size: Int = QRCodeSize, + size: Int = QR_CODE_SIZE, pColor: Int = pixelColor, bColor: Int = backgroundColor ): Bitmap? { @@ -70,18 +78,20 @@ class QRCodeUtils(private val context: Context) { @Throws(WriterException::class) private fun textToImageEncode( value: String, - size: Int = QRCodeSize, + size: Int = QR_CODE_SIZE, pColor: Int = pixelColor, bColor: Int = backgroundColor ): Bitmap? { val bitMatrix: BitMatrix try { - bitMatrix = MultiFormatWriter().encode( - value, - BarcodeFormat.QR_CODE, - size, - size, null - ) + bitMatrix = + MultiFormatWriter().encode( + value, + BarcodeFormat.QR_CODE, + size, + size, + null + ) } catch (IllegalArgumentException: IllegalArgumentException) { return null } @@ -93,10 +103,12 @@ class QRCodeUtils(private val context: Context) { for (y in 0 until bitMatrixHeight) { val offset = y * bitMatrixWidth for (x in 0 until bitMatrixWidth) { - pixels[offset + x] = if (bitMatrix.get(x, y)) - ContextCompat.getColor(context, pColor) - else - ContextCompat.getColor(context, bColor) + pixels[offset + x] = + if (bitMatrix.get(x, y)) { + ContextCompat.getColor(context, pColor) + } else { + ContextCompat.getColor(context, bColor) + } } } val bitmap = Bitmap.createBitmap(bitMatrixWidth, bitMatrixHeight, Bitmap.Config.ARGB_8888) @@ -106,7 +118,7 @@ class QRCodeUtils(private val context: Context) { } companion object { - const val QRCodeSize = 500 + const val QR_CODE_SIZE = 500 var pixelColor = R.color.black var backgroundColor = R.color.white } diff --git a/common/src/main/java/nl/tudelft/trustchain/common/util/TrustChainHelper.kt b/common/src/main/java/nl/tudelft/trustchain/common/util/TrustChainHelper.kt index 0ebc1a2e2..b512d648d 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/util/TrustChainHelper.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/util/TrustChainHelper.kt @@ -67,20 +67,24 @@ class TrustChainHelper( publicKey: ByteArray ): TrustChainBlock { val blockType = "demo_tx_block" - val transaction = mapOf( - "From" to primaryCurrency.toString(), - "Amount from" to amount.toString(), - "To" to secondaryCurrency.toString(), - "Amount to" to price.toString(), - "type" to type.toString() - ) + val transaction = + mapOf( + "From" to primaryCurrency.toString(), + "Amount from" to amount.toString(), + "To" to secondaryCurrency.toString(), + "Amount to" to price.toString(), + "type" to type.toString() + ) return trustChainCommunity.createProposalBlock(blockType, transaction, publicKey) } /** * Creates a new proposal block of type "demo_tx_block", using a float as transaction amount. */ - fun createOfflineTxProposalBlock(amount: Float, publicKey: ByteArray): TrustChainBlock { + fun createOfflineTxProposalBlock( + amount: Float, + publicKey: ByteArray + ): TrustChainBlock { val blockType = "demo_tx_block" val transaction = mapOf("amount" to amount, "offline" to true) return trustChainCommunity.createProposalBlock(blockType, transaction, publicKey) @@ -89,7 +93,10 @@ class TrustChainHelper( /** * Creates a new proposal block of type "demo_tx_block", using a float as transaction amount. */ - fun createTxProposalBlock(amount: Float?, publicKey: ByteArray): TrustChainBlock { + fun createTxProposalBlock( + amount: Float?, + publicKey: ByteArray + ): TrustChainBlock { val blockType = "demo_tx_block" val transaction = mapOf("amount" to amount) return trustChainCommunity.createProposalBlock(blockType, transaction, publicKey) diff --git a/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/entity/IdentityAttribute.kt b/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/entity/IdentityAttribute.kt index 5359f7dff..b2558eb5a 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/entity/IdentityAttribute.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/entity/IdentityAttribute.kt @@ -10,35 +10,31 @@ data class IdentityAttribute( * The unique attribute ID. */ val id: String, - /** * The attribute name. */ var name: String, - /** * The attribute value. */ var value: String, - /** * Attribute added on date. */ val added: Date, - /** * Attribute modified on date. */ var modified: Date, ) : Serializable { - - fun serialize(): ByteArray = JSONObject().apply { - put(IDENTITY_ATTRIBUTE_ID, id) - put(IDENTITY_ATTRIBUTE_NAME, name) - put(IDENTITY_ATTRIBUTE_VALUE, value) - put(IDENTITY_ATTRIBUTE_ADDED, added) - put(IDENTITY_ATTRIBUTE_MODIFIED, modified) - }.toString().toByteArray() + fun serialize(): ByteArray = + JSONObject().apply { + put(IDENTITY_ATTRIBUTE_ID, id) + put(IDENTITY_ATTRIBUTE_NAME, name) + put(IDENTITY_ATTRIBUTE_VALUE, value) + put(IDENTITY_ATTRIBUTE_ADDED, added) + put(IDENTITY_ATTRIBUTE_MODIFIED, modified) + }.toString().toByteArray() override fun toString(): String { return "$name $value" @@ -51,17 +47,21 @@ data class IdentityAttribute( private const val IDENTITY_ATTRIBUTE_ADDED = "attribute_added" private const val IDENTITY_ATTRIBUTE_MODIFIED = "attribute_modified" - val IDENTITY_ATTRIBUTES = listOf( - "Country", - "City", - "Home Address", - "Zip Code", - "Email", - "Phone Number", - "Mobile Number" - ) + val IDENTITY_ATTRIBUTES = + listOf( + "Country", + "City", + "Home Address", + "Zip Code", + "Email", + "Phone Number", + "Mobile Number" + ) - override fun deserialize(buffer: ByteArray, offset: Int): Pair { + override fun deserialize( + buffer: ByteArray, + offset: Int + ): Pair { val offsetBuffer = buffer.copyOfRange(offset, buffer.size) val json = JSONObject(offsetBuffer.decodeToString()) return Pair( diff --git a/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/entity/IdentityInfo.kt b/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/entity/IdentityInfo.kt index 4cfd91be7..ea91b12b8 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/entity/IdentityInfo.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/entity/IdentityInfo.kt @@ -9,28 +9,26 @@ data class IdentityInfo( * The given names of the identity */ val initials: String?, - /** * The surname of the identity */ val surname: String?, - /** * The verification status of the identity */ val isVerified: Boolean, - /** * The hash of the image of the identity */ val imageHash: String? ) : Serializable { - fun serialize(): ByteArray = JSONObject().apply { - put(IDENTITY_INFO_INITIALS, initials) - put(IDENTITY_INFO_SURNAME, surname) - put(IDENTITY_INFO_VERIFIED, isVerified) - put(IDENTITY_INFO_IMAGE_HASH, imageHash) - }.toString().toByteArray() + fun serialize(): ByteArray = + JSONObject().apply { + put(IDENTITY_INFO_INITIALS, initials) + put(IDENTITY_INFO_SURNAME, surname) + put(IDENTITY_INFO_VERIFIED, isVerified) + put(IDENTITY_INFO_IMAGE_HASH, imageHash) + }.toString().toByteArray() companion object : Deserializable { private const val IDENTITY_INFO_INITIALS = "identity_info_initials" @@ -38,7 +36,10 @@ data class IdentityInfo( private const val IDENTITY_INFO_VERIFIED = "identity_info_verified" private const val IDENTITY_INFO_IMAGE_HASH = "identity_info_image_hash" - override fun deserialize(buffer: ByteArray, offset: Int): Pair { + override fun deserialize( + buffer: ByteArray, + offset: Int + ): Pair { val offsetBuffer = buffer.copyOfRange(offset, buffer.size) val json = JSONObject(offsetBuffer.decodeToString()) diff --git a/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/entity/TransferRequest.kt b/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/entity/TransferRequest.kt index 70971c7f2..10d1e9727 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/entity/TransferRequest.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/entity/TransferRequest.kt @@ -13,29 +13,26 @@ data class TransferRequest( * The (optional) description of the transfer request */ val description: String?, - /** * The requested amount for transfer */ val amount: Long, - /** * The requestor of the request */ val requestor: PublicKey, - /** * The receiver of the request */ val receiver: PublicKey ) : Serializable { - - fun serialize(): ByteArray = JSONObject().apply { - put(TRANSFER_REQUEST_DESCRIPTION, description) - put(TRANSFER_REQUEST_AMOUNT, amount) - put(TRANSFER_REQUEST_REQUESTOR, requestor.keyToBin().toHex()) - put(TRANSFER_REQUEST_RECEIVER, receiver.keyToBin().toHex()) - }.toString().toByteArray() + fun serialize(): ByteArray = + JSONObject().apply { + put(TRANSFER_REQUEST_DESCRIPTION, description) + put(TRANSFER_REQUEST_AMOUNT, amount) + put(TRANSFER_REQUEST_REQUESTOR, requestor.keyToBin().toHex()) + put(TRANSFER_REQUEST_RECEIVER, receiver.keyToBin().toHex()) + }.toString().toByteArray() companion object : Deserializable { const val TRANSFER_REQUEST_DESCRIPTION = "description" @@ -43,7 +40,10 @@ data class TransferRequest( const val TRANSFER_REQUEST_REQUESTOR = "requestor" const val TRANSFER_REQUEST_RECEIVER = "receiver" - override fun deserialize(buffer: ByteArray, offset: Int): Pair { + override fun deserialize( + buffer: ByteArray, + offset: Int + ): Pair { val offsetBuffer = buffer.copyOfRange(offset, buffer.size) val json = JSONObject(offsetBuffer.decodeToString()) return Pair( diff --git a/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/extensions/ImageExtensions.kt b/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/extensions/ImageExtensions.kt index 4cf89fbc3..4c063f320 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/extensions/ImageExtensions.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/extensions/ImageExtensions.kt @@ -18,7 +18,10 @@ fun decodeBytes(encoded: String): ByteArray = Base64.decode(encoded, Base64.DEFA /** * Convert image bitmap to bytearray */ -fun imageBytes(bitmap: Bitmap, quality: Int = 100): ByteArray? { +fun imageBytes( + bitmap: Bitmap, + quality: Int = 100 +): ByteArray? { val baos = ByteArrayOutputStream() return try { @@ -45,7 +48,10 @@ fun bytesToImage(bytes: ByteArray): Bitmap? { /** * Encode image bitmap to string */ -fun encodeImage(bitmap: Bitmap, quality: Int = 100): String? { +fun encodeImage( + bitmap: Bitmap, + quality: Int = 100 +): String? { val baos = ByteArrayOutputStream() return try { @@ -78,14 +84,15 @@ fun decodeImage(decoded: String): Bitmap? { fun Bitmap.resize(maxDimension: Float): Bitmap? { return try { val scale = if (width > maxDimension || height > maxDimension) maxDimension / maxOf(width, height) else 1.0f - val matrix = Matrix().apply { - postScale(scale, scale) - } + val matrix = + Matrix().apply { + postScale(scale, scale) + } val resized = Bitmap.createBitmap(this, 0, 0, width, height, matrix, false) Log.d("VTLOG", "BITMAP WIDTH: $width ${resized.width}") Log.d("VTLOG", "BITMAP HEIGHT: $height ${resized.height}") - Log.d("VTLOG", "BITMAP SIZE IS: ${this.byteCount} ${resized?.byteCount}") + Log.d("VTLOG", "BITMAP SIZE IS: ${this.byteCount} ${resized.byteCount}") resized } catch (e: Exception) { e.printStackTrace() diff --git a/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/extensions/ViewExtensions.kt b/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/extensions/ViewExtensions.kt index e4a5ed209..e3343d3a9 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/extensions/ViewExtensions.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/valuetransfer/extensions/ViewExtensions.kt @@ -6,7 +6,10 @@ import android.view.animation.AnimationUtils import androidx.core.view.isVisible import nl.tudelft.trustchain.common.R -fun View.viewEnterFromLeft(context: Context, duration: Long? = null) { +fun View.viewEnterFromLeft( + context: Context, + duration: Long? = null +) { val animation = AnimationUtils.loadAnimation(context, R.anim.enter_from_left) if (duration != null) animation.duration = duration @@ -16,7 +19,10 @@ fun View.viewEnterFromLeft(context: Context, duration: Long? = null) { } } -fun View.viewEnterFromRight(context: Context, duration: Long? = null) { +fun View.viewEnterFromRight( + context: Context, + duration: Long? = null +) { val animation = AnimationUtils.loadAnimation(context, R.anim.enter_from_right) if (duration != null) animation.duration = duration @@ -26,7 +32,10 @@ fun View.viewEnterFromRight(context: Context, duration: Long? = null) { } } -fun View.viewExitToLeft(context: Context, duration: Long? = null) { +fun View.viewExitToLeft( + context: Context, + duration: Long? = null +) { val animation = AnimationUtils.loadAnimation(context, R.anim.exit_to_left) if (duration != null) animation.duration = duration @@ -36,7 +45,10 @@ fun View.viewExitToLeft(context: Context, duration: Long? = null) { } } -fun View.viewExitToRight(context: Context, duration: Long? = null) { +fun View.viewExitToRight( + context: Context, + duration: Long? = null +) { val animation = AnimationUtils.loadAnimation(context, R.anim.exit_to_right) if (duration != null) animation.duration = duration @@ -46,7 +58,10 @@ fun View.viewExitToRight(context: Context, duration: Long? = null) { } } -fun View.viewFadeIn(context: Context, duration: Long? = null) { +fun View.viewFadeIn( + context: Context, + duration: Long? = null +) { val animation = AnimationUtils.loadAnimation(context, R.anim.fade_in) if (duration != null) animation.duration = duration @@ -56,7 +71,10 @@ fun View.viewFadeIn(context: Context, duration: Long? = null) { } } -fun View.viewFadeOut(context: Context, duration: Long? = null) { +fun View.viewFadeOut( + context: Context, + duration: Long? = null +) { val animation = AnimationUtils.loadAnimation(context, R.anim.fade_out) if (duration != null) animation.duration = duration @@ -66,7 +84,11 @@ fun View.viewFadeOut(context: Context, duration: Long? = null) { } } -fun View.exitEnterView(context: Context, destination: View, forward: Boolean = true) { +fun View.exitEnterView( + context: Context, + destination: View, + forward: Boolean = true +) { if (forward) { this.viewExitToLeft(context) destination.viewEnterFromRight(context) diff --git a/common/src/main/java/nl/tudelft/trustchain/common/wallet/MultiSigWallet.kt b/common/src/main/java/nl/tudelft/trustchain/common/wallet/MultiSigWallet.kt index 7281d17c2..730f354f7 100644 --- a/common/src/main/java/nl/tudelft/trustchain/common/wallet/MultiSigWallet.kt +++ b/common/src/main/java/nl/tudelft/trustchain/common/wallet/MultiSigWallet.kt @@ -11,5 +11,8 @@ interface MultiSigWallet { * does not need to immediately be finished after this method finishes. In fact, usually this is * not the case with multi-signature wallets. */ - fun startTransaction(amount: Double, address: String) + fun startTransaction( + amount: Double, + address: String + ) } diff --git a/common/src/test/java/nl/tudelft/trustchain/common/MarketCommunityTest.kt b/common/src/test/java/nl/tudelft/trustchain/common/MarketCommunityTest.kt index b145d5797..d691bef04 100644 --- a/common/src/test/java/nl/tudelft/trustchain/common/MarketCommunityTest.kt +++ b/common/src/test/java/nl/tudelft/trustchain/common/MarketCommunityTest.kt @@ -1,6 +1,11 @@ package nl.tudelft.trustchain.common -import io.mockk.* +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import io.mockk.runs +import io.mockk.spyk +import io.mockk.verify import nl.tudelft.ipv8.Peer import nl.tudelft.ipv8.messaging.EndpointAggregator import nl.tudelft.ipv8.peerdiscovery.Network diff --git a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/TransactionRepositoryTest.kt b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/TransactionRepositoryTest.kt index 6f78d034e..1b13c31fb 100644 --- a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/TransactionRepositoryTest.kt +++ b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/TransactionRepositoryTest.kt @@ -4,6 +4,6 @@ import org.junit.Test class TransactionRepositoryTest { @Test - fun TestInit() { + fun testInit() { } } diff --git a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenBaseValidatorTest.kt b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenBaseValidatorTest.kt index af84e39cf..d17815846 100644 --- a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenBaseValidatorTest.kt +++ b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenBaseValidatorTest.kt @@ -10,20 +10,20 @@ import java.math.BigInteger @ExperimentalUnsignedTypes class EuroTokenBaseValidatorTest { - @Test fun validateEuroTokenBlockCreate() { - TestBlock(block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT) + testBlock(blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT) } @Test fun test_valid_balance_genesis() { // Test validating a genesis block with 0 balance - val db = Database() - val block = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT, - transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L) - ) + val db = database() + val block = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT, + transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L) + ) val result = validate(block, db) assertEquals(ValidationResult.Valid, result) } @@ -31,100 +31,109 @@ class EuroTokenBaseValidatorTest { @Test fun test_invalid_balance_genesis() { // Test validating a genesis block with an unearned balance - val db = Database() - val block = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to 1L, - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(5) + val db = database() + val block = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to 1L, + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(5) + ) ) - ) val result = validate(block, db) assertTrue(result is ValidationResult.Invalid) assertEquals( (result as ValidationResult.Invalid).errors[0], - EuroTokenBaseValidator.InvalidBalance("").TYPE + EuroTokenBaseValidator.InvalidBalance("").type ) } @Test fun test_missing_balance() { // Test validating a genesis block without a balance - val db = Database() - val block = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT, - transaction = mapOf() - ) + val db = database() + val block = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT, + transaction = mapOf() + ) val result = validate(block, db) assertTrue(result is ValidationResult.Invalid) assertEquals( (result as ValidationResult.Invalid).errors[0], - EuroTokenBaseValidator.MissingBalance("").TYPE + EuroTokenBaseValidator.MissingBalance("").type ) } @Test fun test_missing_validated_balance() { - val db = Database() - val gatewayStore = TestGatewayStore() - val A = TestWallet() - val G = TestGateway(gatewayStore) - - val G1 = TestBlock( - key = G, - block_type = TransactionRepository.BLOCK_TYPE_CREATE, - transaction = mapOf(TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10)), - links = A.pub() - ) + val db = database() + val gatewayStore = testGatewayStore() + val a = testWallet() + val g = testGateway(gatewayStore) + + val g1 = + testBlock( + key = g, + blockType = TransactionRepository.BLOCK_TYPE_CREATE, + transaction = mapOf(TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10)), + links = a.pub() + ) - var result = validate(G1, db) + var result = validate(g1, db) assertEquals(ValidationResult.Valid, result) - db.addBlock(G1) - - val A1 = TestBlock( - key = A, - block_type = TransactionRepository.BLOCK_TYPE_CREATE, - transaction = mapOf(TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10)), - linked = G1 - ) + db.addBlock(g1) + + val a1 = + testBlock( + key = a, + blockType = TransactionRepository.BLOCK_TYPE_CREATE, + transaction = mapOf(TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10)), + linked = g1 + ) - result = validate(A1, db) + result = validate(a1, db) assertEquals(ValidationResult.Valid, result) - db.addBlock(A1) - - val A2 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(5), - TransactionRepository.KEY_BALANCE to 5L - ), - previous = A1 - ) - result = validate(A2, db) + db.addBlock(a1) + + val a2 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(5), + TransactionRepository.KEY_BALANCE to 5L + ), + previous = a1 + ) + result = validate(a2, db) assertEquals( (result as ValidationResult.Invalid).errors[0], - EuroTokenBaseValidator.InsufficientValidatedBalance("").TYPE + EuroTokenBaseValidator.InsufficientValidatedBalance("").type ) } @Test fun test_double_validate() { // Test validating a block that points towards a previous block - val db = Database() + val db = database() - val prev = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT, - transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L) - ) + val prev = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT, + transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L) + ) var result = validate(prev, db) assertEquals(result, ValidationResult.Valid) db.addBlock(prev) - val block = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT, - transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L), - previous = prev - ) + val block = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT, + transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L), + previous = prev + ) result = validate(block, db) assertEquals(result, ValidationResult.Valid) } @@ -132,118 +141,130 @@ class EuroTokenBaseValidatorTest { @Test fun test_double_validate_skip_non_eurotoken() { // Test validating a block that points towards a previous block with a non eurotoken block in between - val db = Database() - val gatewayStore = TestGatewayStore() + val db = database() + val gatewayStore = testGatewayStore() - val G = TestGateway(gatewayStore) + val g = testGateway(gatewayStore) - val A1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT, - transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L), - links = G.pub() - ) - var result = validate(A1, db) + val a1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT, + transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L), + links = g.pub() + ) + var result = validate(a1, db) assertEquals(result, ValidationResult.Valid) - db.addBlock(A1) - - val A2 = TestBlock( - block_type = "NonEurotoken", - transaction = mapOf(), - previous = A1 - ) - db.addBlock(A2) + db.addBlock(a1) - val A3 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT, - transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L), - previous = A2, - links = G.pub() - ) - result = validate(A3, db) + val a2 = + testBlock( + blockType = "NonEurotoken", + transaction = mapOf(), + previous = a1 + ) + db.addBlock(a2) + + val a3 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT, + transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L), + previous = a2, + links = g.pub() + ) + result = validate(a3, db) assertEquals(result, ValidationResult.Valid) } @Test fun test_missing_previous() { // Test validating a block that points towards a missing block - val db = Database() + val db = database() - val gatewayStore = TestGatewayStore() + val gatewayStore = testGatewayStore() - val G = TestGateway(gatewayStore) + val g = testGateway(gatewayStore) - val A1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT, - transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L), - links = G.pub() - ) - var result = validate(A1, db) + val a1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT, + transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L), + links = g.pub() + ) + var result = validate(a1, db) assertEquals(result, ValidationResult.Valid) // db.addBlock(A1) MISSING!!! - val A2 = TestBlock( - block_type = "NonEurotoken", - transaction = mapOf(), - previous = A1 - ) - db.addBlock(A2) - - val A3 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to 0L, - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(5) - ), - previous = A2, - links = G.pub() - ) - result = validate(A3, db) + val a2 = + testBlock( + blockType = "NonEurotoken", + transaction = mapOf(), + previous = a1 + ) + db.addBlock(a2) + + val a3 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to 0L, + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(5) + ), + previous = a2, + links = g.pub() + ) + result = validate(a3, db) assertEquals(result, ValidationResult.PartialPrevious) } @Test fun test_get_balance_receive_block_with_crawl() { - val db = Database() - val gatewayStore = TestGatewayStore() + val db = database() + val gatewayStore = testGatewayStore() - val G = TestGateway(gatewayStore) + val g = testGateway(gatewayStore) - val A = TestWallet() + val a = testWallet() - val A1 = TestBlock( - key = A, - block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT, - transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L) - ) - var result = validate(A1, db) + val a1 = + testBlock( + key = a, + blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT, + transaction = mapOf(TransactionRepository.KEY_BALANCE to 0L) + ) + var result = validate(a1, db) assertEquals(result, ValidationResult.Valid) - db.addBlock(A1) - - val B2 = getWalletBlockWithBalance(10, db, G) - - val B3 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(5), - TransactionRepository.KEY_BALANCE to 5L - ), - previous = B2, - links = A.pub() - ) - result = validate(B3, db) + db.addBlock(a1) + + val b2 = getWalletBlockWithBalance(10, db, g) + + val b3 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(5), + TransactionRepository.KEY_BALANCE to 5L + ), + previous = b2, + links = a.pub() + ) + result = validate(b3, db) assertEquals(result, ValidationResult.Valid) - db.addBlock(B3) - - val A2 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(5), - TransactionRepository.KEY_BALANCE to 5L - ), - previous = A1, - linked = B3 - ) - val balance = getBalanceForBlock(A2, db) + db.addBlock(b3) + + val a2 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(5), + TransactionRepository.KEY_BALANCE to 5L + ), + previous = a1, + linked = b3 + ) + val balance = getBalanceForBlock(a2, db) assertEquals(balance, 5L) } } diff --git a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCheckpointValidatorTest.kt b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCheckpointValidatorTest.kt index d5207d881..496f30b37 100644 --- a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCheckpointValidatorTest.kt +++ b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCheckpointValidatorTest.kt @@ -11,112 +11,128 @@ import java.math.BigInteger class EuroTokenCheckpointValidatorTest { @Test fun test_init() { - TestBlock(block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT) + testBlock(blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT) } @Test fun test_missing_checkpoint_links() { // Test validating a block that points towards a previous block - val db = Database() - - val gatewayStore = TestGatewayStore() - val G = TestGateway(gatewayStore) - - val A = TestWallet() - - val G1 = TestBlock( - key = G, - block_type = TransactionRepository.BLOCK_TYPE_CREATE, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) - ), - links = A.pub() - ) - - val A1 = TestBlock( - key = A, - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) - ), - linked = G1 - ) - db.addBlock(G1) - db.addBlock(A1) - - val A2 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to 10L - ), - previous = A1, - links = G.pub() - ) - - var result = validate(A2, db) + val db = database() + + val gatewayStore = testGatewayStore() + val g = testGateway(gatewayStore) + + val a = testWallet() + + val g1 = + testBlock( + key = g, + blockType = TransactionRepository.BLOCK_TYPE_CREATE, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) + ), + links = a.pub() + ) + + val a1 = + testBlock( + key = a, + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) + ), + linked = g1 + ) + db.addBlock(g1) + db.addBlock(a1) + + val a2 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to 10L + ), + previous = a1, + links = g.pub() + ) + + var result = validate(a2, db) assertEquals(result, ValidationResult.Valid) - db.addBlock(A2) - - val G2 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_CREATE, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) - ), - previous = G1, - links = A.pub() - ) - db.addBlock(G2) - - val A3 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_CREATE, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) - ), - previous = A2, - linked = G2 - ) - - result = validate(A3, db) + db.addBlock(a2) + + val g2 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_CREATE, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) + ), + previous = g1, + links = a.pub() + ) + db.addBlock(g2) + + val a3 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_CREATE, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) + ), + previous = a2, + linked = g2 + ) + + result = validate(a3, db) assertEquals(result, ValidationResult.Valid) - db.addBlock(A3) - - val A4 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to 20L - ), - previous = A3, - links = G.pub() - ) - - result = validate(A4, db) + db.addBlock(a3) + + val a4 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to 20L + ), + previous = a3, + links = g.pub() + ) + + result = validate(a4, db) assertEquals(result, ValidationResult.Valid) - db.addBlock(A4) - - val A5 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to 0L, - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(20) - ), - previous = A4 - ) - - result = validate(A5, db) + db.addBlock(a4) + + val a5 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to 0L, + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(20) + ), + previous = a4 + ) + + result = validate(a5, db) assertTrue(result is ValidationResult.MissingBlocks) assertEquals((result as ValidationResult.MissingBlocks).blockRanges.size, 2) - val G3 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to 10L - ), - previous = G2, - linked = A2 - ) - db.addBlock(G3) - - result = validate(A5, db) + val g3 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to 10L + ), + previous = g2, + linked = a2 + ) + db.addBlock(g3) + + result = validate(a5, db) println(result) assertTrue(result is ValidationResult.MissingBlocks) assertEquals((result as ValidationResult.MissingBlocks).blockRanges.size, 1) diff --git a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCreationValidatorTest.kt b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCreationValidatorTest.kt index 8f2efb3ee..33656a4f0 100644 --- a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCreationValidatorTest.kt +++ b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenCreationValidatorTest.kt @@ -8,53 +8,56 @@ import org.junit.Test @ExperimentalUnsignedTypes class EuroTokenCreationValidatorTest { - @Test fun test_init() { - TestBlock(block_type = TransactionRepository.BLOCK_TYPE_CREATE) + testBlock(blockType = TransactionRepository.BLOCK_TYPE_CREATE) } @Test fun test_missing_amount() { - val db = Database() + val db = database() - val block = TestBlock(block_type = TransactionRepository.BLOCK_TYPE_CREATE, transaction = mapOf()) + val block = testBlock(blockType = TransactionRepository.BLOCK_TYPE_CREATE, transaction = mapOf()) val result = validate(block, db) assertTrue(result is ValidationResult.Invalid) - assertEquals((result as ValidationResult.Invalid).errors[0], EuroTokenCreationValidator.MissingAmount("").TYPE) + assertEquals((result as ValidationResult.Invalid).errors[0], EuroTokenCreationValidator.MissingAmount("").type) } @Test fun test_valid_creation() { // Test Valid send after receiving - val db = Database() - - val gatewayStore = TestGatewayStore() - val G = TestGateway(gatewayStore) - - val A = TestWallet() - - val G1 = TestBlock( - key = G, - block_type = TransactionRepository.BLOCK_TYPE_CREATE, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to 10L - ), - links = A.pub() - ) - db.addBlock(G1) - val A1 = TestBlock( - key = A, - block_type = TransactionRepository.BLOCK_TYPE_CREATE, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to 10L - ), - linked = G1 - ) - val result = validate(A1, db) + val db = database() + + val gatewayStore = testGatewayStore() + val g = testGateway(gatewayStore) + + val a = testWallet() + + val g1 = + testBlock( + key = g, + blockType = TransactionRepository.BLOCK_TYPE_CREATE, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to 10L + ), + links = a.pub() + ) + db.addBlock(g1) + val a1 = + testBlock( + key = a, + blockType = TransactionRepository.BLOCK_TYPE_CREATE, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to 10L + ), + linked = g1 + ) + val result = validate(a1, db) assertEquals(result, ValidationResult.Valid) - db.addBlock(A1) + db.addBlock(a1) } } diff --git a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenDestructionValidatorTest.kt b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenDestructionValidatorTest.kt index 9f6ff2ce8..4af9886f2 100644 --- a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenDestructionValidatorTest.kt +++ b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenDestructionValidatorTest.kt @@ -9,111 +9,118 @@ import java.math.BigInteger @ExperimentalUnsignedTypes class EuroTokenDestructionValidatorTest { - @Test fun test_init() { - TestBlock(block_type = TransactionRepository.BLOCK_TYPE_DESTROY) + testBlock(blockType = TransactionRepository.BLOCK_TYPE_DESTROY) } @Test fun test_valid_send_id() { // Test Valid send after receiving - val db = Database() - val gatewayStore = TestGatewayStore() - - val G = TestGateway(gatewayStore) - - val A2 = getWalletBlockWithBalance(10, db, G) - - val A3 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_DESTROY, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L, - TransactionRepository.KEY_PAYMENT_ID to "ID" - ), - previous = A2 - ) + val db = database() + val gatewayStore = testGatewayStore() + + val g = testGateway(gatewayStore) + + val a2 = getWalletBlockWithBalance(10, db, g) + + val a3 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_DESTROY, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L, + TransactionRepository.KEY_PAYMENT_ID to "ID" + ), + previous = a2 + ) - val result = validate(A3, db) + val result = validate(a3, db) assertEquals(result, ValidationResult.Valid) } @Test fun test_valid_send_iban() { // Test Valid send after receiving - val db = Database() - - val gatewayStore = TestGatewayStore() - val G = TestGateway(gatewayStore) - - val A2 = getWalletBlockWithBalance(10, db, G) - - val A3 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_DESTROY, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L, - TransactionRepository.KEY_IBAN to "IBAN" - ), - previous = A2 - ) + val db = database() + + val gatewayStore = testGatewayStore() + val g = testGateway(gatewayStore) + + val a2 = getWalletBlockWithBalance(10, db, g) + + val a3 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_DESTROY, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L, + TransactionRepository.KEY_IBAN to "IBAN" + ), + previous = a2 + ) - val result = validate(A3, db) + val result = validate(a3, db) assertEquals(result, ValidationResult.Valid) } @Test fun test_missing_amount() { // Test Valid send after receiving - val db = Database() - - val gatewayStore = TestGatewayStore() - val G = TestGateway(gatewayStore) - - val A2 = getWalletBlockWithBalance(10, db, G) - - val A3 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_DESTROY, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to 0L, - TransactionRepository.KEY_IBAN to "IBAN" - ), - previous = A2 - ) + val db = database() + + val gatewayStore = testGatewayStore() + val g = testGateway(gatewayStore) + + val a2 = getWalletBlockWithBalance(10, db, g) + + val a3 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_DESTROY, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to 0L, + TransactionRepository.KEY_IBAN to "IBAN" + ), + previous = a2 + ) - val result = validate(A3, db) + val result = validate(a3, db) assertTrue(result is ValidationResult.Invalid) assertEquals( (result as ValidationResult.Invalid).errors[0], - EuroTokenDestructionValidator.MissingAmount("").TYPE + EuroTokenDestructionValidator.MissingAmount("").type ) } @Test fun test_missing_payment_id_and_iban() { // Test Valid send after receiving - val db = Database() - - val gatewayStore = TestGatewayStore() - val G = TestGateway(gatewayStore) - - val A2 = getWalletBlockWithBalance(10, db, G) - - val A3 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_DESTROY, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L - ), - previous = A2 - ) + val db = database() + + val gatewayStore = testGatewayStore() + val g = testGateway(gatewayStore) + + val a2 = getWalletBlockWithBalance(10, db, g) + + val a3 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_DESTROY, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ), + previous = a2 + ) - val result = validate(A3, db) + val result = validate(a3, db) assertTrue(result is ValidationResult.Invalid) assertEquals( (result as ValidationResult.Invalid).errors[0], - EuroTokenDestructionValidator.MissingPaymentIDorIBAN("").TYPE + EuroTokenDestructionValidator.MissingPaymentIDorIBAN("").type ) } @@ -121,50 +128,54 @@ class EuroTokenDestructionValidatorTest { fun test_invalid_send() { // Test balance not deducted // Test Valid send after receiving - val db = Database() - - val gatewayStore = TestGatewayStore() - val G = TestGateway(gatewayStore) - - val A2 = getWalletBlockWithBalance(10, db, G) - - val A3 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_DESTROY, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 10L, - TransactionRepository.KEY_IBAN to "IBAN" - ), - previous = A2 - ) + val db = database() + + val gatewayStore = testGatewayStore() + val g = testGateway(gatewayStore) + + val a2 = getWalletBlockWithBalance(10, db, g) + + val a3 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_DESTROY, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 10L, + TransactionRepository.KEY_IBAN to "IBAN" + ), + previous = a2 + ) - val result = validate(A3, db) + val result = validate(a3, db) assertTrue(result is ValidationResult.Invalid) assertEquals( (result as ValidationResult.Invalid).errors[0], - EuroTokenBaseValidator.InvalidBalance("").TYPE + EuroTokenBaseValidator.InvalidBalance("").type ) } @Test fun test_invalid_send2() { // Balance is not available on transfer - val db = Database() - - val A1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_DESTROY, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to -10L, - TransactionRepository.KEY_IBAN to "IBAN" + val db = database() + + val a1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_DESTROY, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to -10L, + TransactionRepository.KEY_IBAN to "IBAN" + ) ) - ) - val result = validate(A1, db) + val result = validate(a1, db) assertTrue(result is ValidationResult.Invalid) assertEquals( (result as ValidationResult.Invalid).errors[0], - EuroTokenBaseValidator.InsufficientBalance("").TYPE + EuroTokenBaseValidator.InsufficientBalance("").type ) } } diff --git a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenRollbackValidatorTest.kt b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenRollbackValidatorTest.kt index 7fcc36a48..9aa349563 100644 --- a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenRollbackValidatorTest.kt +++ b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenRollbackValidatorTest.kt @@ -10,271 +10,306 @@ import java.math.BigInteger @ExperimentalUnsignedTypes class EuroTokenRollbackValidatorTest { - @Test fun test_init() { - TestBlock(block_type = TransactionRepository.BLOCK_TYPE_ROLLBACK) + testBlock(blockType = TransactionRepository.BLOCK_TYPE_ROLLBACK) } @Test fun test_valid_rollback() { // Test Valid rollback after receiving - val db = Database() + val db = database() // Receive money - val B1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L + val b1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ) ) - ) - val A1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L - ), - linked = B1 - ) - db.addBlock(B1) - db.addBlock(A1) + val a1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ), + linked = b1 + ) + db.addBlock(b1) + db.addBlock(a1) - var result = validate(A1, db) + var result = validate(a1, db) assertEquals(result, ValidationResult.Valid) // roll back the transaction - val A2 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_ROLLBACK, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L, - TransactionRepository.KEY_TRANSACTION_HASH to A1.calculateHash().toHex() - ), - previous = A1 - ) + val a2 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_ROLLBACK, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L, + TransactionRepository.KEY_TRANSACTION_HASH to a1.calculateHash().toHex() + ), + previous = a1 + ) - result = validate(A2, db) + result = validate(a2, db) assertEquals(result, ValidationResult.Valid) } @Test fun test_valid_rollback_missing_transaction() { // Test Valid rollback after receiving - val db = Database() + val db = database() // Receive money - val B1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L + val b1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ) ) - ) - val A1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L - ), - linked = B1 - ) - db.addBlock(B1) - db.addBlock(A1) + val a1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ), + linked = b1 + ) + db.addBlock(b1) + db.addBlock(a1) - var result = validate(A1, db) + var result = validate(a1, db) assertEquals(result, ValidationResult.Valid) // roll back the transaction - val A2 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_ROLLBACK, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L, - TransactionRepository.KEY_TRANSACTION_HASH to "ABCD" - ), - previous = A1 - ) + val a2 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_ROLLBACK, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L, + TransactionRepository.KEY_TRANSACTION_HASH to "ABCD" + ), + previous = a1 + ) - result = validate(A2, db) + result = validate(a2, db) assertEquals(result, ValidationResult.Valid) } @Test fun test_missing_amount() { // Test Valid send after receiving - val db = Database() + val db = database() // Receive money - val B1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L + val b1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ) ) - ) - val A1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L - ), - linked = B1 - ) - db.addBlock(B1) - db.addBlock(A1) + val a1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ), + linked = b1 + ) + db.addBlock(b1) + db.addBlock(a1) - var result = validate(A1, db) + var result = validate(a1, db) assertEquals(result, ValidationResult.Valid) // roll back the transaction - val A2 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_ROLLBACK, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to 0L, - TransactionRepository.KEY_TRANSACTION_HASH to A1.calculateHash().toHex() - ), - previous = A1 - ) + val a2 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_ROLLBACK, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to 0L, + TransactionRepository.KEY_TRANSACTION_HASH to a1.calculateHash().toHex() + ), + previous = a1 + ) - result = validate(A2, db) + result = validate(a2, db) assertTrue(result is ValidationResult.Invalid) assertEquals( (result as ValidationResult.Invalid).errors[0], - EuroTokenRollBackValidator.MissingAmount("").TYPE + EuroTokenRollBackValidator.MissingAmount("").type ) } @Test fun test_missing_hash() { // Test Valid rollback after receiving - val db = Database() + val db = database() // Receive money - val B1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L + val b1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ) ) - ) - val A1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L - ), - linked = B1 - ) - db.addBlock(B1) - db.addBlock(A1) + val a1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ), + linked = b1 + ) + db.addBlock(b1) + db.addBlock(a1) - var result = validate(A1, db) + var result = validate(a1, db) assertEquals(result, ValidationResult.Valid) // roll back the transaction - val A2 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_ROLLBACK, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L - ), - previous = A1 - ) + val a2 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_ROLLBACK, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ), + previous = a1 + ) - result = validate(A2, db) + result = validate(a2, db) assertTrue(result is ValidationResult.Invalid) assertEquals( (result as ValidationResult.Invalid).errors[0], - EuroTokenRollBackValidator.MissingTransactionHash("").TYPE + EuroTokenRollBackValidator.MissingTransactionHash("").type ) } @Test fun test_missing_previous() { // Test Valid rollback after receiving - val db = Database() + val db = database() // Receive money - val B1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L + val b1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ) ) - ) - val A1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L - ), - linked = B1 - ) - db.addBlock(B1) + val a1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ), + linked = b1 + ) + db.addBlock(b1) // db.addBlock(A1) - var result = validate(A1, db) + var result = validate(a1, db) assertEquals(result, ValidationResult.Valid) // roll back the transaction - val A2 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_ROLLBACK, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L, - TransactionRepository.KEY_TRANSACTION_HASH to A1.calculateHash().toHex() - ), - previous = A1 - ) + val a2 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_ROLLBACK, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L, + TransactionRepository.KEY_TRANSACTION_HASH to a1.calculateHash().toHex() + ), + previous = a1 + ) - result = validate(A2, db) + result = validate(a2, db) assertTrue(result is ValidationResult.PartialPrevious) } @Test fun test_invalid_amount() { // Test amount doesnt match rolled back transaction - val db = Database() + val db = database() // Receive money - val B1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L + val b1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ) ) - ) - val A1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), - TransactionRepository.KEY_BALANCE to 0L - ), - linked = B1 - ) - db.addBlock(B1) - db.addBlock(A1) + val a1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10), + TransactionRepository.KEY_BALANCE to 0L + ), + linked = b1 + ) + db.addBlock(b1) + db.addBlock(a1) - var result = validate(A1, db) + var result = validate(a1, db) assertEquals(result, ValidationResult.Valid) // roll back the transaction - val A2 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_ROLLBACK, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(5), - TransactionRepository.KEY_BALANCE to 5L, - TransactionRepository.KEY_TRANSACTION_HASH to A1.calculateHash().toHex() - ), - previous = A1 - ) + val a2 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_ROLLBACK, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(5), + TransactionRepository.KEY_BALANCE to 5L, + TransactionRepository.KEY_TRANSACTION_HASH to a1.calculateHash().toHex() + ), + previous = a1 + ) - result = validate(A2, db) + result = validate(a2, db) assertTrue(result is ValidationResult.Invalid) assertEquals( (result as ValidationResult.Invalid).errors[0], - EuroTokenRollBackValidator.InvalidTransaction("").TYPE + EuroTokenRollBackValidator.InvalidTransaction("").type ) } } diff --git a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenTransferValidatorTest.kt b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenTransferValidatorTest.kt index 7b2c9c71a..738532595 100644 --- a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenTransferValidatorTest.kt +++ b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/EuroTokenTransferValidatorTest.kt @@ -9,104 +9,111 @@ import java.math.BigInteger @ExperimentalUnsignedTypes class EuroTokenTransferValidatorTest { - @Test fun test_init() { - TestBlock(block_type = TransactionRepository.BLOCK_TYPE_TRANSFER) + testBlock(blockType = TransactionRepository.BLOCK_TYPE_TRANSFER) } @Test fun test_valid_send() { // Test Valid send after receiving - val db = Database() - - val gatewayStore = TestGatewayStore() - val G = TestGateway(gatewayStore) - - val A2 = getWalletBlockWithBalance(10, db, G) - - val A3 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to 0L, - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) - ), - previous = A2 - ) + val db = database() + + val gatewayStore = testGatewayStore() + val g = testGateway(gatewayStore) + + val a2 = getWalletBlockWithBalance(10, db, g) + + val a3 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to 0L, + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) + ), + previous = a2 + ) - val result = validate(A3, db) + val result = validate(a3, db) assertEquals(result, ValidationResult.Valid) } @Test fun test_missing_amount() { // Test missing amount - val db = Database() + val db = database() - val gatewayStore = TestGatewayStore() - val G = TestGateway(gatewayStore) + val gatewayStore = testGatewayStore() + val g = testGateway(gatewayStore) - val A2 = getWalletBlockWithBalance(10, db, G) + val a2 = getWalletBlockWithBalance(10, db, g) - val A3 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to 0L - ), - previous = A2 - ) + val a3 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to 0L + ), + previous = a2 + ) - val result = validate(A3, db) + val result = validate(a3, db) assertTrue(result is ValidationResult.Invalid) assertEquals( (result as ValidationResult.Invalid).errors[0], - EuroTokenTransferValidator.MissingAmount("").TYPE + EuroTokenTransferValidator.MissingAmount("").type ) } @Test fun test_invalid_send() { // Balance is not deducted on transfer - val db = Database() - - val gatewayStore = TestGatewayStore() - val G = TestGateway(gatewayStore) - - val A2 = getWalletBlockWithBalance(10, db, G) - - val A3 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to 10L, - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) - ), - previous = A2 - ) + val db = database() + + val gatewayStore = testGatewayStore() + val gateway = testGateway(gatewayStore) + + val a2 = getWalletBlockWithBalance(10, db, gateway) + + val a3 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to 10L, + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) + ), + previous = a2 + ) - val result = validate(A3, db) + val result = validate(a3, db) assertTrue(result is ValidationResult.Invalid) assertEquals( (result as ValidationResult.Invalid).errors[0], - EuroTokenBaseValidator.InvalidBalance("").TYPE + EuroTokenBaseValidator.InvalidBalance("").type ) } @Test fun test_invalid_send2() { // Balance is not available on transfer - val db = Database() - val A1 = TestBlock( - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to -10L, - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) + val db = database() + val a1 = + testBlock( + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to -10L, + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(10) + ) ) - ) - val result = validate(A1, db) + val result = validate(a1, db) assertTrue(result is ValidationResult.Invalid) assertEquals( (result as ValidationResult.Invalid).errors[0], - EuroTokenBaseValidator.InsufficientBalance("").TYPE + EuroTokenBaseValidator.InsufficientBalance("").type ) } } diff --git a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/ValidatorTestUtils.kt b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/ValidatorTestUtils.kt index 6a0371fdb..449b4c225 100644 --- a/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/ValidatorTestUtils.kt +++ b/common/src/test/java/nl/tudelft/trustchain/common/eurotoken/blocks/ValidatorTestUtils.kt @@ -1,7 +1,7 @@ package nl.tudelft.trustchain.common.eurotoken.blocks -import com.squareup.sqldelight.db.SqlDriver -import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver +import app.cash.sqldelight.db.SqlDriver +import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver import io.mockk.mockk import nl.tudelft.ipv8.attestation.trustchain.* import nl.tudelft.ipv8.attestation.trustchain.store.TrustChainSQLiteStore @@ -15,103 +15,120 @@ import nl.tudelft.trustchain.common.eurotoken.TransactionRepository import java.math.BigInteger import java.util.* -val validatorMappings = mapOf( - TransactionRepository.BLOCK_TYPE_CHECKPOINT to EuroTokenCheckpointValidator(mockk(relaxed = true)), - TransactionRepository.BLOCK_TYPE_TRANSFER to EuroTokenTransferValidator(mockk(relaxed = true)), - TransactionRepository.BLOCK_TYPE_CREATE to EuroTokenCreationValidator(mockk(relaxed = true)), - TransactionRepository.BLOCK_TYPE_ROLLBACK to EuroTokenRollBackValidator(mockk(relaxed = true)), - TransactionRepository.BLOCK_TYPE_DESTROY to EuroTokenDestructionValidator(mockk(relaxed = true)) -) +val validatorMappings = + mapOf( + TransactionRepository.BLOCK_TYPE_CHECKPOINT to EuroTokenCheckpointValidator(mockk(relaxed = true)), + TransactionRepository.BLOCK_TYPE_TRANSFER to EuroTokenTransferValidator(mockk(relaxed = true)), + TransactionRepository.BLOCK_TYPE_CREATE to EuroTokenCreationValidator(mockk(relaxed = true)), + TransactionRepository.BLOCK_TYPE_ROLLBACK to EuroTokenRollBackValidator(mockk(relaxed = true)), + TransactionRepository.BLOCK_TYPE_DESTROY to EuroTokenDestructionValidator(mockk(relaxed = true)) + ) @ExperimentalUnsignedTypes -fun getWalletBlockWithBalance(balance: Long, db: TrustChainSQLiteStore, gateway: PrivateKey): TrustChainBlock { - val new = TestWallet() - val before = TestBlock( // not really verified or added to DB, the checkpoint should "hide" it - key = new, - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(balance), - TransactionRepository.KEY_BALANCE to 0L - ), - linked = TestBlock( - key = gateway, - block_type = TransactionRepository.BLOCK_TYPE_TRANSFER, - transaction = mapOf( - TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(balance), - TransactionRepository.KEY_BALANCE to 0L - ) +fun getWalletBlockWithBalance( + balance: Long, + db: TrustChainSQLiteStore, + gateway: PrivateKey +): TrustChainBlock { + val new = testWallet() + // not really verified or added to DB, the checkpoint should "hide" it + val before = + testBlock( + key = new, + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(balance), + TransactionRepository.KEY_BALANCE to 0L + ), + linked = + testBlock( + key = gateway, + blockType = TransactionRepository.BLOCK_TYPE_TRANSFER, + transaction = + mapOf( + TransactionRepository.KEY_AMOUNT to BigInteger.valueOf(balance), + TransactionRepository.KEY_BALANCE to 0L + ) + ) + ) + val req = + testBlock( + key = new, + blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to balance + ), + previous = before, + links = gateway.pub() ) - ) - val req = TestBlock( - key = new, - block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to balance - ), - previous = before, - links = gateway.pub() - ) db.addBlock(req) db.addBlock( - TestBlock( + testBlock( key = gateway, - block_type = TransactionRepository.BLOCK_TYPE_CHECKPOINT, - transaction = mapOf( - TransactionRepository.KEY_BALANCE to balance - ), + blockType = TransactionRepository.BLOCK_TYPE_CHECKPOINT, + transaction = + mapOf( + TransactionRepository.KEY_BALANCE to balance + ), linked = req ) ) return req } -fun TestWallet(): PrivateKey { +fun testWallet(): PrivateKey { return JavaCryptoProvider.generateKey() } -fun TestGatewayStore(): GatewayStore { +fun testGatewayStore(): GatewayStore { val driver: SqlDriver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY) nl.tudelft.common.sqldelight.Database.Schema.create(driver) val database = nl.tudelft.common.sqldelight.Database(driver) return GatewayStore(database) } -fun TestGateway(gatewayStore: GatewayStore): PrivateKey { +fun testGateway(gatewayStore: GatewayStore): PrivateKey { val key = JavaCryptoProvider.generateKey() gatewayStore.addGateway(key.pub(), "Test Gateway", "127.0.0.1", 8900) return key } -fun validate(block: TrustChainBlock, database: TrustChainStore): ValidationResult { +fun validate( + block: TrustChainBlock, + database: TrustChainStore +): ValidationResult { return validatorMappings[block.type]?.validate(block, database) ?: ValidationResult.Valid } @ExperimentalUnsignedTypes -fun TestBlock( - block_type: String, +fun testBlock( + blockType: String, key: PrivateKey? = null, transaction: Map? = null, links: PublicKey? = null, linked: TrustChainBlock? = null, previous: TrustChainBlock? = null ): TrustChainBlock { - val pkey = key ?: TestWallet() - val block = TrustChainBlock( - linked?.type ?: block_type, - TransactionEncoding.encode(transaction ?: linked?.transaction ?: mapOf()), - pkey.pub().keyToBin(), - previous?.sequenceNumber?.plus(1u) ?: GENESIS_SEQ, - linked?.publicKey ?: links?.keyToBin() ?: TestWallet().pub().keyToBin(), - linked?.sequenceNumber ?: UNKNOWN_SEQ, - previous?.calculateHash() ?: GENESIS_HASH, - EMPTY_SIG, - Date() - ) + val pkey = key ?: testWallet() + val block = + TrustChainBlock( + linked?.type ?: blockType, + TransactionEncoding.encode(transaction ?: linked?.transaction ?: mapOf()), + pkey.pub().keyToBin(), + previous?.sequenceNumber?.plus(1u) ?: GENESIS_SEQ, + linked?.publicKey ?: links?.keyToBin() ?: testWallet().pub().keyToBin(), + linked?.sequenceNumber ?: UNKNOWN_SEQ, + previous?.calculateHash() ?: GENESIS_HASH, + EMPTY_SIG, + Date() + ) block.sign(pkey) return block } -fun Database(): TrustChainSQLiteStore { +fun database(): TrustChainSQLiteStore { val driver: SqlDriver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY) nl.tudelft.ipv8.sqldelight.Database.Schema.create(driver) val database = nl.tudelft.ipv8.sqldelight.Database(driver) diff --git a/common/src/test/java/nl/tudelft/trustchain/common/messaging/TradePayloadTest.kt b/common/src/test/java/nl/tudelft/trustchain/common/messaging/TradePayloadTest.kt index 592b7cdce..0fea9f03a 100644 --- a/common/src/test/java/nl/tudelft/trustchain/common/messaging/TradePayloadTest.kt +++ b/common/src/test/java/nl/tudelft/trustchain/common/messaging/TradePayloadTest.kt @@ -7,14 +7,15 @@ import org.junit.Test class TradePayloadTest { @Test fun serializeOutputDeserializesToOriginal() { - val payload = TradePayload( - byteArrayOf(0x00), - Currency.DYMBE_DOLLAR, - Currency.BTC, - 100.0, - 100.0, - TradePayload.Type.ASK - ) + val payload = + TradePayload( + byteArrayOf(0x00), + Currency.DYMBE_DOLLAR, + Currency.BTC, + 100.0, + 100.0, + TradePayload.Type.ASK + ) val serializedPayload = payload.serialize() val deserializedPayload = TradePayload.deserialize(serializedPayload).first assertEquals(payload, deserializedPayload) diff --git a/currencyii/build.gradle b/currencyii/build.gradle index 981c931a2..6cf6a97b9 100644 --- a/currencyii/build.gradle +++ b/currencyii/build.gradle @@ -1,6 +1,5 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' apply plugin: 'androidx.navigation.safeargs.kotlin' apply plugin: 'org.jlleitschuh.gradle.ktlint' @@ -9,14 +8,14 @@ ktlint { android = true outputToConsole = true ignoreFailures = false + verbose = true } android { - compileSdkVersion 33 - defaultConfig { - minSdkVersion 24 - targetSdkVersion 33 + minSdkVersion 26 + compileSdk 34 + targetSdkVersion 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -29,12 +28,12 @@ android { } compileOptions { - targetCompatibility JavaVersion.VERSION_1_8 - sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_17.toString() } buildFeatures { @@ -87,7 +86,7 @@ dependencies { // Testing implementation 'androidx.legacy:legacy-support-v4:1.0.0' testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1' - testImplementation "io.mockk:mockk:1.9.3" + testImplementation "io.mockk:mockk:$mockk_version" androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' @@ -107,6 +106,6 @@ dependencies { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { kotlinOptions.freeCompilerArgs += [ - "-opt-in=kotlin.Experimental,kotlin.ExperimentalUnsignedTypes" + "-opt-in=kotlin.ExperimentalUnsignedTypes" ] } diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/CoinCommunity.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/CoinCommunity.kt index 7de16ee88..ac7d1ed1e 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/CoinCommunity.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/CoinCommunity.kt @@ -53,9 +53,7 @@ class CoinCommunity constructor(serviceId: String = "02313685c1912a141279f8248fc * **NOTE** the latest walletBlockData should be given, otherwise the serialized transaction is invalid. * @param walletBlock - the latest (that you know of) shared wallet block. */ - fun proposeJoinWallet( - walletBlock: TrustChainBlock - ): SWSignatureAskTransactionData { + fun proposeJoinWallet(walletBlock: TrustChainBlock): SWSignatureAskTransactionData { return daoJoinHelper.proposeJoinWallet(myPeer, walletBlock) } @@ -153,8 +151,9 @@ class CoinCommunity constructor(serviceId: String = "02313685c1912a141279f8248fc * swBlockHash - the hash of one of the blocks associated with a shared wallet. */ fun fetchLatestSharedWalletBlock(swBlockHash: ByteArray): TrustChainBlock? { - val swBlock = getTrustChainCommunity().database.getBlockWithHash(swBlockHash) - ?: return null + val swBlock = + getTrustChainCommunity().database.getBlockWithHash(swBlockHash) + ?: return null val swBlocks = getTrustChainCommunity().database.getBlocksWithType(JOIN_BLOCK) return fetchLatestSharedWalletBlock(swBlock, swBlocks) } @@ -225,14 +224,16 @@ class CoinCommunity constructor(serviceId: String = "02313685c1912a141279f8248fc */ fun fetchProposalBlocks(): List { val joinProposals = getTrustChainCommunity().database.getBlocksWithType(SIGNATURE_ASK_BLOCK) - val transferProposals = getTrustChainCommunity().database.getBlocksWithType( - TRANSFER_FUNDS_ASK_BLOCK - ) + val transferProposals = + getTrustChainCommunity().database.getBlocksWithType( + TRANSFER_FUNDS_ASK_BLOCK + ) return joinProposals .union(transferProposals) .filter { - fetchSignatureRequestReceiver(it) == myPeer.publicKey.keyToBin() - .toHex() && !checkEnoughFavorSignatures(it) + fetchSignatureRequestReceiver(it) == + myPeer.publicKey.keyToBin() + .toHex() && !checkEnoughFavorSignatures(it) } .distinctBy { fetchSignatureRequestProposalId(it) } .sortedByDescending { it.timestamp } @@ -242,7 +243,10 @@ class CoinCommunity constructor(serviceId: String = "02313685c1912a141279f8248fc * Fetch all DAO blocks that contain a signature. These blocks are the response of a signature request. * Signatures are fetched from [SIGNATURE_AGREEMENT_BLOCK] type blocks. */ - fun fetchProposalResponses(walletId: String, proposalId: String): List { + fun fetchProposalResponses( + walletId: String, + proposalId: String + ): List { return getTrustChainCommunity().database.getBlocksWithType(SIGNATURE_AGREEMENT_BLOCK) .filter { val blockData = SWResponseSignatureTransactionData(it.transaction) @@ -256,7 +260,10 @@ class CoinCommunity constructor(serviceId: String = "02313685c1912a141279f8248fc * Fetch all DAO blocks that contain a negative signature. These blocks are the response of a negative signature request. * Signatures are fetched from [SIGNATURE_AGREEMENT_NEGATIVE_BLOCK] type blocks. */ - fun fetchNegativeProposalResponses(walletId: String, proposalId: String): List { + fun fetchNegativeProposalResponses( + walletId: String, + proposalId: String + ): List { return getTrustChainCommunity().database.getBlocksWithType( SIGNATURE_AGREEMENT_NEGATIVE_BLOCK ) @@ -277,10 +284,12 @@ class CoinCommunity constructor(serviceId: String = "02313685c1912a141279f8248fc votedInFavor: Boolean, context: Context ) { - val latestHash = SWSignatureAskTransactionData(block.transaction).getData() - .SW_PREVIOUS_BLOCK_HASH - val mostRecentSWBlock = fetchLatestSharedWalletBlock(latestHash.hexToBytes()) - ?: throw IllegalStateException("Most recent DAO block not found") + val latestHash = + SWSignatureAskTransactionData(block.transaction).getData() + .SW_PREVIOUS_BLOCK_HASH + val mostRecentSWBlock = + fetchLatestSharedWalletBlock(latestHash.hexToBytes()) + ?: throw IllegalStateException("Most recent DAO block not found") val joinBlock = SWJoinBlockTransactionData(mostRecentSWBlock.transaction).getData() val oldTransaction = joinBlock.SW_TRANSACTION_SERIALIZED @@ -296,10 +305,12 @@ class CoinCommunity constructor(serviceId: String = "02313685c1912a141279f8248fc votedInFavor: Boolean, context: Context ) { - val latestHash = SWTransferFundsAskTransactionData(block.transaction).getData() - .SW_PREVIOUS_BLOCK_HASH - val mostRecentSWBlock = fetchLatestSharedWalletBlock(latestHash.hexToBytes()) - ?: throw IllegalStateException("Most recent DAO block not found") + val latestHash = + SWTransferFundsAskTransactionData(block.transaction).getData() + .SW_PREVIOUS_BLOCK_HASH + val mostRecentSWBlock = + fetchLatestSharedWalletBlock(latestHash.hexToBytes()) + ?: throw IllegalStateException("Most recent DAO block not found") val transferBlock = SWTransferDoneTransactionData(mostRecentSWBlock.transaction).getData() val oldTransaction = transferBlock.SW_TRANSACTION_SERIALIZED @@ -350,12 +361,13 @@ class CoinCommunity constructor(serviceId: String = "02313685c1912a141279f8248fc val sw = discoverSharedWallets().filter { b -> SWJoinBlockTransactionData(b.transaction).getData().SW_UNIQUE_ID == data.SW_UNIQUE_ID }[0] val swData = SWJoinBlockTransactionData(sw.transaction).getData() - val againstSignatures = ArrayList( - fetchNegativeProposalResponses( - data.SW_UNIQUE_ID, - data.SW_UNIQUE_PROPOSAL_ID + val againstSignatures = + ArrayList( + fetchNegativeProposalResponses( + data.SW_UNIQUE_ID, + data.SW_UNIQUE_PROPOSAL_ID + ) ) - ) val totalVoters = swData.SW_BITCOIN_PKS val requiredVotes = data.SW_SIGNATURES_REQUIRED @@ -366,12 +378,13 @@ class CoinCommunity constructor(serviceId: String = "02313685c1912a141279f8248fc * Check if the number of required votes are more than the number of possible votes minus the negative votes. */ fun canWinTransferRequest(data: SWTransferFundsAskBlockTD): Boolean { - val againstSignatures = ArrayList( - fetchNegativeProposalResponses( - data.SW_UNIQUE_ID, - data.SW_UNIQUE_PROPOSAL_ID + val againstSignatures = + ArrayList( + fetchNegativeProposalResponses( + data.SW_UNIQUE_ID, + data.SW_UNIQUE_PROPOSAL_ID + ) ) - ) val totalVoters = data.SW_BITCOIN_PKS val requiredVotes = data.SW_SIGNATURES_REQUIRED diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/TrustChainHelper.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/TrustChainHelper.kt index c9ebd945b..0f9e19ad8 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/TrustChainHelper.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/TrustChainHelper.kt @@ -66,7 +66,10 @@ class TrustChainHelper( /** * Creates an agreement block to a specified proposal block, using a custom transaction. */ - fun createAgreementBlock(link: TrustChainBlock, transaction: TrustChainTransaction) { + fun createAgreementBlock( + link: TrustChainBlock, + transaction: TrustChainTransaction + ) { trustChainCommunity.createAgreementBlock(link, transaction) } diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/CoinUtil.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/CoinUtil.kt index d22c7c5b2..fb89388ba 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/CoinUtil.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/CoinUtil.kt @@ -6,7 +6,6 @@ import org.bitcoinj.params.MainNetParams import org.bitcoinj.params.TestNet3Params class CoinUtil { - /** * Low priority: transaction gets confirmed in 7+ blocks * Medium priority: transaction gets confirmed in 3-6 blocks @@ -36,19 +35,22 @@ class CoinUtil { params: NetworkParameters, txPriority: TxPriority = TxPriority.MEDIUM_PRIORITY ): Long { - val fee: Int = when (params) { - MainNetParams.get() -> when (txPriority) { - TxPriority.LOW_PRIORITY -> 15000 - TxPriority.MEDIUM_PRIORITY -> 25000 - TxPriority.HIGH_PRIORITY -> 57000 - } - TestNet3Params.get() -> when (txPriority) { - TxPriority.LOW_PRIORITY -> 15000 - TxPriority.MEDIUM_PRIORITY -> 19000 - TxPriority.HIGH_PRIORITY -> 19000 + val fee: Int = + when (params) { + MainNetParams.get() -> + when (txPriority) { + TxPriority.LOW_PRIORITY -> 15000 + TxPriority.MEDIUM_PRIORITY -> 25000 + TxPriority.HIGH_PRIORITY -> 57000 + } + TestNet3Params.get() -> + when (txPriority) { + TxPriority.LOW_PRIORITY -> 15000 + TxPriority.MEDIUM_PRIORITY -> 19000 + TxPriority.HIGH_PRIORITY -> 19000 + } + else -> return calculateFeeWithPriority(MainNetParams.get(), txPriority) } - else -> return calculateFeeWithPriority(MainNetParams.get(), txPriority) - } return fee.toLong() } diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/WalletManager.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/WalletManager.kt index 52dfa7bbf..ede83e27e 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/WalletManager.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/WalletManager.kt @@ -35,7 +35,7 @@ const val MIN_BLOCKCHAIN_PEERS_PRODUCTION = 5 const val REG_TEST_FAUCET_IP = "131.180.27.224" const val REG_TEST_FAUCET_DOMAIN = "taproot.tribler.org" -var MIN_BLOCKCHAIN_PEERS = MIN_BLOCKCHAIN_PEERS_TEST_NET +var minBlockchainPeers = MIN_BLOCKCHAIN_PEERS_TEST_NET // TODO only allow one proposal at a time (not multiple transfers or multiple joins) @@ -78,40 +78,44 @@ class WalletManager( init { Log.i("Coin", "Coin: WalletManager attempting to start.") - params = when (walletManagerConfiguration.network) { - BitcoinNetworkOptions.TEST_NET -> TestNet3Params.get() - BitcoinNetworkOptions.PRODUCTION -> MainNetParams.get() - BitcoinNetworkOptions.REG_TEST -> RegTestParams.get() - } + params = + when (walletManagerConfiguration.network) { + BitcoinNetworkOptions.TEST_NET -> TestNet3Params.get() + BitcoinNetworkOptions.PRODUCTION -> MainNetParams.get() + BitcoinNetworkOptions.REG_TEST -> RegTestParams.get() + } - val filePrefix = when (walletManagerConfiguration.network) { - BitcoinNetworkOptions.TEST_NET -> TEST_NET_WALLET_NAME - BitcoinNetworkOptions.PRODUCTION -> MAIN_NET_WALLET_NAME - BitcoinNetworkOptions.REG_TEST -> REG_TEST_WALLET_NAME - } + val filePrefix = + when (walletManagerConfiguration.network) { + BitcoinNetworkOptions.TEST_NET -> TEST_NET_WALLET_NAME + BitcoinNetworkOptions.PRODUCTION -> MAIN_NET_WALLET_NAME + BitcoinNetworkOptions.REG_TEST -> REG_TEST_WALLET_NAME + } - kit = object : WalletAppKit(params, walletDir, filePrefix) { - override fun onSetupCompleted() { - // Make a fresh new key if no keys in stored wallet. - if (wallet().keyChainGroupSize < 1) { - Log.i("Coin", "Coin: Added manually created fresh key") - wallet().importKey(ECKey()) - } - wallet().allowSpendingUnconfirmedTransactions() - Log.i("Coin", "Coin: WalletManager started successfully.") - onSetupCompletedListeners.forEach { - Log.i("Coin", "Coin: calling listener $it") - it() + kit = + object : WalletAppKit(params, walletDir, filePrefix) { + override fun onSetupCompleted() { + // Make a fresh new key if no keys in stored wallet. + if (wallet().keyChainGroupSize < 1) { + Log.i("Coin", "Coin: Added manually created fresh key") + wallet().importKey(ECKey()) + } + wallet().allowSpendingUnconfirmedTransactions() + Log.i("Coin", "Coin: WalletManager started successfully.") + onSetupCompletedListeners.forEach { + Log.i("Coin", "Coin: calling listener $it") + it() + } } } - } - MIN_BLOCKCHAIN_PEERS = when (params) { - RegTestParams.get() -> MIN_BLOCKCHAIN_PEERS_REG_TEST - MainNetParams.get() -> MIN_BLOCKCHAIN_PEERS_PRODUCTION - TestNet3Params.get() -> MIN_BLOCKCHAIN_PEERS_TEST_NET - else -> MIN_BLOCKCHAIN_PEERS - } + minBlockchainPeers = + when (params) { + RegTestParams.get() -> MIN_BLOCKCHAIN_PEERS_REG_TEST + MainNetParams.get() -> MIN_BLOCKCHAIN_PEERS_PRODUCTION + TestNet3Params.get() -> MIN_BLOCKCHAIN_PEERS_TEST_NET + else -> minBlockchainPeers + } if (params == RegTestParams.get()) { try { @@ -127,36 +131,39 @@ class WalletManager( "Coin", "Coin: received a key to import, will clear the wallet and download again." ) - val deterministicSeed = DeterministicSeed( - serializedDeterministicKey.seed, - null, - "", - serializedDeterministicKey.creationTime - ) + val deterministicSeed = + DeterministicSeed( + serializedDeterministicKey.seed, + null, + "", + serializedDeterministicKey.creationTime + ) kit.restoreWalletFromSeed(deterministicSeed) } - kit.setDownloadListener(object : DownloadProgressTracker() { - override fun progress( - pct: Double, - blocksSoFar: Int, - date: Date? - ) { - super.progress(pct, blocksSoFar, date) - val percentage = pct.toInt() - progress = percentage - println("Progress: $percentage") - Log.i("Coin", "Progress: $percentage") - } + kit.setDownloadListener( + object : DownloadProgressTracker() { + override fun progress( + pct: Double, + blocksSoFar: Int, + date: Date? + ) { + super.progress(pct, blocksSoFar, date) + val percentage = pct.toInt() + progress = percentage + println("Progress: $percentage") + Log.i("Coin", "Progress: $percentage") + } - override fun doneDownload() { - super.doneDownload() - progress = 100 - Log.i("Coin", "Download Complete!") - Log.i("Coin", "Balance: ${kit.wallet().balance}") - isDownloading = false + override fun doneDownload() { + super.doneDownload() + progress = 100 + Log.i("Coin", "Download Complete!") + Log.i("Coin", "Balance: ${kit.wallet().balance}") + isDownloading = false + } } - }) + ) Log.i("Coin", "Coin: starting the setup of kit.") kit.setBlockingStartup(false) @@ -175,10 +182,11 @@ class WalletManager( Log.i( "Coin", - "Coin: Address from private key is: " + LegacyAddress.fromKey( - params, - key - ).toString() + "Coin: Address from private key is: " + + LegacyAddress.fromKey( + params, + key + ).toString() ) kit.wallet().importKey(key) @@ -243,13 +251,11 @@ class WalletManager( * @param entranceFee the entrance fee you are sending * @return Pair - successfully send the transaction, serializedTransaction */ - fun safeCreationAndSendGenesisWallet( - entranceFee: Coin - ): Pair { - val (_, aggPubKey) = MuSig.generate_musig_key(listOf(protocolECKey())) + fun safeCreationAndSendGenesisWallet(entranceFee: Coin): Pair { + val (_, aggPubKey) = MuSig.generateMusigKey(listOf(protocolECKey())) val pubKeyDataMusig = aggPubKey.getEncoded(true) - val addressMuSig = TaprootUtil.key_to_witness(pubKeyDataMusig) + val addressMuSig = TaprootUtil.keyToWitness(pubKeyDataMusig) val transaction = Transaction(params) @@ -300,15 +306,16 @@ class WalletManager( val oldMultiSignatureOutput = oldTransaction.vout.filter { it.scriptPubKey.size == 35 }[0].nValue - val newKeys = networkPublicHexKeys.map { publicHexKey: String -> - ECKey.fromPublicOnly(publicHexKey.hexToBytes()) - } + val newKeys = + networkPublicHexKeys.map { publicHexKey: String -> + ECKey.fromPublicOnly(publicHexKey.hexToBytes()) + } - val (_, aggPubKey) = MuSig.generate_musig_key(newKeys) + val (_, aggPubKey) = MuSig.generateMusigKey(newKeys) val pubKeyDataMusig = aggPubKey.getEncoded(true) - val addressMuSig = TaprootUtil.key_to_witness(pubKeyDataMusig) + val addressMuSig = TaprootUtil.keyToWitness(pubKeyDataMusig) val newMultiSignatureOutputMoney = Coin.valueOf(oldMultiSignatureOutput).add(entranceFee) newTransaction.addOutput( @@ -316,10 +323,11 @@ class WalletManager( Address.fromString(params, addressMuSig) ) - val prevTx = Transaction( - params, - oldTransactionSerialized.hexToBytes() - ) + val prevTx = + Transaction( + params, + oldTransactionSerialized.hexToBytes() + ) val prevTxOutput = prevTx.outputs.filter { it.scriptBytes.size == 35 }[0] newTransaction.addInput( @@ -340,8 +348,9 @@ class WalletManager( Log.i("Coin", "Joining DAO - newtxid: " + newTransaction.txId.toString()) Log.i( "Coin", - "Joining DAO - serialized new tx without signatures: " + newTransaction.bitcoinSerialize() - .toHex() + "Joining DAO - serialized new tx without signatures: " + + newTransaction.bitcoinSerialize() + .toHex() ) // TODO there is probably a bug if multiple vins are required by our own wallet (for example, multiple small txin's combined to 1 big vout) @@ -365,32 +374,35 @@ class WalletManager( walletId: String, context: Context ): BigInteger { - val (cMap, aggPubKey) = MuSig.generate_musig_key(publicKeys) + val (cMap, aggPubKey) = MuSig.generateMusigKey(publicKeys) val detKey = key as DeterministicKey - val privChallenge1 = detKey.privKey.multiply(BigInteger(1, cMap[key.decompress()])).mod( - Schnorr.n - ) + val privChallenge1 = + detKey.privKey.multiply(BigInteger(1, cMap[key.decompress()])).mod( + Schnorr.n + ) val index = oldTransaction.vout.indexOf(oldTransaction.vout.filter { it.scriptPubKey.size == 35 }[0]) - val sighashMuSig = CTransaction.TaprootSignatureHash( - newTransaction, - oldTransaction.vout, - SIGHASH_ALL_TAPROOT, - input_index = index.toShort() - ) - val signature = MuSig.sign_musig( - ECKey.fromPrivate(privChallenge1), - getNonceKey(walletId, context).first, - MuSig.aggregate_schnorr_nonces( - nonces - ).first, - aggPubKey, - sighashMuSig - ) + val sighashMuSig = + CTransaction.taprootSignatureHash( + newTransaction, + oldTransaction.vout, + SIGHASH_ALL_TAPROOT, + inputIndex = index.toShort() + ) + val signature = + MuSig.signMusig( + ECKey.fromPrivate(privChallenge1), + getNonceKey(walletId, context).first, + MuSig.aggregateSchnorrNonces( + nonces + ).first, + aggPubKey, + sighashMuSig + ) Log.i( "NONCE_KEY", @@ -418,18 +430,19 @@ class WalletManager( Log.i("Coin", "Coin: using ${signaturesOfOldOwners.size} signatures.") val aggregateSignature = - MuSig.aggregate_musig_signatures(signaturesOfOldOwners, aggregateNonce) + MuSig.aggregateMusigSignatures(signaturesOfOldOwners, aggregateNonce) val index = newTransaction.vin.indexOf(newTransaction.vin.filter { it.scriptSig.isEmpty() }[0]) val cTxInWitness = CTxInWitness(arrayOf(aggregateSignature)) - val cTxWitness = CTxWitness( - arrayOf( - CTxInWitness(), - CTxInWitness() - ) - ) // our transactions only have 2 inputs + val cTxWitness = + CTxWitness( + arrayOf( + CTxInWitness(), + CTxInWitness() + ) + ) // our transactions only have 2 inputs cTxWitness.vtxinwit[index] = cTxInWitness newTransaction.wit = cTxWitness @@ -468,36 +481,39 @@ class WalletManager( ): BigInteger { val detKey = key as DeterministicKey - val (cMap, aggPubKey) = MuSig.generate_musig_key(publicKeys) + val (cMap, aggPubKey) = MuSig.generateMusigKey(publicKeys) val pubKeyDataMuSig = aggPubKey.getEncoded(true) - val (oldTransaction, newTransaction) = constructNewTransaction( - oldTransactionSerialized, - pubKeyDataMuSig, - paymentAmount, - receiverAddress - ) + val (oldTransaction, newTransaction) = + constructNewTransaction( + oldTransactionSerialized, + pubKeyDataMuSig, + paymentAmount, + receiverAddress + ) Log.i( "Coin", - "Transfer funds DAO - serialized new tx without signature: " + newTransaction.serialize() - .toHex() + "Transfer funds DAO - serialized new tx without signature: " + + newTransaction.serialize() + .toHex() ) val privChallenge = detKey.privKey.multiply(BigInteger(1, cMap[key.decompress()])).mod(Schnorr.n) - val sighashMuSig = CTransaction.TaprootSignatureHash( - newTransaction, - arrayOf(oldTransaction.vout.filter { it.scriptPubKey.size == 35 }[0]), - SIGHASH_ALL_TAPROOT, - input_index = 0 - ) + val sighashMuSig = + CTransaction.taprootSignatureHash( + newTransaction, + arrayOf(oldTransaction.vout.filter { it.scriptPubKey.size == 35 }[0]), + SIGHASH_ALL_TAPROOT, + inputIndex = 0 + ) - return MuSig.sign_musig( + return MuSig.signMusig( ECKey.fromPrivate(privChallenge), getNonceKey(walletId, context).first, - MuSig.aggregate_schnorr_nonces( + MuSig.aggregateSchnorrNonces( nonces ).first, aggPubKey, @@ -525,18 +541,19 @@ class WalletManager( receiverAddress: Address, paymentAmount: Long ): Pair { - val (_, aggPubKey) = MuSig.generate_musig_key(publicKeys) + val (_, aggPubKey) = MuSig.generateMusigKey(publicKeys) val pubKeyDataMuSig = aggPubKey.getEncoded(true) - val (_, newTransaction) = constructNewTransaction( - oldTransactionSerialized, - pubKeyDataMuSig, - paymentAmount, - receiverAddress - ) + val (_, newTransaction) = + constructNewTransaction( + oldTransactionSerialized, + pubKeyDataMuSig, + paymentAmount, + receiverAddress + ) val aggregateSignature = - MuSig.aggregate_musig_signatures(signaturesOfOldOwners, aggregateNonce) + MuSig.aggregateMusigSignatures(signaturesOfOldOwners, aggregateNonce) val cTxInWitness = CTxInWitness(arrayOf(aggregateSignature)) val cTxWitness = CTxWitness(arrayOf(cTxInWitness)) @@ -545,8 +562,9 @@ class WalletManager( Log.i( "Coin", - "Transfer funds DAO - final serialized new tx with signature: " + newTransaction.serialize() - .toHex() + "Transfer funds DAO - final serialized new tx with signature: " + + newTransaction.serialize() + .toHex() ) return Pair(sendTaprootTransaction(newTransaction), newTransaction.serialize().toHex()) @@ -569,7 +587,7 @@ class WalletManager( val newTransaction = Transaction(params) val oldTransaction = CTransaction().deserialize(oldTransactionSerialized.hexToBytes()) - val addressMuSig = TaprootUtil.key_to_witness(pubKeyDataMuSig) + val addressMuSig = TaprootUtil.keyToWitness(pubKeyDataMuSig) val newMultiSignatureOutputMoney = Coin.valueOf(paymentAmount) newTransaction.addOutput(newMultiSignatureOutputMoney, receiverAddress) @@ -600,26 +618,30 @@ class WalletManager( */ private fun sendTaprootTransaction(transaction: CTransaction): Boolean { Log.i("Coin", "Sending serialized transaction to the server: ${transaction.serialize().toHex()}") - val url = URL( - "https://$REG_TEST_FAUCET_DOMAIN/generateBlock?tx_id=${ - transaction.serialize().toHex() - }" - ) + val url = + URL( + "https://$REG_TEST_FAUCET_DOMAIN/generateBlock?tx_id=${ + transaction.serialize().toHex() + }" + ) val executor: ExecutorService = Executors.newCachedThreadPool(Executors.defaultThreadFactory()) - val future: Future = executor.submit(object : Callable { - override fun call(): Boolean { - val connection = url.openConnection() as HttpURLConnection - - try { - return connection.responseCode == 200 - } finally { - connection.disconnect() + val future: Future = + executor.submit( + object : Callable { + override fun call(): Boolean { + val connection = url.openConnection() as HttpURLConnection + + try { + return connection.responseCode == 200 + } finally { + connection.disconnect() + } + } } - } - }) + ) return try { future.get(DEFAULT_BITCOIN_MAX_TIMEOUT, TimeUnit.SECONDS) @@ -633,7 +655,11 @@ class WalletManager( * @param swUniqueId - String, the unique id of the DAO you want to create a nonce for * @param privateKey - String, the private key that needs to be stored */ - fun storeNonceKey(swUniqueId: String, context: Context, privateKey: String) { + fun storeNonceKey( + swUniqueId: String, + context: Context, + privateKey: String + ) { val nonceKeyData = context.getSharedPreferences("nonce_keys", 0)!! val editor = nonceKeyData.edit() Log.i("NONCE_KEY", "Stored key for DAO: $swUniqueId") @@ -647,9 +673,12 @@ class WalletManager( * @param swUniqueId - String, the unique id of the DAO you want to create a nonce for * @return nonce key pair */ - fun addNewNonceKey(swUniqueId: String, context: Context): Pair { + fun addNewNonceKey( + swUniqueId: String, + context: Context + ): Pair { val nonceKeyData = context.getSharedPreferences("nonce_keys", 0)!! - val nonce = TaprootUtil.generate_schnorr_nonce(ECKey().privKeyBytes) + val nonce = TaprootUtil.generateSchnorrNonce(ECKey().privKeyBytes) val privateKey = nonce.first.privKey.toByteArray().toHex() val editor = nonceKeyData.edit() Log.i("NONCE_KEY", "New key created for DAO: $swUniqueId") @@ -664,9 +693,12 @@ class WalletManager( * @param swUniqueId - String, the unique id of the DAO you want to get a nonce for * @return nonce key pair */ - private fun getNonceKey(swUniqueId: String, context: Context): Pair { + private fun getNonceKey( + swUniqueId: String, + context: Context + ): Pair { val nonceKeyData = context.getSharedPreferences("nonce_keys", 0)!! - return TaprootUtil.generate_schnorr_nonce(nonceKeyData.getString(swUniqueId, "")!!.hexToBytes()) + return TaprootUtil.generateSchnorrNonce(nonceKeyData.getString(swUniqueId, "")!!.hexToBytes()) } companion object { @@ -676,13 +708,15 @@ class WalletManager( * @return SerializedDeterministicKey */ fun generateRandomDeterministicSeed(paramsRaw: BitcoinNetworkOptions): SerializedDeterministicKey { - val params = when (paramsRaw) { - BitcoinNetworkOptions.TEST_NET -> TestNet3Params.get() - BitcoinNetworkOptions.PRODUCTION -> MainNetParams.get() - BitcoinNetworkOptions.REG_TEST -> RegTestParams.get() - } - val keyChainGroup = KeyChainGroup.builder(params, KeyChainGroupStructure.DEFAULT) - .fromRandom(Script.ScriptType.P2PKH).build() + val params = + when (paramsRaw) { + BitcoinNetworkOptions.TEST_NET -> TestNet3Params.get() + BitcoinNetworkOptions.PRODUCTION -> MainNetParams.get() + BitcoinNetworkOptions.REG_TEST -> RegTestParams.get() + } + val keyChainGroup = + KeyChainGroup.builder(params, KeyChainGroupStructure.DEFAULT) + .fromRandom(Script.ScriptType.P2PKH).build() return deterministicSeedToSerializedDeterministicKey(keyChainGroup.activeKeyChain.seed!!) } diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/WalletManagerAndroid.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/WalletManagerAndroid.kt index ae56c5e10..07be8d384 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/WalletManagerAndroid.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/WalletManagerAndroid.kt @@ -2,10 +2,11 @@ package nl.tudelft.trustchain.currencyii.coin import android.content.Context +// TODO: Clean up Thread usage. + /** * Singleton class for WalletManager which also sets-up Android specific things. */ -// TODO: Clean up Thread usage. object WalletManagerAndroid { private var walletManager: WalletManager? = null private var context: Context? = null @@ -28,17 +29,19 @@ object WalletManagerAndroid { fun init(): WalletManager { val walletDir = context.filesDir - val configuration = configuration - ?: throw IllegalStateException("Configuration is not set") + val configuration = + configuration + ?: throw IllegalStateException("Configuration is not set") WalletManagerAndroid.context = context - val walletManager = WalletManager( - configuration, - walletDir, - configuration.key, - configuration.addressPrivateKeyPair - ) + val walletManager = + WalletManager( + configuration, + walletDir, + configuration.key, + configuration.addressPrivateKeyPair + ) WalletManagerAndroid.walletManager = walletManager isRunning = true diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/WalletManagerConfiguration.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/WalletManagerConfiguration.kt index 614a13a18..f7169879a 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/WalletManagerConfiguration.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/coin/WalletManagerConfiguration.kt @@ -11,7 +11,9 @@ data class AddressPrivateKeyPair( ) enum class BitcoinNetworkOptions { - PRODUCTION, REG_TEST, TEST_NET + PRODUCTION, + REG_TEST, + TEST_NET } class WalletManagerConfiguration( diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWJoinBlockTransactionData.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWJoinBlockTransactionData.kt index 4838afd18..d5f306352 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWJoinBlockTransactionData.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWJoinBlockTransactionData.kt @@ -16,7 +16,8 @@ data class SWJoinBlockTD( ) class SWJoinBlockTransactionData(data: JsonObject) : SWBlockTransactionData( - data, CoinCommunity.JOIN_BLOCK + data, + CoinCommunity.JOIN_BLOCK ) { fun getData(): SWJoinBlockTD { return Gson().fromJson(getJsonString(), SWJoinBlockTD::class.java) diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWResponseNegativeSignatureTransactionData.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWResponseNegativeSignatureTransactionData.kt index 7ce7bd00d..99f22b0c4 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWResponseNegativeSignatureTransactionData.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWResponseNegativeSignatureTransactionData.kt @@ -14,13 +14,17 @@ data class SWResponseNegativeSignatureBlockTD( ) class SWResponseNegativeSignatureTransactionData(data: JsonObject) : SWBlockTransactionData( - data, CoinCommunity.SIGNATURE_AGREEMENT_NEGATIVE_BLOCK + data, + CoinCommunity.SIGNATURE_AGREEMENT_NEGATIVE_BLOCK ) { fun getData(): SWResponseNegativeSignatureBlockTD { return Gson().fromJson(getJsonString(), SWResponseNegativeSignatureBlockTD::class.java) } - fun matchesProposal(walletId: String, proposalId: String): Boolean { + fun matchesProposal( + walletId: String, + proposalId: String + ): Boolean { val data = getData() return data.SW_UNIQUE_ID == walletId && data.SW_UNIQUE_PROPOSAL_ID == proposalId } @@ -41,7 +45,6 @@ class SWResponseNegativeSignatureTransactionData(data: JsonObject) : SWBlockTran nonce ) ) - ) constructor(transaction: TrustChainTransaction) : this(SWUtil.parseTransaction(transaction)) diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWResponseSignatureTransactionData.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWResponseSignatureTransactionData.kt index 98c9f4239..f0d589f6f 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWResponseSignatureTransactionData.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWResponseSignatureTransactionData.kt @@ -14,13 +14,17 @@ data class SWResponseSignatureBlockTD( ) class SWResponseSignatureTransactionData(data: JsonObject) : SWBlockTransactionData( - data, CoinCommunity.SIGNATURE_AGREEMENT_BLOCK + data, + CoinCommunity.SIGNATURE_AGREEMENT_BLOCK ) { fun getData(): SWResponseSignatureBlockTD { return Gson().fromJson(getJsonString(), SWResponseSignatureBlockTD::class.java) } - fun matchesProposal(walletId: String, proposalId: String): Boolean { + fun matchesProposal( + walletId: String, + proposalId: String + ): Boolean { val data = getData() return data.SW_UNIQUE_ID == walletId && data.SW_UNIQUE_PROPOSAL_ID == proposalId } diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWSignatureAskTransactionData.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWSignatureAskTransactionData.kt index 27fb3652d..0d182a774 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWSignatureAskTransactionData.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWSignatureAskTransactionData.kt @@ -15,7 +15,8 @@ data class SWSignatureAskBlockTD( ) open class SWSignatureAskTransactionData(data: JsonObject) : SWBlockTransactionData( - data, CoinCommunity.SIGNATURE_ASK_BLOCK + data, + CoinCommunity.SIGNATURE_ASK_BLOCK ) { fun getData(): SWSignatureAskBlockTD { return Gson().fromJson(getJsonString(), SWSignatureAskBlockTD::class.java) @@ -38,7 +39,6 @@ open class SWSignatureAskTransactionData(data: JsonObject) : SWBlockTransactionD requiredSignatures, receiverPk ) - ) ) diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWTransferDoneTransactionData.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWTransferDoneTransactionData.kt index f33f4d76b..753b33fb9 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWTransferDoneTransactionData.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWTransferDoneTransactionData.kt @@ -17,7 +17,8 @@ data class SWTransferDoneBlockTD( ) class SWTransferDoneTransactionData(data: JsonObject) : SWBlockTransactionData( - data, CoinCommunity.TRANSFER_FINAL_BLOCK + data, + CoinCommunity.TRANSFER_FINAL_BLOCK ) { fun getData(): SWTransferDoneBlockTD { return Gson().fromJson(getJsonString(), SWTransferDoneBlockTD::class.java) @@ -68,7 +69,6 @@ class SWTransferDoneTransactionData(data: JsonObject) : SWBlockTransactionData( satoshiAmount, transferFundsAddressSerialized ) - ) ) diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWTransferFundsAskTransactionData.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWTransferFundsAskTransactionData.kt index 9df7a7148..f093d07e9 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWTransferFundsAskTransactionData.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWTransferFundsAskTransactionData.kt @@ -18,7 +18,8 @@ data class SWTransferFundsAskBlockTD( ) class SWTransferFundsAskTransactionData(data: JsonObject) : SWBlockTransactionData( - data, CoinCommunity.TRANSFER_FUNDS_ASK_BLOCK + data, + CoinCommunity.TRANSFER_FUNDS_ASK_BLOCK ) { fun getData(): SWTransferFundsAskBlockTD { return Gson().fromJson(getJsonString(), SWTransferFundsAskBlockTD::class.java) @@ -47,7 +48,6 @@ class SWTransferFundsAskTransactionData(data: JsonObject) : SWBlockTransactionDa receiverPk, transactionSerialized ) - ) ) diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWUtil.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWUtil.kt index 80fc674a1..c30077821 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWUtil.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/sharedWallet/SWUtil.kt @@ -9,7 +9,6 @@ import kotlin.math.ceil import kotlin.math.min object SWUtil { - /** * The minimal tx amount defined for creating transactions to avoid dusty transactions */ @@ -22,10 +21,11 @@ object SWUtil { @JvmStatic fun randomUUID(): String { val uuid: UUID = UUID.randomUUID() - val src: ByteArray = ByteBuffer.wrap(ByteArray(16)) - .putLong(uuid.mostSignificantBits) - .putLong(uuid.leastSignificantBits) - .array() + val src: ByteArray = + ByteBuffer.wrap(ByteArray(16)) + .putLong(uuid.mostSignificantBits) + .putLong(uuid.leastSignificantBits) + .array() return Base64.getUrlEncoder().encodeToString(src).substring(0, 22) } @@ -35,7 +35,10 @@ object SWUtil { } @JvmStatic - fun percentageToIntThreshold(total: Int, percentage: Int): Int { + fun percentageToIntThreshold( + total: Int, + percentage: Int + ): Int { val totalAmount = total.toDouble() val oldThreshold = percentage.toDouble() val threshold = ceil((oldThreshold / 100.0) * totalAmount).toInt() diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/BaseFragment.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/BaseFragment.kt index 5437c3510..edbd96f5c 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/BaseFragment.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/BaseFragment.kt @@ -11,7 +11,9 @@ import nl.tudelft.trustchain.currencyii.CoinCommunity import nl.tudelft.trustchain.currencyii.R import nl.tudelft.trustchain.currencyii.TrustChainHelper -abstract class BaseFragment(@LayoutRes contentLayoutId: Int = 0) : Fragment(contentLayoutId) { +abstract class BaseFragment( + @LayoutRes contentLayoutId: Int = 0 +) : Fragment(contentLayoutId) { protected val trustchain: TrustChainHelper by lazy { TrustChainHelper(getTrustChainCommunity()) } diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/bitcoin/BitcoinFragment.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/bitcoin/BitcoinFragment.kt index c7032853f..739b669d1 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/bitcoin/BitcoinFragment.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/bitcoin/BitcoinFragment.kt @@ -7,25 +7,37 @@ import android.graphics.PorterDuff import android.os.Bundle import android.os.Handler import android.util.Log -import android.view.* +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup import android.widget.Toast import androidx.core.content.ContextCompat.getSystemService import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController -import kotlinx.android.synthetic.main.bitcoin_networks.* -import kotlinx.android.synthetic.main.fragment_bitcoin.* import nl.tudelft.trustchain.currencyii.R -import nl.tudelft.trustchain.currencyii.coin.* +import nl.tudelft.trustchain.currencyii.coin.AddressPrivateKeyPair +import nl.tudelft.trustchain.currencyii.coin.BitcoinNetworkOptions +import nl.tudelft.trustchain.currencyii.coin.REG_TEST_FAUCET_DOMAIN +import nl.tudelft.trustchain.currencyii.coin.WalletManagerAndroid +import nl.tudelft.trustchain.currencyii.coin.WalletManagerConfiguration +import nl.tudelft.trustchain.currencyii.databinding.FragmentBitcoinBinding import nl.tudelft.trustchain.currencyii.ui.BaseFragment import org.bitcoinj.core.Coin import org.bitcoinj.core.NetworkParameters import org.bitcoinj.wallet.Wallet import java.net.HttpURLConnection import java.net.URL -import java.util.concurrent.* -import kotlin.Exception +import java.util.concurrent.Callable +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.Future +import java.util.concurrent.TimeUnit const val BALANCE_THRESHOLD = "5" + /** * A simple [Fragment] subclass. * Use the [BitcoinFragment.newInstance] factory method to @@ -34,16 +46,22 @@ const val BALANCE_THRESHOLD = "5" class BitcoinFragment : BaseFragment(R.layout.fragment_bitcoin), ImportKeyDialog.ImportKeyDialogListener { + @Suppress("ktlint:standard:property-naming") // False positive + private var _binding: FragmentBitcoinBinding? = null + private val binding get() = _binding!! private var getBitcoinPressed = false + @Deprecated("Deprecated in Java") override fun onActivityCreated(savedInstanceState: Bundle?) { + @Suppress("DEPRECATION") super.onActivityCreated(savedInstanceState) initClickListeners() } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + @Suppress("DEPRECATION") setHasOptionsMenu(true) } @@ -53,7 +71,10 @@ class BitcoinFragment : refresh() } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateOptionsMenu( + menu: Menu, + inflater: MenuInflater + ) { // TODO: Try catch not too nice. try { WalletManagerAndroid.getInstance() @@ -65,7 +86,9 @@ class BitcoinFragment : inflater.inflate(R.menu.bitcoin_options, menu) } + @Deprecated("Deprecated in Java") override fun onOptionsItemSelected(item: MenuItem): Boolean { + @Suppress("DEPRECATION") return when (item.itemId) { R.id.item_bitcoin_blockchain_download -> { Log.i("Coin", "Navigating from BitcoinFragment to BlockchainDownloadFragment") @@ -76,38 +99,40 @@ class BitcoinFragment : ) true } + R.id.item_bitcoin_wallet_settings -> { Log.i("Coin", "Navigating from BitcoinFragment to DaoImportOrCreate") findNavController().navigate(BitcoinFragmentDirections.actionBitcoinFragmentToDaoImportOrCreate()) true } + else -> super.onOptionsItemSelected(item) } } private fun initClickListeners() { val walletManager = WalletManagerAndroid.getInstance() - button_copy_public_address.setOnClickListener { + binding.buttonCopyPublicAddress.setOnClickListener { copyToClipboard(walletManager.protocolAddress().toString()) } - button_copy_wallet_seed.setOnClickListener { + binding.buttonCopyWalletSeed.setOnClickListener { val seed = walletManager.toSeed() copyToClipboard("${seed.seed}, ${seed.creationTime}") } - button_copy_bitcoin_public_key.setOnClickListener { + binding.buttonCopyBitcoinPublicKey.setOnClickListener { copyToClipboard(walletManager.networkPublicECKeyHex()) } - bitcoin_refresh_swiper.setOnRefreshListener { + binding.bitcoinRefreshSwiper.setOnRefreshListener { this.refresh() @Suppress("DEPRECATION") Handler().postDelayed( { try { - bitcoin_refresh_swiper.isRefreshing = false + binding.bitcoinRefreshSwiper.isRefreshing = false } catch (e: Exception) { } }, @@ -137,12 +162,16 @@ class BitcoinFragment : /** * Disable the get BTC button, sets the color to gray and changes the onclick listener */ - @Suppress("DEPRECATION") private fun disableGetBitcoinButton() { - add_btc.isClickable = false - add_btc.background.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY) - add_btc.setOnClickListener { - Toast.makeText(this.requireContext(), "You already have enough bitcoin don't you think?", Toast.LENGTH_SHORT).show() + binding.addBtc.isClickable = false + @Suppress("DEPRECATION") // TODO: Remove deprecated code. + binding.addBtc.background.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY) + binding.addBtc.setOnClickListener { + Toast.makeText( + this.requireContext(), + "You already have enough bitcoin don't you think?", + Toast.LENGTH_SHORT + ).show() } } @@ -151,38 +180,53 @@ class BitcoinFragment : */ private fun enableGetBitcoinButton() { val walletManager = WalletManagerAndroid.getInstance() - add_btc.isClickable = true - add_btc.setOnClickListener { + binding.addBtc.isClickable = true + binding.addBtc.setOnClickListener { if (!getBitcoinPressed) { getBitcoinPressed = true if (!addBTC(walletManager.protocolAddress().toString())) { Log.e("Coin", "The server response is failing") - Toast.makeText(this.requireContext(), "Something went wrong, please delete system32", Toast.LENGTH_SHORT).show() + Toast.makeText( + this.requireContext(), + "Something went wrong, please delete system32", + Toast.LENGTH_SHORT + ).show() } else { - Toast.makeText(this.requireContext(), "Successfully added 10 BTC", Toast.LENGTH_SHORT).show() + Toast.makeText( + this.requireContext(), + "Successfully added 0.10 BTC", + Toast.LENGTH_SHORT + ).show() Thread.sleep(1000) - Toast.makeText(this.requireContext(), "It can take up to a minute to register in your balance", Toast.LENGTH_SHORT).show() + Toast.makeText( + this.requireContext(), + "It can take up to a minute to register in your balance", + Toast.LENGTH_SHORT + ).show() this.refresh(true) } } else { - Toast.makeText(this.requireContext(), "You are already given an amount of BTC, please wait a little longer", Toast.LENGTH_SHORT).show() + Toast.makeText( + this.requireContext(), + "You are already given an amount of BTC, please wait a little longer", + Toast.LENGTH_SHORT + ).show() } } } private fun refresh(animation: Boolean? = false) { if (animation!!) { - bitcoin_refresh_swiper.isRefreshing = true - - @Suppress("DEPRECATION") + binding.bitcoinRefreshSwiper.isRefreshing = true + @Suppress("DEPRECATION") // TODO: Remove deprecated code. Handler().postDelayed( { try { - bitcoin_refresh_swiper.isRefreshing = false - } catch (e: Exception) { + binding.bitcoinRefreshSwiper.isRefreshing = false + } catch (_: Exception) { } }, 1500 @@ -195,18 +239,20 @@ class BitcoinFragment : val walletManager = WalletManagerAndroid.getInstance() - walletBalance.text = walletManager.kit.wallet().balance.toFriendlyString() - walletEstimatedBalance.text = walletManager.kit.wallet().getBalance(Wallet.BalanceType.ESTIMATED).toFriendlyString() - chosenNetwork.text = when (walletManager.params.id) { - NetworkParameters.ID_MAINNET -> "Production Network" - NetworkParameters.ID_REGTEST -> "RegTest Network" - NetworkParameters.ID_TESTNET -> "TestNet Network" - else -> "Unknown Network selected" - } + binding.walletBalance.text = walletManager.kit.wallet().balance.toFriendlyString() + binding.walletEstimatedBalance.text = + walletManager.kit.wallet().getBalance(Wallet.BalanceType.ESTIMATED).toFriendlyString() + binding.chosenNetwork.text = + when (walletManager.params.id) { + NetworkParameters.ID_MAINNET -> "Production Network" + NetworkParameters.ID_REGTEST -> "RegTest Network" + NetworkParameters.ID_TESTNET -> "TestNet Network" + else -> "Unknown Network selected" + } val seed = walletManager.toSeed() - walletSeed.text = "${seed.seed}, ${seed.creationTime}" - yourPublicHex.text = walletManager.networkPublicECKeyHex() - protocolKey.text = walletManager.protocolAddress().toString() + binding.walletSeed.text = "${seed.seed}, ${seed.creationTime}" + binding.yourPublicHex.text = walletManager.networkPublicECKeyHex() + binding.protocolKey.text = walletManager.protocolAddress().toString() if (checkTooMuchBitcoin()) { disableGetBitcoinButton() @@ -223,27 +269,31 @@ class BitcoinFragment : * @return Boolean - if the transaction was successful */ private fun addBTC(address: String): Boolean { - val executor: ExecutorService = Executors.newCachedThreadPool(Executors.defaultThreadFactory()) + val executor: ExecutorService = + Executors.newCachedThreadPool(Executors.defaultThreadFactory()) val future: Future val url = "https://$REG_TEST_FAUCET_DOMAIN/addBTC?address=$address" - future = executor.submit(object : Callable { - override fun call(): Boolean { - val connection = URL(url).openConnection() as HttpURLConnection - - try { - // If it fails, check if there is enough balance available on the server - // Otherwise reset the bitcoin network on the server (there is only 15k BTC available). - // Also check if the Python server is still running! - Log.i("Coin", url) - Log.i("Coin", connection.responseMessage) - return connection.responseCode == 200 - } finally { - connection.disconnect() + future = + executor.submit( + object : Callable { + override fun call(): Boolean { + val connection = URL(url).openConnection() as HttpURLConnection + + try { + // If it fails, check if there is enough balance available on the server + // Otherwise reset the bitcoin network on the server (there is only 15k BTC available). + // Also check if the Python server is still running! + Log.i("Coin", url) + Log.i("Coin", connection.responseMessage) + return connection.responseCode == 200 + } finally { + connection.disconnect() + } + } } - } - }) + ) return try { future.get(10, TimeUnit.SECONDS) @@ -256,10 +306,16 @@ class BitcoinFragment : inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { // Inflate the layout for this fragment showNavBar() - return inflater.inflate(R.layout.fragment_bitcoin, container, false) + _binding = FragmentBitcoinBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null } companion object { @@ -273,21 +329,18 @@ class BitcoinFragment : fun newInstance() = BitcoinFragment() } - override fun onImport(address: String, privateKey: String) { + override fun onImport( + address: String, + privateKey: String, + network: BitcoinNetworkOptions + ) { if (!WalletManagerAndroid.isRunning) { - val config = WalletManagerConfiguration( - when (bitcoin_network_radio_group.checkedRadioButtonId) { - R.id.production_radiobutton -> BitcoinNetworkOptions.PRODUCTION - R.id.testnet_radiobutton -> BitcoinNetworkOptions.TEST_NET - R.id.regtest_radiobutton -> BitcoinNetworkOptions.REG_TEST - else -> { - Toast.makeText(this.requireContext(), "Please select a bitcoin network first", Toast.LENGTH_SHORT).show() - return - } - }, - null, - AddressPrivateKeyPair(address, privateKey) - ) + val config = + WalletManagerConfiguration( + network, + null, + AddressPrivateKeyPair(address, privateKey) + ) try { WalletManagerAndroid.Factory(this.requireContext().applicationContext) @@ -297,8 +350,8 @@ class BitcoinFragment : Toast.makeText( this.requireContext(), "Something went wrong while initializing the new wallet. ${ - t.message - ?: "No further information" + t.message + ?: "No further information" }.", Toast.LENGTH_SHORT ).show() diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/bitcoin/BlockchainDownloadFragment.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/bitcoin/BlockchainDownloadFragment.kt index c71e1a38b..a12f36256 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/bitcoin/BlockchainDownloadFragment.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/bitcoin/BlockchainDownloadFragment.kt @@ -5,14 +5,11 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Button -import android.widget.ProgressBar -import android.widget.TextView import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController -import kotlinx.android.synthetic.main.fragment_blockchain_download.* import nl.tudelft.trustchain.currencyii.R import nl.tudelft.trustchain.currencyii.coin.WalletManagerAndroid +import nl.tudelft.trustchain.currencyii.databinding.FragmentBlockchainDownloadBinding import nl.tudelft.trustchain.currencyii.ui.BaseFragment import org.bitcoinj.params.MainNetParams import org.bitcoinj.params.RegTestParams @@ -25,12 +22,17 @@ import kotlin.concurrent.thread * create an instance of this fragment. */ class BlockchainDownloadFragment : BaseFragment(R.layout.fragment_blockchain_download) { + @Suppress("ktlint:standard:property-naming") // False positive + private var _binding: FragmentBlockchainDownloadBinding? = null + private val binding get() = _binding!! + @Deprecated("Deprecated in Java") override fun onActivityCreated(savedInstanceState: Bundle?) { + @Suppress("DEPRECATION") super.onActivityCreated(savedInstanceState) // TODO: The routing is cleaner to do via the previously displayed fragment. - bitcoin_progress_continue.setOnClickListener { + binding.bitcoinProgressContinue.setOnClickListener { val navController = findNavController() val args = BlockchainDownloadFragmentArgs.fromBundle(requireArguments()) when (args.parent) { @@ -39,14 +41,17 @@ class BlockchainDownloadFragment : BaseFragment(R.layout.fragment_blockchain_dow Log.i("Coin", "Default value, navigating to My DAOs.") navController.navigate(BlockchainDownloadFragmentDirections.actionBlockchainDownloadFragmentToMyDAOsFragment()) } + R.id.myDAOsFragment -> { Log.i("Coin", "Navigating to My DAOs.") navController.navigate(BlockchainDownloadFragmentDirections.actionBlockchainDownloadFragmentToMyDAOsFragment()) } + R.id.bitcoinFragment -> { Log.i("Coin", "Navigating to My Wallet.") navController.navigate(BlockchainDownloadFragmentDirections.actionBlockchainDownloadFragmentToBitcoinFragment()) } + else -> { // Else just navigate to whatever was passed. Log.i("Coin", "Navigating to ${args.parent}.") @@ -62,39 +67,50 @@ class BlockchainDownloadFragment : BaseFragment(R.layout.fragment_blockchain_dow savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment - val fragment = inflater.inflate(R.layout.fragment_blockchain_download, container, false) + _binding = FragmentBlockchainDownloadBinding.inflate(inflater, container, false) + val view = binding.root if (WalletManagerAndroid.isInitialized()) { - fragment.findViewById(R.id.bitcoin_download_percentage).text = + binding.bitcoinDownloadPercentage.text = "${WalletManagerAndroid.getInstance().progress}%" - fragment.findViewById(R.id.bitcoin_download_progress).progress = + binding.bitcoinDownloadProgress.progress = WalletManagerAndroid.getInstance().progress - val networkName = when (WalletManagerAndroid.getInstance().params) { - RegTestParams.get() -> "RegTest" - TestNet3Params.get() -> "TestNet" - MainNetParams.get() -> "MainNet" - else -> return null - } - fragment.findViewById(R.id.downloading_chain_tv).text = "Please wait while the chain from $networkName is downloading. " + val networkName = + when (WalletManagerAndroid.getInstance().params) { + RegTestParams.get() -> "RegTest" + TestNet3Params.get() -> "TestNet" + MainNetParams.get() -> "MainNet" + else -> return null + } + binding.downloadingChainTv.text = + "Please wait while the chain from $networkName is downloading. " + thread { + val bitcoinDownloadPercentage = binding.bitcoinDownloadPercentage + val bitcoinDownloadProgress = binding.bitcoinDownloadProgress + val bitcoinProgressContinue = binding.bitcoinProgressContinue // TODO: find a better way of handling uninitialized wallet managers while not stopping the while loop while (WalletManagerAndroid.getInstance().progress < 100) { Thread.sleep(500) if (!WalletManagerAndroid.isInitialized()) { break } - fragment.findViewById(R.id.bitcoin_download_percentage).text = + + bitcoinDownloadPercentage.text = "${WalletManagerAndroid.getInstance().progress}%" - fragment.findViewById(R.id.bitcoin_download_progress).progress = + bitcoinDownloadProgress.progress = WalletManagerAndroid.getInstance().progress } - fragment.findViewById(R.id.bitcoin_download_percentage).text = - "Fully Synced!" - fragment.findViewById