diff --git a/.gitignore b/.gitignore index 66e553b6e..1a29acd2f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ build *.iml local.properties .gradle -gossipML/.cxx **.project **.settings **.classpath diff --git a/.gitmodules b/.gitmodules index 8c9eb5b03..6991e3845 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "kotlin-ipv8"] path = kotlin-ipv8 url = https://github.com/Tribler/kotlin-ipv8.git -[submodule "gossipML/superapp-essentia"] - path = gossipML/superapp-essentia - url = https://github.com/Tribler/superapp-essentia.git diff --git a/README.md b/README.md index f830993e1..2a95f778d 100644 --- a/README.md +++ b/README.md @@ -4,17 +4,6 @@ This repository contains a collection of Android apps built on top of [IPv8](htt ## Apps -### TrustChain Explorer - -**TrustChain Explorer** allows to browse the TrustChain blocks stored locally on the device and crawl chains of other connected peers. It also demonstrates how to interact with `TrustChainCommunity`. It defines its own `DemoCommunity` to ensure that all users using the app are able to discover each other easily. The content of the app is split into several tabs: - -- **Peers:** A list of discovered peers in `DemoCommunity`. For each peer, there is a time since the last sent and received message, and an average ping latency. After clicking on the peer item, a list of mutual blocks in TrustChain is shown. It is possible to create and send a new proposal block by clicking on the plus icon. A crawl request send be sent by clicking on the refresh button. -- **Chains:** A list of discovered chains in `TrustChainCommunity`, ordered by their length. After clicking on the item, the list of stored blocks is shown. -- **All Blocks:** A stream of all received blocks, updated in real-time as new blocks are received from the network. -- **My Chain:** A list of blocks in which the current user is participating either as a sender or a receiver. It is possible to create a new self-signed block by clicking on the plus icon. It is posible to sign received blocks if they are not defined to be signed automatically. - - - ### PeerChat PeerChat implements a fully functional prototype of a distributed messaging app. First, the users have to exchange the public keys by scanning each other's QR code, or by copy-pasting the hexadecimal public keys. This guarantees authenticity of all messages which are signed by their author. It prevents man-in-the-middle and impersonation attacks. @@ -25,9 +14,6 @@ An online indicator and the last message is shown for each contact. Users can ex -### DeToks -**Decentralised TikTok** skeleton app for the CS4160 Blockchain Engineering (2022/23) course. - ### Digital Euro The Superapp is connected to the European IBAN Euro system. @@ -67,70 +53,6 @@ Zooming into the actual mechanism of QR-Codes (Creative Commons CC0 license - sh -### AI trading bot -The AI trading bot is a zero-server AI, which ultimately can understand markets, limit orderbooks, bid/ask pairs and global stock patterns using only smartphones for computing power and connection. -Built on top of Trustchain, the app provides a small decentralized market for trading, providing safe and verifiable transaction for any arbitrary change of goods. - -**AI trading bot** consist of two parts. -1. An AI trading bot using a Naive Bayes Classifier which buys or sells Bitcoins in a decentralized market. -2. Sending and receiving money to and from other peers. - -**Trading** -The AI trading bot app is visible upon opening the superapp. It receives bids and asks from other peers that want to buy or sell Bitcoins for Dymbe Dollars. -Upon receiving a bid or ask, it decides to either execute the offer or not. -The bot can be toggled on and off using the toggle on the home screen. - -**Send/Receive** -In the sending/receiving money tab one can send money to, or receive money from a different peer. -There are two ways to find a public key: -1. The receiving peer presses the send/receive toggle. His public key will be shown as a QR-code. Now pressing the "scan" button on the sender's device allows you can scan the QR code of the receiver. -2. As a sender, go to the "Peers" fragment in the app, and press the public key of the receiver. - -
-[More about AI trading bot](trustchain-trader/readme.md) - -### Market Bot - -The market bot app can generate bids and asks which are received by the peers in the market community. -The bid and asks can either be generated automatically or manually. Those bids and asks will be sent as IPv8 messages. - -
-[More about Market Bot](trustchain-payloadgenerator/readme.md) - -### Luxury Socialism -{_recent events have turned this into_ **really bad naming**} We build a DAO for a better world. Luxury socialism is an Android application built on top of [IPv8](https://github.com/Tribler/kotlin-ipv8) and [Trustchain](https://github.com/Tribler/kotlin-ipv8/blob/master/doc/TrustChainCommunity.md), and is integrated into the [Trustchain Superapp](https://github.com/Tribler/trustchain-superapp). It is a proof-of-concept implementation of a DAO system using Trustchain and Bitcoin. Trustchain is used for communication and bookkeeping while the Bitcoin blockchain is used to have collective multi-signature wallets for each DAO. The content of the app is split up in several tabs: -* **First Time Launch**: The first time the app is launched, the user must setup his bitcoin wallet. Afterwhich the chain will sync and he is routed to the main screens. -* **My DAO's**: A list of all DAO's that the user participates in. Selecting a DAO will allow a user to create a transfer proposal from that DAO. -* **All DAO's**: A list of all discovered DAO's in the network which the user can propose to join. -* **Proposals**: A list of all proposals that the user can vote on. This can either be join proposals or proposals from someone else to transfer funds from one of the DAO's. -* **My Wallet**: Overview of the used Bitcoin wallet and the ability to chain this to another. -* **Duplicate Wallet**: In case the user has wallet files for TestNet, Production or Regtest, the user is allowed to select which one to keep. After the user selected either one, the files belonging to other network type are backed up. This, thus, ensures that the wallet is not lost. - -Currently, the Luxury Socialism app only allows Regtest, since it uses a future update of Bitcoin called Taproot. Once Taproot is officially released, the app can support TestNet or Production again. Taproot allows the DAO to scale to thousands or even millions of users. The beauty of Taproot is that it uses Schnorr signatures for each transaction. This enables transaction sizes that are equal independent of the number of users in a DAO, since each user combines their signature collaberatively into one for the whole DAO. This also ensures privacy, since it is no longer possible to tell if a transaction's is from a single person, or a million of persons. - - -
- -

- - - -

