diff --git a/detoks/build.gradle b/detoks/build.gradle index 16e19ba57..0bfe89e03 100644 --- a/detoks/build.gradle +++ b/detoks/build.gradle @@ -39,6 +39,11 @@ android { dependencies { implementation project(':common') + api(project(':ipv8-jvm')) { + exclude group: 'net.java.dev.jna' + exclude group: 'org.slf4j' + exclude group: 'com.goterl' + } // AndroidX implementation 'androidx.appcompat:appcompat:1.6.1' @@ -83,6 +88,7 @@ dependencies { implementation files('../common/libs/jlibtorrent-android-x86_64-' + jlibtorrent_version + '.jar') implementation 'com.devbrackets.android:exomedia:4.3.0' + implementation "com.squareup.sqldelight:sqlite-driver:$sqldelight_version" } tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/DeToksCommunity.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/DeToksCommunity.kt index 1fb1563bf..8ee14f5ca 100644 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/DeToksCommunity.kt +++ b/detoks/src/main/java/nl/tudelft/trustchain/detoks/DeToksCommunity.kt @@ -3,7 +3,6 @@ package nl.tudelft.trustchain.detoks import android.content.Context import android.util.Log import com.frostwire.jlibtorrent.Sha1Hash -import nl.tudelft.ipv8.Community import nl.tudelft.ipv8.Overlay import nl.tudelft.ipv8.Peer import nl.tudelft.ipv8.messaging.Packet @@ -11,7 +10,9 @@ import nl.tudelft.ipv8.messaging.Serializable import nl.tudelft.trustchain.detoks.gossiper.* -class DeToksCommunity(private val context: Context) : Community() { +class DeToksCommunity( + private val context: Context + ) : TransactionEngine(DetoksConfig.DETOKS_SERVICE_ID) { private val walletManager = WalletManager(context) private val visitedPeers = mutableListOf() @@ -36,9 +37,6 @@ class DeToksCommunity(private val context: Context) : Community() { const val MESSAGE_BOOT_RESPONSE = 6 } - override val serviceId = "c86a7db45eb3563ae047639817baec4db2bc7c25" - - fun sendTokens(amount: Int, recipientMid: String) { val senderWallet = walletManager.getOrCreateWallet(myPeer.mid) diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/DetoksConfig.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/DetoksConfig.kt new file mode 100644 index 000000000..ed7e990cf --- /dev/null +++ b/detoks/src/main/java/nl/tudelft/trustchain/detoks/DetoksConfig.kt @@ -0,0 +1,7 @@ +package nl.tudelft.trustchain.detoks + +class DetoksConfig() { + companion object { + const val DETOKS_SERVICE_ID = "c86a7db45eb3563ae047639817baec4db2bc7c25" + } +} diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/TransactionEngine.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/TransactionEngine.kt new file mode 100644 index 000000000..749f4a04e --- /dev/null +++ b/detoks/src/main/java/nl/tudelft/trustchain/detoks/TransactionEngine.kt @@ -0,0 +1,114 @@ +package nl.tudelft.trustchain.detoks + +import nl.tudelft.ipv8.Community +import nl.tudelft.ipv8.Overlay +import nl.tudelft.ipv8.Peer +import nl.tudelft.ipv8.attestation.trustchain.BlockBuilder +import nl.tudelft.ipv8.attestation.trustchain.TrustChainBlock +import nl.tudelft.ipv8.attestation.trustchain.payload.HalfBlockBroadcastPayload +import nl.tudelft.ipv8.attestation.trustchain.payload.HalfBlockPayload +import nl.tudelft.ipv8.messaging.Packet +import nl.tudelft.ipv8.util.random +import java.util.* +import mu.KotlinLogging + + +open class TransactionEngine (override val serviceId: String): Community() { + private val broadcastFanOut = 25 + private val ttl = 100 + private val logger = KotlinLogging.logger {} + + object MessageId { + const val HALF_BLOCK: Int = 11 + const val HALF_BLOCK_ENCRYPTED: Int = 12 + const val HALF_BLOCK_BROADCAST: Int = 13 + const val HALF_BLOCK_BROADCAST_ENCRYPTED: Int = 14 + } + + init { + messageHandlers[MessageId.HALF_BLOCK] = ::onHalfBlockPacket + messageHandlers[MessageId.HALF_BLOCK_BROADCAST] = ::onHalfBlockBroadcastPacket + messageHandlers[MessageId.HALF_BLOCK_ENCRYPTED] = ::onHalfBlockPacket + messageHandlers[MessageId.HALF_BLOCK_BROADCAST_ENCRYPTED] = ::onHalfBlockBroadcastPacket + } + + fun sendTransaction(blockBuilder: BlockBuilder, peer: Peer?, encrypt: Boolean = false) { + logger.info { "Sending transaction..." } + val block = blockBuilder.sign() + + if (peer != null) { + sendBlockToRecipient(peer, block, encrypt) + } else { + sendBlockBroadcast(block, encrypt) + } + } + + private fun sendBlockToRecipient(peer: Peer, block: TrustChainBlock, encrypt: Boolean) { + val payload = HalfBlockPayload.fromHalfBlock(block) + + val data = if (encrypt) { + serializePacket(MessageId.HALF_BLOCK_ENCRYPTED, payload, false, encrypt = true, recipient = peer) + } else { + serializePacket(MessageId.HALF_BLOCK, payload, false) + } + + send(peer, data) + } + + private fun sendBlockBroadcast(block: TrustChainBlock, encrypt: Boolean) { + val payload = HalfBlockBroadcastPayload.fromHalfBlock(block, ttl.toUInt()) + val randomPeers = getPeers().random(broadcastFanOut) + for (randomPeer in randomPeers) { + val data = if (encrypt) { + serializePacket(MessageId.HALF_BLOCK_BROADCAST_ENCRYPTED, payload, false, encrypt = true, recipient = randomPeer) + } else { + serializePacket(MessageId.HALF_BLOCK_BROADCAST, payload, false) + } + send(randomPeer, data) + } + } + + private fun onHalfBlockPacket(packet: Packet) { + logger.info { ("Half block packet received from: " + packet.source.toString()) } + } + + private fun onHalfBlockBroadcastPacket(packet: Packet) { + logger.info { ("Half block packet received from broadcast from: " + packet.source.toString()) } + } + + override fun onPacket(packet: Packet) { + val sourceAddress = packet.source + val data = packet.data + + val probablePeer = network.getVerifiedByAddress(sourceAddress) + if (probablePeer != null) { + probablePeer.lastResponse = Date() + } + + val packetPrefix = data.copyOfRange(0, prefix.size) + if (!packetPrefix.contentEquals(prefix)) { + // logger.debug("prefix not matching") + return + } + + val msgId = data[prefix.size].toUByte().toInt() + + val handler = messageHandlers[msgId] + + if (handler != null) { + try { + handler(packet) + } catch (e: Exception) { + e.printStackTrace() + } + } else { + logger.info { "Received unknown message $msgId from $sourceAddress" } + } + } + + class Factory(private val serviceId: String) : Overlay.Factory(TransactionEngine::class.java) { + override fun create(): TransactionEngine { + return TransactionEngine(serviceId) + } + } +}