diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/CoinCommunity.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/CoinCommunity.kt index 7c67a78bb..7e6a43b73 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/CoinCommunity.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/CoinCommunity.kt @@ -3,6 +3,7 @@ package nl.tudelft.trustchain.currencyii import android.app.Activity import android.content.Context import android.util.Log +import android.widget.Toast import nl.tudelft.ipv8.Community import nl.tudelft.ipv8.Overlay import nl.tudelft.ipv8.Peer @@ -56,6 +57,8 @@ open class CoinCommunity constructor( messageHandlers[MessageId.ELECTED_RESPONSE] = ::onElectedResponsePacket messageHandlers[MessageId.ALIVE_RESPONSE] = ::onAliveResponsePacket messageHandlers[MessageId.SIGNATURE_ASK] = ::onSignPayloadResponsePacket + messageHandlers[MessageId.JOIN_DAO_DATA] = ::onDaoJoinDataPacket + } private fun getTrustChainCommunity(): TrustChainCommunity { @@ -298,6 +301,29 @@ open class CoinCommunity constructor( this.onSignPayloadResponse(peer, payload) } + private fun onDaoJoinDataPacket(packet: Packet) { + Log.d("LEADER", "Received data from Peer wanting to join") + + val (peer, payload) = + packet.getAuthPayload( + SignPayload.Deserializer + ) + try { + Log.d("LEADER", "Peer wanting to join: ${peer.publicKey}") + joinBitcoinWallet( + payload.mostRecentSWBlock.transaction, + payload.proposeBlockData, + payload.signatures, + this.context + ) + // Add new nonceKey after joining a DAO + WalletManagerAndroid.getInstance() + .addNewNonceKey(payload.proposeBlockData.SW_UNIQUE_ID, this.context) + } catch (t: Throwable) { + Log.e("LEADER", "Joining failed. ${t.message ?: "No further information"}.") + } + } + fun onSignPayloadResponse( peer: Peer, payload: SignPayload @@ -318,6 +344,8 @@ open class CoinCommunity constructor( } } + + fun onAliveResponse( peer: Peer, payload: AlivePayload @@ -444,7 +472,25 @@ open class CoinCommunity constructor( Thread.sleep(1000) } Log.d("LEADER", "Leader found.") - Log.d("LEADER", "sending proposal to leader...") + + + + val currentLeader = getCurrentLeader()[publicKeyBlock.decodeToString()]!! + Log.d("LEADER", "sending dao join transaction data to leader ${currentLeader.publicKey}") + val payload = SignPayload( + getServiceIdNew().toByteArray(), + mostRecentSWBlock, + proposeBlockData, + signatures); + val packet = serializePacket(MessageId.JOIN_DAO_DATA, payload) + send(currentLeader, packet) + + Toast.makeText( + context, + "Sending DAO join data to ${currentLeader.publicKey}", + Toast.LENGTH_SHORT + ).show() + sendPayload( getCurrentLeader()[publicKeyBlock.decodeToString()]!!, SignPayload( @@ -651,6 +697,8 @@ open class CoinCommunity constructor( const val ELECTED_RESPONSE = 2 const val ALIVE_RESPONSE = 3 const val SIGNATURE_ASK = 4 + const val JOIN_DAO_DATA = 5 + } companion object { diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/payload/SignPayload.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/payload/SignPayload.kt index 49cfee0b6..889aa5c30 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/payload/SignPayload.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/payload/SignPayload.kt @@ -1,10 +1,17 @@ package nl.tudelft.trustchain.currencyii.payload -import nl.tudelft.ipv8.messaging.* -import nl.tudelft.trustchain.currencyii.sharedWallet.SWSignatureAskBlockTD -import com.google.gson.Gson +import com.google.gson.GsonBuilder import com.google.gson.reflect.TypeToken import nl.tudelft.ipv8.attestation.trustchain.TrustChainBlock +import nl.tudelft.ipv8.messaging.Deserializable +import nl.tudelft.ipv8.messaging.SERIALIZED_USHORT_SIZE +import nl.tudelft.ipv8.messaging.Serializable +import nl.tudelft.ipv8.messaging.deserializeUInt +import nl.tudelft.ipv8.messaging.deserializeUShort +import nl.tudelft.ipv8.messaging.serializeUInt +import nl.tudelft.ipv8.messaging.serializeUShort import nl.tudelft.trustchain.currencyii.sharedWallet.SWResponseSignatureBlockTD +import nl.tudelft.trustchain.currencyii.sharedWallet.SWSignatureAskBlockTD +import java.util.Date class SignPayload( val DAOid: ByteArray, @@ -13,13 +20,32 @@ class SignPayload( val signatures: List ) : Serializable { override fun serialize(): ByteArray { - val gson = Gson() + val gson = GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").create(); val daoIdSizeBytes = serializeUShort(DAOid.size) - val mostRecentSWBlockJson = gson.toJson(mostRecentSWBlock) - val mostRecentSWBlockBytes = mostRecentSWBlockJson.toByteArray() - val mostRecentSWBlockSizeBytes = serializeUShort(mostRecentSWBlockBytes.size) + // serialize each property seperately for mostRecentSWBlock + val trustBlockTypeBytes = mostRecentSWBlock.type.toByteArray() + val trustBlockTypeSizeBytes = serializeUShort(trustBlockTypeBytes.size) + + val trustBlockRawTransactionSizeBytes = serializeUShort(mostRecentSWBlock.rawTransaction.size) + val trustBlockPublicKeySizeBytes = serializeUShort(mostRecentSWBlock.publicKey.size) + + val sequenceBytes = serializeUInt(mostRecentSWBlock.sequenceNumber) + val sequenceSizeBytes = serializeUShort(sequenceBytes.size) + + val linkPublicKeySizeBytes = serializeUShort(mostRecentSWBlock.linkPublicKey.size) + + val linkSequenceNumberBytes = serializeUInt(mostRecentSWBlock.linkSequenceNumber) + val linkSequenceNumberSizeBytes = serializeUShort(linkSequenceNumberBytes.size) + + val prevHashSizeBytes = serializeUShort(mostRecentSWBlock.previousHash.size) + val signatureSizeBytes = serializeUShort(mostRecentSWBlock.signature.size) + + val timeStampBytes = gson.toJson(mostRecentSWBlock.timestamp).toByteArray() + val timeStampSizeBytes = serializeUShort(timeStampBytes.size) + + val proposeBlockDataJson = gson.toJson(proposeBlockData) val proposeBlockDataBytes = proposeBlockDataJson.toByteArray() @@ -30,13 +56,21 @@ class SignPayload( val signaturesSizeBytes = serializeUShort(signaturesBytes.size) return daoIdSizeBytes + DAOid + - mostRecentSWBlockSizeBytes + mostRecentSWBlockBytes + + trustBlockTypeSizeBytes + trustBlockTypeBytes + + trustBlockRawTransactionSizeBytes + mostRecentSWBlock.rawTransaction + + trustBlockPublicKeySizeBytes + mostRecentSWBlock.publicKey + + sequenceSizeBytes + sequenceBytes + + linkPublicKeySizeBytes + mostRecentSWBlock.linkPublicKey + + linkSequenceNumberSizeBytes + linkSequenceNumberBytes + + prevHashSizeBytes + mostRecentSWBlock.previousHash + + signatureSizeBytes + mostRecentSWBlock.signature + + timeStampSizeBytes + timeStampBytes + proposeBlockDataSizeBytes + proposeBlockDataBytes + signaturesSizeBytes + signaturesBytes } companion object Deserializer : Deserializable { - val gson = Gson() + val gson = GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").create(); override fun deserialize( buffer: ByteArray, @@ -52,17 +86,55 @@ class SignPayload( ) localOffset += daoIdSize - val mostRecentSWBlockSize = deserializeUShort(buffer, offset + localOffset) + val typeSize = deserializeUShort(buffer, offset + localOffset) localOffset += SERIALIZED_USHORT_SIZE - val mostRecentSWBlock = - gson.fromJson( - buffer.copyOfRange( - offset + localOffset, - offset + localOffset + mostRecentSWBlockSize - ).decodeToString(), - TrustChainBlock::class.java - ) - localOffset += mostRecentSWBlockSize + val type = buffer.copyOfRange(offset + localOffset, offset + localOffset + typeSize) + localOffset += typeSize + + val rawTransactionSize = deserializeUShort(buffer, offset + localOffset) + localOffset += SERIALIZED_USHORT_SIZE + val rawTransaction = buffer.copyOfRange(offset + localOffset, offset + localOffset + rawTransactionSize) + localOffset += rawTransactionSize + + val publicKeySize = deserializeUShort(buffer, offset + localOffset) + localOffset += SERIALIZED_USHORT_SIZE + val publicKey = buffer.copyOfRange(offset + localOffset, offset + localOffset + publicKeySize) + localOffset += publicKeySize + + val sequenceNumberSize = deserializeUShort(buffer, offset + localOffset) + localOffset += SERIALIZED_USHORT_SIZE + val sequenceNumber = buffer.copyOfRange(offset + localOffset, offset + localOffset + sequenceNumberSize) + localOffset += sequenceNumberSize + + val linkPublicKeySize = deserializeUShort(buffer, offset + localOffset) + localOffset += SERIALIZED_USHORT_SIZE + val linkPublicKey = buffer.copyOfRange(offset + localOffset, offset + localOffset + linkPublicKeySize) + localOffset += linkPublicKeySize + + val linkSequenceNumberSize = deserializeUShort(buffer, offset + localOffset) + localOffset += SERIALIZED_USHORT_SIZE + val linkSequenceNumber = buffer.copyOfRange(offset + localOffset, offset + localOffset + linkSequenceNumberSize) + localOffset += linkSequenceNumberSize + + val previousHashSize = deserializeUShort(buffer, offset + localOffset) + localOffset += SERIALIZED_USHORT_SIZE + val previousHash = buffer.copyOfRange(offset + localOffset, offset + localOffset + previousHashSize) + localOffset += previousHashSize + + val signatureSize = deserializeUShort(buffer, offset + localOffset) + localOffset += SERIALIZED_USHORT_SIZE + val signature = buffer.copyOfRange(offset + localOffset, offset + localOffset + signatureSize) + localOffset += signatureSize + + val timestampSize = deserializeUShort(buffer, offset + localOffset) + localOffset += SERIALIZED_USHORT_SIZE + val timestamp = buffer.copyOfRange(offset + localOffset, offset + localOffset + timestampSize) + localOffset += timestampSize + + val date = gson.fromJson(timestamp.decodeToString(), Date::class.java) + val mostRecentSWBlock = TrustChainBlock(type.decodeToString(), rawTransaction, publicKey, deserializeUInt(sequenceNumber), + linkPublicKey, deserializeUInt(linkSequenceNumber), previousHash, signature, date) + val proposeBlockDataSize = deserializeUShort(buffer, offset + localOffset) localOffset += SERIALIZED_USHORT_SIZE diff --git a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/bitcoin/JoinDAOFragment.kt b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/bitcoin/JoinDAOFragment.kt index 541e5c941..f67d2f9b9 100644 --- a/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/bitcoin/JoinDAOFragment.kt +++ b/currencyii/src/main/java/nl/tudelft/trustchain/currencyii/ui/bitcoin/JoinDAOFragment.kt @@ -14,7 +14,6 @@ import nl.tudelft.ipv8.attestation.trustchain.TrustChainBlock import nl.tudelft.ipv8.util.toHex import nl.tudelft.trustchain.currencyii.CoinCommunity import nl.tudelft.trustchain.currencyii.R -import nl.tudelft.trustchain.currencyii.coin.WalletManagerAndroid import nl.tudelft.trustchain.currencyii.databinding.FragmentJoinNetworkBinding import nl.tudelft.trustchain.currencyii.sharedWallet.SWJoinBlockTransactionData import nl.tudelft.trustchain.currencyii.sharedWallet.SWResponseSignatureBlockTD @@ -235,20 +234,21 @@ class JoinDAOFragment : BaseFragment(R.layout.fragment_join_network) { signatures, latestHash ) - try { - getCoinCommunity().joinBitcoinWallet( - mostRecentSWBlock.transaction, - proposeBlockData, - signatures, - context - ) - // Add new nonceKey after joining a DAO - WalletManagerAndroid.getInstance() - .addNewNonceKey(proposeBlockData.SW_UNIQUE_ID, context) - } catch (t: Throwable) { - Log.e("Coin", "Joining failed. ${t.message ?: "No further information"}.") - setAlertText(t.message ?: "Unexpected error occurred. Try again") - } + +// try { +// getCoinCommunity().joinBitcoinWallet( +// mostRecentSWBlock.transaction, +// proposeBlockData, +// signatures, +// context +// ) +// // Add new nonceKey after joining a DAO +// WalletManagerAndroid.getInstance() +// .addNewNonceKey(proposeBlockData.SW_UNIQUE_ID, context) +// } catch (t: Throwable) { +// Log.e("Coin", "Joining failed. ${t.message ?: "No further information"}.") +// setAlertText(t.message ?: "Unexpected error occurred. Try again") +// } // Update wallets UI list fetchSharedWalletsAndUpdateUI() diff --git a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/leaderElection/LeaderElectionTest.kt b/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/leaderElection/LeaderElectionTest.kt index fb735bfaf..16f132c48 100644 --- a/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/leaderElection/LeaderElectionTest.kt +++ b/currencyii/src/test/java/nl/tudelft/trustchain/currencyii/leaderElection/LeaderElectionTest.kt @@ -27,6 +27,7 @@ import nl.tudelft.trustchain.currencyii.sharedWallet.SWSignatureAskBlockTD import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test +import java.util.Calendar class PayloadTest { @@ -84,12 +85,12 @@ class PayloadTest { } @Test - fun electionPayloadRequestTest() { + fun electionPayloadSerializeTest() { + val context = mockk() val coinCommunity = CoinCommunity(context) val dAOid = "Dao_id" val me = mockk() - val meKey = mockk() coinCommunity.myPeer = me @@ -101,11 +102,47 @@ class PayloadTest { every { me.updateClock(any()) } returns Unit every { me.key } returns mockk() + val sig1 = SWResponseSignatureBlockTD("SignatureId1", "ProposalId", "SignatureId1Serialized", "BTC_PK1", "NONCE1") + val sig2 = SWResponseSignatureBlockTD("SignatureId2", "ProposalId", "SignatureId2Serialized", "BTC_PK2", "NONCE2") + val sig3 = SWResponseSignatureBlockTD("SignatureId3", "ProposalId", "SignatureId3Serialized", "BTC_PK3", "NONCE3") + val daoIdBytes = dAOid.toByteArray() - val packet = coinCommunity.createElectionRequest(daoIdBytes) - val packetLastElements = packet.takeLast(daoIdBytes.size) + val signatures = listOf(sig1, sig2, sig3) + val trustChainBlock = TrustChainBlock("type", "rawTransaction".toByteArray(), "publicKey".toByteArray(), 42U, "linkPublicKey".toByteArray(), + 12U, "previousHash".toByteArray(), "signature".toByteArray(), Calendar.getInstance().time) + val proposeBlockData = SWSignatureAskBlockTD("SW_UNIQUE_ID", "SW_UNIQUE_PROPOSAL_ID", + "SW_TRANSACTION_SERIALIZED", "SW_PREVIOUS_BLOCK_HASH", 5, "SW_RECEIVER_PK") + + val payload = SignPayload(daoIdBytes, trustChainBlock, proposeBlockData, signatures) + val serialized = payload.serialize() + val deserialized = SignPayload.deserialize(serialized) + + + assertEquals(payload.DAOid.decodeToString(), deserialized.first.DAOid.decodeToString()) + assertEquals(payload.mostRecentSWBlock.type, deserialized.first.mostRecentSWBlock.type) + assertEquals(payload.mostRecentSWBlock.rawTransaction.decodeToString(), deserialized.first.mostRecentSWBlock.rawTransaction.decodeToString()) + assertEquals(payload.mostRecentSWBlock.publicKey.decodeToString(), deserialized.first.mostRecentSWBlock.publicKey.decodeToString()) + assertEquals(payload.mostRecentSWBlock.sequenceNumber, deserialized.first.mostRecentSWBlock.sequenceNumber) + assertEquals(payload.mostRecentSWBlock.linkPublicKey.decodeToString(), deserialized.first.mostRecentSWBlock.linkPublicKey.decodeToString()) + assertEquals(payload.mostRecentSWBlock.linkSequenceNumber, deserialized.first.mostRecentSWBlock.linkSequenceNumber) + assertEquals(payload.mostRecentSWBlock.previousHash.decodeToString(), deserialized.first.mostRecentSWBlock.previousHash.decodeToString()) + assertEquals(payload.mostRecentSWBlock.signature.decodeToString(), deserialized.first.mostRecentSWBlock.signature.decodeToString()) + assertEquals(payload.mostRecentSWBlock.timestamp.time, deserialized.first.mostRecentSWBlock.timestamp.time) + + assertEquals(payload.signatures.first().SW_UNIQUE_ID, deserialized.first.signatures.first().SW_UNIQUE_ID) + assertEquals(payload.signatures.first().SW_BITCOIN_PK, deserialized.first.signatures.first().SW_BITCOIN_PK) + assertEquals(payload.signatures.last().SW_NONCE, deserialized.first.signatures.last().SW_NONCE) + assertEquals(payload.signatures.size, deserialized.first.signatures.size) + assertEquals(payload.signatures.last().SW_UNIQUE_PROPOSAL_ID, deserialized.first.signatures.last().SW_UNIQUE_PROPOSAL_ID) + + assertEquals(payload.proposeBlockData.SW_UNIQUE_PROPOSAL_ID, deserialized.first.proposeBlockData.SW_UNIQUE_PROPOSAL_ID) + assertEquals(payload.proposeBlockData.SW_TRANSACTION_SERIALIZED, deserialized.first.proposeBlockData.SW_TRANSACTION_SERIALIZED) + assertEquals(payload.proposeBlockData.SW_SIGNATURES_REQUIRED, deserialized.first.proposeBlockData.SW_SIGNATURES_REQUIRED) + assertEquals(payload.proposeBlockData.SW_PREVIOUS_BLOCK_HASH, deserialized.first.proposeBlockData.SW_PREVIOUS_BLOCK_HASH) + assertEquals(payload.proposeBlockData.SW_UNIQUE_ID, deserialized.first.proposeBlockData.SW_UNIQUE_ID) + assertEquals(payload.proposeBlockData.SW_RECEIVER_PK, deserialized.first.proposeBlockData.SW_RECEIVER_PK) + - assertEquals(daoIdBytes.toList(), packetLastElements) } }