diff --git a/.editorconfig b/.editorconfig index 8e25e7b5..3e6339eb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,5 +9,7 @@ trim_trailing_whitespace = true insert_final_newline = true end_of_line = lf -# ktlint -disabled_rules=no-wildcard-imports,import-ordering,max-line-length +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 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 73082c2c..4678a485 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: uses: actions/setup-java@v2 with: distribution: 'zulu' - java-version: '11' + java-version: '17' java-package: jdk - name: Grant execute permission for gradlew diff --git a/build.gradle b/build.gradle index b28d0392..708ffe75 100644 --- a/build.gradle +++ b/build.gradle @@ -1,16 +1,16 @@ // 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' - // https://github.com/cashapp/sqldelight/issues/1574 - ext.sqldelight_version = '1.5.2' - ext.nav_version = "2.5.3" - ext.fragment_version = "1.5.4" - ext.lifecycle_version = "2.5.1" - ext.dokka_version = "0.10.1" + 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.dokka_version = '0.10.1' + ext.mockk_version = '1.13.9' repositories { google() mavenCentral() @@ -18,10 +18,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.0' 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" // NOTE: Do not place your application dependencies here; they belong @@ -50,7 +50,7 @@ task clean(type: Delete) { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { kotlinOptions.freeCompilerArgs += [ - "-opt-in=kotlin.Experimental,kotlin.ExperimentalUnsignedTypes", + "-opt-in=kotlin.ExperimentalUnsignedTypes", "-opt-in=kotlin.RequiresOptIn" ] } diff --git a/demo-android/build.gradle b/demo-android/build.gradle index 0dc5210b..8c0a93f6 100644 --- a/demo-android/build.gradle +++ b/demo-android/build.gradle @@ -1,20 +1,22 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' android { - compileSdkVersion 33 defaultConfig { applicationId "nl.tudelft.ipv8.demo" minSdkVersion 22 - targetSdkVersion 33 - versionCode 1 - versionName "0.1" + compileSdk 34 + versionCode 2 + versionName "0.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } + buildFeatures { + viewBinding true + } + buildTypes { release { minifyEnabled false @@ -25,21 +27,20 @@ android { // 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_11 - targetCompatibility JavaVersion.VERSION_11 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() + jvmTarget = JavaVersion.VERSION_17.toString() allWarningsAsErrors = true } - viewBinding { - enabled = true - } - packagingOptions { - exclude 'META-INF/kotlinx-coroutines-core.kotlin_module' + resources { + excludes += ['META-INF/kotlinx-coroutines-core.kotlin_module'] + } } + namespace 'nl.tudelft.trustchain.demo' } @@ -89,7 +90,7 @@ dependencies { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { kotlinOptions.freeCompilerArgs += [ - "-opt-in=kotlin.Experimental,kotlin.ExperimentalUnsignedTypes", + "-opt-in=kotlin.ExperimentalUnsignedTypes", "-opt-in=kotlin.RequiresOptIn" ] } diff --git a/demo-android/src/main/java/nl/tudelft/trustchain/demo/DemoApplication.kt b/demo-android/src/main/java/nl/tudelft/trustchain/demo/DemoApplication.kt index 85d0c9a0..b23b2be4 100644 --- a/demo-android/src/main/java/nl/tudelft/trustchain/demo/DemoApplication.kt +++ b/demo-android/src/main/java/nl/tudelft/trustchain/demo/DemoApplication.kt @@ -6,7 +6,7 @@ import android.os.Build import android.util.Log import androidx.core.content.getSystemService import androidx.preference.PreferenceManager -import com.squareup.sqldelight.android.AndroidSqliteDriver +import app.cash.sqldelight.driver.android.AndroidSqliteDriver import nl.tudelft.ipv8.IPv8Configuration import nl.tudelft.ipv8.Overlay import nl.tudelft.ipv8.OverlayConfiguration @@ -21,7 +21,6 @@ import nl.tudelft.ipv8.attestation.trustchain.validation.TransactionValidator import nl.tudelft.ipv8.attestation.trustchain.validation.ValidationResult import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider -import nl.tudelft.ipv8.messaging.tftp.TFTPCommunity import nl.tudelft.ipv8.peerdiscovery.DiscoveryCommunity import nl.tudelft.ipv8.peerdiscovery.strategy.PeriodicSimilarity import nl.tudelft.ipv8.peerdiscovery.strategy.RandomChurn @@ -34,24 +33,20 @@ import nl.tudelft.trustchain.demo.service.TrustChainService class DemoApplication : Application() { override fun onCreate() { super.onCreate() - defaultCryptoProvider = AndroidCryptoProvider initIPv8() } private fun initIPv8() { - val config = IPv8Configuration(overlays = listOf( - createDiscoveryCommunity(), - createTrustChainCommunity(), - createDemoCommunity() - ), walkerInterval = 5.0) - - IPv8Android.Factory(this) - .setConfiguration(config) - .setPrivateKey(getPrivateKey()) - .setServiceClass(TrustChainService::class.java) - .init() + val config = IPv8Configuration( + overlays = listOf( + createDiscoveryCommunity(), createTrustChainCommunity(), createDemoCommunity() + ), walkerInterval = 5.0 + ) + + IPv8Android.Factory(this).setConfiguration(config).setPrivateKey(getPrivateKey()) + .setServiceClass(TrustChainService::class.java).init() initTrustChain() } @@ -62,8 +57,7 @@ class DemoApplication : Application() { trustchain.registerTransactionValidator(BLOCK_TYPE, object : TransactionValidator { override fun validate( - block: TrustChainBlock, - database: TrustChainStore + block: TrustChainBlock, database: TrustChainStore ): ValidationResult { if (block.transaction["message"] != null || block.isAgreement) { return ValidationResult.Valid @@ -92,8 +86,8 @@ class DemoApplication : Application() { val periodicSimilarity = PeriodicSimilarity.Factory() val nsd = NetworkServiceDiscovery.Factory(getSystemService()!!) - val bluetoothManager = getSystemService() - ?: throw IllegalStateException("BluetoothManager not available") + val bluetoothManager = + getSystemService() ?: throw IllegalStateException("BluetoothManager not available") val strategies = mutableListOf( randomWalk, randomChurn, periodicSimilarity, nsd ) @@ -103,8 +97,7 @@ class DemoApplication : Application() { } return OverlayConfiguration( - DiscoveryCommunity.Factory(), - strategies + DiscoveryCommunity.Factory(), strategies ) } @@ -114,16 +107,14 @@ class DemoApplication : Application() { val store = TrustChainSQLiteStore(Database(driver)) val randomWalk = RandomWalk.Factory() return OverlayConfiguration( - TrustChainCommunity.Factory(settings, store), - listOf(randomWalk) + TrustChainCommunity.Factory(settings, store), listOf(randomWalk) ) } private fun createDemoCommunity(): OverlayConfiguration { val randomWalk = RandomWalk.Factory() return OverlayConfiguration( - Overlay.Factory(DemoCommunity::class.java), - listOf(randomWalk) + Overlay.Factory(DemoCommunity::class.java), listOf(randomWalk) ) } @@ -134,9 +125,7 @@ class DemoApplication : Application() { return if (privateKey == null) { // Generate a new key on the first launch val newKey = AndroidCryptoProvider.generateKey() - prefs.edit() - .putString(PREF_PRIVATE_KEY, newKey.keyToBin().toHex()) - .apply() + prefs.edit().putString(PREF_PRIVATE_KEY, newKey.keyToBin().toHex()).apply() newKey } else { AndroidCryptoProvider.keyFromPrivateBin(privateKey.hexToBytes()) diff --git a/demo-android/src/main/java/nl/tudelft/trustchain/demo/DemoCommunity.kt b/demo-android/src/main/java/nl/tudelft/trustchain/demo/DemoCommunity.kt index 7a007a5b..c56f1dcb 100644 --- a/demo-android/src/main/java/nl/tudelft/trustchain/demo/DemoCommunity.kt +++ b/demo-android/src/main/java/nl/tudelft/trustchain/demo/DemoCommunity.kt @@ -1,13 +1,11 @@ package nl.tudelft.trustchain.demo -import nl.tudelft.ipv8.IPv4Address import nl.tudelft.ipv8.Community +import nl.tudelft.ipv8.IPv4Address import nl.tudelft.ipv8.Peer import nl.tudelft.ipv8.android.IPv8Android import nl.tudelft.ipv8.attestation.trustchain.TrustChainCommunity -import nl.tudelft.ipv8.messaging.* import nl.tudelft.ipv8.messaging.payload.IntroductionResponsePayload -import nl.tudelft.ipv8.messaging.payload.PuncturePayload import java.util.* class DemoCommunity : Community() { diff --git a/demo-android/src/main/java/nl/tudelft/trustchain/demo/service/TrustChainService.kt b/demo-android/src/main/java/nl/tudelft/trustchain/demo/service/TrustChainService.kt index 41a58132..c0cee030 100644 --- a/demo-android/src/main/java/nl/tudelft/trustchain/demo/service/TrustChainService.kt +++ b/demo-android/src/main/java/nl/tudelft/trustchain/demo/service/TrustChainService.kt @@ -11,14 +11,11 @@ import nl.tudelft.trustchain.demo.ui.DemoActivity class TrustChainService : IPv8Service() { override fun createNotification(): NotificationCompat.Builder { val trustChainExplorerIntent = Intent(this, DemoActivity::class.java) - val pendingIntent = TaskStackBuilder.create(this) - .addNextIntentWithParentStack(trustChainExplorerIntent) + val pendingIntent = TaskStackBuilder.create(this).addNextIntentWithParentStack(trustChainExplorerIntent) .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT) - return NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_CONNECTION) - .setContentTitle("IPv8 Demo") - .setContentText("Running") - .setSmallIcon(R.drawable.ic_insert_link_black_24dp) + return NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_CONNECTION).setContentTitle("IPv8 Demo") + .setContentText("Running").setSmallIcon(R.drawable.ic_insert_link_black_24dp) .setContentIntent(pendingIntent) } } diff --git a/demo-android/src/main/java/nl/tudelft/trustchain/demo/ui/DemoActivity.kt b/demo-android/src/main/java/nl/tudelft/trustchain/demo/ui/DemoActivity.kt index 190dd451..6fa0644f 100644 --- a/demo-android/src/main/java/nl/tudelft/trustchain/demo/ui/DemoActivity.kt +++ b/demo-android/src/main/java/nl/tudelft/trustchain/demo/ui/DemoActivity.kt @@ -9,24 +9,25 @@ import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.mattskala.itemadapter.ItemAdapter -import kotlinx.android.synthetic.main.fragment_peers.* import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import nl.tudelft.ipv8.android.IPv8Android import nl.tudelft.trustchain.demo.DemoCommunity import nl.tudelft.trustchain.demo.R +import nl.tudelft.trustchain.demo.databinding.FragmentPeersBinding import nl.tudelft.trustchain.demo.ui.peers.AddressItem import nl.tudelft.trustchain.demo.ui.peers.AddressItemRenderer import nl.tudelft.trustchain.demo.ui.peers.PeerItem import nl.tudelft.trustchain.demo.ui.peers.PeerItemRenderer class DemoActivity : AppCompatActivity() { + private lateinit var binding: FragmentPeersBinding private val adapter = ItemAdapter() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - setContentView(R.layout.fragment_peers) + binding = FragmentPeersBinding.inflate(layoutInflater) + setContentView(binding.root) adapter.registerRenderer(PeerItemRenderer { // NOOP @@ -36,9 +37,9 @@ class DemoActivity : AppCompatActivity() { // NOOP }) - recyclerView.adapter = adapter - recyclerView.layoutManager = LinearLayoutManager(this) - recyclerView.addItemDecoration(DividerItemDecoration(this, LinearLayout.VERTICAL)) + binding.recyclerView.adapter = adapter + binding.recyclerView.layoutManager = LinearLayoutManager(this) + binding.recyclerView.addItemDecoration(DividerItemDecoration(this, LinearLayout.VERTICAL)) loadNetworkInfo() } @@ -49,12 +50,10 @@ class DemoActivity : AppCompatActivity() { val demoCommunity = IPv8Android.getInstance().getOverlay()!! val peers = demoCommunity.getPeers() - val discoveredAddresses = demoCommunity.network - .getWalkableAddresses(demoCommunity.serviceId) + val discoveredAddresses = demoCommunity.network.getWalkableAddresses(demoCommunity.serviceId) - val discoveredBluetoothAddresses = demoCommunity.network - .getNewBluetoothPeerCandidates() - .map { it.address } + val discoveredBluetoothAddresses = + demoCommunity.network.getNewBluetoothPeerCandidates().map { it.address } val peerItems = peers.map { PeerItem( @@ -65,29 +64,25 @@ class DemoActivity : AppCompatActivity() { val addressItems = discoveredAddresses.map { address -> val contacted = demoCommunity.discoveredAddressesContacted[address] AddressItem( - address, - null, - contacted + address, null, contacted ) } val bluetoothAddressItems = discoveredBluetoothAddresses.map { address -> AddressItem( - address, - null, - null + address, null, null ) } val items = peerItems + bluetoothAddressItems + addressItems adapter.updateItems(items) - txtCommunityName.text = demoCommunity.javaClass.simpleName - txtPeerCount.text = "${peers.size} peers" + binding.txtCommunityName.text = demoCommunity.javaClass.simpleName + binding.txtPeerCount.text = "${peers.size} peers" val textColorResId = if (peers.isNotEmpty()) R.color.green else R.color.red val textColor = ResourcesCompat.getColor(resources, textColorResId, null) - txtPeerCount.setTextColor(textColor) - imgEmpty.isVisible = items.isEmpty() + binding.txtPeerCount.setTextColor(textColor) + binding.imgEmpty.isVisible = items.isEmpty() delay(1000) } diff --git a/demo-android/src/main/java/nl/tudelft/trustchain/demo/ui/peers/AddressItemRenderer.kt b/demo-android/src/main/java/nl/tudelft/trustchain/demo/ui/peers/AddressItemRenderer.kt index 0a7dc724..f3f5689b 100644 --- a/demo-android/src/main/java/nl/tudelft/trustchain/demo/ui/peers/AddressItemRenderer.kt +++ b/demo-android/src/main/java/nl/tudelft/trustchain/demo/ui/peers/AddressItemRenderer.kt @@ -4,8 +4,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.view.isVisible import com.mattskala.itemadapter.ItemLayoutRenderer -import kotlinx.android.synthetic.main.item_peer.view.* import nl.tudelft.trustchain.demo.R +import nl.tudelft.trustchain.demo.databinding.ItemPeerBinding import java.util.* import kotlin.math.roundToInt @@ -15,19 +15,20 @@ class AddressItemRenderer( AddressItem::class.java) { @SuppressLint("SetTextI18n") override fun bindView(item: AddressItem, view: View) = with(view) { - txtPeerId.text = "?" - txtAddress.text = item.address.toString() + val binding = ItemPeerBinding.bind(view) + binding.txtPeerId.text = "?" + binding.txtAddress.text = item.address.toString() val lastRequest = item.contacted val lastResponse = item.discovered - txtBluetoothAddress.isVisible = false + binding.txtBluetoothAddress.isVisible = false - txtLastSent.text = if (lastRequest != null) + binding.txtLastSent.text = if (lastRequest != null) "" + ((Date().time - lastRequest.time) / 1000.0).roundToInt() + " s" else "?" - txtLastReceived.text = if (lastResponse != null) + binding.txtLastReceived.text = if (lastResponse != null) "" + ((Date().time - lastResponse.time) / 1000.0).roundToInt() + " s" else "?" - txtAvgPing.text = "? ms" + binding.txtAvgPing.text = "? ms" setOnClickListener { onItemClick(item) diff --git a/demo-android/src/main/java/nl/tudelft/trustchain/demo/ui/peers/PeerItemRenderer.kt b/demo-android/src/main/java/nl/tudelft/trustchain/demo/ui/peers/PeerItemRenderer.kt index d8fa7a57..627b5d97 100644 --- a/demo-android/src/main/java/nl/tudelft/trustchain/demo/ui/peers/PeerItemRenderer.kt +++ b/demo-android/src/main/java/nl/tudelft/trustchain/demo/ui/peers/PeerItemRenderer.kt @@ -4,33 +4,35 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.view.isVisible import com.mattskala.itemadapter.ItemLayoutRenderer -import kotlinx.android.synthetic.main.item_peer.view.* import nl.tudelft.trustchain.demo.R +import nl.tudelft.trustchain.demo.databinding.ItemPeerBinding import java.util.* import kotlin.math.roundToInt class PeerItemRenderer( private val onItemClick: (PeerItem) -> Unit ) : ItemLayoutRenderer( - PeerItem::class.java) { + PeerItem::class.java +) { @SuppressLint("SetTextI18n") override fun bindView(item: PeerItem, view: View) = with(view) { - txtPeerId.text = item.peer.mid - txtAddress.text = item.peer.address.toString() - txtAddress.isVisible = !item.peer.address.isEmpty() - txtBluetoothAddress.text = item.peer.bluetoothAddress?.toString() - txtBluetoothAddress.isVisible = item.peer.bluetoothAddress != null + val binding = ItemPeerBinding.bind(view) + binding.txtPeerId.text = item.peer.mid + binding.txtAddress.text = item.peer.address.toString() + binding.txtAddress.isVisible = !item.peer.address.isEmpty() + binding.txtBluetoothAddress.text = item.peer.bluetoothAddress?.toString() + binding.txtBluetoothAddress.isVisible = item.peer.bluetoothAddress != null val avgPing = item.peer.getAveragePing() val lastRequest = item.peer.lastRequest val lastResponse = item.peer.lastResponse - txtLastSent.text = if (lastRequest != null) - "" + ((Date().time - lastRequest.time) / 1000.0).roundToInt() + " s" else "?" + binding.txtLastSent.text = + if (lastRequest != null) "" + ((Date().time - lastRequest.time) / 1000.0).roundToInt() + " s" else "?" - txtLastReceived.text = if (lastResponse != null) - "" + ((Date().time - lastResponse.time) / 1000.0).roundToInt() + " s" else "?" + binding.txtLastReceived.text = + if (lastResponse != null) "" + ((Date().time - lastResponse.time) / 1000.0).roundToInt() + " s" else "?" - txtAvgPing.text = if (!avgPing.isNaN()) "" + (avgPing * 1000).roundToInt() + " ms" else "? ms" + binding.txtAvgPing.text = if (!avgPing.isNaN()) "" + (avgPing * 1000).roundToInt() + " ms" else "? ms" setOnClickListener { onItemClick(item) diff --git a/demo-jvm/build.gradle b/demo-jvm/build.gradle index bc3a2b60..daabf534 100644 --- a/demo-jvm/build.gradle +++ b/demo-jvm/build.gradle @@ -15,9 +15,14 @@ dependencies { // Logging implementation 'io.github.microutils:kotlin-logging:1.7.7' - implementation "com.squareup.sqldelight:sqlite-driver:$sqldelight_version" + implementation "app.cash.sqldelight:sqlite-driver:$sqldelight_version" } run { systemProperties System.getProperties() } + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} diff --git a/demo-jvm/src/main/java/nl/tudelft/ipv8/jvm/demo/Application.kt b/demo-jvm/src/main/java/nl/tudelft/ipv8/jvm/demo/Application.kt index 85c6d241..d2048fb0 100644 --- a/demo-jvm/src/main/java/nl/tudelft/ipv8/jvm/demo/Application.kt +++ b/demo-jvm/src/main/java/nl/tudelft/ipv8/jvm/demo/Application.kt @@ -1,8 +1,8 @@ package nl.tudelft.ipv8.jvm.demo -import com.squareup.sqldelight.db.SqlDriver -import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver -import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver.Companion.IN_MEMORY +import app.cash.sqldelight.db.SqlDriver +import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver +import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver.Companion.IN_MEMORY import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -13,11 +13,9 @@ import nl.tudelft.ipv8.attestation.trustchain.TrustChainCommunity import nl.tudelft.ipv8.attestation.trustchain.TrustChainSettings import nl.tudelft.ipv8.attestation.trustchain.store.TrustChainSQLiteStore import nl.tudelft.ipv8.keyvault.JavaCryptoProvider -import nl.tudelft.ipv8.messaging.Endpoint import nl.tudelft.ipv8.messaging.EndpointAggregator import nl.tudelft.ipv8.messaging.udp.UdpEndpoint import nl.tudelft.ipv8.peerdiscovery.DiscoveryCommunity -import nl.tudelft.ipv8.peerdiscovery.Network import nl.tudelft.ipv8.peerdiscovery.strategy.PeriodicSimilarity import nl.tudelft.ipv8.peerdiscovery.strategy.RandomChurn import nl.tudelft.ipv8.peerdiscovery.strategy.RandomWalk @@ -71,11 +69,13 @@ class Application { val udpEndpoint = UdpEndpoint(8090, InetAddress.getByName("0.0.0.0")) val endpoint = EndpointAggregator(udpEndpoint, null) - val config = IPv8Configuration(overlays = listOf( - createDiscoveryCommunity(), - createTrustChainCommunity(), - createDemoCommunity() - ), walkerInterval = 1.0) + val config = IPv8Configuration( + overlays = listOf( + createDiscoveryCommunity(), + createTrustChainCommunity(), + createDemoCommunity() + ), walkerInterval = 1.0 + ) val ipv8 = IPv8(endpoint, config, myPeer) ipv8.start() diff --git a/gradle.properties b/gradle.properties index 23339e0d..47954809 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,3 +19,5 @@ android.useAndroidX=true android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official +android.nonTransitiveRClass=false +android.nonFinalResIds=false diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 28f207f0..2f10fb20 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue Jan 12 11:23:56 CET 2021 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-all.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/ipv8-android/build.gradle b/ipv8-android/build.gradle index fe959aeb..9be9460d 100644 --- a/ipv8-android/build.gradle +++ b/ipv8-android/build.gradle @@ -1,6 +1,5 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' apply plugin: 'org.jlleitschuh.gradle.ktlint' ktlint { @@ -8,15 +7,14 @@ ktlint { android = true outputToConsole = true ignoreFailures = true + verbose = true } android { - compileSdkVersion 33 - defaultConfig { minSdkVersion 22 - targetSdkVersion 33 + compileSdk 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles 'consumer-rules.pro' @@ -30,12 +28,12 @@ android { } compileOptions { - targetCompatibility JavaVersion.VERSION_11 - sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() + jvmTarget = JavaVersion.VERSION_17.toString() allWarningsAsErrors = true freeCompilerArgs += [ "-opt-in=kotlin.RequiresOptIn" @@ -46,7 +44,7 @@ android { } dependencies { - api (project(':ipv8')) { + api(project(':ipv8')) { exclude module: 'lazysodium-java' } @@ -70,8 +68,8 @@ dependencies { implementation 'no.nordicsemi.android.support.v18:scanner:1.4.2' implementation 'io.github.microutils:kotlin-logging:1.7.7' - api "com.squareup.sqldelight:android-driver:$sqldelight_version" - api "com.squareup.sqldelight:coroutines-extensions:$sqldelight_version" + api "app.cash.sqldelight:android-driver:$sqldelight_version" + api "app.cash.sqldelight:coroutines-extensions:$sqldelight_version" testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.5' diff --git a/ipv8-android/src/androidTest/java/nl/tudelft/ipv8/android/ExampleInstrumentedTest.kt b/ipv8-android/src/androidTest/java/nl/tudelft/ipv8/android/ExampleInstrumentedTest.kt index 5e193769..d9e5fdeb 100644 --- a/ipv8-android/src/androidTest/java/nl/tudelft/ipv8/android/ExampleInstrumentedTest.kt +++ b/ipv8-android/src/androidTest/java/nl/tudelft/ipv8/android/ExampleInstrumentedTest.kt @@ -1,13 +1,11 @@ package nl.tudelft.ipv8.android -import androidx.test.platform.app.InstrumentationRegistry import androidx.test.ext.junit.runners.AndroidJUnit4 - +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith -import org.junit.Assert.* - /** * Instrumented test, which will execute on an Android device. * diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/IPv8Android.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/IPv8Android.kt index e42357e0..b7a99bfd 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/IPv8Android.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/IPv8Android.kt @@ -37,7 +37,6 @@ object IPv8Android { class Factory( private val application: Application, ) { - private var privateKey: PrivateKey? = null private var identityPrivateKeySmall: BonehPrivateKey? = null private var identityPrivateKeyBig: BonehPrivateKey? = null @@ -94,46 +93,59 @@ object IPv8Android { } private fun create(): IPv8 { - val privateKey = privateKey - ?: throw IllegalStateException("Private key is not set") - - val configuration = configuration - ?: throw IllegalStateException("Configuration is not set") - - val connectivityManager = application.getSystemService() - ?: throw IllegalStateException("ConnectivityManager not found") - - val udpEndpoint = AndroidUdpEndpoint( - 8090, - InetAddress.getByName("0.0.0.0"), - connectivityManager - ) - - val bluetoothManager = application.getSystemService() - ?: throw IllegalStateException("BluetoothManager not found") - - val myPeer = Peer( - privateKey, - identityPrivateKeySmall = this.identityPrivateKeySmall, - identityPrivateKeyBig = this.identityPrivateKeyBig, - identityPrivateKeyHuge = this.identityPrivateKeyHuge - ) + val privateKey = privateKey ?: throw IllegalStateException("Private key is not set") + + val configuration = + configuration ?: throw IllegalStateException("Configuration is not set") + + val connectivityManager = + application.getSystemService() + ?: throw IllegalStateException("ConnectivityManager not found") + + val udpEndpoint = + AndroidUdpEndpoint( + 8090, + InetAddress.getByName("0.0.0.0"), + connectivityManager, + ) + + val bluetoothManager = + application.getSystemService() + ?: throw IllegalStateException("BluetoothManager not found") + + val myPeer = + Peer( + privateKey, + identityPrivateKeySmall = this.identityPrivateKeySmall, + identityPrivateKeyBig = this.identityPrivateKeyBig, + identityPrivateKeyHuge = this.identityPrivateKeyHuge, + ) val network = Network() val gattServer = GattServerManager(application, myPeer) val bleAdvertiser = IPv8BluetoothLeAdvertiser(bluetoothManager) val bleScanner = IPv8BluetoothLeScanner(bluetoothManager, network) - val bluetoothEndpoint = if ( - bluetoothManager.adapter != null && Build.VERSION.SDK_INT >= 24 - ) BluetoothLeEndpoint( - application, bluetoothManager, gattServer, bleAdvertiser, bleScanner, network, myPeer - ) else null - - val endpointAggregator = EndpointAggregator( - udpEndpoint, - bluetoothEndpoint - ) + val bluetoothEndpoint = + if (bluetoothManager.adapter != null) { + BluetoothLeEndpoint( + application, + bluetoothManager, + gattServer, + bleAdvertiser, + bleScanner, + network, + myPeer, + ) + } else { + null + } + + val endpointAggregator = + EndpointAggregator( + udpEndpoint, + bluetoothEndpoint, + ) return IPv8(endpointAggregator, configuration, myPeer, network) } diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeAdvertiser.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeAdvertiser.kt index 2405970f..8ed71ea8 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeAdvertiser.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeAdvertiser.kt @@ -13,7 +13,7 @@ import nl.tudelft.ipv8.util.hexToBytes private val logger = KotlinLogging.logger {} class IPv8BluetoothLeAdvertiser( - bluetoothManager: BluetoothManager + bluetoothManager: BluetoothManager, ) { private val bluetoothAdapter = bluetoothManager.adapter @@ -21,28 +21,30 @@ class IPv8BluetoothLeAdvertiser( bluetoothAdapter.bluetoothLeAdvertiser } - private val advertiseCallback = object : AdvertiseCallback() { - override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) { - logger.debug { "onStartSuccess" } - isAdvertising = true - } + private val advertiseCallback = + object : AdvertiseCallback() { + override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) { + logger.debug { "onStartSuccess" } + isAdvertising = true + } - override fun onStartFailure(errorCode: Int) { - logger.error { "onStartFailure $errorCode" } - isAdvertising = false + override fun onStartFailure(errorCode: Int) { + logger.error { "onStartFailure $errorCode" } + isAdvertising = false + } } - } private var isAdvertising = false @SuppressLint("MissingPermission") // TODO: Fix permission usage. fun start(myPeer: Peer) { - val settings = AdvertiseSettings.Builder() - .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER) - .setTimeout(0) - // make sure the server is connectable! - .setConnectable(true) - .build() + val settings = + AdvertiseSettings.Builder() + .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER) + .setTimeout(0) + // make sure the server is connectable! + .setConnectable(true) + .build() val advertiseData = getAdvertiseData() val scanResponse = getScanResponse(myPeer) @@ -67,7 +69,7 @@ class IPv8BluetoothLeAdvertiser( .setIncludeDeviceName(false) .addServiceData( ParcelUuid(GattServerManager.ADVERTISE_IDENTITY_UUID), - myPeer.mid.hexToBytes() + myPeer.mid.hexToBytes(), ) .build() } diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeDiscovery.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeDiscovery.kt index 740ac743..9fbe1356 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeDiscovery.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeDiscovery.kt @@ -11,12 +11,13 @@ private val logger = KotlinLogging.logger {} */ class BluetoothLeDiscovery( private val overlay: Overlay, - private val peers: Int + private val peers: Int, ) : DiscoveryStrategy { override fun takeStep() { - val bluetoothPeers = overlay.network.verifiedPeers.filter { - it.bluetoothAddress != null - } + val bluetoothPeers = + overlay.network.verifiedPeers.filter { + it.bluetoothAddress != null + } if (bluetoothPeers.size >= peers) return @@ -39,7 +40,7 @@ class BluetoothLeDiscovery( * The maximum number of peers we should connect to over Bluetooth. */ class Factory( - private val peers: Int = 7 + private val peers: Int = 7, ) : DiscoveryStrategy.Factory() { override fun create(): BluetoothLeDiscovery { return BluetoothLeDiscovery(getOverlay(), peers) diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeEndpoint.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeEndpoint.kt index b4d1eb21..ab423d13 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeEndpoint.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeEndpoint.kt @@ -23,7 +23,7 @@ class BluetoothLeEndpoint( private val bleAdvertiser: IPv8BluetoothLeAdvertiser, private val bleScanner: IPv8BluetoothLeScanner, private val network: Network, - private val myPeer: Peer + private val myPeer: Peer, ) : BluetoothEndpoint() { /** * True if we are currently advertising and sending packets to connected GATT servers. @@ -32,42 +32,51 @@ class BluetoothLeEndpoint( private val clients: MutableMap = mutableMapOf() - private val clientCallbacks = object : GattClientCallbacks() { - override fun onPeerDiscovered(peer: Peer) { - network.addVerifiedPeer(peer) + private val clientCallbacks = + object : GattClientCallbacks() { + override fun onPeerDiscovered(peer: Peer) { + network.addVerifiedPeer(peer) + } + + override fun onPacketWrite( + device: BluetoothDevice, + data: ByteArray, + ) { + notifyListeners(Packet(BluetoothAddress(device.address), data)) + } + + override fun onDeviceDisconnected(device: BluetoothDevice) { + network.removeByAddress(BluetoothAddress(device.address)) + clients.remove(BluetoothAddress(device.address)) + } + + override fun onError( + device: BluetoothDevice, + message: String, + errorCode: Int, + ) { + logger.error { "GATT error: $device $message $errorCode" } + } } - override fun onPacketWrite(device: BluetoothDevice, data: ByteArray) { - notifyListeners(Packet(BluetoothAddress(device.address), data)) + private val serverCallbacks = + object : BleServerManagerCallbacks { + override fun onDeviceConnectedToServer(device: BluetoothDevice) { + // A device has connected to our GATT server. Initiate connection to their GATT server to provide + // bidirectional communication. + logger.info { "Device connected to server: $device" } + connectTo(BluetoothAddress(device.address)) + } + + override fun onDeviceDisconnectedFromServer(device: BluetoothDevice) { + logger.info { "Device disconnected from server: $device" } + } + + override fun onServerReady() { + // NOOP + } } - override fun onDeviceDisconnected(device: BluetoothDevice) { - network.removeByAddress(BluetoothAddress(device.address)) - clients.remove(BluetoothAddress(device.address)) - } - - override fun onError(device: BluetoothDevice, message: String, errorCode: Int) { - logger.error { "GATT error: $device $message $errorCode" } - } - } - - private val serverCallbacks = object : BleServerManagerCallbacks { - override fun onDeviceConnectedToServer(device: BluetoothDevice) { - // A device has connected to our GATT server. Initiate connection to their GATT server to provide - // bidirectional communication. - logger.info { "Device connected to server: $device" } - connectTo(BluetoothAddress(device.address)) - } - - override fun onDeviceDisconnectedFromServer(device: BluetoothDevice) { - logger.info { "Device disconnected from server: $device" } - } - - override fun onServerReady() { - // NOOP - } - } - init { gattServer.setManagerCallbacks(serverCallbacks) } @@ -76,7 +85,10 @@ class BluetoothLeEndpoint( return isOpen } - override fun send(peer: BluetoothAddress, data: ByteArray) { + override fun send( + peer: BluetoothAddress, + data: ByteArray, + ) { logger.debug { "Send to $peer: ${data.size} B" } val client = clients[peer] client?.send(data) diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/GattClientCallbacks.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/GattClientCallbacks.kt index 744a2626..558f2f43 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/GattClientCallbacks.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/GattClientCallbacks.kt @@ -7,7 +7,10 @@ import no.nordicsemi.android.ble.BleManagerCallbacks abstract class GattClientCallbacks : BleManagerCallbacks { abstract fun onPeerDiscovered(peer: Peer) - abstract fun onPacketWrite(device: BluetoothDevice, data: ByteArray) + abstract fun onPacketWrite( + device: BluetoothDevice, + data: ByteArray, + ) override fun onDeviceDisconnecting(device: BluetoothDevice) { // NOOP @@ -25,7 +28,10 @@ abstract class GattClientCallbacks : BleManagerCallbacks { // NOOP } - override fun onServicesDiscovered(device: BluetoothDevice, optionalServicesFound: Boolean) { + override fun onServicesDiscovered( + device: BluetoothDevice, + optionalServicesFound: Boolean, + ) { // NOOP } diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/GattClientManager.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/GattClientManager.kt index 5a3f75f3..2cf34a2e 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/GattClientManager.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/GattClientManager.kt @@ -23,7 +23,10 @@ class GattClientManager(context: Context) : BleManager(cont return IPv8GattCallback() } - override fun log(priority: Int, message: String) { + override fun log( + priority: Int, + message: String, + ) { Log.println(priority, "IPv8BleManager", message) } @@ -62,10 +65,11 @@ class GattClientManager(context: Context) : BleManager(cont .with { device, data -> val value = data.value if (value != null) { - val peer = Peer( - bluetoothAddress = BluetoothAddress(device.address), - key = defaultCryptoProvider.keyFromPublicBin(value) - ) + val peer = + Peer( + bluetoothAddress = BluetoothAddress(device.address), + key = defaultCryptoProvider.keyFromPublicBin(value), + ) callbacks.onPeerDiscovered(peer) } } @@ -73,9 +77,10 @@ class GattClientManager(context: Context) : BleManager(cont } override fun onServerReady(server: BluetoothGattServer) { - serverCharacteristic = server - .getService(GattServerManager.SERVICE_UUID) - .getCharacteristic(GattServerManager.WRITE_CHARACTERISTIC_UUID) + serverCharacteristic = + server + .getService(GattServerManager.SERVICE_UUID) + .getCharacteristic(GattServerManager.WRITE_CHARACTERISTIC_UUID) setWriteCallback(serverCharacteristic) .with { device, data -> diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/GattServerManager.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/GattServerManager.kt index b3593c8d..90c2551f 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/GattServerManager.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/GattServerManager.kt @@ -10,9 +10,12 @@ import java.util.* class GattServerManager( context: Context, - private val myPeer: Peer + private val myPeer: Peer, ) : BleServerManager(context) { - override fun log(priority: Int, message: String) { + override fun log( + priority: Int, + message: String, + ) { Log.println(priority, "GattServerManager", message) } @@ -23,15 +26,15 @@ class GattServerManager( characteristic( WRITE_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE, - BluetoothGattCharacteristic.PERMISSION_WRITE + BluetoothGattCharacteristic.PERMISSION_WRITE, ), characteristic( IDENTITY_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ, - myPeer.publicKey.keyToBin() - ) - ) + myPeer.publicKey.keyToBin(), + ), + ), ) } diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/IPv8BluetoothLeScanner.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/IPv8BluetoothLeScanner.kt index e2fc0818..f106446a 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/IPv8BluetoothLeScanner.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/IPv8BluetoothLeScanner.kt @@ -17,7 +17,7 @@ private val logger = KotlinLogging.logger {} @OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class) class IPv8BluetoothLeScanner( private val bluetoothManager: BluetoothManager, - private val network: Network + private val network: Network, ) { private var isScanning = false private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob()) @@ -28,40 +28,47 @@ class IPv8BluetoothLeScanner( bluetoothManager.adapter.bluetoothLeScanner } - private val scanCallback = object : ScanCallback() { - override fun onBatchScanResults(results: MutableList) { - logger.debug { "onBatchScanResults: ${results.size} results" } - } + private val scanCallback = + object : ScanCallback() { + override fun onBatchScanResults(results: MutableList) { + logger.debug { "onBatchScanResults: ${results.size} results" } + } - override fun onScanFailed(errorCode: Int) { - logger.error { "onScanFailed: $errorCode" } - isScanning = false - } + override fun onScanFailed(errorCode: Int) { + logger.error { "onScanFailed: $errorCode" } + isScanning = false + } - override fun onScanResult(callbackType: Int, result: ScanResult) { - val device = result.device - val identity = result.scanRecord?.serviceData - ?.get(ParcelUuid(GattServerManager.ADVERTISE_IDENTITY_UUID)) - val rssi = result.rssi - val txPowerLevel = result.scanRecord?.txPowerLevel - - val uuids = result.scanRecord?.serviceUuids?.map { - it.uuid - } ?: listOf() - - if (uuids.contains(SERVICE_UUID)) { - logger.debug { "Discovered Bluetooth device: ${device.address}" } - val bluetoothAddress = BluetoothAddress(device.address) - val peer = BluetoothPeerCandidate( - identity?.toString(Charsets.US_ASCII), - bluetoothAddress, - txPowerLevel, - rssi - ) - network.discoverBluetoothPeer(peer) + override fun onScanResult( + callbackType: Int, + result: ScanResult, + ) { + val device = result.device + val identity = + result.scanRecord?.serviceData + ?.get(ParcelUuid(GattServerManager.ADVERTISE_IDENTITY_UUID)) + val rssi = result.rssi + val txPowerLevel = result.scanRecord?.txPowerLevel + + val uuids = + result.scanRecord?.serviceUuids?.map { + it.uuid + } ?: listOf() + + if (uuids.contains(SERVICE_UUID)) { + logger.debug { "Discovered Bluetooth device: ${device.address}" } + val bluetoothAddress = BluetoothAddress(device.address) + val peer = + BluetoothPeerCandidate( + identity?.toString(Charsets.US_ASCII), + bluetoothAddress, + txPowerLevel, + rssi, + ) + network.discoverBluetoothPeer(peer) + } } } - } @SuppressLint("MissingPermission") // TODO: Fix permission usage. fun start() { @@ -69,12 +76,14 @@ class IPv8BluetoothLeScanner( isScanning = true - val settingsBuilder = ScanSettings.Builder() - .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER) + val settingsBuilder = + ScanSettings.Builder() + .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER) - val serviceScanFilter = ScanFilter.Builder() - .setServiceUuid(ParcelUuid(SERVICE_UUID)) - .build() + val serviceScanFilter = + ScanFilter.Builder() + .setServiceUuid(ParcelUuid(SERVICE_UUID)) + .build() leScanner.startScan(listOf(serviceScanFilter), settingsBuilder.build(), scanCallback) } @@ -98,19 +107,23 @@ class IPv8BluetoothLeScanner( * Starts a periodic scan where each scan window takes [duration] ms and there is [pause] ms * long pause between scans. */ - fun startPeriodicScan(duration: Long, pause: Long) { - scanJob = scope.launch { - while (isActive) { - if (bluetoothManager.adapter.isEnabled) { - start() - delay(duration) - stop() - } else { - logger.warn { "Bluetooth is not enabled" } + fun startPeriodicScan( + duration: Long, + pause: Long, + ) { + scanJob = + scope.launch { + while (isActive) { + if (bluetoothManager.adapter.isEnabled) { + start() + delay(duration) + stop() + } else { + logger.warn { "Bluetooth is not enabled" } + } + delay(pause) } - delay(pause) } - } } /** diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/udp/UdpEndpoint.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/udp/UdpEndpoint.kt index a56e82e3..002bd96f 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/udp/UdpEndpoint.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/udp/UdpEndpoint.kt @@ -14,21 +14,24 @@ private val logger = KotlinLogging.logger {} class AndroidUdpEndpoint( port: Int, ip: InetAddress, - private val connectivityManager: ConnectivityManager + private val connectivityManager: ConnectivityManager, ) : UdpEndpoint(port, ip) { - - private val defaultNetworkCallback = object : ConnectivityManager.NetworkCallback() { - override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) { - super.onLinkPropertiesChanged(network, linkProperties) - logger.debug("onLinkPropertiesChanged " + linkProperties.linkAddresses) - for (linkAddress in linkProperties.linkAddresses) { - if (linkAddress.address is Inet4Address && !linkAddress.address.isLoopbackAddress) { - val estimatedAddress = IPv4Address(linkAddress.address.hostAddress!!, getSocketPort()) - setEstimatedLan(estimatedAddress) + private val defaultNetworkCallback = + object : ConnectivityManager.NetworkCallback() { + override fun onLinkPropertiesChanged( + network: Network, + linkProperties: LinkProperties, + ) { + super.onLinkPropertiesChanged(network, linkProperties) + logger.debug("onLinkPropertiesChanged " + linkProperties.linkAddresses) + for (linkAddress in linkProperties.linkAddresses) { + if (linkAddress.address is Inet4Address && !linkAddress.address.isLoopbackAddress) { + val estimatedAddress = IPv4Address(linkAddress.address.hostAddress!!, getSocketPort()) + setEstimatedLan(estimatedAddress) + } } } } - } override fun startLanEstimation() { if (Build.VERSION.SDK_INT >= 24) { diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/peerdiscovery/NetworkServiceDiscovery.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/peerdiscovery/NetworkServiceDiscovery.kt index 13d59aad..e355b4e5 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/peerdiscovery/NetworkServiceDiscovery.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/peerdiscovery/NetworkServiceDiscovery.kt @@ -2,6 +2,7 @@ package nl.tudelft.ipv8.android.peerdiscovery import android.net.nsd.NsdManager import android.net.nsd.NsdServiceInfo +import android.os.Build import mu.KotlinLogging import nl.tudelft.ipv8.IPv4Address import nl.tudelft.ipv8.Overlay @@ -16,90 +17,106 @@ private val logger = KotlinLogging.logger {} */ class NetworkServiceDiscovery( private val nsdManager: NsdManager, - private val overlay: Overlay + private val overlay: Overlay, ) : DiscoveryStrategy { private var serviceName: String? = null - private val registrationListener = object : NsdManager.RegistrationListener { - override fun onServiceRegistered(serviceInfo: NsdServiceInfo) { - // Save the service name. Android may have changed it in order to - // resolve a conflict, so update the name you initially requested - // with the name Android actually used. - logger.info { "Service registered: $serviceInfo" } - serviceName = serviceInfo.serviceName - } + private val registrationListener = + object : NsdManager.RegistrationListener { + override fun onServiceRegistered(serviceInfo: NsdServiceInfo) { + // Save the service name. Android may have changed it in order to + // resolve a conflict, so update the name you initially requested + // with the name Android actually used. + logger.info { "Service registered: $serviceInfo" } + serviceName = serviceInfo.serviceName + } - override fun onRegistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { - // Registration failed! Put debugging code here to determine why. - logger.error { "Service registration failed: $errorCode" } - } + override fun onRegistrationFailed( + serviceInfo: NsdServiceInfo, + errorCode: Int, + ) { + // Registration failed! Put debugging code here to determine why. + logger.error { "Service registration failed: $errorCode" } + } - override fun onServiceUnregistered(serviceInfo: NsdServiceInfo) { - // Service has been unregistered. This only happens when you call - // NsdManager.unregisterService() and pass in this listener. - logger.info { "Service unregistered: $serviceInfo" } - } + override fun onServiceUnregistered(serviceInfo: NsdServiceInfo) { + // Service has been unregistered. This only happens when you call + // NsdManager.unregisterService() and pass in this listener. + logger.info { "Service unregistered: $serviceInfo" } + } - override fun onUnregistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { - // Unregistration failed. Put debugging code here to determine why. - logger.error { "Service unregistration failed: $errorCode" } + override fun onUnregistrationFailed( + serviceInfo: NsdServiceInfo, + errorCode: Int, + ) { + // Unregistration failed. Put debugging code here to determine why. + logger.error { "Service unregistration failed: $errorCode" } + } } - } // Instantiate a new DiscoveryListener - private val discoveryListener = object : NsdManager.DiscoveryListener { - - // Called as soon as service discovery begins. - override fun onDiscoveryStarted(regType: String) { - logger.debug { "Service discovery started" } - } + private val discoveryListener = + object : NsdManager.DiscoveryListener { + // Called as soon as service discovery begins. + override fun onDiscoveryStarted(regType: String) { + logger.debug { "Service discovery started" } + } - override fun onServiceFound(serviceInfo: NsdServiceInfo) { - // A service was found! Do something with it. - logger.debug { "Service found: $serviceInfo" } + override fun onServiceFound(serviceInfo: NsdServiceInfo) { + // A service was found! Do something with it. + logger.debug { "Service found: $serviceInfo" } - if (serviceInfo.serviceType == SERVICE_TYPE) { - // This is IPv8 service + if (serviceInfo.serviceType == SERVICE_TYPE) { + // This is IPv8 service - if (serviceInfo.serviceName == serviceName) { - logger.debug { "Found its own service" } - } + if (serviceInfo.serviceName == serviceName) { + logger.debug { "Found its own service" } + } - val serviceId = getServiceId(serviceInfo.serviceName) + val serviceId = getServiceId(serviceInfo.serviceName) - logger.debug { "Service ID: $serviceId" } + logger.debug { "Service ID: $serviceId" } - if (serviceId == overlay.serviceId) { - nsdManager.resolveService(serviceInfo, createResolveListener()) + if (serviceId == overlay.serviceId) { + @Suppress("DEPRECATION") // TODO: Replace with registerServiceInfoCallback. + nsdManager.resolveService(serviceInfo, createResolveListener()) + } } } - } - override fun onServiceLost(service: NsdServiceInfo) { - // When the network service is no longer available. - // Internal bookkeeping code goes here. - logger.debug { "Service lost: $service" } - } + override fun onServiceLost(service: NsdServiceInfo) { + // When the network service is no longer available. + // Internal bookkeeping code goes here. + logger.debug { "Service lost: $service" } + } - override fun onDiscoveryStopped(serviceType: String) { - logger.debug("Discovery stopped: $serviceType") - } + override fun onDiscoveryStopped(serviceType: String) { + logger.debug("Discovery stopped: $serviceType") + } - override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) { - logger.error("Discovery failed: $errorCode") - nsdManager.stopServiceDiscovery(this) - } + override fun onStartDiscoveryFailed( + serviceType: String, + errorCode: Int, + ) { + logger.error("Discovery failed: $errorCode") + nsdManager.stopServiceDiscovery(this) + } - override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) { - logger.error { "Discovery failed: $errorCode" } - nsdManager.stopServiceDiscovery(this) + override fun onStopDiscoveryFailed( + serviceType: String, + errorCode: Int, + ) { + logger.error { "Discovery failed: $errorCode" } + nsdManager.stopServiceDiscovery(this) + } } - } private fun createResolveListener(): NsdManager.ResolveListener { return object : NsdManager.ResolveListener { - - override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { + override fun onResolveFailed( + serviceInfo: NsdServiceInfo, + errorCode: Int, + ) { // Called when the resolve fails. Use the error code to debug. logger.error("Resolve failed: $errorCode") } @@ -108,7 +125,15 @@ class NetworkServiceDiscovery( logger.info("Service resolved: $serviceInfo") val peer = overlay.myPeer - val address = IPv4Address(serviceInfo.host.hostAddress!!, serviceInfo.port) + + val hostAddress = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + serviceInfo.hostAddresses.first().hostAddress!! + } else { + @Suppress("DEPRECATION") // Deprecated in API 34. So false positive. + serviceInfo.host.hostAddress!! + } + val address = IPv4Address(hostAddress, serviceInfo.port) if (overlay.myEstimatedLan != address) { logger.debug { "Discovered address: $address" } @@ -120,7 +145,10 @@ class NetworkServiceDiscovery( } } - private fun registerService(port: Int, serviceName: String) { + private fun registerService( + port: Int, + serviceName: String, + ) { val serviceInfo = NsdServiceInfo() // The name is subject to change based on conflicts // with other services advertised on the same network. @@ -197,7 +225,7 @@ class NetworkServiceDiscovery( } class Factory( - private val nsdManager: NsdManager + private val nsdManager: NsdManager, ) : DiscoveryStrategy.Factory() { override fun create(): NetworkServiceDiscovery { return NetworkServiceDiscovery(nsdManager, getOverlay()) diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/service/IPv8Service.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/service/IPv8Service.kt index 231f7dde..6466e165 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/service/IPv8Service.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/service/IPv8Service.kt @@ -7,6 +7,7 @@ import android.app.PendingIntent.FLAG_IMMUTABLE import android.app.PendingIntent.FLAG_UPDATE_CURRENT import android.app.Service import android.content.Intent +import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC import android.os.Build import android.os.Build.VERSION.SDK_INT import android.os.IBinder @@ -73,11 +74,12 @@ open class IPv8Service : Service(), LifecycleObserver { // the NotificationChannel class is new and not in the support library if (SDK_INT >= Build.VERSION_CODES.O) { val importance = NotificationManager.IMPORTANCE_LOW - val channel = NotificationChannel( - NOTIFICATION_CHANNEL_CONNECTION, - getString(R.string.notification_channel_connection_title), - importance - ) + val channel = + NotificationChannel( + NOTIFICATION_CHANNEL_CONNECTION, + getString(R.string.notification_channel_connection_title), + importance, + ) channel.description = getString(R.string.notification_channel_connection_description) // Register the channel with the system; you can't change the importance // or other notification behaviors after this @@ -88,14 +90,18 @@ open class IPv8Service : Service(), LifecycleObserver { private fun showForegroundNotification() { val cancelBroadcastIntent = Intent(this, StopIPv8Receiver::class.java) - val flags = when { - SDK_INT >= Build.VERSION_CODES.M -> FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE - else -> FLAG_UPDATE_CURRENT - } - val cancelPendingIntent = PendingIntent.getBroadcast( - applicationContext, - 0, cancelBroadcastIntent, flags - ) + val flags = + when { + SDK_INT >= Build.VERSION_CODES.M -> FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE + else -> FLAG_UPDATE_CURRENT + } + val cancelPendingIntent = + PendingIntent.getBroadcast( + applicationContext, + 0, + cancelBroadcastIntent, + flags, + ) val builder = createNotification() @@ -104,10 +110,18 @@ open class IPv8Service : Service(), LifecycleObserver { builder.addAction(NotificationCompat.Action(0, "Stop", cancelPendingIntent)) } - startForeground( - ONGOING_NOTIFICATION_ID, - builder.build() - ) + if (SDK_INT > Build.VERSION_CODES.TIRAMISU) { + startForeground( + ONGOING_NOTIFICATION_ID, + builder.build(), + FOREGROUND_SERVICE_TYPE_DATA_SYNC, + ) + } else { + startForeground( + ONGOING_NOTIFICATION_ID, + builder.build(), + ) + } } /** diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/service/StopIPv8Receiver.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/service/StopIPv8Receiver.kt index a3064b27..2ccde239 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/service/StopIPv8Receiver.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/service/StopIPv8Receiver.kt @@ -6,7 +6,10 @@ import android.content.Intent import nl.tudelft.ipv8.android.IPv8Android class StopIPv8Receiver : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { + override fun onReceive( + context: Context, + intent: Intent, + ) { val serviceIntent = Intent(context, IPv8Android.serviceClass) context.stopService(serviceIntent) } diff --git a/ipv8-jvm/build.gradle b/ipv8-jvm/build.gradle index 2b0dc684..b352e8a7 100644 --- a/ipv8-jvm/build.gradle +++ b/ipv8-jvm/build.gradle @@ -7,5 +7,10 @@ dependencies { implementation "net.java.dev.jna:jna:5.5.0" implementation 'org.slf4j:slf4j-simple:2.0.6' - implementation "com.squareup.sqldelight:sqlite-driver:$sqldelight_version" + implementation "app.cash.sqldelight:sqlite-driver:$sqldelight_version" +} + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } diff --git a/ipv8/build.gradle b/ipv8/build.gradle index e22116d6..5a00e0e0 100644 --- a/ipv8/build.gradle +++ b/ipv8/build.gradle @@ -1,14 +1,9 @@ apply plugin: 'kotlin' - apply plugin: 'java-library' - apply plugin: 'jacoco' - apply plugin: 'org.jetbrains.dokka' - apply plugin: 'org.jlleitschuh.gradle.ktlint' - -apply plugin: 'com.squareup.sqldelight' +apply plugin: 'app.cash.sqldelight' dokka { outputFormat = 'html' @@ -16,10 +11,12 @@ dokka { } sqldelight { - Database { - packageName = "nl.tudelft.ipv8.sqldelight" - sourceFolders = ["sqldelight"] - schemaOutputDirectory = file("src/main/sqldelight/databases") + databases { + Database { + packageName = "nl.tudelft.ipv8.sqldelight" + srcDirs = files(["src/main/sqldelight"]) + schemaOutputDirectory = file("src/main/sqldelight/databases") + } } } @@ -28,6 +25,8 @@ ktlint { android = true outputToConsole = true ignoreFailures = false + verbose = true + filter { // https://github.com/JLLeitschuh/ktlint-gradle/issues/97 exclude { "**/generated/**" } @@ -38,9 +37,9 @@ ktlint { jacocoTestReport { reports { - xml.enabled true - csv.enabled true - html.enabled true + xml.required = true + csv.required = true + html.required = true } // TODO: exclude generated files @@ -74,8 +73,8 @@ dependencies { // Testing testImplementation 'junit:junit:4.12' - testImplementation "io.mockk:mockk:1.9.3" - testImplementation "com.squareup.sqldelight:sqlite-driver:$sqldelight_version" + testImplementation "io.mockk:mockk:$mockk_version" + testImplementation "app.cash.sqldelight:sqlite-driver:$sqldelight_version" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" @@ -87,7 +86,12 @@ dependencies { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { kotlinOptions.freeCompilerArgs += [ - "-opt-in=kotlin.Experimental,kotlin.ExperimentalUnsignedTypes", + "-opt-in=kotlin.ExperimentalUnsignedTypes", "-Werror" // Set Kotlin compiler warnings as errors ] } + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/messaging/udp/UdpEndpoint.kt b/ipv8/src/main/java/nl/tudelft/ipv8/messaging/udp/UdpEndpoint.kt index 0d3100cf..38779672 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/messaging/udp/UdpEndpoint.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/messaging/udp/UdpEndpoint.kt @@ -1,7 +1,6 @@ package nl.tudelft.ipv8.messaging.udp import kotlinx.coroutines.* -import kotlinx.coroutines.channels.Channel import mu.KotlinLogging import nl.tudelft.ipv8.Community import nl.tudelft.ipv8.IPv4Address @@ -18,7 +17,7 @@ private val logger = KotlinLogging.logger {} open class UdpEndpoint( private val port: Int, private val ip: InetAddress, - private val tftpEndpoint: TFTPEndpoint = TFTPEndpoint() + private val tftpEndpoint: TFTPEndpoint = TFTPEndpoint(), ) : Endpoint() { private var socket: DatagramSocket? = null @@ -29,24 +28,29 @@ open class UdpEndpoint( private var lanEstimationJob: Job? = null init { - tftpEndpoint.addListener(object : EndpointListener { - override fun onPacket(packet: Packet) { - logger.debug( - "Received TFTP packet (${packet.data.size} B) from ${packet.source}" - ) - notifyListeners(packet) - } + tftpEndpoint.addListener( + object : EndpointListener { + override fun onPacket(packet: Packet) { + logger.debug( + "Received TFTP packet (${packet.data.size} B) from ${packet.source}", + ) + notifyListeners(packet) + } - override fun onEstimatedLanChanged(address: IPv4Address) { - } - }) + override fun onEstimatedLanChanged(address: IPv4Address) { + } + }, + ) } override fun isOpen(): Boolean { return socket?.isBound == true } - override fun send(peer: Peer, data: ByteArray) { + override fun send( + peer: Peer, + data: ByteArray, + ) { if (!isOpen()) throw IllegalStateException("UDP socket is closed") val address = peer.address @@ -58,8 +62,10 @@ open class UdpEndpoint( if (peer.supportsTFTP) { tftpEndpoint.send(address, data) } else { - logger.warn { "The packet is larger then UDP_PAYLOAD_LIMIT and the peer " + - "does not support TFTP" } + logger.warn { + "The packet is larger then UDP_PAYLOAD_LIMIT and the peer " + + "does not support TFTP" + } } } else { send(address, data) @@ -70,7 +76,10 @@ open class UdpEndpoint( } } - fun send(address: IPv4Address, data: ByteArray) = scope.launch(Dispatchers.IO) { + fun send( + address: IPv4Address, + data: ByteArray, + ) = scope.launch(Dispatchers.IO) { try { val datagramPacket = DatagramPacket(data, data.size, address.toSocketAddress()) socket?.send(datagramPacket) @@ -123,12 +132,13 @@ open class UdpEndpoint( } open fun startLanEstimation() { - lanEstimationJob = scope.launch { - while (isActive) { - estimateLan() - delay(60_000) + lanEstimationJob = + scope.launch { + while (isActive) { + estimateLan() + delay(60_000) + } } - } } private fun estimateLan() { @@ -153,25 +163,26 @@ open class UdpEndpoint( return socket?.localPort ?: port } - private fun bindSocket(socket: DatagramSocket) = scope.launch { - try { - val receiveData = ByteArray(UDP_PAYLOAD_LIMIT) - while (isActive) { - val receivePacket = DatagramPacket(receiveData, receiveData.size) - withContext(Dispatchers.IO) { - socket.receive(receivePacket) + private fun bindSocket(socket: DatagramSocket) = + scope.launch { + try { + val receiveData = ByteArray(UDP_PAYLOAD_LIMIT) + while (isActive) { + val receivePacket = DatagramPacket(receiveData, receiveData.size) + withContext(Dispatchers.IO) { + socket.receive(receivePacket) + } + handleReceivedPacket(receivePacket) } - handleReceivedPacket(receivePacket) + } catch (e: IOException) { + e.printStackTrace() } - } catch (e: IOException) { - e.printStackTrace() } - } internal fun handleReceivedPacket(receivePacket: DatagramPacket) { logger.debug( "Received packet (${receivePacket.length} B) from " + - "${receivePacket.address.hostAddress}:${receivePacket.port}" + "${receivePacket.address.hostAddress}:${receivePacket.port}", ) // Check whether prefix is IPv8 or TFTP @@ -182,7 +193,7 @@ open class UdpEndpoint( val packet = Packet(sourceAddress, receivePacket.data.copyOf(receivePacket.length)) logger.debug( - "Received UDP packet (${receivePacket.length} B) from $sourceAddress" + "Received UDP packet (${receivePacket.length} B) from $sourceAddress", ) notifyListeners(packet) diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/TrustChainCrawlerTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/TrustChainCrawlerTest.kt index 2041af55..9bf5037b 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/TrustChainCrawlerTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/TrustChainCrawlerTest.kt @@ -1,10 +1,10 @@ package nl.tudelft.ipv8.attestation.trustchain -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.coEvery import io.mockk.spyk -import kotlinx.coroutines.* +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runBlockingTest import nl.tudelft.ipv8.BaseCommunityTest import nl.tudelft.ipv8.Peer @@ -14,7 +14,7 @@ import nl.tudelft.ipv8.peerdiscovery.Network import nl.tudelft.ipv8.sqldelight.Database import org.junit.Assert import org.junit.Test -import java.util.* +import java.util.Date @OptIn(ExperimentalCoroutinesApi::class) class TrustChainCrawlerTest : BaseCommunityTest() { @@ -38,131 +38,139 @@ class TrustChainCrawlerTest : BaseCommunityTest() { @Suppress("DEPRECATION") // TODO: rewrite usage of coroutines in testing. @Test - fun crawlChain_noop() = runBlockingTest { - val crawler = TrustChainCrawler() - val trustChainCommunity = spyk(getCommunity()) - crawler.trustChainCommunity = trustChainCommunity - - val newKey = JavaCryptoProvider.generateKey() - - val block = TrustChainBlock( - "custom", - "hello".toByteArray(Charsets.US_ASCII), - newKey.pub().keyToBin(), - 1u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - trustChainCommunity.database.addBlock(block) - - val peer = Peer(newKey) - - // We have all blocks - crawler.crawlChain(peer, 1u) - Assert.assertEquals(1, trustChainCommunity.database.getAllBlocks().size) - } + fun crawlChain_noop() = + runBlockingTest { + val crawler = TrustChainCrawler() + val trustChainCommunity = spyk(getCommunity()) + crawler.trustChainCommunity = trustChainCommunity + + val newKey = JavaCryptoProvider.generateKey() + + val block = + TrustChainBlock( + "custom", + "hello".toByteArray(Charsets.US_ASCII), + newKey.pub().keyToBin(), + 1u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + trustChainCommunity.database.addBlock(block) + + val peer = Peer(newKey) + + // We have all blocks + crawler.crawlChain(peer, 1u) + Assert.assertEquals(1, trustChainCommunity.database.getAllBlocks().size) + } @Suppress("DEPRECATION") // TODO: rewrite usage of coroutines in testing. @Test - fun crawlChain_singleBlock() = runBlockingTest { - val crawler = TrustChainCrawler() - val trustChainCommunity = spyk(getCommunity()) - crawler.trustChainCommunity = trustChainCommunity - - val newKey = JavaCryptoProvider.generateKey() - - val block1 = TrustChainBlock( - "custom", - "hello".toByteArray(Charsets.US_ASCII), - newKey.pub().keyToBin(), - 1u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - val block2 = TrustChainBlock( - "custom", - "hello".toByteArray(Charsets.US_ASCII), - newKey.pub().keyToBin(), - 2u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - trustChainCommunity.database.addBlock(block1) - - val peer = Peer(newKey) - - coEvery { - trustChainCommunity.sendCrawlRequest(any(), any(), LongRange(2, 2)) - } answers { - trustChainCommunity.database.addBlock(block2) - listOf(block2) - } + fun crawlChain_singleBlock() = + runBlockingTest { + val crawler = TrustChainCrawler() + val trustChainCommunity = spyk(getCommunity()) + crawler.trustChainCommunity = trustChainCommunity + + val newKey = JavaCryptoProvider.generateKey() + + val block1 = + TrustChainBlock( + "custom", + "hello".toByteArray(Charsets.US_ASCII), + newKey.pub().keyToBin(), + 1u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + val block2 = + TrustChainBlock( + "custom", + "hello".toByteArray(Charsets.US_ASCII), + newKey.pub().keyToBin(), + 2u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) - // Fetch a single block - crawler.crawlChain(peer, 2u) + trustChainCommunity.database.addBlock(block1) - Assert.assertEquals(2, trustChainCommunity.database.getAllBlocks().size) - } + val peer = Peer(newKey) + + coEvery { + trustChainCommunity.sendCrawlRequest(any(), any(), LongRange(2, 2)) + } answers { + trustChainCommunity.database.addBlock(block2) + listOf(block2) + } + + // Fetch a single block + crawler.crawlChain(peer, 2u) + + Assert.assertEquals(2, trustChainCommunity.database.getAllBlocks().size) + } @Suppress("DEPRECATION") // TODO: rewrite usage of coroutines in testing. @Test - fun crawlChain_fillGap() = runBlockingTest { - val crawler = TrustChainCrawler() - val trustChainCommunity = spyk(getCommunity()) - crawler.trustChainCommunity = trustChainCommunity - - val newKey = JavaCryptoProvider.generateKey() - - val block1 = TrustChainBlock( - "custom", - "hello".toByteArray(Charsets.US_ASCII), - newKey.pub().keyToBin(), - 1u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - val block2 = TrustChainBlock( - "custom", - "hello".toByteArray(Charsets.US_ASCII), - newKey.pub().keyToBin(), - 2u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - trustChainCommunity.database.addBlock(block2) - - val peer = Peer(newKey) - - coEvery { - trustChainCommunity.sendCrawlRequest(any(), any(), LongRange(1, 1)) - } answers { - trustChainCommunity.database.addBlock(block1) - listOf(block1) - } + fun crawlChain_fillGap() = + runBlockingTest { + val crawler = TrustChainCrawler() + val trustChainCommunity = spyk(getCommunity()) + crawler.trustChainCommunity = trustChainCommunity + + val newKey = JavaCryptoProvider.generateKey() + + val block1 = + TrustChainBlock( + "custom", + "hello".toByteArray(Charsets.US_ASCII), + newKey.pub().keyToBin(), + 1u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + val block2 = + TrustChainBlock( + "custom", + "hello".toByteArray(Charsets.US_ASCII), + newKey.pub().keyToBin(), + 2u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) - // Fetch one block - crawler.crawlChain(peer, 2u) + trustChainCommunity.database.addBlock(block2) - Assert.assertEquals(2, trustChainCommunity.database.getAllBlocks().size) - } + val peer = Peer(newKey) + + coEvery { + trustChainCommunity.sendCrawlRequest(any(), any(), LongRange(1, 1)) + } answers { + trustChainCommunity.database.addBlock(block1) + listOf(block1) + } + + // Fetch one block + crawler.crawlChain(peer, 2u) + + Assert.assertEquals(2, trustChainCommunity.database.getAllBlocks().size) + } } diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/store/TrustChainStoreTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/store/TrustChainStoreTest.kt index 1f1cc71e..09f92bb6 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/store/TrustChainStoreTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/store/TrustChainStoreTest.kt @@ -1,11 +1,14 @@ package nl.tudelft.ipv8.attestation.trustchain.store +import app.cash.sqldelight.db.SqlDriver +import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver +import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver.Companion.IN_MEMORY import com.goterl.lazysodium.LazySodiumJava import com.goterl.lazysodium.SodiumJava -import com.squareup.sqldelight.db.SqlDriver -import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver -import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver.Companion.IN_MEMORY -import nl.tudelft.ipv8.attestation.trustchain.* +import nl.tudelft.ipv8.attestation.trustchain.ANY_COUNTERPARTY_PK +import nl.tudelft.ipv8.attestation.trustchain.EMPTY_SIG +import nl.tudelft.ipv8.attestation.trustchain.GENESIS_HASH +import nl.tudelft.ipv8.attestation.trustchain.TrustChainBlock import nl.tudelft.ipv8.keyvault.LibNaClSK import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider @@ -13,7 +16,7 @@ import nl.tudelft.ipv8.sqldelight.Database import nl.tudelft.ipv8.util.hexToBytes import org.junit.Assert import org.junit.Test -import java.util.* +import java.util.Date private val lazySodium = LazySodiumJava(SodiumJava()) @@ -35,41 +38,44 @@ class TrustChainStoreTest { fun getBlock() { val store = createTrustChainStore() - val block1 = TrustChainBlock( - "custom1", - "hello".toByteArray(Charsets.US_ASCII), - getPrivateKey().pub().keyToBin(), - 1u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - val block2 = TrustChainBlock( - "custom2", - "hello".toByteArray(Charsets.US_ASCII), - getPrivateKey().pub().keyToBin(), - 2u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - val block3 = TrustChainBlock( - "custom2", - "hello".toByteArray(Charsets.US_ASCII), - getPrivateKey().pub().keyToBin(), - 3u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) + val block1 = + TrustChainBlock( + "custom1", + "hello".toByteArray(Charsets.US_ASCII), + getPrivateKey().pub().keyToBin(), + 1u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + val block2 = + TrustChainBlock( + "custom2", + "hello".toByteArray(Charsets.US_ASCII), + getPrivateKey().pub().keyToBin(), + 2u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + val block3 = + TrustChainBlock( + "custom2", + "hello".toByteArray(Charsets.US_ASCII), + getPrivateKey().pub().keyToBin(), + 3u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) store.addBlock(block1) store.addBlock(block2) @@ -99,143 +105,175 @@ class TrustChainStoreTest { fun getBlockBeforeAfter() { val store = createTrustChainStore() - val block1 = TrustChainBlock( - "custom1", - "hello".toByteArray(Charsets.US_ASCII), - getPrivateKey().pub().keyToBin(), - 1u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - val block2 = TrustChainBlock( - "custom2", - "hello".toByteArray(Charsets.US_ASCII), - getPrivateKey().pub().keyToBin(), - 2u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) + val block1 = + TrustChainBlock( + "custom1", + "hello".toByteArray(Charsets.US_ASCII), + getPrivateKey().pub().keyToBin(), + 1u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + val block2 = + TrustChainBlock( + "custom2", + "hello".toByteArray(Charsets.US_ASCII), + getPrivateKey().pub().keyToBin(), + 2u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) store.addBlock(block1) store.addBlock(block2) - Assert.assertEquals(block1.sequenceNumber, - store.getBlockBefore(block2)?.sequenceNumber) + Assert.assertEquals( + block1.sequenceNumber, + store.getBlockBefore(block2)?.sequenceNumber, + ) - Assert.assertEquals(block1.sequenceNumber, - store.getBlockBefore(block2, "custom1")?.sequenceNumber) + Assert.assertEquals( + block1.sequenceNumber, + store.getBlockBefore(block2, "custom1")?.sequenceNumber, + ) - Assert.assertEquals(block2.sequenceNumber, - store.getBlockAfter(block1)?.sequenceNumber) + Assert.assertEquals( + block2.sequenceNumber, + store.getBlockAfter(block1)?.sequenceNumber, + ) - Assert.assertEquals(block2.sequenceNumber, - store.getBlockAfter(block1, "custom2")?.sequenceNumber) + Assert.assertEquals( + block2.sequenceNumber, + store.getBlockAfter(block1, "custom2")?.sequenceNumber, + ) } @Test fun getLatest() { val publicKey = getPrivateKey().pub().keyToBin() - val block1 = TrustChainBlock( - "custom1", - "hello".toByteArray(Charsets.US_ASCII), - publicKey, - 1u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - val block2 = TrustChainBlock( - "custom1", - "hello".toByteArray(Charsets.US_ASCII), - publicKey, - 2u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - val block3 = TrustChainBlock( - "custom2", - "hello".toByteArray(Charsets.US_ASCII), - publicKey, - 3u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) + val block1 = + TrustChainBlock( + "custom1", + "hello".toByteArray(Charsets.US_ASCII), + publicKey, + 1u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + val block2 = + TrustChainBlock( + "custom1", + "hello".toByteArray(Charsets.US_ASCII), + publicKey, + 2u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + val block3 = + TrustChainBlock( + "custom2", + "hello".toByteArray(Charsets.US_ASCII), + publicKey, + 3u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) val store = createTrustChainStore() store.addBlock(block1) store.addBlock(block2) store.addBlock(block3) - Assert.assertEquals(block3.sequenceNumber, - store.getLatest(block2.publicKey)?.sequenceNumber) + Assert.assertEquals( + block3.sequenceNumber, + store.getLatest(block2.publicKey)?.sequenceNumber, + ) - Assert.assertEquals(block2.sequenceNumber, - store.getLatest(block2.publicKey, "custom1")?.sequenceNumber) + Assert.assertEquals( + block2.sequenceNumber, + store.getLatest(block2.publicKey, "custom1")?.sequenceNumber, + ) - Assert.assertEquals(3, store.getLatestBlocks(publicKey, limit = 10, - blockTypes = null).size) + Assert.assertEquals( + 3, + store.getLatestBlocks( + publicKey, + limit = 10, + blockTypes = null, + ).size, + ) - Assert.assertEquals(2, store.getLatestBlocks(publicKey, limit = 10, - blockTypes = listOf("custom1")).size) + Assert.assertEquals( + 2, + store.getLatestBlocks( + publicKey, + limit = 10, + blockTypes = listOf("custom1"), + ).size, + ) } @Test fun crawl() { val publicKey = getPrivateKey().pub().keyToBin() - val block1 = TrustChainBlock( - "custom1", - "hello".toByteArray(Charsets.US_ASCII), - publicKey, - 1u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - val block2 = TrustChainBlock( - "custom1", - "hello".toByteArray(Charsets.US_ASCII), - publicKey, - 2u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - val block3 = TrustChainBlock( - "custom2", - "hello".toByteArray(Charsets.US_ASCII), - publicKey, - 10u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) + val block1 = + TrustChainBlock( + "custom1", + "hello".toByteArray(Charsets.US_ASCII), + publicKey, + 1u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + val block2 = + TrustChainBlock( + "custom1", + "hello".toByteArray(Charsets.US_ASCII), + publicKey, + 2u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + val block3 = + TrustChainBlock( + "custom2", + "hello".toByteArray(Charsets.US_ASCII), + publicKey, + 10u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) val store = createTrustChainStore() store.addBlock(block1) @@ -250,49 +288,59 @@ class TrustChainStoreTest { Assert.assertEquals(3L, store.getLowestSequenceNumberUnknown(publicKey)) Assert.assertEquals(LongRange(3, 9), store.getLowestRangeUnknown(block1.publicKey)) - Assert.assertEquals(2, store.crawl(publicKey, 1, 5, - 10).size) + Assert.assertEquals( + 2, + store.crawl( + publicKey, + 1, + 5, + 10, + ).size, + ) } @Test fun getLinked() { val publicKey = getPrivateKey().pub().keyToBin() - val block1 = TrustChainBlock( - "custom1", - "hello".toByteArray(Charsets.US_ASCII), - publicKey, - 1u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - val block2 = TrustChainBlock( - "custom1", - "hello".toByteArray(Charsets.US_ASCII), - publicKey, - 2u, - publicKey, - 1u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - val block3 = TrustChainBlock( - "custom1", - "hello".toByteArray(Charsets.US_ASCII), - publicKey, - 10u, - publicKey, - 1u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) + val block1 = + TrustChainBlock( + "custom1", + "hello".toByteArray(Charsets.US_ASCII), + publicKey, + 1u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + val block2 = + TrustChainBlock( + "custom1", + "hello".toByteArray(Charsets.US_ASCII), + publicKey, + 2u, + publicKey, + 1u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + val block3 = + TrustChainBlock( + "custom1", + "hello".toByteArray(Charsets.US_ASCII), + publicKey, + 10u, + publicKey, + 1u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) val store = createTrustChainStore() store.addBlock(block1) @@ -310,41 +358,44 @@ class TrustChainStoreTest { val publicKey = getPrivateKey().pub().keyToBin() val publicKey2 = defaultCryptoProvider.generateKey().pub().keyToBin() - val block1 = TrustChainBlock( - "custom1", - "hello".toByteArray(Charsets.US_ASCII), - publicKey, - 1u, - ANY_COUNTERPARTY_PK, - 0u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - val block2 = TrustChainBlock( - "custom1", - "hello".toByteArray(Charsets.US_ASCII), - publicKey, - 2u, - publicKey, - 1u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) - - val block3 = TrustChainBlock( - "custom1", - "hello".toByteArray(Charsets.US_ASCII), - publicKey2, - 10u, - publicKey, - 1u, - GENESIS_HASH, - EMPTY_SIG, - Date() - ) + val block1 = + TrustChainBlock( + "custom1", + "hello".toByteArray(Charsets.US_ASCII), + publicKey, + 1u, + ANY_COUNTERPARTY_PK, + 0u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + val block2 = + TrustChainBlock( + "custom1", + "hello".toByteArray(Charsets.US_ASCII), + publicKey, + 2u, + publicKey, + 1u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) + + val block3 = + TrustChainBlock( + "custom1", + "hello".toByteArray(Charsets.US_ASCII), + publicKey2, + 10u, + publicKey, + 1u, + GENESIS_HASH, + EMPTY_SIG, + Date(), + ) val store = createTrustChainStore() store.addBlock(block1) diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/peerdiscovery/strategy/RandomChurnTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/peerdiscovery/strategy/RandomChurnTest.kt index 9bd0f16f..4e5398ba 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/peerdiscovery/strategy/RandomChurnTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/peerdiscovery/strategy/RandomChurnTest.kt @@ -11,7 +11,7 @@ import nl.tudelft.ipv8.peerdiscovery.DiscoveryCommunity import nl.tudelft.ipv8.peerdiscovery.Network import org.junit.Test import java.time.Instant -import java.util.* +import java.util.Date class RandomChurnTest { @Test @@ -23,12 +23,14 @@ class RandomChurnTest { every { overlay.network } returns network every { network.getRandomPeers(any()) } returns listOf(peer) - val randomChurn = RandomChurn.Factory(sampleSize = 8) - .setOverlay(overlay).create() + val randomChurn = RandomChurn.Factory(sampleSize = 8).setOverlay(overlay).create() randomChurn.takeStep() - verify { network.getRandomPeers(8) } - confirmVerified() + verify(exactly = 1) { + network.getRandomPeers(8) + } + + confirmVerified(network) } @Test @@ -41,8 +43,7 @@ class RandomChurnTest { every { overlay.network } returns network every { network.getRandomPeers(any()) } returns listOf(peer) - val randomChurn = RandomChurn.Factory(sampleSize = 8) - .setOverlay(overlay).create() + val randomChurn = RandomChurn.Factory(sampleSize = 8).setOverlay(overlay).create() randomChurn.takeStep() verify { network.getRandomPeers(8) } @@ -59,9 +60,7 @@ class RandomChurnTest { every { overlay.network } returns network every { network.getRandomPeers(any()) } returns listOf(peer) - val randomChurn = RandomChurn.Factory(sampleSize = 8) - .setOverlay(overlay) - .create() + val randomChurn = RandomChurn.Factory(sampleSize = 8).setOverlay(overlay).create() randomChurn.takeStep() verify { network.getRandomPeers(8) } diff --git a/tracker/build.gradle b/tracker/build.gradle index 009e1c43..36fe6c98 100644 --- a/tracker/build.gradle +++ b/tracker/build.gradle @@ -18,7 +18,7 @@ dependencies { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { kotlinOptions.freeCompilerArgs += [ - "-opt-in=kotlin.Experimental,kotlin.ExperimentalUnsignedTypes" + "-opt-in=kotlin.ExperimentalUnsignedTypes" ] }