-
- -https://user-images.githubusercontent.com/23526224/116259903-85efd900-a776-11eb-93b1-384936d215c4.mp4 - - -[More about Luxury Socialism](currencyii/README.md) - -### TrustChain Voter -The TrustChain Voter can be used to create a proposal on which the community can vote. The functionality has been split up in two parts: a Voting API, which provides the core voting functionality, and a TrustChain Voter submodule, which serves to demonstrate the capabilities of the voting API. Below, the process of creating a proposal (left) and casting a vote (right) can be seen. - -- [More about the Voting API](common/README.md#votinghelper) -- [More about the TrustChain Voter submodule](trustchain-voter/README.md) - - - ### Freedom-of-Computing App Freedom-of-Computing provides users with the ability to freely distribute and execute code in the form of APK applications on the trustchain superapp. In order to facilitate the sharing of applications, Freedom-of-Computing contains a gossiping mechanism which periodically shares local applications to other users and downloads unseen applications from other users. This sharing is conducted through a torrent peer-to-peer (P2P) network and uses the EVA Protocol as a fallback. Once the application has been downloaded by the users, they can dynamically load and execute it. The application, apart from being an .APK file, needs to have a specific format for the execution to work, the requirements/constraints are listed inside [the documentation](freedomOfComputing/README.md). @@ -141,13 +63,6 @@ The left demo shows the upload procedure, while the right demo shows the downloa [More about Freedom-of-Computing App](freedomOfComputing/README.md) -### Distributed AI app -The distributed AI app is a proof-of-concept of distributed, server less, machine learning. - -- [More about the Distributed AI app](distributedai/docs/README.md) - - - ### MusicDAO In short, the MusicDAO is an IPv8 app where users can share and discover tracks on the trustchain. Track streaming, downloading, and seeking interactions are done using JLibtorrent. @@ -162,41 +77,6 @@ Video 1: Load example. This uses a defaul Video 2: Share track. Note: as a fresh magnet link is generated in this video, there is only 1 peer. For this reason it will be difficult to obtain the metadata of the magnet link (cold start issue, write about this in thesis) so the video stops there. -### Federated, privacy-preserving music recommendations via gossiping - -This is a demonstration of machine learning which relies exclusively on edge computing. Music recommendation inside the MusicDAO is used to demonstrate gossip-based machine learning. - -Every time a user opens MusicDAO, they are asked to reload the page in order to get recommendations. The recommendation engine yields two recommendations made by two different models: a musical feature-based model and a collaborative filtering model. The collaborative filtering model is based on federated matrix factorization as introduced in [this paper](https://dmle.iais.fraunhofer.de/papers/hegedus2019decentralized.pdf). The feature-based models are from this [paper](https://arxiv.org/pdf/1109.1396.pdf), called Adaline and Pegasos. These models are trained on audio features extracted from music files with the [Essentia library](https://essentia.upf.edu/). - - -The feature-based models are gossiped along random walks through the network. At each peer they are merged and re-trained on peer's local data. The matrix factorization model seeks to learn a factorization of the user-song matrix. This means that one of the two factors contains only information on how users generally rate each song. This matrix can then be gossiped around the network while a user's personal vector as well as their listening history are kept private. - - [More about federated machine learning using gossiping for music recommendations](gossipML/README.md) - -### Atomic Swap - -AtomicSwap app allows two users to exchange different cryptocurrencies without the involvement of a third party and without having to trust each other. This is achieved by implementing the Atomic Swap protocol. - -User can create trade offers by sending Ipv8 messages indicating that they wish to trade to the Swap community. Others can then accept the offer by sending another Ipv8 message. The swap procedure starts when the initiator receives an accept message for their trade offer. - -Below is a video demo that shows the steps to do an atomic swap. - -Alternate Text - -[More about The Atomic Swap app](atomic-swap/README.md) - -### Literature Dao - -LiteratureDao app aims to be a decentralized scientific literature repository, proving: -Sharing, storing, and searching of scientific publications through the p2p ipv8 network. - -![local_upload](https://user-images.githubusercontent.com/33283063/167591620-a9547f63-e778-4ea9-a594-a7d1d9a4f169.gif) -![peers](https://user-images.githubusercontent.com/33283063/167591634-6e0b8aaf-11c8-4ee7-b36d-616255fa5347.PNG) -![search_in_keywords](https://user-images.githubusercontent.com/33283063/167591635-a68c0d2c-16de-4a44-ba73-fc52688252eb.gif) -![url_upload](https://user-images.githubusercontent.com/33283063/167591643-75a305ae-2098-4138-9f60-14818f63000e.gif) - - -[More about literature dao app](literaturedao/README.md) - ### Do you want to add your own app? - [Adding your own app to the TrustChain Super App](doc/AppTutorial.md) diff --git a/app/build.gradle b/app/build.gradle index b60ec42e3..97db41481 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -111,36 +111,19 @@ allprojects { } dependencies { - implementation project(':trustchain-voter') - implementation project(':trustchain-explorer') - implementation project(':trustchain-trader') - implementation project(':trustchain-payloadgenerator') implementation project(':debug') - implementation project(':distributedai') implementation project(':freedomOfComputing') - implementation project(':peerchat') implementation project(':eurotoken') - implementation project(':ig-ssi') - implementation project(':liquidity-pool') implementation project(':valuetransfer') - implementation project(':atomic-swap') - implementation project(':literaturedao') - implementation project(':detoks') api(project(':common')) { exclude group: 'net.java.dev.jna' } api(project(':common-ethereum')) { exclude group: 'net.java.dev.jna' } - api(project(':currencyii')) { - exclude group: 'net.java.dev.jna' - } api(project(':musicdao')) { exclude group: 'net.java.dev.jna' } - api(project(':gossipML')) { - exclude group: 'net.java.dev.jna' - } implementation 'org.jetbrains.kotlinx:kotlinx-serialization-runtime:1.0-M1-1.4.0-rc' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 21c59701f..1dcd46984 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -60,15 +60,6 @@ android:name=".ui.dashboard.DashboardSelectorActivity" android:parentActivityName=".ui.dashboard.DashboardActivity" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -186,11 +125,6 @@ android:enabled="true" android:exported="false" /> - - diff --git a/app/src/main/java/nl/tudelft/trustchain/app/AppDefinition.kt b/app/src/main/java/nl/tudelft/trustchain/app/AppDefinition.kt index 1942e953c..1f1ad3866 100644 --- a/app/src/main/java/nl/tudelft/trustchain/app/AppDefinition.kt +++ b/app/src/main/java/nl/tudelft/trustchain/app/AppDefinition.kt @@ -5,22 +5,10 @@ import androidx.annotation.ColorRes import androidx.annotation.DrawableRes import nl.tudelft.trustchain.musicdao.MusicActivity import nl.tudelft.trustchain.FOC.MainActivityFOC -import nl.tudelft.trustchain.atomicswap.AtomicSwapActivity import nl.tudelft.trustchain.common.R -import nl.tudelft.trustchain.explorer.ui.TrustChainExplorerActivity -import nl.tudelft.trustchain.currencyii.CurrencyIIMainActivity import nl.tudelft.trustchain.debug.DebugActivity -import nl.tudelft.trustchain.distributedAI.DistributedActivity import nl.tudelft.trustchain.eurotoken.EuroTokenMainActivity -import nl.tudelft.trustchain.ssi.SSIMainActivity -import nl.tudelft.trustchain.liquidity.LiquidityPoolMainActivity -import nl.tudelft.trustchain.literaturedao.LiteratureDaoActivity -import nl.tudelft.trustchain.payloadgenerator.ui.TrustChainPayloadGeneratorActivity -import nl.tudelft.trustchain.peerchat.PeerChatActivity -import nl.tudelft.trustchain.trader.ui.TrustChainTraderActivity import nl.tudelft.trustchain.valuetransfer.ValueTransferMainActivity -import nl.tudelft.trustchain.voting.VotingActivity -import nl.tudelft.trustchain.detoks.DeToksActivity enum class AppDefinition( @DrawableRes val icon: Int, @@ -29,79 +17,18 @@ enum class AppDefinition( val activity: Class, val disableImageTint: Boolean = false, ) { - DETOKS( - R.drawable.ic_detox_logo, - "DeToks", - R.color.black, - DeToksActivity::class.java, - true, - ), - EIGHTEEN_PLUS( - R.drawable.ic_18_plus, - "18+", - R.color.red, - SSIMainActivity::class.java, - true, - ), - PEERCHAT( - R.drawable.ic_chat_black_24dp, - "PeerChat", - R.color.purple, - PeerChatActivity::class.java - ), - TRUSTCHAIN_EXPLORER( - R.drawable.ic_device_hub_black_24dp, - "TrustChain Explorer", - R.color.red, - TrustChainExplorerActivity::class.java - ), DEBUG( R.drawable.ic_bug_report_black_24dp, "Debug", R.color.dark_gray, DebugActivity::class.java ), - CURRENCY_II( - R.drawable.ic_bitcoin, - "Luxury Communism", - R.color.metallic_gold, - CurrencyIIMainActivity::class.java - ), - TRUSTCHAIN_TRADER( - R.drawable.ic_device_hub_black_24dp, - "AI trading bot", - R.color.blue, - TrustChainTraderActivity::class.java - ), - TRUSTCHAIN_PAYLOADGENERATOR( - R.drawable.ic_add_black_24dp, - "Market Bot", - R.color.black, - TrustChainPayloadGeneratorActivity::class.java - ), - FREEDOM_OF_COMPUTING( - R.drawable.ic_naruto, - "Freedom of Computing", - R.color.blue, - MainActivityFOC::class.java - ), - DNA( - R.drawable.ic_bug_report_black_24dp, - "Distributed AI", - R.color.red, - DistributedActivity::class.java - ), - VOTING( - R.drawable.abc_ic_voice_search_api_material, - "Voter", - R.color.android_green, - VotingActivity::class.java - ), - MUSIC_DAO( - android.R.drawable.ic_media_play, - "MusicDAO", - R.color.black, - MusicActivity::class.java + VALUETRANSFER( + R.drawable.ic_idelft_logo, + "IDelft", + R.color.colorPrimaryValueTransfer, + ValueTransferMainActivity::class.java, + true, ), EUROTOKEN( R.drawable.ic_baseline_euro_symbol_24, @@ -109,29 +36,16 @@ enum class AppDefinition( R.color.metallic_gold, EuroTokenMainActivity::class.java ), - LIQUIDITY( - R.drawable.ic_pool, - "Liquidity Pool", - R.color.blue, - LiquidityPoolMainActivity::class.java - ), - VALUETRANSFER( - R.drawable.ic_idelft_logo, - "IDelft", - R.color.colorPrimaryValueTransfer, - ValueTransferMainActivity::class.java, - true, + MUSIC_DAO( + android.R.drawable.ic_media_play, + "MusicDAO", + R.color.black, + MusicActivity::class.java ), - ATOMIC_SWAP( - R.drawable.ic_atomic_swap_24dp, - "Atomic Swap", + FREEDOM_OF_COMPUTING( + R.drawable.ic_naruto, + "Freedom of Computing", R.color.blue, - AtomicSwapActivity::class.java - ), - LITERATUREDAO( - R.drawable.ic_book_hover_over_hand, - "LiteratureDao", - R.color.green, - LiteratureDaoActivity::class.java + MainActivityFOC::class.java ), } diff --git a/app/src/main/java/nl/tudelft/trustchain/app/AppLoader.kt b/app/src/main/java/nl/tudelft/trustchain/app/AppLoader.kt index b32703fcf..374bba96e 100644 --- a/app/src/main/java/nl/tudelft/trustchain/app/AppLoader.kt +++ b/app/src/main/java/nl/tudelft/trustchain/app/AppLoader.kt @@ -72,10 +72,10 @@ class AppLoader( companion object { val PREFERRED_APPS = stringSetPreferencesKey("preferred_apps") val DEFAULT_APPS = setOf( - AppDefinition.DETOKS.appName, AppDefinition.VALUETRANSFER.appName, AppDefinition.MUSIC_DAO.appName, - AppDefinition.EIGHTEEN_PLUS.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 a36465999..5b7507123 100644 --- a/app/src/main/java/nl/tudelft/trustchain/app/TrustChainApplication.kt +++ b/app/src/main/java/nl/tudelft/trustchain/app/TrustChainApplication.kt @@ -6,6 +6,7 @@ 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 @@ -53,27 +54,18 @@ import nl.tudelft.ipv8.util.hexToBytes import nl.tudelft.ipv8.util.toHex import nl.tudelft.trustchain.FOC.community.FOCCommunity import nl.tudelft.trustchain.app.service.TrustChainService -import nl.tudelft.trustchain.atomicswap.AtomicSwapCommunity -import nl.tudelft.trustchain.atomicswap.AtomicSwapTrustchainConstants -import nl.tudelft.trustchain.atomicswap.ui.swap.LOG import nl.tudelft.trustchain.common.DemoCommunity import nl.tudelft.trustchain.common.MarketCommunity import nl.tudelft.trustchain.common.bitcoin.WalletService import nl.tudelft.trustchain.common.eurotoken.GatewayStore import nl.tudelft.trustchain.common.eurotoken.TransactionRepository -import nl.tudelft.trustchain.currencyii.CoinCommunity -import nl.tudelft.trustchain.detoks.DeToksCommunity +import nl.tudelft.trustchain.musicdao.core.dao.CoinCommunity import nl.tudelft.trustchain.eurotoken.community.EuroTokenCommunity import nl.tudelft.trustchain.eurotoken.db.TrustStore -import nl.tudelft.trustchain.gossipML.RecommenderCommunity -import nl.tudelft.trustchain.gossipML.db.RecommenderStore -import nl.tudelft.trustchain.literaturedao.ipv8.LiteratureCommunity -import nl.tudelft.trustchain.peerchat.community.PeerChatCommunity -import nl.tudelft.trustchain.peerchat.db.PeerChatStore +import nl.tudelft.trustchain.valuetransfer.community.PeerChatCommunity +import nl.tudelft.trustchain.valuetransfer.util.PeerChatStore import nl.tudelft.trustchain.valuetransfer.community.IdentityCommunity import nl.tudelft.trustchain.valuetransfer.db.IdentityStore -import nl.tudelft.trustchain.voting.VotingCommunity -import nl.tudelft.gossipML.sqldelight.Database as MLDatabase val Context.dataStore: DataStore by preferencesDataStore(name = "settings") @@ -85,6 +77,7 @@ class TrustChainApplication : Application() { var isFirstRun: Boolean = false lateinit var appLoader: AppLoader + @RequiresApi(Build.VERSION_CODES.M) override fun onCreate() = runBlocking { super.onCreate() launch { @@ -99,6 +92,7 @@ class TrustChainApplication : Application() { } } + @RequiresApi(Build.VERSION_CODES.M) fun initIPv8() { val config = IPv8Configuration( overlays = listOf( @@ -109,17 +103,12 @@ class TrustChainApplication : Application() { createTFTPCommunity(), createDemoCommunity(), createWalletCommunity(), - createAtomicSwapCommunity(), createMarketCommunity(), createCoinCommunity(), createDaoCommunity(), - createVotingCommunity(), createMusicCommunity(), - createLiteratureCommunity(), - createRecommenderCommunity(), createIdentityCommunity(), createFOCCommunity(), - createDeToksCommunity() ), walkerInterval = 5.0 ) @@ -215,52 +204,6 @@ class TrustChainApplication : Application() { } } ) - - trustchain.registerTransactionValidator( - AtomicSwapTrustchainConstants.ATOMIC_SWAP_COMPLETED_BLOCK, - object : TransactionValidator { - override fun validate( - block: TrustChainBlock, - database: TrustChainStore - ): ValidationResult { - if (( - block.transaction[AtomicSwapTrustchainConstants.TRANSACTION_FROM_COIN] != null && - block.transaction[AtomicSwapTrustchainConstants.TRANSACTION_TO_COIN] != null && - block.transaction[AtomicSwapTrustchainConstants.TRANSACTION_FROM_AMOUNT] != null && - block.transaction[AtomicSwapTrustchainConstants.TRANSACTION_TO_AMOUNT] != null && - block.transaction[AtomicSwapTrustchainConstants.TRANSACTION_OFFER_ID] != null - ) || - block.isAgreement - ) { - return ValidationResult.Valid - } else { - return ValidationResult.Invalid(listOf("Proposal invalid")) - } - } - } - ) - - trustchain.registerBlockSigner( - AtomicSwapTrustchainConstants.ATOMIC_SWAP_COMPLETED_BLOCK, - object : BlockSigner { - override fun onSignatureRequest(block: TrustChainBlock) { - trustchain.createAgreementBlock(block, mapOf()) - Log.d(LOG, "Bob created a trustchain agreement block") - } - } - ) - - trustchain.addListener( - AtomicSwapTrustchainConstants.ATOMIC_SWAP_COMPLETED_BLOCK, - object : BlockListener { - override fun onBlockReceived(block: TrustChainBlock) { - Log.d( - "AtomicSwap", - "onBlockReceived: ${block.blockId} ${block.transaction}" - ) - } - } - ) } private fun createWalletCommunity(): OverlayConfiguration { @@ -275,14 +218,6 @@ class TrustChainApplication : Application() { ) } - private fun createAtomicSwapCommunity(): OverlayConfiguration { - val randomWalk = RandomWalk.Factory() - return OverlayConfiguration( - Overlay.Factory(AtomicSwapCommunity::class.java), - listOf(randomWalk) - ) - } - private fun createDiscoveryCommunity(): OverlayConfiguration { val randomWalk = RandomWalk.Factory() val randomChurn = RandomChurn.Factory() @@ -388,17 +323,6 @@ class TrustChainApplication : Application() { ) } - private fun createVotingCommunity(): OverlayConfiguration { - val settings = TrustChainSettings() - val driver = AndroidSqliteDriver(Database.Schema, this, "voting.db") - val store = TrustChainSQLiteStore(Database(driver)) - val randomWalk = RandomWalk.Factory() - return OverlayConfiguration( - VotingCommunity.Factory(settings, store), - listOf(randomWalk) - ) - } - private fun createMusicCommunity(): OverlayConfiguration { val settings = TrustChainSettings() // TODO: Re-concile this community with Reccomender Community @@ -411,36 +335,6 @@ class TrustChainApplication : Application() { ) } - // TODO: Fix for older Android versions. - @SuppressLint("NewApi") - private fun createLiteratureCommunity(): OverlayConfiguration { - val settings = TrustChainSettings() - val driver = AndroidSqliteDriver(Database.Schema, this, "music.db") - val store = TrustChainSQLiteStore(Database(driver)) - val randomWalk = RandomWalk.Factory() - return OverlayConfiguration( - LiteratureCommunity.Factory(this, settings, store), - listOf(randomWalk) - ) - } - - @OptIn(DelicateCoroutinesApi::class) // TODO: Verify whether usage is correct. - private fun createRecommenderCommunity(): OverlayConfiguration { - val settings = TrustChainSettings() - val musicDriver = AndroidSqliteDriver(Database.Schema, this, "music.db") - val musicStore = TrustChainSQLiteStore(Database(musicDriver)) - val driver = AndroidSqliteDriver(MLDatabase.Schema, this, "recommend.db") - val database = MLDatabase(driver) - - val recommendStore = RecommenderStore.getInstance(musicStore, database) - recommendStore.essentiaJob = GlobalScope.launch { recommendStore.addAllLocalFeatures() } - val randomWalk = RandomWalk.Factory() - return OverlayConfiguration( - RecommenderCommunity.Factory(recommendStore, settings, musicStore), - listOf(randomWalk) - ) - } - private fun createFOCCommunity(): OverlayConfiguration { val randomWalk = RandomWalk.Factory() return OverlayConfiguration( @@ -449,14 +343,6 @@ class TrustChainApplication : Application() { ) } - private fun createDeToksCommunity(): OverlayConfiguration { - val randomWalk = RandomWalk.Factory() - return OverlayConfiguration( - DeToksCommunity.Factory(this), - listOf(randomWalk) - ) - } - private fun getIdAlgorithmKey(idFormat: String): BonehPrivateKey { val prefs = PreferenceManager.getDefaultSharedPreferences(this) val privateKey = prefs.getString(idFormat, null) 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 103970f8a..dd4af6e29 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 @@ -5,19 +5,21 @@ 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.explorer.ui.TrustChainExplorerActivity +import nl.tudelft.trustchain.app.ui.dashboard.DashboardActivity +@RequiresApi(Build.VERSION_CODES.M) class TrustChainService : IPv8Service() { override fun createNotification(): NotificationCompat.Builder { - val trustChainExplorerIntent = Intent(this, TrustChainExplorerActivity::class.java) + 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(trustChainExplorerIntent) + .addNextIntentWithParentStack(trustChainDashboardIntent) .getPendingIntent(0, flags) return NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_CONNECTION) diff --git a/currencyii/src/main/res/drawable/ic_arrow_drop_down_black_16dp.xml b/app/src/main/res/drawable/ic_arrow_drop_down_black_16dp.xml similarity index 100% rename from currencyii/src/main/res/drawable/ic_arrow_drop_down_black_16dp.xml rename to app/src/main/res/drawable/ic_arrow_drop_down_black_16dp.xml diff --git a/currencyii/src/main/res/drawable/ic_arrow_drop_up_black_16dp.xml b/app/src/main/res/drawable/ic_arrow_drop_up_black_16dp.xml similarity index 100% rename from currencyii/src/main/res/drawable/ic_arrow_drop_up_black_16dp.xml rename to app/src/main/res/drawable/ic_arrow_drop_up_black_16dp.xml diff --git a/currencyii/src/main/res/drawable/ic_insert_link_black_24dp.xml b/app/src/main/res/drawable/ic_insert_link_black_24dp.xml similarity index 100% rename from currencyii/src/main/res/drawable/ic_insert_link_black_24dp.xml rename to app/src/main/res/drawable/ic_insert_link_black_24dp.xml diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml index 384d43552..acbd7df15 100644 --- a/app/src/main/res/layout/app_bar_main.xml +++ b/app/src/main/res/layout/app_bar_main.xml @@ -3,7 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="nl.tudelft.trustchain.explorer.ui.MainActivity"> + tools:context="nl.tudelft.trustchain.app.ui.dashboard.DashboardActivity"> - Hello blank fragment - Proposals - - diff --git a/currencyii/src/main/res/values/styles.xml b/currencyii/src/main/res/values/styles.xml deleted file mode 100644 index 5885930df..000000000 --- a/currencyii/src/main/res/values/styles.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - diff --git a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/coin/WalletManagerTest.kt b/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/coin/WalletManagerTest.kt deleted file mode 100644 index fe3b8b29a..000000000 --- a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/coin/WalletManagerTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -package nl.tudelft.trustchain.currencyii.coin - -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.Test -import java.io.File - -class WalletManagerTest { - - companion object { - lateinit var walletManager: WalletManager - - @BeforeAll - @JvmStatic - fun setup() { - val config = WalletManagerConfiguration(BitcoinNetworkOptions.REG_TEST) - walletManager = WalletManager( - config, - File(".") - ) - } - } - - /** - * Wallet address should be correct format (same regex as used on regtest server). - */ - @Test - fun testProtocolAddress() { - val addressRegex = Regex("[a-km-zA-HJ-NP-Z1-9]{25,50}$") - val actual = walletManager.protocolAddress() - val matches: Boolean = actual.toString().matches(addressRegex) - assertTrue(matches) - } -} diff --git a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/CTransactionTest.kt b/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/CTransactionTest.kt deleted file mode 100644 index 7cee0e005..000000000 --- a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/CTransactionTest.kt +++ /dev/null @@ -1,145 +0,0 @@ -package nl.tudelft.trustchain.currencyii.util.taproot - -import nl.tudelft.ipv8.util.hexToBytes -import nl.tudelft.ipv8.util.toHex -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test - -class CTransactionTest { - - @Test - fun taprootSignature() { - val hash = "9810b6e1b42d1f5d3c9377c5b1c3b6bb2ee0f96427d9adead6c99626798faac8" - val publicKey: ByteArray = "001420501761e7ba8b479cc516488d47e8f5d02e52d7".hexToBytes() - val coutPoint = COutPoint(hash = hash, n = 0) - val cTxIn = CTxIn(prevout = coutPoint, scriptSig = byteArrayOf(), nSequence = 0) - val cTxOut = CTxOut(nValue = (0.50000000 * 100_000_000).toLong(), scriptPubKey = publicKey) - val spending_tx = CTransaction( - nVersion = 1, - vin = arrayOf(cTxIn), - vout = arrayOf(cTxOut), - wit = CTxWitness(), - nLockTime = 0 - ) - - val publicKey2 = - "5121003dd5fc3c1766d0a73466a5997da83efcc529107c9ecd0c56e2a28519f0eb3104".hexToBytes() - val txVout = CTxOut(nValue = (1.00000000 * 100_000_000).toLong(), scriptPubKey = publicKey2) - - val expected = - "c58660789cf1bbd4c265823168ccdc2e13a5f97c4d2e8742e08e16ee21d0929a" - val actual = - CTransaction.TaprootSignatureHash( - spending_tx, - arrayOf(txVout), - SIGHASH_ALL_TAPROOT, - input_index = 0 - ).toHex() - - assertEquals(expected, actual) - } - - @Test - fun cTxInSerialize() { - val prevout = COutPoint( - hash = "92ba46893466d7d219a3980db4bf33206cf85ec5ce7726e9062b943d62fe995d", - n = 0 - ) - val ctxIn = CTxIn(prevout = prevout) - val expected = - "5d99fe623d942b06e92677cec55ef86c2033bfb40d98a319d2d766348946ba92000000000000000000" - val actual = ctxIn.serialize().toHex() - - assertEquals(expected, actual) - } - - @Test - fun cTransactionSerializeWithWitness2() { - val hash = "9810b6e1b42d1f5d3c9377c5b1c3b6bb2ee0f96427d9adead6c99626798faac8" - val publicKey: ByteArray = "001420501761e7ba8b479cc516488d47e8f5d02e52d7".hexToBytes() - val coutPoint = COutPoint(hash = hash, n = 0) - val cTxIn = CTxIn(prevout = coutPoint, scriptSig = byteArrayOf(), nSequence = 0) - val cTxOut = CTxOut(nValue = (0.50000000 * 100_000_000).toLong(), scriptPubKey = publicKey) - val spending_tx = CTransaction( - nVersion = 1, - vin = arrayOf(cTxIn), - vout = arrayOf(cTxOut), - wit = CTxWitness(), - nLockTime = 0 - ) - - spending_tx.wit.vtxinwit = arrayOf(CTxInWitness(arrayOf("7bdd007a2ada0fbf18fe8ea7858398e2775195db1a2cef127ef38eef861027bf4f058be84a536603799b4acce1f0eeb048c634d740aa38351cb18b7465e4b125".hexToBytes()))) - val expected = "01000000000101c8aa8f792696c9d6eaadd92764f9e02ebbb6c3b1c577933c5d1f2db4e1b610980000000000000000000180f0fa020000000016001420501761e7ba8b479cc516488d47e8f5d02e52d701407bdd007a2ada0fbf18fe8ea7858398e2775195db1a2cef127ef38eef861027bf4f058be84a536603799b4acce1f0eeb048c634d740aa38351cb18b7465e4b12500000000" - val actual = spending_tx.serialize().toHex() - - assertEquals(expected, actual) - } - - @Test - fun cTransactionDeserializeWithWitness() { - val expected = "01000000000101c8aa8f792696c9d6eaadd92764f9e02ebbb6c3b1c577933c5d1f2db4e1b610980000000000000000000180f0fa020000000016001420501761e7ba8b479cc516488d47e8f5d02e52d701407bdd007a2ada0fbf18fe8ea7858398e2775195db1a2cef127ef38eef861027bf4f058be84a536603799b4acce1f0eeb048c634d740aa38351cb18b7465e4b12500000000" - val actual = CTransaction().deserialize(expected.hexToBytes()).serialize().toHex() - - assertEquals(expected, actual) - } - - @Test - fun cTransactionSerializeWithWitness() { - val hash = "92ba46893466d7d219a3980db4bf33206cf85ec5ce7726e9062b943d62fe995d" - val publicKey: ByteArray = "0014062b4b39acb17d358f130b15ca3e92acfe1604d6".hexToBytes() - val cOutpoint = COutPoint(hash = hash, n = 0) - val ctxIn = CTxIn(prevout = cOutpoint) - val cTxOut = CTxOut(nValue = (0.69000000 * 100_000_000).toLong(), scriptPubKey = publicKey) - val cTxInWitness = - CTxInWitness(arrayOf("475ecd0cfdbbadb8fa891e7c341e6290a0ceb13f16d9943d57600bc93c26b7b5efdd37da69d86fe73d38331d407521e08c2dcde0400cdb8cb5938e7e7d831536".hexToBytes())) - val cTxWitness = CTxWitness(arrayOf(cTxInWitness)) - val cTransaction = CTransaction( - nVersion = 1, - vin = arrayOf(ctxIn), - vout = arrayOf(cTxOut), - wit = cTxWitness, - nLockTime = 0 - ) - - val expected = "010000000001015d99fe623d942b06e92677cec55ef86c2033bfb40d98a319d2d766348946ba920000000000000000000140db1c0400000000160014062b4b39acb17d358f130b15ca3e92acfe1604d60140475ecd0cfdbbadb8fa891e7c341e6290a0ceb13f16d9943d57600bc93c26b7b5efdd37da69d86fe73d38331d407521e08c2dcde0400cdb8cb5938e7e7d83153600000000" - val actual = cTransaction.serialize().toHex() - - assertEquals(expected, actual) - } - - @Test - fun cScriptGetSizeEmpty() { - val tapScript = CScript() - assertEquals(tapScript.size(), 0) - } - - @Test - fun cScriptGetSizeNotEmpty() { - val tapScript = CScript("aa".toByteArray()) - assertEquals(tapScript.size(), 2) - } - - @Test - fun cScriptToHexEmpty() { - val tapScript = CScript() - assertEquals(tapScript.toHex(), "") - } - - @Test - fun cScriptToHexNotEmpty() { - val tapScript = CScript("aa".toByteArray()) - assertEquals(tapScript.toHex(), "6161") - } - - @Test - fun cScriptOpHasCode() { - val cScriptOp = CScriptOp(1) - assertEquals(cScriptOp.hashCode(), 1) - } - - @Test - fun cTXWitnessIsNull() { - val cTxWitness = CTxWitness() - assertEquals(cTxWitness.isNull(), true) - } -} diff --git a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/KeyTest.kt b/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/KeyTest.kt deleted file mode 100644 index e2b9c3f3e..000000000 --- a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/KeyTest.kt +++ /dev/null @@ -1,19 +0,0 @@ -package nl.tudelft.trustchain.currencyii.util.taproot - -import org.bitcoinj.core.ECKey -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test -import java.math.BigInteger - -class KeyTest { - - @Test - fun generate_schnorr_nonce() { - val nonce = TaprootUtil.generate_schnorr_nonce(ECKey().privKeyBytes) - - val expected = BigInteger.ONE - val actual = Schnorr.jacobi(nonce.second.affineYCoord.toBigInteger()) - - assertEquals(expected, actual) - } -} diff --git a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/MessagesTest.kt b/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/MessagesTest.kt deleted file mode 100644 index f8ee03662..000000000 --- a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/MessagesTest.kt +++ /dev/null @@ -1,45 +0,0 @@ -package nl.tudelft.trustchain.currencyii.util.taproot - -import nl.tudelft.ipv8.util.hexToBytes -import nl.tudelft.ipv8.util.toHex -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test - -class MessagesTest { - - @Test - fun ser_string() { - val input = "210214bff3ba68d53bf47b029192a3ff841a14974f06b418368347eca254139762f5ac2102c39c2eb831bc354939e70955d360350d23dc65c13f5dd7380886fe2ddf954175ba529c6982012088a9140f29b5431fd985d12c6074072f98fd0ae7939d8887690114b2".hexToBytes() - val expected = "68210214bff3ba68d53bf47b029192a3ff841a14974f06b418368347eca254139762f5ac2102c39c2eb831bc354939e70955d360350d23dc65c13f5dd7380886fe2ddf954175ba529c6982012088a9140f29b5431fd985d12c6074072f98fd0ae7939d8887690114b2" - val actual = Messages.serString(input).toHex() - - assertEquals(expected, actual) - } - - @Test - fun ser_string_A() { - val input = "2103148fe4ff9ee1cfdf53c422e621bf2608e215a824ace294b4776b2ab7db49d000ac".hexToBytes() - val expected = "232103148fe4ff9ee1cfdf53c422e621bf2608e215a824ace294b4776b2ab7db49d000ac" - val actual = Messages.serString(input).toHex() - - assertEquals(expected, actual) - } - - @Test - fun ser_string_B() { - val input = "21027f293ae45f4b27d6120079f43fcaca248c19db824724338f392289c34789e6c9ac".hexToBytes() - val expected = "2321027f293ae45f4b27d6120079f43fcaca248c19db824724338f392289c34789e6c9ac" - val actual = Messages.serString(input).toHex() - - assertEquals(expected, actual) - } - - @Test - fun ser_string_C() { - val input = "210247c1ef4926e56835b8bf975ba14608d2ced2e82b6659ad820aa431d7a6299c1dac".hexToBytes() - val expected = "23210247c1ef4926e56835b8bf975ba14608d2ced2e82b6659ad820aa431d7a6299c1dac" - val actual = Messages.serString(input).toHex() - - assertEquals(expected, actual) - } -} diff --git a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/MuSigTest.kt b/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/MuSigTest.kt deleted file mode 100644 index 02a4d6470..000000000 --- a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/MuSigTest.kt +++ /dev/null @@ -1,100 +0,0 @@ -package nl.tudelft.trustchain.currencyii.util.taproot - -import nl.tudelft.ipv8.util.hexToBytes -import nl.tudelft.ipv8.util.toHex -import org.bitcoinj.core.ECKey -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test - -import java.math.BigInteger - -class MuSigTest { - - @Test - fun aggregate_musig_signatures() { - val nonceKey1 = ECKey.fromPrivate(BigInteger("514451593258031455215956018794650590333274290798379324717376700610851698631")) - val nonceKey2 = ECKey.fromPrivate(BigInteger("11956400277919736063286645919884525832160975522703242034429953595835464801432")) - val R_agg = MuSig.aggregate_schnorr_nonces(listOf(nonceKey1, nonceKey2)).first - - val s1 = BigInteger("87702316580188192134768828685038019069684190982614451361055363232288478978335") - val s2 = BigInteger("70205003187379344988121702708730152167489459605852932449770410784261163634250") - - val expected = "7bdd007a2ada0fbf18fe8ea7858398e2775195db1a2cef127ef38eef861027bf5d1c6031344b0127f0ebc54b27eb1b7a1cd34229e86be03a2e521ccd92066e28" - val actual = MuSig.aggregate_musig_signatures(listOf(s1, s2), R_agg).toHex() - - assertEquals(expected, actual) - } - - @Test - fun sign_musig() { - val key1 = ECKey.fromPrivate(BigInteger("88218786999700320424912157840922001183470238663577897435520060565802125439712")) - val key2 = ECKey.fromPrivate(BigInteger("11756621930195768229168784074199362003209438395325908648574429387730312779458")) - val agg_pubkey = MuSig.generate_musig_key(listOf(key1, key2)).second - - val key1_c = ECKey.fromPrivate(BigInteger("1831054192583883058098689099279726084283766354549572339919052854814308263405")) - val nonceKey1 = ECKey.fromPrivate(BigInteger("514451593258031455215956018794650590333274290798379324717376700610851698631")) - val nonceKey2 = ECKey.fromPrivate(BigInteger("11956400277919736063286645919884525832160975522703242034429953595835464801432")) - val R_agg = MuSig.aggregate_schnorr_nonces(listOf(nonceKey1, nonceKey2)).first - - val sighash_musig = "594dc4e841a628509c9467fdcb7361de7b7bba490bedd601d18d4ba7d752888b".hexToBytes() - - val expected = BigInteger("87702316580188192134768828685038019069684190982614451361055363232288478978335") - val actual = MuSig.sign_musig(key1_c, nonceKey1, R_agg, agg_pubkey, sighash_musig) - - assertEquals(expected, actual) - } - - @Test - fun generate_musig_key() { - val key1 = ECKey.fromPrivate(BigInteger("88218786999700320424912157840922001183470238663577897435520060565802125439712")) - val key2 = ECKey.fromPrivate(BigInteger("11756621930195768229168784074199362003209438395325908648574429387730312779458")) - - val expected = "023dd5fc3c1766d0a73466a5997da83efcc529107c9ecd0c56e2a28519f0eb3104" - val (cMap, actual) = MuSig.generate_musig_key(listOf(key1, key2)) - - assertEquals(expected, actual.getEncoded(true).toHex()) - - val expectedPrivChallenge1 = BigInteger("1831054192583883058098689099279726084283766354549572339919052854814308263405") - val expectedPrivChallenge2 = BigInteger("102505784576051217526024106275692022993285503780642991935683834028794254508839") - val expectedPubChallenge1 = "027018cf68d40bae2a6c2b3dcee830b2f02c11586cfbd21955ba3e6a3f1d0da05b" - val expectedPubChallenge2 = "0288fd645aca21c03b53abbe67f5cfb62fe65da0fd9277f9b4a00b0dee64e9eb1f" - - val actualPrivChallenge1 = key1.privKey.multiply(BigInteger(1, cMap[key1])).mod(Schnorr.n) - val actualPrivChallenge2 = key2.privKey.multiply(BigInteger(1, cMap[key2])).mod(Schnorr.n) - val actualPubChallenge1 = key1.pubKeyPoint.multiply(BigInteger(1, cMap[key1])).getEncoded(true).toHex() - val actualPubChallenge2 = key2.pubKeyPoint.multiply(BigInteger(1, cMap[key2])).getEncoded(true).toHex() - - assertEquals(expectedPrivChallenge1, actualPrivChallenge1) - assertEquals(expectedPrivChallenge2, actualPrivChallenge2) - assertEquals(expectedPubChallenge1, actualPubChallenge1) - assertEquals(expectedPubChallenge2, actualPubChallenge2) - - val pubkeyDataMuSig = actual.getEncoded(true) - - val expectedAddress = "bcrt1pqq7atlpuzandpfe5v6jejldg8m7v22gs0j0v6rzku23g2x0savcsgwp82mv" - val actualAddress = TaprootUtil.key_to_witness(pubkeyDataMuSig) - - assertEquals(expectedAddress, actualAddress) - } - - @Test - fun aggregate_schnorr_nonces() { - var key1 = ECKey.fromPrivate(BigInteger("2c68916c316d82ea8f3ebb27037354741ce080464590268780ffca750c5727f6", 16)) - var key2 = ECKey.fromPrivate(BigInteger("08d538794fcc7766ecc1e0fd9c1642e5cd5147c67807cce4d46144db5fcc8534", 16)) - - var expected = "03326be2da46e2af92df7df4affacc9afdd8b0fb80e7958da65da62b6fc67883f4" - var actual = MuSig.aggregate_schnorr_nonces(listOf(key1, key2)) - - assertEquals(expected, actual.first.getEncoded(true).toHex()) - assertTrue(actual.second) - - key1 = ECKey.fromPrivate(BigInteger("01232b5623b219913420d5570fd5052538c8ee3014adfc9c8d9a73585110f7c7", 16)) - key2 = ECKey.fromPrivate(BigInteger("1a6f152e82687bd327d65dafb44c84dad1bcc605c9a128231ce0725305ffdc98", 16)) - - expected = "037bdd007a2ada0fbf18fe8ea7858398e2775195db1a2cef127ef38eef861027bf" - actual = MuSig.aggregate_schnorr_nonces(listOf(key1, key2)) - - assertEquals(expected, actual.first.getEncoded(true).toHex()) - assertFalse(actual.second) - } -} diff --git a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/SchnorrTest.kt b/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/SchnorrTest.kt deleted file mode 100644 index d63b5980d..000000000 --- a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/SchnorrTest.kt +++ /dev/null @@ -1,42 +0,0 @@ -package nl.tudelft.trustchain.currencyii.util.taproot - -import nl.tudelft.trustchain.currencyii.util.taproot.Schnorr.* -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.CsvFileSource -import java.math.BigInteger - -/** - * Test was written using code and csv provided on: https://github.com/miketwk/bip-schnorr-java/ - */ -class SchnorrTest { - - @ParameterizedTest - @CsvFileSource( - files = arrayOf("src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/test-vectors.csv"), - numLinesToSkip = 1 - ) - fun schnorrTestCSVFile( - index: Int, - secKey: String?, - publicKey: String, - message: String, - signature: String, - result: Boolean, - comment: String? - ) { - val msg = hexStringToByteArray(message) - val pubKey = hexStringToByteArray(publicKey) - - if (secKey != null && !secKey.isEmpty()) { - val seckeyNum = BigInteger(secKey, 16) - val sig_actual: String = bytesToHex(schnorr_sign(msg, seckeyNum)) - - assertEquals(signature, sig_actual, "Failed signing for test $index, expected $signature but got: $sig_actual") - } - - val result_actual = schnorr_verify(msg, pubKey, hexStringToByteArray(signature)) - - assertEquals(result, result_actual, "Failed verification for test $index, expected: $result but got: $result_actual, explanation: $comment") - } -} diff --git a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/test-vectors.csv b/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/test-vectors.csv deleted file mode 100644 index feb89efb5..000000000 --- a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/util/taproot/test-vectors.csv +++ /dev/null @@ -1,17 +0,0 @@ -index,seckey,pubkey,msg,sig,result,comment -1,0000000000000000000000000000000000000000000000000000000000000001,0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,0000000000000000000000000000000000000000000000000000000000000000,787A848E71043D280C50470E8E1532B2DD5D20EE912A45DBDD2BD1DFBF187EF67031A98831859DC34DFFEEDDA86831842CCD0079E1F92AF177F7F22CC1DCED05,TRUE, -2,B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD,TRUE, -3,C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C7,03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B,5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C,00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BE00880371D01766935B92D2AB4CD5C8A2A5837EC57FED7660773A05F0DE142380,TRUE, -4,,03DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34,4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703,00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6302A8DC32E64E86A333F20EF56EAC9BA30B7246D6D25E22ADB8C6BE1AEB08D49D,TRUE, -5,,031B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0000000000000000000000000000000000000000000000000000000000000000,52818579ACA59767E3291D91B76B637BEF062083284992F2D95F564CA6CB4E3530B1DA849C8E8304ADC0CFE870660334B3CFC18E825EF1DB34CFAE3DFC5D8187,TRUE,"test fails if jacobi symbol of x(R) instead of y(R) is used" -6,,03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,570DD4CA83D4E6317B8EE6BAE83467A1BF419D0767122DE409394414B05080DCE9EE5F237CBD108EABAE1E37759AE47F8E4203DA3532EB28DB860F33D62D49BD,TRUE,"test fails if msg is reduced modulo p or n" -7,,03EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34,4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703,00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6302A8DC32E64E86A333F20EF56EAC9BA30B7246D6D25E22ADB8C6BE1AEB08D49D,FALSE,"public key not on the curve" -8,,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1DFA16AEE06609280A19B67A24E1977E4697712B5FD2943914ECD5F730901B4AB7,FALSE,"incorrect R residuosity" -9,,03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B,5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C, 00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BED092F9D860F1776A1F7412AD8A1EB50DACCC222BC8C0E26B2056DF2F273EFDEC,FALSE,"negated message" -10,,0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,0000000000000000000000000000000000000000000000000000000000000000,787A848E71043D280C50470E8E1532B2DD5D20EE912A45DBDD2BD1DFBF187EF68FCE5677CE7A623CB20011225797CE7A8DE1DC6CCD4F754A47DA6C600E59543C,FALSE,"negated s value" -11,,03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD,FALSE,"negated public key" -12,,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,00000000000000000000000000000000000000000000000000000000000000009E9D01AF988B5CEDCE47221BFA9B222721F3FA408915444A4B489021DB55775F,FALSE,"sG - eP is infinite. Test fails in single verification if jacobi(y(inf)) is defined as 1 and x(inf) as 0" -13,,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,0000000000000000000000000000000000000000000000000000000000000001D37DDF0254351836D84B1BD6A795FD5D523048F298C4214D187FE4892947F728,FALSE,"sG - eP is infinite. Test fails in single verification if jacobi(y(inf)) is defined as 1 and x(inf) as 1" -14,,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD,FALSE,"sig[0:32] is not an X coordinate on the curve" -15,,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2F1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD,FALSE,"sig[0:32] is equal to field size" -16,,02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,FALSE,"sig[32:64] is equal to curve order" \ No newline at end of file diff --git a/detoks/.gitignore b/detoks/.gitignore deleted file mode 100644 index 796b96d1c..000000000 --- a/detoks/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/detoks/build.gradle b/detoks/build.gradle deleted file mode 100644 index 0bfe89e03..000000000 --- a/detoks/build.gradle +++ /dev/null @@ -1,98 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' - -android { - compileSdkVersion 33 - - defaultConfig { - minSdkVersion 22 - targetSdkVersion 33 - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles 'consumer-rules.pro' - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = "1.8" - allWarningsAsErrors = true - } - - - buildFeatures { - viewBinding = true - } - namespace 'nl.tudelft.trustchain.detoks' -} - -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' - implementation 'androidx.core:core-ktx:1.9.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation "androidx.recyclerview:recyclerview:1.2.1" - implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" - implementation "androidx.navigation:navigation-ui-ktx:$nav_version" - implementation "androidx.fragment:fragment-ktx:$fragment_version" - implementation "androidx.preference:preference:1.2.0" - implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" - - // Material - implementation 'com.google.android.material:material:1.8.0' - - // Kotlin - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" - implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - - // Logging - implementation 'io.github.microutils:kotlin-logging:1.7.7' - implementation 'com.github.tony19:logback-android:2.0.0' - - implementation 'com.github.MattSkala:recyclerview-itemadapter:0.4' - - // Testing - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' - - // TODO fix direct import, this should rely on common. - // BitTorrent - implementation files('../common/libs/jlibtorrent-' + jlibtorrent_version + '.jar') - implementation files('../common/libs/jlibtorrent-android-arm64-' + jlibtorrent_version + '.jar') - implementation files('../common/libs/jlibtorrent-android-arm-' + jlibtorrent_version + '.jar') - implementation files('../common/libs/jlibtorrent-android-x86-' + jlibtorrent_version + '.jar') - 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 { - kotlinOptions.freeCompilerArgs += [ - "-opt-in=kotlin.RequiresOptIn", "-Werror" - ] -} diff --git a/detoks/consumer-rules.pro b/detoks/consumer-rules.pro deleted file mode 100644 index e69de29bb..000000000 diff --git a/detoks/proguard-rules.pro b/detoks/proguard-rules.pro deleted file mode 100644 index f1b424510..000000000 --- a/detoks/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/detoks/src/main/AndroidManifest.xml b/detoks/src/main/AndroidManifest.xml deleted file mode 100644 index 8414c63ed..000000000 --- a/detoks/src/main/AndroidManifest.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/DeToksCommunity.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/DeToksCommunity.kt deleted file mode 100644 index 8ee14f5ca..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/DeToksCommunity.kt +++ /dev/null @@ -1,145 +0,0 @@ -package nl.tudelft.trustchain.detoks - -import android.content.Context -import android.util.Log -import com.frostwire.jlibtorrent.Sha1Hash -import nl.tudelft.ipv8.Overlay -import nl.tudelft.ipv8.Peer -import nl.tudelft.ipv8.messaging.Packet -import nl.tudelft.ipv8.messaging.Serializable -import nl.tudelft.trustchain.detoks.gossiper.* - - -class DeToksCommunity( - private val context: Context - ) : TransactionEngine(DetoksConfig.DETOKS_SERVICE_ID) { - - private val walletManager = WalletManager(context) - private val visitedPeers = mutableListOf() - - init { - messageHandlers[MESSAGE_TORRENT_ID] = ::onTorrentGossip - messageHandlers[MESSAGE_TRANSACTION_ID] = ::onTransactionMessage - messageHandlers[MESSAGE_WATCH_TIME_ID] = :: onWatchTimeGossip - messageHandlers[MESSAGE_NETWORK_SIZE_ID] = :: onNetworkSizeGossip - messageHandlers[MESSAGE_BOOT_REQUEST] = :: onBootRequestGossip - messageHandlers[MESSAGE_BOOT_RESPONSE] = :: onBootResponseGossip - - } - - companion object { - const val LOGGING_TAG = "DeToksCommunity" - const val MESSAGE_TORRENT_ID = 1 - const val MESSAGE_TRANSACTION_ID = 2 - const val MESSAGE_WATCH_TIME_ID = 3 - const val MESSAGE_NETWORK_SIZE_ID = 4 - const val MESSAGE_BOOT_REQUEST = 5 - const val MESSAGE_BOOT_RESPONSE = 6 - } - - fun sendTokens(amount: Int, recipientMid: String) { - val senderWallet = walletManager.getOrCreateWallet(myPeer.mid) - - Log.d(LOGGING_TAG, "my wallet ${senderWallet.balance}") - - if (senderWallet.balance >= amount) { - Log.d(LOGGING_TAG, "Sending $amount money to $recipientMid") - senderWallet.balance -= amount - walletManager.setWalletBalance(myPeer.mid, senderWallet.balance) - - val recipientWallet = walletManager.getOrCreateWallet(recipientMid) - recipientWallet.balance += amount - walletManager.setWalletBalance(recipientMid, recipientWallet.balance) - - for (peer in getPeers()) { - val packet = serializePacket( - MESSAGE_TRANSACTION_ID, - TransactionMessage(amount, myPeer.mid, recipientMid) - ) - send(peer.address, packet) - } - } else { - Log.d(LOGGING_TAG, "Insufficient funds!") - } - - } - - fun gossipWith(peer: Peer, message: Serializable, id: Int) { - Log.d(LOGGING_TAG, "Gossiping with ${peer.mid}, msg id: $id") - - val packet = serializePacket(id, message) - - // Send a token only to a new peer - if (!visitedPeers.contains(peer)) { - visitedPeers.add(peer) - sendTokens(1, peer.mid) - } - - send(peer.address, packet) - } - - private fun onTransactionMessage(packet: Packet) { - val (_, payload) = packet.getAuthPayload(TransactionMessage.Deserializer) - - val senderWallet = walletManager.getOrCreateWallet(payload.senderMID) - - if (senderWallet.balance >= payload.amount) { - senderWallet.balance -= payload.amount - walletManager.setWalletBalance(payload.senderMID, senderWallet.balance) - - val recipientWallet = walletManager.getOrCreateWallet(payload.recipientMID) - recipientWallet.balance += payload.amount - walletManager.setWalletBalance(payload.recipientMID, recipientWallet.balance) - - Log.d(LOGGING_TAG, "Received ${payload.amount} tokens from ${payload.senderMID}") - } else { - Log.d(LOGGING_TAG, "Insufficient funds from ${payload.senderMID}!") - } - } - - private fun onTorrentGossip(packet: Packet) { - val payload = packet.getPayload(TorrentMessage.Deserializer) - val torrentManager = TorrentManager.getInstance(context) - payload.data.forEach { - torrentManager.addTorrent(Sha1Hash(it.first), it.second) - } - } - - private fun onWatchTimeGossip(packet: Packet) { - val (peer, payload) = packet.getAuthPayload(WatchTimeMessage.Deserializer) - val torrentManager = TorrentManager.getInstance(context) - Log.d(LOGGING_TAG, "Received watch time entry from ${peer.mid}, payload: ${payload.data}") - - payload.data.forEach { - torrentManager.profile.updateEntryWatchTime( - it.first, - it.second, - false - ) - } - } - - private fun onNetworkSizeGossip(packet: Packet) { - val (peer, payload) = packet.getAuthPayload(NetworkSizeMessage.Deserializer) - NetworkSizeGossiper.receivedResponse(payload, peer) - } - - private fun onBootRequestGossip(packet: Packet) { - val (peer, _) = packet.getAuthPayload(BootMessage.Deserializer) - BootGossiper.receivedRequest(peer) - } - - private fun onBootResponseGossip(packet: Packet) { - val (_, payload) = packet.getAuthPayload(BootMessage.Deserializer) - BootGossiper.receivedResponse(payload.data) - } - - class Factory( - private val context: Context - ) : Overlay.Factory(DeToksCommunity::class.java) { - override fun create(): DeToksCommunity { - return DeToksCommunity(context) - } - } -} - diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/DeToksFragment.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/DeToksFragment.kt deleted file mode 100644 index e6b2557d3..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/DeToksFragment.kt +++ /dev/null @@ -1,87 +0,0 @@ -package nl.tudelft.trustchain.detoks - -import android.os.Bundle -import android.util.Log -import android.view.View -import androidx.viewpager2.widget.ViewPager2 -import kotlinx.android.synthetic.main.fragment_detoks.* -import mu.KotlinLogging -import nl.tudelft.trustchain.common.ui.BaseFragment -import java.io.File -import java.io.FileOutputStream - -class DeToksFragment : BaseFragment(R.layout.fragment_detoks) { - private lateinit var torrentManager: TorrentManager - private val logger = KotlinLogging.logger {} - private var previousVideoAdapterIndex = 0 - - private val torrentDir: String - get() = "${requireActivity().cacheDir.absolutePath}/torrent" - private val mediaCacheDir: String - get() = "${requireActivity().cacheDir.absolutePath}/media" - - private fun cacheDefaultTorrent() { - try { - val dir1 = File(mediaCacheDir) - if (!dir1.exists()) { - dir1.mkdirs() - } - val dir2 = File(torrentDir) - if (!dir2.exists()) { - dir2.mkdirs() - } - val file = File("$torrentDir/$DEFAULT_TORRENT_FILE") - if (!file.exists()) { - val outputStream = FileOutputStream(file) - val ins = requireActivity().resources.openRawResource(R.raw.detoks) - outputStream.write(ins.readBytes()) - ins.close() - outputStream.close() - } - } catch (e: Exception) { - Log.e("DeToks", "Failed to cache default torrent: $e") - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - cacheDefaultTorrent() - torrentManager = TorrentManager.getInstance(requireActivity()) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - viewPagerVideos.adapter = VideosAdapter(torrentManager) - viewPagerVideos.currentItem = 0 - onPageChangeCallback() - } - - /** - * This functions allows for looping back to start of the video pool. - */ - private fun onPageChangeCallback() { - viewPagerVideos.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { - override fun onPageScrollStateChanged(state: Int) { - super.onPageScrollStateChanged(state) - - if (state == ViewPager2.SCROLL_STATE_IDLE) { - when (viewPagerVideos.currentItem - previousVideoAdapterIndex) { - 1 -> torrentManager.notifyIncrease() - -1 -> torrentManager.notifyDecrease() - 0 -> {} // Do nothing - else -> { - logger.error { "Something went wrong with the video adapter index" } - } - } - previousVideoAdapterIndex = viewPagerVideos.currentItem - } - } - }) - } - - companion object { - const val DEFAULT_CACHING_AMOUNT = 2 - const val DEFAULT_TORRENT_FILE = "detoks.torrent" - } -} diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/DeToksMainActivity.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/DeToksMainActivity.kt deleted file mode 100644 index 485e7c653..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/DeToksMainActivity.kt +++ /dev/null @@ -1,37 +0,0 @@ -package nl.tudelft.trustchain.detoks - -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import android.content.ServiceConnection -import android.os.Bundle -import android.os.IBinder -import nl.tudelft.trustchain.common.BaseActivity -import nl.tudelft.trustchain.detoks.gossiper.GossiperService - -class DeToksActivity : BaseActivity() { - override val navigationGraph = R.navigation.nav_graph_detoks - var gossipService: GossiperService? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - val actionBar = supportActionBar - actionBar!!.hide() - - Intent(this, GossiperService::class.java).also { intent -> - startService(intent) - bindService(intent, gossipConnection, Context.BIND_AUTO_CREATE) - } - } - - private val gossipConnection = object : ServiceConnection { - override fun onServiceConnected(className: ComponentName, service: IBinder) { - val binder = service as GossiperService.LocalBinder - gossipService = binder.getService() - } - - override fun onServiceDisconnected(p0: ComponentName?) { - gossipService = null - } - } -} diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/DetoksConfig.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/DetoksConfig.kt deleted file mode 100644 index ed7e990cf..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/DetoksConfig.kt +++ /dev/null @@ -1,7 +0,0 @@ -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/Profile.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/Profile.kt deleted file mode 100644 index d784d2f83..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/Profile.kt +++ /dev/null @@ -1,43 +0,0 @@ -package nl.tudelft.trustchain.detoks - -import android.util.Log -import nl.tudelft.trustchain.detoks.gossiper.NetworkSizeGossiper -import java.lang.Long.min - - -class ProfileEntry( - var duration: Long = 0, // Video duration - var watchTime: Long = 0, // Average watch time - val firstSeen: Long = System.currentTimeMillis() -) : Comparable { - override fun compareTo(other: ProfileEntry): Int = when { - this.watchTime != other.watchTime -> this.watchTime compareTo other.watchTime - this.firstSeen != other.firstSeen -> this.firstSeen compareTo other.firstSeen - else -> 0 - } -} - -class Profile( - val torrents: HashMap = HashMap() -) { - object ProfileConfig { const val MAX_DURATION_RATIO = 10 } - - fun updateEntryWatchTime(key: String, time: Long, myUpdate: Boolean) { - if(!torrents.contains(key)) torrents[key] = ProfileEntry() - - if(myUpdate) { - val newTime = min(time, torrents[key]!!.watchTime * ProfileConfig.MAX_DURATION_RATIO) - torrents[key]!!.watchTime += (newTime / NetworkSizeGossiper.networkSizeEstimate) - } else { - torrents[key]!!.watchTime += time - torrents[key]!!.watchTime /= 2 - } - Log.i(DeToksCommunity.LOGGING_TAG, "Updated watchtime of $key to ${torrents[key]!!.watchTime}") - } - - fun updateEntryDuration(key: String, duration: Long) { - if(!torrents.contains(key)) torrents[key] = ProfileEntry() - torrents[key]!!.duration = duration - Log.i(DeToksCommunity.LOGGING_TAG, "Updated duration of $key to ${torrents[key]!!.duration}") - } -} diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/TorrentManager.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/TorrentManager.kt deleted file mode 100644 index 12982d98c..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/TorrentManager.kt +++ /dev/null @@ -1,379 +0,0 @@ -package nl.tudelft.trustchain.detoks - -import android.content.Context -import android.media.MediaMetadataRetriever -import android.os.Build -import android.util.Log -import androidx.annotation.RequiresApi -import com.frostwire.jlibtorrent.* -import com.frostwire.jlibtorrent.alerts.AddTorrentAlert -import com.frostwire.jlibtorrent.alerts.Alert -import com.frostwire.jlibtorrent.alerts.AlertType -import com.frostwire.jlibtorrent.alerts.BlockFinishedAlert -import kotlinx.coroutines.TimeoutCancellationException -import kotlinx.coroutines.delay -import kotlinx.coroutines.withTimeout -import mu.KotlinLogging -import java.io.File - -/** - * This class manages the torrent files and the video pool. - * It is responsible for downloading the torrent files and caching the videos. - * It also provides the videos to the video adapter. - */ -class TorrentManager private constructor ( - private val cacheDir: File, - private val torrentDir: File, - private val cachingAmount: Int = 1, -) { - private val sessionManager = SessionManager() - private val logger = KotlinLogging.logger {} - private val torrentFiles = mutableListOf() - - val profile = Profile(HashMap()) - - private var lastTimeStamp: Long - private var currentIndex = 0 - - init { - clearMediaCache() - initializeSessionManager() - buildTorrentIndex() - initializeVideoPool() - lastTimeStamp = System.currentTimeMillis() - } - - companion object { - private lateinit var instance: TorrentManager - fun getInstance(context: Context): TorrentManager { - if (!::instance.isInitialized) { - instance = TorrentManager( - File("${context.cacheDir.absolutePath}/media"), - File("${context.cacheDir.absolutePath}/torrent"), - DeToksFragment.DEFAULT_CACHING_AMOUNT - ) - } - return instance - } - } - - fun notifyIncrease() { - Log.i("DeToks", "Increasing index ... ${(currentIndex + 1) % getNumberOfTorrents()}") - notifyChange((currentIndex + 1) % getNumberOfTorrents(), loopedToFront = true) - } - - fun notifyDecrease() { - Log.i("DeToks", "Decreasing index ... ${(currentIndex - 1) % getNumberOfTorrents()}") - notifyChange((currentIndex - 1) % getNumberOfTorrents()) - } - - /** - * This function provides the video at the given index. - * If the video is not downloaded yet, it will wait for it to be downloaded. - * If the video is not downloaded after the timeout, it will return the video anyway. - */ - suspend fun provideContent(index: Int = currentIndex, timeout: Long = 10000): TorrentMediaInfo { - Log.i("DeToks", "Providing content ... $index, ${index % getNumberOfTorrents()}") - val content = torrentFiles.gett(index % getNumberOfTorrents()) - - return try { - withTimeout(timeout) { - Log.i("DeToks", "Waiting for content ... $index") - while (!content.isDownloaded()) { - delay(100) - } - profile.updateEntryDuration( - MagnetLink.hashFromMagnet(content.handle.makeMagnetUri()), - content.getVideoDuration()) - } - content.asMediaInfo() - } catch (e: TimeoutCancellationException) { - Log.i("DeToks", "Timeout for content ... $index") - content.asMediaInfo() - } - } - - fun getNumberOfTorrents(): Int { - return torrentFiles.size - } - - /** - * Update the time and return the difference - */ - private fun updateTime() : Long { - val oldTimeStamp = lastTimeStamp - lastTimeStamp = System.currentTimeMillis() - return lastTimeStamp - oldTimeStamp - } - - /** - * This function updates the current index of the cache. - */ - private fun notifyChange( - newIndex: Int, - loopedToFront: Boolean = false - ) { - if (newIndex == currentIndex) { - return - } - if (cachingAmount * 2 + 1 >= getNumberOfTorrents()) { - val uri = torrentFiles.gett(currentIndex).handle.makeMagnetUri() - profile.updateEntryWatchTime( - MagnetLink.hashFromMagnet(uri), - updateTime(), - true) - profile.updateEntryDuration( - MagnetLink.hashFromMagnet(uri), - torrentFiles.gett(currentIndex).getVideoDuration()) - currentIndex = newIndex - return - } - - if (newIndex > currentIndex || loopedToFront) { - torrentFiles.gett(currentIndex - cachingAmount).deleteFile() - torrentFiles.gett(newIndex + cachingAmount).downloadFile() - } else { - torrentFiles.gett(currentIndex + cachingAmount).deleteFile() - torrentFiles.gett(newIndex - cachingAmount).downloadFile() - - } - val uri = torrentFiles.gett(currentIndex).handle.makeMagnetUri() - profile.updateEntryWatchTime( - MagnetLink.hashFromMagnet(uri), - updateTime(), - true) - profile.updateEntryDuration( - MagnetLink.hashFromMagnet(uri), - torrentFiles.gett(currentIndex).getVideoDuration()) - currentIndex = newIndex - } - - private fun initializeVideoPool() { - if (torrentFiles.size < cachingAmount * 2) { - logger.error("Not enough torrents to initialize video pool") - return - } - for (i in (currentIndex - cachingAmount)..(currentIndex + cachingAmount)) { - val torrent = torrentFiles.gett(i) - if (i == currentIndex) { - torrent.downloadWithMaxPriority() - } else { - torrent.downloadFile() - } - } - } - - /** - * This function builds the torrent index. It adds all the torrent files in the torrent - * directory to Libtorrent and selects all .mp4 files for download. - */ - private fun buildTorrentIndex() { - val files = torrentDir.listFiles() - if (files != null) { - for (file in files) { - if (file.extension == "torrent") { - val torrentInfo = TorrentInfo(file) - sessionManager.download(torrentInfo, cacheDir) - val handle = sessionManager.find(torrentInfo.infoHash()) - handle.setFlags(TorrentFlags.SEQUENTIAL_DOWNLOAD) - val priorities = Array(torrentInfo.numFiles()) { Priority.IGNORE } - handle.prioritizeFiles(priorities) - handle.pause() - for (it in 0 until torrentInfo.numFiles()) { - val fileName = torrentInfo.files().fileName(it) - if (fileName.endsWith(".mp4")) { - val torrent = TorrentHandler( - cacheDir, - handle, - torrentInfo.name(), - fileName, - it - ) - torrentFiles.add(torrent) - profile.torrents[torrent.handle.makeMagnetUri()] = ProfileEntry() - } - } - } - } - } - } - - private fun initializeSessionManager() { - sessionManager.addListener(object : AlertListener { - override fun types(): IntArray? { - return null - } - - @RequiresApi(Build.VERSION_CODES.N) - override fun alert(alert: Alert<*>) { - when (alert.type()) { - AlertType.ADD_TORRENT -> { - val a = alert as AddTorrentAlert - println("Torrent added: ${a.torrentName()}") - } - AlertType.BLOCK_FINISHED -> { - val a = alert as BlockFinishedAlert - val p = (a.handle().status().progress() * 100).toInt() - logger.info { ("Progress: " + p + " for torrent name: " + a.torrentName()) } - logger.info { sessionManager.stats().totalDownload() } - } - AlertType.TORRENT_FINISHED -> { - logger.info { "Torrent finished" } - } - else -> {} - } - } - }) - - sessionManager.start() - } - - private fun clearMediaCache() { - deleteRecursive(cacheDir) - } - - private fun deleteRecursive(fileOrDirectory: File) { - if (fileOrDirectory.isDirectory) for (child in fileOrDirectory.listFiles()!!) deleteRecursive( - child - ) - fileOrDirectory.delete() - } - - fun addTorrent(hash: Sha1Hash, magnet: String) { - if (sessionManager.find(hash) != null) return - - val torrentInfo = getInfoFromMagnet(magnet)?:return - - Log.d(DeToksCommunity.LOGGING_TAG,"Adding new torrent: ${torrentInfo.name()}") - - sessionManager.download(torrentInfo, cacheDir) - val handle = sessionManager.find(hash) - handle.setFlags(TorrentFlags.SEQUENTIAL_DOWNLOAD) - handle.prioritizeFiles(arrayOf(Priority.IGNORE)) - handle.pause() - - for (it in 0 until torrentInfo.numFiles()) { - val fileName = torrentInfo.files().fileName(it) - if (fileName.endsWith(".mp4")) { - val torrent = TorrentHandler( - cacheDir, - handle, - torrentInfo.name(), - fileName, - it - ) - torrentFiles.add(torrent) - profile.torrents[torrent.handle.makeMagnetUri()] = ProfileEntry() - } - } - } - - private fun getInfoFromMagnet(magnet: String): TorrentInfo? { - val bytes = sessionManager.fetchMagnet(magnet, 10)?:return null - return TorrentInfo.bdecode(bytes) - } - - fun getListOfTorrents(): List { - return torrentFiles.map {it.handle}.distinct() - } - - fun getWatchedTorrents(): List { - return (profile.torrents.keys).toList() - } - - fun getUnwatchedTorrents(): List { - return (torrentFiles.map { it.handle.makeMagnetUri() } subtract profile.torrents.keys).toList() - } - - class TorrentHandler( - private val cacheDir: File, - val handle: TorrentHandle, - val torrentName: String, - val fileName: String, - val fileIndex: Int - ) { - - var isDownloading: Boolean = false - - fun getPath(): String { - return "$cacheDir/$torrentName/$fileName" - } - - fun getVideoDuration() : Long { - if(!isDownloaded()) return 0 - val retriever = MediaMetadataRetriever() - retriever.setDataSource(getPath()) - return retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong() ?: 0 - } - - fun isPlayable(): Boolean { - return handle.fileProgress()[fileIndex] / handle.torrentFile().files() - .fileSize(fileIndex) > 0.8 - } - - fun isDownloaded(): Boolean { - return handle.fileProgress()[fileIndex] == handle.torrentFile().files() - .fileSize(fileIndex) - } - - fun deleteFile() { - handle.filePriority(fileIndex, Priority.IGNORE) - val file = File("$cacheDir/$torrentName/$fileName") - if (file.exists()) { - file.delete() - } - isDownloading = false - } - - fun downloadWithMaxPriority() { - downloadFile() - setMaximumPriority() - } - - fun downloadFile() { - if (isDownloading) { - return - } - isDownloading = true - handle.resume() - handle.forceRecheck() - handle.setFlags(TorrentFlags.SEQUENTIAL_DOWNLOAD) - handle.filePriority(fileIndex, Priority.NORMAL) - handle.pause() - handle.resume() - } - - fun setMaximumPriority() { - handle.resume() - handle.filePriority(fileIndex, Priority.SEVEN) - handle.pause() - handle.resume() - } - - fun asMediaInfo(): TorrentMediaInfo { - return TorrentMediaInfo(torrentName, fileName, getPath()) - } - - } - - // Extension functions to loop around the index of a lists. - private fun List.gett(index: Int): E = this[index.mod(size)] - - private fun List.gettIndex(index: Int): Int = index.mod(size) -} - -class TorrentMediaInfo( - val torrentName: String, - val fileName: String, - val fileURI: String, -) - -class MagnetLink { - companion object { - fun hashFromMagnet(magnet: String) : String { - return magnet - .substringAfter("xt=urn:btih:") - .substringBefore("&") - } - } -} diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/TransactionEngine.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/TransactionEngine.kt deleted file mode 100644 index 749f4a04e..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/TransactionEngine.kt +++ /dev/null @@ -1,114 +0,0 @@ -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) - } - } -} diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/TransactionMessage.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/TransactionMessage.kt deleted file mode 100644 index 5e1e8fd94..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/TransactionMessage.kt +++ /dev/null @@ -1,38 +0,0 @@ -package nl.tudelft.trustchain.detoks - -import nl.tudelft.ipv8.messaging.Deserializable -import nl.tudelft.ipv8.messaging.Serializable -import java.io.ByteArrayInputStream -import java.io.ByteArrayOutputStream -import java.io.ObjectInputStream -import java.io.ObjectOutputStream - -data class TransactionMessage( - val amount: Int, - val senderMID: String, - val recipientMID: String -) : Serializable { - - override fun serialize(): ByteArray { - val stream = ByteArrayOutputStream() - val oos = ObjectOutputStream(stream) - oos.writeInt(amount) - oos.writeUTF(senderMID) - oos.writeUTF(recipientMID) - oos.flush() - return stream.toByteArray() - } - - companion object Deserializer : Deserializable { - override fun deserialize(buffer: ByteArray, offset: Int): Pair { - val stream = ByteArrayInputStream(buffer, offset, buffer.size - offset) - val ois = ObjectInputStream(stream) - val amount = ois.readInt() - val senderMID = ois.readUTF() - val recipientMID = ois.readUTF() - val message = TransactionMessage(amount, senderMID, recipientMID) - return Pair(message, stream.available()) - } - } - -} diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/VideoAdapter.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/VideoAdapter.kt deleted file mode 100644 index a94de8f07..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/VideoAdapter.kt +++ /dev/null @@ -1,93 +0,0 @@ -package nl.tudelft.trustchain.detoks - -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ProgressBar -import android.widget.TextView -import android.widget.VideoView -import androidx.recyclerview.widget.RecyclerView -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - - -class VideosAdapter( - private val torrentManager: TorrentManager, - private val onPlaybackError: (() -> Unit)? = null, - private val videoScaling: Boolean = false, -) : - RecyclerView.Adapter() { - private val mVideoItems: List = - List(100) { VideoItem(torrentManager::provideContent) } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideoViewHolder { - return VideoViewHolder( - LayoutInflater.from(parent.context) - .inflate(R.layout.item_video, parent, false), - videoScaling, - ) - } - - - override fun onBindViewHolder(holder: VideoViewHolder, position: Int) { - Log.i("DeToks", "onBindViewHolder: $position") - holder.setVideoData(mVideoItems[position], position, onPlaybackError) - } - - override fun getItemCount(): Int { - return mVideoItems.size - } - - class VideoViewHolder(itemView: View, private val videoScaling: Boolean = false) : - RecyclerView.ViewHolder(itemView) { - var mVideoView: VideoView - var txtTitle: TextView - var txtDesc: TextView - var mProgressBar: ProgressBar - - init { - mVideoView = itemView.findViewById(R.id.videoView) - txtTitle = itemView.findViewById(R.id.txtTitle) - txtDesc = itemView.findViewById(R.id.txtDesc) - mProgressBar = itemView.findViewById(R.id.progressBar) - } - - fun setVideoData(item: VideoItem, position: Int, onPlaybackError: (() -> Unit)? = null) { - CoroutineScope(Dispatchers.Main).launch { - val content = item.content(position, 10000) - txtTitle.text = content.fileName - txtDesc.text = content.torrentName - mVideoView.setVideoPath(content.fileURI) - Log.i("DeToks", "Received content: ${content.fileURI}") - mVideoView.setOnPreparedListener { mp -> - mProgressBar.visibility = View.GONE - mp.start() - if (videoScaling) { - val videoRatio = mp.videoWidth / mp.videoHeight.toFloat() - val screenRatio = mVideoView.width / mVideoView.height.toFloat() - val scale = videoRatio / screenRatio - if (scale >= 1f) { - mVideoView.scaleX = scale - } else { - mVideoView.scaleY = 1f / scale - } - } - } - mVideoView.setOnCompletionListener { mp -> mp.start() } - mVideoView.setOnErrorListener { p1, what, extra -> - Log.i("DeToks", "onError: $p1, $what, $extra") - if (onPlaybackError != null) { - onPlaybackError() - true - } else { - true - } - } - } - } - } -} - -class VideoItem(val content: suspend (Int, Long) -> TorrentMediaInfo) diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/WalletManager.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/WalletManager.kt deleted file mode 100644 index 06006d553..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/WalletManager.kt +++ /dev/null @@ -1,26 +0,0 @@ -package nl.tudelft.trustchain.detoks - -import android.content.SharedPreferences -import android.content.Context - -class WalletManager(private val context: Context) { - private val mWalletPrefs: SharedPreferences = - context.getSharedPreferences(WALLET_PREFS_NAME, Context.MODE_PRIVATE) - - fun getOrCreateWallet(peerId: String): Wallet { - val balance = mWalletPrefs.getFloat(peerId, 10.0f) - return Wallet(balance) - } - - fun setWalletBalance(peerId: String, balance: Float) { - val editor = mWalletPrefs.edit() - editor.putFloat(peerId, balance) - editor.apply() - } - - companion object { - private const val WALLET_PREFS_NAME = "WalletPrefs" - } -} - -data class Wallet(var balance: Float = 10.0f) diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/BootGossiper.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/BootGossiper.kt deleted file mode 100644 index cb2c05cb9..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/BootGossiper.kt +++ /dev/null @@ -1,84 +0,0 @@ -package nl.tudelft.trustchain.detoks.gossiper - -import android.util.Log -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import nl.tudelft.ipv8.Peer -import nl.tudelft.ipv8.android.IPv8Android -import nl.tudelft.ipv8.messaging.Deserializable -import nl.tudelft.trustchain.detoks.DeToksCommunity - -class BootGossiper( - override val delay: Long, - override val peers: Int -) : Gossiper() { - - var maxLoops = (30000/delay).toInt() - - override fun startGossip(coroutineScope: CoroutineScope) { - coroutineScope.launch { - while (coroutineScope.isActive && running) { - if (maxLoops <= 1) - running = false - gossip() - maxLoops -= 1 - delay(delay) - } - } - } - - override suspend fun gossip() { - val deToksCommunity = IPv8Android.getInstance().getOverlay()!! - val randomPeers = pickRandomN(deToksCommunity.getPeers(), peers) - - randomPeers.forEach { - deToksCommunity.gossipWith( - it, - BootMessage(listOf()), - DeToksCommunity.MESSAGE_BOOT_REQUEST - ) - } - } - - companion object { - var running = true - - fun receivedRequest(peer: Peer) { - val data = listOf( - Pair("NetworkSize", NetworkSizeGossiper.networkSizeEstimate.toString()) - ) - val deToksCommunity = IPv8Android.getInstance().getOverlay()!! - deToksCommunity.gossipWith( - peer, - BootMessage(data), - DeToksCommunity.MESSAGE_BOOT_RESPONSE - ) - } - - fun receivedResponse(data: List>) { - data.forEach { - when(it.first) { - "NetworkSize" -> - NetworkSizeGossiper.networkSizeEstimate = it.second.toInt() - else -> - Log.d(DeToksCommunity.LOGGING_TAG, "Received data in boot message that wasn't recognized") - } - } - running = false - Log.d(DeToksCommunity.LOGGING_TAG, "Received boot response, shutting down gossiper") - } - } -} - -class BootMessage(data: List>) : GossipMessage(data) { - companion object Deserializer : Deserializable { - override fun deserialize(buffer: ByteArray, offset: Int): Pair { - val msg = deserializeMessage(buffer, offset){ - return@deserializeMessage Pair(it.getString(0), it.getString(1)) - } - return Pair(BootMessage(msg.first), msg.second) - } - } -} diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/GossipMessage.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/GossipMessage.kt deleted file mode 100644 index b2c279e6d..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/GossipMessage.kt +++ /dev/null @@ -1,29 +0,0 @@ -package nl.tudelft.trustchain.detoks.gossiper - -import nl.tudelft.ipv8.messaging.Serializable -import org.json.JSONArray - -abstract class GossipMessage( - val data: List> - ) : Serializable { - - - override fun serialize(): ByteArray { - return JSONArray(data.map { JSONArray(arrayOf(it.first, it.second)) }.toTypedArray()) - .toString().toByteArray() - } - - companion object Deserializer { - - fun deserializeMessage(buffer: ByteArray, offset: Int, func: (JSONArray) -> T): Pair, Int> { - val tempStr = String(buffer, offset,buffer.size - offset) - val json = JSONArray(tempStr) - val entries = mutableListOf() - - for (i in 0 until json.length()) - entries.add(func(json.getJSONArray(i))) - - return Pair(entries, offset) - } - } -} diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/Gossiper.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/Gossiper.kt deleted file mode 100644 index a69f835e1..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/Gossiper.kt +++ /dev/null @@ -1,40 +0,0 @@ -package nl.tudelft.trustchain.detoks.gossiper - -import kotlinx.coroutines.CoroutineScope -import nl.tudelft.ipv8.util.random - -abstract class Gossiper { - - /** - * Interval between gossips. - */ - abstract val delay: Long - - /** - * Number of peers to gossip with. - */ - abstract val peers: Int - - - /** - * Instantiates the gossiping process. - */ - abstract fun startGossip(coroutineScope: CoroutineScope) - - /** - * The gossip routine. - */ - abstract suspend fun gossip() - - /** - * Returns a list of n random elements from collection. - * If the collection is empty returns an empty list. - * If n is larger than the collection size, returns the collection. - */ - protected fun pickRandomN(collection: List, n: Int): List { - if (collection.isEmpty()) return listOf() - if (collection.size < n) return collection - - return collection.random(n).toList() - } -} diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/GossiperService.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/GossiperService.kt deleted file mode 100644 index 24e59fb15..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/GossiperService.kt +++ /dev/null @@ -1,50 +0,0 @@ -package nl.tudelft.trustchain.detoks.gossiper - -import android.app.Service -import android.content.Intent -import android.os.Binder -import android.os.IBinder -import kotlinx.coroutines.* -import nl.tudelft.ipv8.android.IPv8Android -import nl.tudelft.trustchain.detoks.DeToksCommunity -import kotlin.system.exitProcess - -class GossiperService : Service() { - private val binder = LocalBinder() - private val scope = CoroutineScope(Dispatchers.IO) - - /** - * Add all gossiper services in the list to have them started by this service. - */ - private val gossiperList: List = listOf( - BootGossiper(1000L, 4), - NetworkSizeGossiper(30000L, 4, 1), - TorrentGossiper(4000L, 4, 4, this), - WatchTimeGossiper(4000L, 4, 4, this) - ) - - - inner class LocalBinder : Binder() { - fun getService(): GossiperService = this@GossiperService - } - - override fun onBind(intent: Intent): IBinder { - return binder - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - return START_NOT_STICKY - } - - override fun onCreate() { - super.onCreate() - gossiperList.forEach { it.startGossip(scope) } - } - - override fun onDestroy() { - scope.cancel() - super.onDestroy() - - exitProcess(0) - } -} diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/NetworkSizeGossiper.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/NetworkSizeGossiper.kt deleted file mode 100644 index 6e6a35c82..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/NetworkSizeGossiper.kt +++ /dev/null @@ -1,115 +0,0 @@ -package nl.tudelft.trustchain.detoks.gossiper - -import android.util.Log -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import nl.tudelft.ipv8.Peer -import nl.tudelft.ipv8.android.IPv8Android -import nl.tudelft.ipv8.messaging.Deserializable -import nl.tudelft.trustchain.detoks.DeToksCommunity -import kotlin.random.Random.Default.nextDouble - -class NetworkSizeGossiper( - override val delay: Long, - override val peers: Int, - private val leaders: Int -) : Gossiper() { - - private var firstCycle = true - - override fun startGossip(coroutineScope: CoroutineScope) { - coroutineScope.launch { - while (coroutineScope.isActive) { - if (firstCycle) { - firstCycle = false - delay(System.currentTimeMillis() % delay) - } - gossip() - delay(delay) - } - } - } - - override suspend fun gossip() { - val deToksCommunity = IPv8Android.getInstance().getOverlay()!! - - if (leaderEstimates.isNotEmpty()) - networkSizeEstimate = (1 / leaderEstimates.minOfOrNull { it.second }!!).toInt() - - awaitingResponse.clear() - - val chanceLeader = leaders / (networkSizeEstimate.toDouble()) - Log.d(DeToksCommunity.LOGGING_TAG, "Chance to become leader: $chanceLeader, leaders: $leaders, networksize estimate: $networkSizeEstimate") - leaderEstimates = if (nextDouble() < chanceLeader) - listOf(Pair(deToksCommunity.myPeer.mid, 1.0)) - else listOf() - - val randomPeers = pickRandomN(deToksCommunity.getPeers(), peers) - randomPeers.forEach { - awaitingResponse.add(it.mid) - deToksCommunity.gossipWith( - it, - NetworkSizeMessage(leaderEstimates), - DeToksCommunity.MESSAGE_NETWORK_SIZE_ID - ) - } - } - - companion object { - var networkSizeEstimate = 1 - - private var leaderEstimates = listOf>() - - private val awaitingResponse = mutableListOf() - - /** - * Applies counting algorithm to determine network size. - */ - fun receivedResponse(msg: NetworkSizeMessage, peer: Peer) { - if (!awaitingResponse.contains(peer.mid)) { - val deToksCommunity = IPv8Android.getInstance().getOverlay()!! - deToksCommunity.gossipWith( - peer, - NetworkSizeMessage(leaderEstimates), - DeToksCommunity.MESSAGE_NETWORK_SIZE_ID - ) - } - - val myKeys = leaderEstimates.map { it.first } - val otherKeys = msg.data.map { it.first } - - val myUnique = leaderEstimates - .filter { !otherKeys.contains(it.first) } - .map { Pair(it.first, it.second / 2) } - - val otherUnique = msg.data - .filter { !myKeys.contains(it.first) } - .map { Pair(it.first, it.second / 2) } - - val shared = leaderEstimates - .filter { otherKeys.contains(it.first) } - .map { - Pair( - it.first, it.second + ( - msg.data.find { it1 -> it1.first == it.first }?.second ?: 0.0 - ) - ) - } - - leaderEstimates = listOf(myUnique, otherUnique, shared).flatten() - } - } -} - -class NetworkSizeMessage(data: List>) : GossipMessage(data) { - companion object Deserializer : Deserializable { - override fun deserialize(buffer: ByteArray, offset: Int): Pair { - val msg = deserializeMessage(buffer, offset){ - return@deserializeMessage Pair(it.getString(0), it.getDouble(1)) - } - return Pair(NetworkSizeMessage(msg.first), msg.second) - } - } -} diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/TorrentGossiper.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/TorrentGossiper.kt deleted file mode 100644 index 46a7e93f8..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/TorrentGossiper.kt +++ /dev/null @@ -1,60 +0,0 @@ -package nl.tudelft.trustchain.detoks.gossiper - -import android.content.Context -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import nl.tudelft.ipv8.android.IPv8Android -import nl.tudelft.ipv8.messaging.Deserializable -import nl.tudelft.ipv8.util.random -import nl.tudelft.trustchain.detoks.DeToksCommunity -import nl.tudelft.trustchain.detoks.MagnetLink -import nl.tudelft.trustchain.detoks.TorrentManager - -class TorrentGossiper( - override val delay: Long, - override val peers: Int, - private val blocks: Int, - val context: Context -) : Gossiper() { - - override fun startGossip(coroutineScope: CoroutineScope) { - coroutineScope.launch { - while (coroutineScope.isActive) { - gossip() - delay(delay) - } - } - } - - override suspend fun gossip() { - val deToksCommunity = IPv8Android.getInstance().getOverlay()!! - val randomPeers = pickRandomN(deToksCommunity.getPeers(), peers) - val handlers = TorrentManager.getInstance(context).getListOfTorrents() - if (randomPeers.isEmpty() || handlers.isEmpty()) return - - val max = if (handlers.size < blocks) handlers.size else blocks - val randomMagnets = handlers.random(max).map { it.makeMagnetUri() } - - if(randomMagnets.isNotEmpty()) - randomPeers.forEach { - deToksCommunity.gossipWith( - it, - TorrentMessage(randomMagnets.map { it2 -> Pair(MagnetLink.hashFromMagnet(it2), it2) }), - DeToksCommunity.MESSAGE_TORRENT_ID - ) - } - } -} - -class TorrentMessage(data: List>) : GossipMessage(data) { - companion object Deserializer : Deserializable { - override fun deserialize(buffer: ByteArray, offset: Int): Pair { - val msg = deserializeMessage(buffer, offset){ - return@deserializeMessage Pair(it.getString(0), it.getString(1)) - } - return Pair(TorrentMessage(msg.first), msg.second) - } - } -} diff --git a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/WatchTimeGossiper.kt b/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/WatchTimeGossiper.kt deleted file mode 100644 index 217672af4..000000000 --- a/detoks/src/main/java/nl/tudelft/trustchain/detoks/gossiper/WatchTimeGossiper.kt +++ /dev/null @@ -1,59 +0,0 @@ -package nl.tudelft.trustchain.detoks.gossiper - -import android.content.Context -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import nl.tudelft.ipv8.android.IPv8Android -import nl.tudelft.ipv8.messaging.Deserializable -import nl.tudelft.trustchain.detoks.DeToksCommunity -import nl.tudelft.trustchain.detoks.TorrentManager - -class WatchTimeGossiper( - override val delay: Long, - override val peers: Int, - private val blocks: Int, - private val context: Context - - ) : Gossiper() { - - override fun startGossip(coroutineScope: CoroutineScope) { - coroutineScope.launch { - while (coroutineScope.isActive) { - gossip() - delay(delay) - } - } - } - - override suspend fun gossip() { - val deToksCommunity = IPv8Android.getInstance().getOverlay()!! - - val randomPeers = pickRandomN(deToksCommunity.getPeers(), peers) - val randomProfileEntries = pickRandomN( - TorrentManager.getInstance(context).profile.torrents.entries.map { Pair(it.key, it.value.watchTime) }, - blocks - ) - if (randomPeers.isEmpty() || randomProfileEntries.isEmpty()) return - - randomPeers.forEach { - deToksCommunity.gossipWith( - it, - WatchTimeMessage(randomProfileEntries), - DeToksCommunity.MESSAGE_WATCH_TIME_ID - ) - } - } -} - -class WatchTimeMessage(data: List>) : GossipMessage(data) { - companion object Deserializer : Deserializable { - override fun deserialize(buffer: ByteArray, offset: Int): Pair { - val msg = deserializeMessage(buffer, offset){ - return@deserializeMessage Pair(it.getString(0), it.getLong(1)) - } - return Pair(WatchTimeMessage(msg.first), msg.second) - } - } -} diff --git a/detoks/src/main/res/drawable/indicator_offline.xml b/detoks/src/main/res/drawable/indicator_offline.xml deleted file mode 100644 index e9424ceaa..000000000 --- a/detoks/src/main/res/drawable/indicator_offline.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - diff --git a/detoks/src/main/res/drawable/indicator_online.xml b/detoks/src/main/res/drawable/indicator_online.xml deleted file mode 100644 index 8f42993a9..000000000 --- a/detoks/src/main/res/drawable/indicator_online.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - diff --git a/detoks/src/main/res/layout/fragment_detoks.xml b/detoks/src/main/res/layout/fragment_detoks.xml deleted file mode 100644 index 83292c21c..000000000 --- a/detoks/src/main/res/layout/fragment_detoks.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - diff --git a/detoks/src/main/res/layout/item_video.xml b/detoks/src/main/res/layout/item_video.xml deleted file mode 100644 index 89e71504d..000000000 --- a/detoks/src/main/res/layout/item_video.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/detoks/src/main/res/menu/debug_options.xml b/detoks/src/main/res/menu/debug_options.xml deleted file mode 100644 index 231ac8b17..000000000 --- a/detoks/src/main/res/menu/debug_options.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/detoks/src/main/res/navigation/nav_graph_detoks.xml b/detoks/src/main/res/navigation/nav_graph_detoks.xml deleted file mode 100644 index 8a118c39f..000000000 --- a/detoks/src/main/res/navigation/nav_graph_detoks.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - diff --git a/detoks/src/main/res/raw/detoks.torrent b/detoks/src/main/res/raw/detoks.torrent deleted file mode 100644 index 09c9be16a..000000000 Binary files a/detoks/src/main/res/raw/detoks.torrent and /dev/null differ diff --git a/detoks/src/main/res/raw/video.mp4 b/detoks/src/main/res/raw/video.mp4 deleted file mode 100644 index 8345f9f5f..000000000 Binary files a/detoks/src/main/res/raw/video.mp4 and /dev/null differ diff --git a/detoks/src/main/res/raw/video1.mp4 b/detoks/src/main/res/raw/video1.mp4 deleted file mode 100644 index d24e24d96..000000000 Binary files a/detoks/src/main/res/raw/video1.mp4 and /dev/null differ diff --git a/detoks/src/main/res/raw/video2.mp4 b/detoks/src/main/res/raw/video2.mp4 deleted file mode 100644 index 4817145bb..000000000 Binary files a/detoks/src/main/res/raw/video2.mp4 and /dev/null differ diff --git a/detoks/src/main/res/values/strings.xml b/detoks/src/main/res/values/strings.xml deleted file mode 100644 index 2acc09455..000000000 --- a/detoks/src/main/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - DeToks - diff --git a/detoks/src/main/res/values/styles.xml b/detoks/src/main/res/values/styles.xml deleted file mode 100644 index 44041c8f4..000000000 --- a/detoks/src/main/res/values/styles.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/detoks/src/test/java/nl/tudelft/trustchain/debug/ExampleUnitTest.kt b/detoks/src/test/java/nl/tudelft/trustchain/debug/ExampleUnitTest.kt deleted file mode 100644 index 6c3b3f2a4..000000000 --- a/detoks/src/test/java/nl/tudelft/trustchain/debug/ExampleUnitTest.kt +++ /dev/null @@ -1,16 +0,0 @@ -package nl.tudelft.trustchain.debug - -import org.junit.Assert.assertEquals -import org.junit.Test - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} diff --git a/distributedai/.gitignore b/distributedai/.gitignore deleted file mode 100644 index 796b96d1c..000000000 --- a/distributedai/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/distributedai/build.gradle b/distributedai/build.gradle deleted file mode 100644 index a10d0fd32..000000000 --- a/distributedai/build.gradle +++ /dev/null @@ -1,76 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' - -android { - compileSdkVersion 33 - - defaultConfig { - minSdkVersion 22 - targetSdkVersion 33 - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles 'consumer-rules.pro' - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = "1.8" - } - - buildFeatures { - viewBinding = true - } - namespace 'nl.tudelft.trustchain.distributedAI' -} - -dependencies { - implementation project(':common') - - // AndroidX - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.core:core-ktx:1.9.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation "androidx.recyclerview:recyclerview:1.1.0" - implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" - implementation "androidx.navigation:navigation-ui-ktx:$nav_version" - implementation "androidx.fragment:fragment-ktx:$fragment_version" - implementation "androidx.preference:preference:1.1.0" - implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" - - // Material - implementation 'com.google.android.material:material:1.1.0' - - // Kotlin - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3' - implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - - // Logging - implementation 'io.github.microutils:kotlin-logging:1.7.7' - implementation 'com.github.tony19:logback-android:2.0.0' - - implementation 'com.github.MattSkala:recyclerview-itemadapter:0.4' - - - implementation "com.androidplot:androidplot-core:1.5.7" - - // Testing - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' -} diff --git a/distributedai/consumer-rules.pro b/distributedai/consumer-rules.pro deleted file mode 100644 index e69de29bb..000000000 diff --git a/distributedai/docs/README.md b/distributedai/docs/README.md deleted file mode 100644 index 85f136963..000000000 --- a/distributedai/docs/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Distributed-AI - -Distributed-AI is an Android application built on top of [IPv8](https://github.com/Tribler/kotlin-ipv8) -and [Trustchain](https://github.com/Tribler/kotlin-ipv8/blob/master/doc/TrustChainCommunity.md), - and is integrated into the [Trustchain Superapp](https://github.com/Tribler/trustchain-superapp). - -It is a proof-of-concept of distributed, server less, machine learning. The base concept comes from -Róbert Ormándi from the University of Szeged (paper available [here](https://onlinelibrary.wiley.com/doi/abs/10.1002/cpe.2858)). - -Unlike regular machine learning algorithms, which involves the data being present on a single computer, -this distributed machine learning algorithm is capable to learn, by analysing the data present on each -participating peer. The data never leaves the possessor, such that our algorithm could handle -sensitive personal information. Moreso, there is no single server learning a model from the data: every -participating peer has access to the learned model. - -Our current implementation is far from finished. It takes numbers as input and performs a simple linear -regression. It isn't fully integrated with Trustchain's infrastructure, the data is still stored locally. -However, the algorithm performs our algorithm as if the data came from different sources, emulating -being server less. - -**First Time Launch Screens** -
- - - - - - - diff --git a/distributedai/docs/data_picture.png b/distributedai/docs/data_picture.png deleted file mode 100644 index e5418731f..000000000 Binary files a/distributedai/docs/data_picture.png and /dev/null differ diff --git a/distributedai/docs/empty_picture.png b/distributedai/docs/empty_picture.png deleted file mode 100644 index 6b5601e0a..000000000 Binary files a/distributedai/docs/empty_picture.png and /dev/null differ diff --git a/distributedai/docs/menu_picture.png b/distributedai/docs/menu_picture.png deleted file mode 100644 index d7b121d93..000000000 Binary files a/distributedai/docs/menu_picture.png and /dev/null differ diff --git a/distributedai/proguard-rules.pro b/distributedai/proguard-rules.pro deleted file mode 100644 index f1b424510..000000000 --- a/distributedai/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/distributedai/src/androidTest/java/com/example/dna/ExampleInstrumentedTest.kt b/distributedai/src/androidTest/java/com/example/dna/ExampleInstrumentedTest.kt deleted file mode 100644 index 8c45c2657..000000000 --- a/distributedai/src/androidTest/java/com/example/dna/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.example.dna - -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 - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.example.dna.test", appContext.packageName) - } -} diff --git a/distributedai/src/main/AndroidManifest.xml b/distributedai/src/main/AndroidManifest.xml deleted file mode 100644 index cc947c567..000000000 --- a/distributedai/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/DistributedActivity.java b/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/DistributedActivity.java deleted file mode 100644 index e86e91767..000000000 --- a/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/DistributedActivity.java +++ /dev/null @@ -1,59 +0,0 @@ -package nl.tudelft.trustchain.distributedAI; - -import android.os.Bundle; -import android.view.View; -import android.widget.EditText; - -import com.androidplot.xy.XYPlot; - -import nl.tudelft.trustchain.common.BaseActivity; -import nl.tudelft.trustchain.distributedAI.java.Entity; - -public class DistributedActivity extends BaseActivity { - @Override - public int getNavigationGraph() { - return R.navigation.nav_graph_distributed; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_distributed); - - } - - public void sendMessage(View v) { - EditText x_val = findViewById(R.id.dna_x_value); - String x0 = x_val.getText().toString(); - - EditText x_val_2 = findViewById(R.id.dna_x_value2); - String x1 = x_val_2.getText().toString(); - - EditText y_val = findViewById(R.id.dna_y_value); - String y0 = y_val.getText().toString(); - - EditText y_val_2 = findViewById(R.id.dna_y_value2); - String y1 = y_val_2.getText().toString(); - - EditText nr_iterations = findViewById(R.id.dna_iterations); - String itr = nr_iterations.getText().toString(); - - //we add an extra point (1,2), in order to never get a line with 0 error - //so no need to deal with NaN or infinity - double[] x = {Double.parseDouble(x0), Double.parseDouble(x1), 1.0}; - double[] y = {Double.parseDouble(y0), Double.parseDouble(y1), .0}; - - - XYPlot plot = findViewById(R.id.plot); - - plot.clear(); - - Entity entity = new Entity(x, y, plot, Integer.parseInt(itr)); - - entity.run(); - plot.invalidate(); - - - } - -} diff --git a/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/DistributedFragmentJava.java b/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/DistributedFragmentJava.java deleted file mode 100644 index 3165c8178..000000000 --- a/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/DistributedFragmentJava.java +++ /dev/null @@ -1,21 +0,0 @@ -package nl.tudelft.trustchain.distributedAI; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -import androidx.fragment.app.Fragment; - -public class DistributedFragmentJava extends Fragment { - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - - return (FrameLayout) inflater.inflate(R.layout.activity_distributed, container, false); - } - - -} diff --git a/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/java/Entity.java b/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/java/Entity.java deleted file mode 100644 index d8b1193ad..000000000 --- a/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/java/Entity.java +++ /dev/null @@ -1,157 +0,0 @@ -package nl.tudelft.trustchain.distributedAI.java; - - -import android.graphics.Color; - -import com.androidplot.xy.LineAndPointFormatter; -import com.androidplot.xy.SimpleXYSeries; -import com.androidplot.xy.XYPlot; -import com.androidplot.xy.XYSeries; - -import java.util.ArrayList; - -import nl.tudelft.trustchain.distributedAI.java.utils.LinearRegression; - - -public class Entity { - - - /** - * The confidence that we want - */ - public static double theta = 0.99; - /** - * The ABSOLUTE MINIMUM confidence that we are able to tolerate - */ - public static double theta_min = 0.95; - double[] x; - double[] y; - /** - * List of machines. - */ - ArrayList list = new ArrayList<>(); - /** - * The number of interations (cycles). - */ - private int N; - /** - * used for graphing - */ - //XYSeries series = new XYSeries("Convergence over time"); - private XYPlot plot; - - - public Entity(double[] x, double[] y, XYPlot plot, int itr) { - this.x = x; - this.y = y; - this.plot = plot; - this.N = itr; - pupulate(x, y); - } - - - public void run() { - - perform(); - - Pair average = average(); - - System.out.println("OUR_AVERAGE SLOPE: " + average.X() + " OUR AVERAGE INTERCEPT: " + average.Y()); - - System.out.println("[BEST_FIT LINE]: SLOPE:" + new LinearRegression(x, y).slope() + " intercept: " + new LinearRegression(x, y).intercept()); - - System.out.println("BEST FIT LINE error:" + LSQRS(x, y, new LinearRegression(x, y).slope(), new LinearRegression(x, y).intercept())); - - System.out.println("OUR LINE error:" + LSQRS(x, y, average.X(), average.Y())); - double perfectError_maybeNan = LSQRS(x, y, new LinearRegression(x, y).slope(), new LinearRegression(x, y).intercept()); - double perfect_error = Double.isNaN(perfectError_maybeNan) ? 0.01 : perfectError_maybeNan; - System.out.println("RELATIVE ERROR: " + perfect_error / LSQRS(x, y, average.X(), average.Y())); - - double relative_error = LSQRS(x, y, new LinearRegression(x, y).slope(), new LinearRegression(x, y).intercept()) / Math.max(0.001, LSQRS(x, y, average.X(), average.Y())); - } - - - private double LSQRS(double[] x, double[] y, double slope, double intercept) { - - double RESULT = 0; - - for (int i = 0; i < x.length; i++) { - RESULT += (y[i] - (x[i] * slope + intercept)) * (y[i] - (x[i] * slope + intercept)); - } - - return RESULT; - } - - - private void perform() { - - - int it = N; - int div = Math.max(1, N / 10); - - ArrayList xAxis = new ArrayList<>(); - ArrayList yAxis = new ArrayList<>(); - - while (it > 0) { - - for (int i = 0; i < list.size(); i++) { - int rand2 = (int) (Math.random() * (list.size())); - - list.get(rand2).updateUM(list.get(i)); - } - Pair average = average(); - - if (it % div == 0) { - xAxis.add((double) N - it); - - double perfectError_maybeNan = LSQRS(x, y, new LinearRegression(x, y).slope(), new LinearRegression(x, y).intercept()); - double perfect_error = Double.isNaN(perfectError_maybeNan) ? 0.00001 : perfectError_maybeNan; - - yAxis.add(perfect_error / LSQRS(x, y, average.X(), average.Y())); - - } - - it--; - } - XYSeries series1 = new SimpleXYSeries(xAxis, yAxis, "series1"); - - LineAndPointFormatter series1Format = new LineAndPointFormatter(Color.RED, Color.GREEN, Color.BLUE, null); - - plot.addSeries(series1, series1Format); - - - } - - - private Pair average() { - - double sumx = 0, sumy = 0; - - for (int i = 0; i < list.size(); i++) { - sumx += list.get(i).getIntercept(); - sumy += list.get(i).getBias(); - } - return new Pair(sumx / list.size(), sumy / list.size()); - } - - - private void pupulate(double[] x, double[] y) { - for (int i = 0; i < x.length; i++) - list.add(new Machine(x[i], y[i])); - } - - - private void print(double[] x, double[] y) { - for (int i = 0; i < list.size(); i++) - System.out.println(list.get(i)); - - System.out.println("THE REAL VALUE IS:"); - System.out.println("SLOPE: " + new LinearRegression(x, y).slope()); - System.out.println("INTERCEPT: " + new LinearRegression(x, y).intercept()); - } - - - public XYPlot getPlot() { - return this.plot; - } -} diff --git a/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/java/Machine.java b/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/java/Machine.java deleted file mode 100644 index 4584ad2b1..000000000 --- a/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/java/Machine.java +++ /dev/null @@ -1,92 +0,0 @@ -package nl.tudelft.trustchain.distributedAI.java; - -public class Machine { - - static double alpha = 0.005; - - private Pair pair; - private double intercept; //slope //s - private double bias; - - /** - * Constructor, initializes the machine. - * - * @param x - first argument. - * @param y - second argument. - */ - @SuppressWarnings("all") - public Machine(double x, double y) { - this.pair = new Pair(x, y); - - this.intercept = 0; - this.bias = 0; - } - - - //TODO! WHY DOES IT NOT CONVERGE ????? - public void updateMU(Machine other) { - //compute the average - double avg_intercept = (this.intercept + other.getIntercept()) * 0.5; - double avg_bias = (this.bias + other.bias) * 0.5; - - - double interm_intercept = DerivativeWithRespectToIntercept(this.pair.Y(), avg_intercept, this.pair.X(), avg_bias); - double interm_slope = DerivativeWithRespectToSlope(this.pair.Y(), avg_intercept, this.pair.X(), avg_bias); - - - //update - this.intercept = this.intercept - (interm_slope * alpha); - this.bias = this.bias - (interm_intercept * alpha); - } - - - public void updateUM(Machine other) { - double interm_intercept = DerivativeWithRespectToIntercept(this.pair.Y(), this.getIntercept(), this.pair.X(), this.getBias()); - double interm_slope = DerivativeWithRespectToSlope(this.pair.Y(), this.getIntercept(), this.pair.X(), this.getBias()); - - //update - this.intercept = this.intercept - (interm_slope * alpha); - this.bias = this.bias - (interm_intercept * alpha); - - double interm_intercept2 = DerivativeWithRespectToIntercept(this.pair.Y(), other.getIntercept(), this.pair.X(), other.getBias()); - double interm_slope2 = DerivativeWithRespectToSlope(this.pair.Y(), other.getIntercept(), this.pair.X(), other.getBias()); - - //update - double otherintercept = other.intercept - (interm_slope2 * alpha); - double otherbias = other.bias - (interm_intercept2 * alpha); - - //only then average - this.intercept = (this.intercept + otherintercept) * 0.5; - this.bias = (this.bias + otherbias) * 0.5; - } - - - private double DerivativeWithRespectToIntercept(double y, double s, double x, double b) { - return (-2) * (y - s * x - b); - } - - private double DerivativeWithRespectToSlope(double y, double s, double x, double b) { - return (-2) * x * (y - s * x - b); - } - - - //getters and setters - public double getIntercept() { - return intercept; - } - - - public double getBias() { - return bias; - } - - - @Override - public String toString() { - return "Machine{" + - "intercept=" + intercept + - ", bias=" + bias + - '}'; - } - -} diff --git a/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/java/Pair.java b/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/java/Pair.java deleted file mode 100644 index 5930527b7..000000000 --- a/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/java/Pair.java +++ /dev/null @@ -1,21 +0,0 @@ -package nl.tudelft.trustchain.distributedAI.java; - -public class Pair { - private T key; - private T value; - - - public Pair(T value, T key) { - this.key = key; - this.value = value; - } - - - public T Y() { - return key; - } - - public T X() { - return value; - } -} diff --git a/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/java/utils/LinearRegression.java b/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/java/utils/LinearRegression.java deleted file mode 100644 index a73caf2c1..000000000 --- a/distributedai/src/main/java/nl/tudelft/trustchain/distributedAI/java/utils/LinearRegression.java +++ /dev/null @@ -1,175 +0,0 @@ -package nl.tudelft.trustchain.distributedAI.java.utils; /****************************************************************************** - * Compilation: javac utils.LinearRegression.java - * Execution: java utils.LinearRegression - * Dependencies: none - * - * Compute least squares solution to y = beta * x + alpha. - * Simple linear regression. - * - ******************************************************************************/ - -/** - * The {@code utils.LinearRegression} class performs a simple linear regression - * on an set of n data points (yi, xi). - * That is, it fits a straight line y = α + β x, - * (where y is the response variable, x is the predictor variable, - * α is the y-intercept, and β is the slope) - * that minimizes the sum of squared residuals of the linear regression model. - * It also computes associated statistics, including the coefficient of - * determination R2 and the standard deviation of the - * estimates for the slope and y-intercept. - * - * @author Robert Sedgewick - * @author Kevin Wayne - */ -public class LinearRegression { - private final double intercept, slope; - private final double r2; - private final double svar0, svar1; - - /** - * Performs a linear regression on the data points {@code (y[i], x[i])}. - * - * @param x the values of the predictor variable - * @param y the corresponding values of the response variable - * @throws IllegalArgumentException if the lengths of the two arrays are not equal - */ - public LinearRegression(double[] x, double[] y) { - if (x.length != y.length) { - throw new IllegalArgumentException("array lengths are not equal"); - } - int n = x.length; - - // first pass - double sumx = 0.0, sumy = 0.0, sumx2 = 0.0; - for (int i = 0; i < n; i++) { - sumx += x[i]; - sumx2 += x[i] * x[i]; - sumy += y[i]; - } - double xbar = sumx / n; - double ybar = sumy / n; - - // second pass: compute summary statistics - double xxbar = 0.0, yybar = 0.0, xybar = 0.0; - for (int i = 0; i < n; i++) { - xxbar += (x[i] - xbar) * (x[i] - xbar); - yybar += (y[i] - ybar) * (y[i] - ybar); - xybar += (x[i] - xbar) * (y[i] - ybar); - } - slope = xybar / xxbar; - intercept = ybar - slope * xbar; - - // more statistical analysis - double rss = 0.0; // residual sum of squares - double ssr = 0.0; // regression sum of squares - for (int i = 0; i < n; i++) { - double fit = slope * x[i] + intercept; - rss += (fit - y[i]) * (fit - y[i]); - ssr += (fit - ybar) * (fit - ybar); - } - - int degreesOfFreedom = n - 2; - r2 = ssr / yybar; - double svar = rss / degreesOfFreedom; - svar1 = svar / xxbar; - svar0 = svar / n + xbar * xbar * svar1; - } - - /** - * Returns the y-intercept α of the best of the best-fit line y = α + β x. - * - * @return the y-intercept α of the best-fit line y = α + β x - */ - public double intercept() { - return intercept; - } - - /** - * Returns the slope β of the best of the best-fit line y = α + β x. - * - * @return the slope β of the best-fit line y = α + β x - */ - public double slope() { - return slope; - } - - /** - * Returns the coefficient of determination R2. - * - * @return the coefficient of determination R2, - * which is a real number between 0 and 1 - */ - public double R2() { - return r2; - } - - /** - * Returns the standard error of the estimate for the intercept. - * - * @return the standard error of the estimate for the intercept - */ - public double interceptStdErr() { - return Math.sqrt(svar0); - } - - /** - * Returns the standard error of the estimate for the slope. - * - * @return the standard error of the estimate for the slope - */ - public double slopeStdErr() { - return Math.sqrt(svar1); - } - - /** - * Returns the expected response {@code y} given the value of the predictor - * variable {@code x}. - * - * @param x the value of the predictor variable - * @return the expected response {@code y} given the value of the predictor - * variable {@code x} - */ - public double predict(double x) { - return slope * x + intercept; - } - - /** - * Returns a string representation of the simple linear regression model. - * - * @return a string representation of the simple linear regression model, - * including the best-fit line and the coefficient of determination - * R2 - */ - public String toString() { - StringBuilder s = new StringBuilder(); - s.append(String.format("%.2f n + %.2f", slope(), intercept())); - s.append(" (R^2 = " + String.format("%.3f", R2()) + ")"); - return s.toString(); - } - -} - -/****************************************************************************** - * Copyright 2002-2018, Robert Sedgewick and Kevin Wayne. - * - * This file is part of algs4.jar, which accompanies the textbook - * - * Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne, - * Addison-Wesley Professional, 2011, ISBN 0-321-57351-X. - * http://algs4.cs.princeton.edu - * - * - * algs4.jar is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * algs4.jar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with algs4.jar. If not, see http://www.gnu.org/licenses. - ******************************************************************************/ diff --git a/distributedai/src/main/res/drawable/indicator_offline.xml b/distributedai/src/main/res/drawable/indicator_offline.xml deleted file mode 100644 index e9424ceaa..000000000 --- a/distributedai/src/main/res/drawable/indicator_offline.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - diff --git a/distributedai/src/main/res/drawable/indicator_online.xml b/distributedai/src/main/res/drawable/indicator_online.xml deleted file mode 100644 index 8f42993a9..000000000 --- a/distributedai/src/main/res/drawable/indicator_online.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - diff --git a/distributedai/src/main/res/layout/activity_distributed.xml b/distributedai/src/main/res/layout/activity_distributed.xml deleted file mode 100644 index 5cd383a8e..000000000 --- a/distributedai/src/main/res/layout/activity_distributed.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - -