From e887189a2e1f31a729a4370a6fc4a9b1b539b39f Mon Sep 17 00:00:00 2001 From: Bohdan Date: Sun, 7 Aug 2022 20:06:13 +0300 Subject: [PATCH 1/2] Add proper context gap fix --- altchain-plugins/build.gradle.kts | 2 +- .../org/veriblock/alt/plugins/HttpClient.kt | 37 +++++- .../alt/plugins/bitcoin/BitcoinFamilyChain.kt | 46 ++++---- .../bitcoin/BitcoinFamilyChainModel.kt | 19 --- .../plugins/ethereum/EthereumFamilyChain.kt | 23 +++- .../alt/plugins/nxt/NxtFamilyChain.kt | 10 +- .../veriblock/alt/plugins/test/TestChain.kt | 10 +- altchain-sdk/build.gradle.kts | 5 +- .../sdk/alt/SecurityInheritingChain.kt | 11 +- .../veriblock/sdk/alt/model/RpcEntities.kt | 110 ++++++++++++++++++ bootstrap-downloader/build.gradle.kts | 5 +- nodecore-cli/build.gradle.kts | 2 +- nodecore-spv/build.gradle.kts | 5 +- .../nodecore-spv-standalone/build.gradle.kts | 2 +- .../org/veriblock/spv/service/SpvService.kt | 39 ++++++- .../altchain-pop-miner/build.gradle.kts | 2 +- .../veriblock/miners/pop/net/SpvGateway.kt | 4 + .../SecurityInheritingMonitor.kt | 102 ++++++++-------- .../src/main/spa-client/package-lock.json | 2 + pop-miners/pop-miners-common/build.gradle.kts | 2 +- .../veriblock-pop-miner/build.gradle.kts | 2 +- .../build.gradle.kts | 2 +- veriblock-core/build.gradle.kts | 2 +- .../org/veriblock/core/crypto/Sha256Hash.kt | 4 +- .../java/org/veriblock/core/crypto/VbkHash.kt | 31 +++-- .../veriblock/sdk/models/VeriBlockBlock.kt | 8 +- 26 files changed, 353 insertions(+), 134 deletions(-) create mode 100644 altchain-sdk/src/main/kotlin/org/veriblock/sdk/alt/model/RpcEntities.kt diff --git a/altchain-plugins/build.gradle.kts b/altchain-plugins/build.gradle.kts index 9e56e289d..f7093a535 100644 --- a/altchain-plugins/build.gradle.kts +++ b/altchain-plugins/build.gradle.kts @@ -36,7 +36,7 @@ dependencies { implementation("com.google.guava:guava:26.0-jre") // Logging - implementation("io.github.microutils:kotlin-logging:1.6.26") + implementation("io.github.microutils:kotlin-logging:2.1.23") implementation("org.apache.logging.log4j:log4j-api:$log4jVersion") implementation("org.apache.logging.log4j:log4j-core:$log4jVersion") diff --git a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/HttpClient.kt b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/HttpClient.kt index 04e75fdd3..1e6a117f1 100644 --- a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/HttpClient.kt +++ b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/HttpClient.kt @@ -8,16 +8,30 @@ package org.veriblock.alt.plugins +import com.google.gson.ExclusionStrategy +import com.google.gson.FieldAttributes import com.google.gson.Gson +import com.google.gson.JsonDeserializer import com.google.gson.JsonElement -import io.ktor.client.HttpClient -import io.ktor.client.engine.apache.Apache -import io.ktor.client.features.auth.Auth +import io.ktor.client.* +import io.ktor.client.engine.apache.* +import io.ktor.client.features.auth.* import io.ktor.client.features.auth.providers.* -import io.ktor.client.features.json.GsonSerializer -import io.ktor.client.features.json.Json -import io.ktor.http.ContentType +import io.ktor.client.features.json.* +import io.ktor.http.* +import org.veriblock.core.crypto.MerkleRoot +import org.veriblock.core.crypto.PreviousBlockVbkHash +import org.veriblock.core.crypto.PreviousKeystoneVbkHash +import org.veriblock.core.crypto.TruncatedMerkleRoot +import org.veriblock.core.crypto.VbkHash +import org.veriblock.core.crypto.asMerkleRoot +import org.veriblock.core.crypto.asTruncatedMerkleRoot +import org.veriblock.core.crypto.asVbkHash +import org.veriblock.core.crypto.asVbkPreviousBlockHash +import org.veriblock.core.crypto.asVbkPreviousKeystoneHash import org.veriblock.sdk.alt.plugin.HttpAuthConfig +import org.veriblock.sdk.models.SkipSerialisation +import java.lang.annotation.ElementType import java.lang.reflect.Type class HttpException( @@ -26,6 +40,17 @@ class HttpException( ) : RuntimeException(message, cause) private val gson = Gson() + .newBuilder() + .registerTypeAdapter(PreviousBlockVbkHash::class.java, JsonDeserializer { json, _, _ -> json.asString.asVbkPreviousBlockHash() }) + .registerTypeAdapter(PreviousKeystoneVbkHash::class.java, JsonDeserializer { json, _, _ -> json.asString.asVbkPreviousKeystoneHash() }) + .registerTypeAdapter(VbkHash::class.java, JsonDeserializer { json, _, _ -> json.asString.asVbkHash() }) + .registerTypeAdapter(MerkleRoot::class.java, JsonDeserializer { json, _, _ -> json.asString.asMerkleRoot() }) + .registerTypeAdapter(TruncatedMerkleRoot::class.java, JsonDeserializer { json, _, _ -> json.asString.asTruncatedMerkleRoot() }) + .addDeserializationExclusionStrategy(object : ExclusionStrategy { + override fun shouldSkipField(f: FieldAttributes): Boolean = f.getAnnotation(SkipSerialisation::class.java) != null + override fun shouldSkipClass(clazz: Class<*>?): Boolean = false + }) + .create() fun String.fromJson(type: Type): T = gson.fromJson(this, type) fun JsonElement.fromJson(type: Type): T = gson.fromJson(this, type) diff --git a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/bitcoin/BitcoinFamilyChain.kt b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/bitcoin/BitcoinFamilyChain.kt index ebd1dcc9c..8b34653d2 100644 --- a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/bitcoin/BitcoinFamilyChain.kt +++ b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/bitcoin/BitcoinFamilyChain.kt @@ -27,12 +27,14 @@ import org.veriblock.core.utilities.extensions.isHex import org.veriblock.core.utilities.extensions.toHex import org.veriblock.sdk.alt.ApmInstruction import org.veriblock.sdk.alt.model.Atv +import org.veriblock.sdk.alt.model.BtcBlockResponse import org.veriblock.sdk.alt.model.PopMempool import org.veriblock.sdk.alt.model.PopParamsResponse import org.veriblock.sdk.alt.model.SecurityInheritingBlock import org.veriblock.sdk.alt.model.SecurityInheritingTransaction import org.veriblock.sdk.alt.model.SecurityInheritingTransactionVout import org.veriblock.sdk.alt.model.SubmitPopResponse +import org.veriblock.sdk.alt.model.VbkBlockResponse import org.veriblock.sdk.alt.model.Vtb import org.veriblock.sdk.alt.plugin.PluginConfig import org.veriblock.sdk.alt.plugin.PluginSpec @@ -286,9 +288,9 @@ class BitcoinFamilyChain( override fun extractAddressDisplay(addressData: ByteArray): String { return if (config.addressPrefix != null) { val witnessProgram = ByteArray(addressData.size - 2) - addressData.copyInto(witnessProgram, 0,2, addressData.size) + addressData.copyInto(witnessProgram, 0, 2, addressData.size) try { - segwitToBech32(config.addressPrefix,0, witnessProgram) + segwitToBech32(config.addressPrefix, 0, witnessProgram) } catch (exception: Exception) { throw IllegalArgumentException("Can't extract the Bech32 address from the address data: ${addressData.toHex()}", exception) } @@ -335,21 +337,23 @@ class BitcoinFamilyChain( return rpcRequest("getpopparams", emptyList()) } - override suspend fun getVbkBlock(hash: String): VeriBlockBlock? { + override suspend fun getVbkBlockHash(height: Int): String? { + return try { + return rpcRequest("getvbkblockhash", listOf(height)) + } catch (e: RpcException) { + if (e.errorCode == NOT_FOUND_ERROR_CODE) { + // Block not found + null + } else { + throw e + } + } + } + + override suspend fun getVbkBlock(hash: String): VbkBlockResponse? { logger.debug { "Retrieving the VBK block for the hash $hash" } return try { - val response: VbkBlock = rpcRequest("getvbkblock", listOf(hash)) - VeriBlockBlock( - height = response.header?.height ?: error("getvbkblock height field must be set"), - version = response.header.version ?: error("getvbkblock version field must be set"), - previousBlock = response.header.previousBlock?.asAnyVbkHash()?.trimToPreviousBlockSize() ?: error("getvbkblock previousBlock field must be set"), - previousKeystone = response.header.previousKeystone?.asAnyVbkHash()?.trimToPreviousKeystoneSize() ?: error("getvbkblock previousKeystone field must be set"), - secondPreviousKeystone = response.header.secondPreviousKeystone?.asAnyVbkHash()?.trimToPreviousKeystoneSize() ?: error("getvbkblock secondPreviousKeystone field must be set"), - merkleRoot = response.header.merkleRoot?.asTruncatedMerkleRoot() ?: error("getvbkblock merkleRoot field must be set"), - timestamp = response.header.timestamp ?: error("getvbkblock timestamp field must be set"), - difficulty = response.header.difficulty ?: error("getvbkblock difficulty field must be set"), - nonce = response.header.nonce ?: error("getvbkblock nonce field must be set") - ) + return rpcRequest("getvbkblock", listOf(hash)) } catch (e: RpcException) { if (e.errorCode == NOT_FOUND_ERROR_CODE) { // Block not found @@ -365,18 +369,10 @@ class BitcoinFamilyChain( return rpcRequest("getbtcbestblockhash") } - override suspend fun getBtcBlock(hash: String): BitcoinBlock? { + override suspend fun getBtcBlock(hash: String): BtcBlockResponse? { logger.debug { "Retrieving the BTC block for the hash $hash" } return try { - val response: BtcBlockBlock = rpcRequest("getbtcblock", listOf(hash)) - BitcoinBlock( - version = response.header?.version ?: error("getbtcblock version field must be set"), - previousBlock = response.header.previousBlock?.asBtcHash() ?: error("getbtcblock previousBlock field must be set"), - merkleRoot = response.header.merkleRoot?.asMerkleRoot() ?: error("getbtcblock merkleRoot field must be set"), - timestamp = response.header.timestamp ?: error("getbtcblock timestamp field must be set"), - difficulty = 0, // FIXME difficulty field is not at the response - nonce = response.header.nonce ?: error("getbtcblock nonce field must be set") - ) + return rpcRequest("getbtcblock", listOf(hash)) } catch (e: RpcException) { if (e.errorCode == NOT_FOUND_ERROR_CODE) { // Block not found diff --git a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/bitcoin/BitcoinFamilyChainModel.kt b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/bitcoin/BitcoinFamilyChainModel.kt index 105e03360..4056c6de6 100644 --- a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/bitcoin/BitcoinFamilyChainModel.kt +++ b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/bitcoin/BitcoinFamilyChainModel.kt @@ -123,25 +123,6 @@ internal data class BlockChainInfo( val initialblockdownload: Boolean ) -internal data class BtcBlockBlock( - val chainWork: String?, - val height: Int?, - val header: BtcBlockHeader?, - val status: Int?, - val vbkRefs: List?, - val blockOfProofEndorsements: List? -) - -internal data class BtcBlockHeader( - val hash: String?, - val version: Int?, - val previousBlock: String?, - val merkleRoot: String?, - val timestamp: Int?, - val bits: Long?, - val nonce: Int? -) - internal data class VbkBlock( val chainWork: String?, val containingEndorsements: List?, diff --git a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/ethereum/EthereumFamilyChain.kt b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/ethereum/EthereumFamilyChain.kt index 170df7de2..df68a1802 100644 --- a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/ethereum/EthereumFamilyChain.kt +++ b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/ethereum/EthereumFamilyChain.kt @@ -31,13 +31,16 @@ import org.veriblock.core.utilities.extensions.isHex import org.veriblock.core.utilities.extensions.toHex import org.veriblock.sdk.alt.ApmInstruction import org.veriblock.sdk.alt.model.Atv +import org.veriblock.sdk.alt.model.BtcBlockResponse import org.veriblock.sdk.alt.model.NetworkParam import org.veriblock.sdk.alt.model.PopMempool import org.veriblock.sdk.alt.model.PopParamsResponse import org.veriblock.sdk.alt.model.PopPayoutParams import org.veriblock.sdk.alt.model.SecurityInheritingBlock import org.veriblock.sdk.alt.model.SecurityInheritingTransaction +import org.veriblock.sdk.alt.model.StoredInVbkBlockData import org.veriblock.sdk.alt.model.SubmitPopResponse +import org.veriblock.sdk.alt.model.VbkBlockResponse import org.veriblock.sdk.alt.model.Vtb import org.veriblock.sdk.alt.plugin.PluginConfig import org.veriblock.sdk.alt.plugin.PluginSpec @@ -321,13 +324,27 @@ class EthereumFamilyChain( ) } - override suspend fun getVbkBlock(hash: String): VeriBlockBlock? { + override suspend fun getVbkBlock(hash: String): VbkBlockResponse? { val response = rpcRequest( method="pop_getVbkBlockByHash", params = listOf(hash), version = "2.0") - return response.header.toVbkBlock() + return VbkBlockResponse( + chainWork = response.chainWork, + containingEndorsements = response.containingEndorsements, + endorsedBy = response.endorsedBy, + blockOfProofEndorsements = response.blockOfProofEndorsements, + height = response.height, + header = response.header.toVbkBlock(), + status = response.status, + altrefs = response.altrefs, + stored = StoredInVbkBlockData(response.stored.vtbids) + ) + } + + override suspend fun getVbkBlockHash(height: Int): String? { + TODO("Not yet implemented") } override suspend fun getBestKnownBtcBlockHash(): String { @@ -335,7 +352,7 @@ class EthereumFamilyChain( return rpcRequest("pop_getBtcBestBlockHash", version = "2.0") } - override suspend fun getBtcBlock(hash: String): BitcoinBlock? { + override suspend fun getBtcBlock(hash: String): BtcBlockResponse? { TODO("Not yet implemented (getBtcBlock)") // pop_getBtcBlockByHash } diff --git a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/nxt/NxtFamilyChain.kt b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/nxt/NxtFamilyChain.kt index 3436471d2..10f62b555 100644 --- a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/nxt/NxtFamilyChain.kt +++ b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/nxt/NxtFamilyChain.kt @@ -20,11 +20,13 @@ import org.veriblock.core.utilities.extensions.asHexBytes import org.veriblock.sdk.alt.ApmInstruction import org.veriblock.sdk.alt.SecurityInheritingChain import org.veriblock.sdk.alt.model.Atv +import org.veriblock.sdk.alt.model.BtcBlockResponse import org.veriblock.sdk.alt.model.PopMempool import org.veriblock.sdk.alt.model.PopParamsResponse import org.veriblock.sdk.alt.model.SecurityInheritingBlock import org.veriblock.sdk.alt.model.SecurityInheritingTransaction import org.veriblock.sdk.alt.model.SubmitPopResponse +import org.veriblock.sdk.alt.model.VbkBlockResponse import org.veriblock.sdk.alt.model.Vtb import org.veriblock.sdk.alt.plugin.PluginConfig import org.veriblock.sdk.alt.plugin.PluginSpec @@ -90,7 +92,11 @@ class NxtFamilyChain( TODO("Not yet implemented") } - override suspend fun getVbkBlock(hash: String): VeriBlockBlock? { + override suspend fun getVbkBlock(hash: String): VbkBlockResponse? { + TODO("Not yet implemented") + } + + override suspend fun getVbkBlockHash(height: Int): String? { TODO("Not yet implemented") } @@ -98,7 +104,7 @@ class NxtFamilyChain( TODO("Not yet implemented") } - override suspend fun getBtcBlock(hash: String): BitcoinBlock? { + override suspend fun getBtcBlock(hash: String): BtcBlockResponse? { TODO("Not yet implemented") } diff --git a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/test/TestChain.kt b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/test/TestChain.kt index 04cb2efcf..de671213a 100644 --- a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/test/TestChain.kt +++ b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/test/TestChain.kt @@ -24,12 +24,14 @@ import org.veriblock.core.utilities.extensions.toHex import org.veriblock.sdk.alt.ApmInstruction import org.veriblock.sdk.alt.SecurityInheritingChain import org.veriblock.sdk.alt.model.Atv +import org.veriblock.sdk.alt.model.BtcBlockResponse import org.veriblock.sdk.alt.model.PopMempool import org.veriblock.sdk.alt.model.PopParamsResponse import org.veriblock.sdk.alt.model.SecurityInheritingBlock import org.veriblock.sdk.alt.model.SecurityInheritingTransaction import org.veriblock.sdk.alt.model.SecurityInheritingTransactionVout import org.veriblock.sdk.alt.model.SubmitPopResponse +import org.veriblock.sdk.alt.model.VbkBlockResponse import org.veriblock.sdk.alt.model.Vtb import org.veriblock.sdk.alt.plugin.PluginConfig import org.veriblock.sdk.alt.plugin.PluginSpec @@ -136,7 +138,11 @@ class TestChain( TODO("Not yet implemented") } - override suspend fun getVbkBlock(hash: String): VeriBlockBlock? { + override suspend fun getVbkBlock(hash: String): VbkBlockResponse? { + TODO("Not yet implemented") + } + + override suspend fun getVbkBlockHash(height: Int): String? { TODO("Not yet implemented") } @@ -144,7 +150,7 @@ class TestChain( TODO("Not yet implemented") } - override suspend fun getBtcBlock(hash: String): BitcoinBlock? { + override suspend fun getBtcBlock(hash: String): BtcBlockResponse? { TODO("Not yet implemented") } diff --git a/altchain-sdk/build.gradle.kts b/altchain-sdk/build.gradle.kts index d8480ac5f..cfea5fc22 100644 --- a/altchain-sdk/build.gradle.kts +++ b/altchain-sdk/build.gradle.kts @@ -8,6 +8,9 @@ import groovy.lang.GroovyObject import org.jfrog.gradle.plugin.artifactory.dsl.PublisherConfig +repositories { + mavenCentral() +} plugins { java kotlin("jvm") @@ -28,7 +31,7 @@ dependencies { implementation("io.github.config4k:config4k:0.4.0") // Logging - implementation("io.github.microutils:kotlin-logging:1.6.26") + implementation("io.github.microutils:kotlin-logging:2.1.23") // Reflection implementation("org.reflections:reflections:0.9.12") diff --git a/altchain-sdk/src/main/kotlin/org/veriblock/sdk/alt/SecurityInheritingChain.kt b/altchain-sdk/src/main/kotlin/org/veriblock/sdk/alt/SecurityInheritingChain.kt index 23a4e7626..39fdc0129 100644 --- a/altchain-sdk/src/main/kotlin/org/veriblock/sdk/alt/SecurityInheritingChain.kt +++ b/altchain-sdk/src/main/kotlin/org/veriblock/sdk/alt/SecurityInheritingChain.kt @@ -11,11 +11,13 @@ package org.veriblock.sdk.alt import org.veriblock.core.altchain.AltchainPopEndorsement import org.veriblock.core.contracts.BlockEvidence import org.veriblock.sdk.alt.model.Atv +import org.veriblock.sdk.alt.model.BtcBlockResponse import org.veriblock.sdk.alt.model.PopMempool import org.veriblock.sdk.alt.model.PopParamsResponse import org.veriblock.sdk.alt.model.SecurityInheritingBlock import org.veriblock.sdk.alt.model.SecurityInheritingTransaction import org.veriblock.sdk.alt.model.SubmitPopResponse +import org.veriblock.sdk.alt.model.VbkBlockResponse import org.veriblock.sdk.alt.model.Vtb import org.veriblock.sdk.models.* @@ -86,7 +88,12 @@ interface SecurityInheritingChain { /** * Returns the VeriBlockBlock for the given [hash] */ - suspend fun getVbkBlock(hash: String): VeriBlockBlock? + suspend fun getVbkBlock(hash: String): VbkBlockResponse? + + /** + * Returns the VeriBlock Block hash on given [height] from active chain. + */ + suspend fun getVbkBlockHash(height: Int): String? /** * Returns the hash from the best known BTC block @@ -96,7 +103,7 @@ interface SecurityInheritingChain { /** * Returns the BitcoinBlock for the given [hash] */ - suspend fun getBtcBlock(hash: String): BitcoinBlock? + suspend fun getBtcBlock(hash: String): BtcBlockResponse? /** * Returns this security inheriting chain's PoP mempool (ATVs and VTBs). diff --git a/altchain-sdk/src/main/kotlin/org/veriblock/sdk/alt/model/RpcEntities.kt b/altchain-sdk/src/main/kotlin/org/veriblock/sdk/alt/model/RpcEntities.kt new file mode 100644 index 000000000..9e633147a --- /dev/null +++ b/altchain-sdk/src/main/kotlin/org/veriblock/sdk/alt/model/RpcEntities.kt @@ -0,0 +1,110 @@ +package org.veriblock.sdk.alt.model + +import org.veriblock.core.crypto.PreviousBlockVbkHash +import org.veriblock.core.crypto.PreviousKeystoneVbkHash +import org.veriblock.core.crypto.TruncatedMerkleRoot +import org.veriblock.core.crypto.VbkHash +import org.veriblock.sdk.models.VeriBlockBlock + + +/* + "chainWork": "000000000000000000000000000000000000000008d6c888b3d44978f2378750", + "height": 735498, + "header": { + "hash": "000000000000000000036d3be8e84af55f0dd5c9d96facd0ada966a01dcf93da", + "version": 536870912, + "previousBlock": "00000000000000000007912809a58b56e1e49771a79a444031f6177daeb01b8a", + "merkleRoot": "c74527a2b7bbd8ba32c48f2bfa784fc399c77815eec3312359ae16daa5f3d5c3", + "timestamp": 1652028409, + "bits": 386495093, + "nonce": 1198006405 + }, + "status": 2, + "vbkrefs": [ + 3186756 + ], + "blockOfProofEndorsements": [ + "3d9134b1be1fa287b4aa9aff25bc40dd904ff624e16a8a2d752bb24a71e20e11" + ] +} + */ +data class BtcBlockResponse( + val chainWork: String, + val height: Int, + val header: BtcBlockHeader, + val status: Int, + val vbkrefs: List, + val blockOfProofEndorsements: List +) + +data class BtcBlockHeader( + val hash: String, + val version: Int, + val previousBlock: String, + val merkleRoot: String, + val timestamp: Int, + val bits: Long, + val nonce: Int +) + +/* +{ + "chainWork": "00000000000000000000000000000000000000000000000000feab3d9d5b0000", + "containingEndorsements": [ + ], + "endorsedBy": [ + ], + "height": 3321052, + "header": { + "hash": "0000000003f6ccf9299785573a3c24283b89e76eda71d95b", + "height": 3321052, + "version": 2, + "previousBlock": "5ee9f0d20c1ebf6bc18dbcef", + "previousKeystone": "abdd1cc4869a899df7", + "secondPreviousKeystone": "99990eeb6edf9b48f9", + "merkleRoot": "5db7e3221f903446a3406a8bf2150280", + "timestamp": 1659867216, + "difficulty": 85259378, + "nonce": 481316250119, + "id": "3a3c24283b89e76eda71d95b", + "serialized": "410032acdc00025ee9f0d20c1ebf6bc18dbcefabdd1cc4869a899df799990eeb6edf9b48f95db7e3221f903446a3406a8bf215028062ef90500514f4727010af2207" + }, + "status": 516, + "altrefs": 1, + "stored": { + "vtbids": [ + ] + }, + "blockOfProofEndorsements": [ + ] +} + */ + +data class VbkBlockResponse( + val chainWork: String, + val containingEndorsements: List, + val endorsedBy: List, + val blockOfProofEndorsements: List, + val height: Int, + val header: VbkHeader, + val status: Int, + val altrefs: Int, + val stored: StoredInVbkBlockData, +) + +data class VbkHeader ( + val height: Int, + val version: Short, + val previousBlock: PreviousBlockVbkHash, + val previousKeystone: PreviousKeystoneVbkHash, + val secondPreviousKeystone: PreviousKeystoneVbkHash, + val merkleRoot: TruncatedMerkleRoot, + val timestamp: Int, + val difficulty: Int, + val nonce: Long, + val hash: VbkHash +) + +data class StoredInVbkBlockData( + val vtbids: List +) diff --git a/bootstrap-downloader/build.gradle.kts b/bootstrap-downloader/build.gradle.kts index 6a4c6ca95..b6a998e13 100644 --- a/bootstrap-downloader/build.gradle.kts +++ b/bootstrap-downloader/build.gradle.kts @@ -1,5 +1,8 @@ import org.gradle.api.internal.plugins.WindowsStartScriptGenerator +repositories { + mavenCentral() +} plugins { java kotlin("jvm") @@ -14,7 +17,7 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") // Logging - implementation("io.github.microutils:kotlin-logging:1.6.26") + implementation("io.github.microutils:kotlin-logging:2.1.23") implementation("org.apache.logging.log4j:log4j-api:$log4jVersion") implementation("org.apache.logging.log4j:log4j-core:$log4jVersion") implementation("org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion") diff --git a/nodecore-cli/build.gradle.kts b/nodecore-cli/build.gradle.kts index e05ec03a8..156abd70f 100644 --- a/nodecore-cli/build.gradle.kts +++ b/nodecore-cli/build.gradle.kts @@ -30,7 +30,7 @@ dependencies { implementation("org.koin:koin-core:$koinVersion") // Logging - implementation("io.github.microutils:kotlin-logging:1.6.26") + implementation("io.github.microutils:kotlin-logging:2.1.23") implementation("org.apache.logging.log4j:log4j-api:$log4jVersion") implementation("org.apache.logging.log4j:log4j-core:$log4jVersion") implementation("org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion") diff --git a/nodecore-spv/build.gradle.kts b/nodecore-spv/build.gradle.kts index ae8b22e7a..fe317e8c9 100644 --- a/nodecore-spv/build.gradle.kts +++ b/nodecore-spv/build.gradle.kts @@ -7,6 +7,9 @@ // file LICENSE or http://www.opensource.org/licenses/mit-license.php. import org.gradle.api.tasks.testing.logging.TestExceptionFormat +repositories { + mavenCentral() +} plugins { java kotlin("jvm") @@ -31,7 +34,7 @@ dependencies { implementation("io.ktor:ktor-network-jvm:$ktorVersion") // Logging - implementation("io.github.microutils:kotlin-logging:1.6.26") + implementation("io.github.microutils:kotlin-logging:2.1.23") implementation("org.apache.logging.log4j:log4j-api:$log4jVersion") implementation("org.apache.logging.log4j:log4j-core:$log4jVersion") implementation("org.slf4j:slf4j-api:$slf4jVersion") diff --git a/nodecore-spv/nodecore-spv-standalone/build.gradle.kts b/nodecore-spv/nodecore-spv-standalone/build.gradle.kts index 9e350e4c4..2bc71001f 100644 --- a/nodecore-spv/nodecore-spv-standalone/build.gradle.kts +++ b/nodecore-spv/nodecore-spv-standalone/build.gradle.kts @@ -39,7 +39,7 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$coroutinesVersion") // Logging - implementation("io.github.microutils:kotlin-logging:1.6.26") + implementation("io.github.microutils:kotlin-logging:2.1.23") implementation("org.apache.logging.log4j:log4j-api:$log4jVersion") implementation("org.apache.logging.log4j:log4j-core:$log4jVersion") implementation("org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion") diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/service/SpvService.kt b/nodecore-spv/src/main/java/org/veriblock/spv/service/SpvService.kt index 1694d5ae8..673500310 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/service/SpvService.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/service/SpvService.kt @@ -13,6 +13,9 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.toList import nodecore.api.grpc.RpcAdvertiseTransaction +import nodecore.api.grpc.RpcBlockHeader +import nodecore.api.grpc.RpcBlockHeadersByHashesRequest +import nodecore.api.grpc.RpcBlockInfo import nodecore.api.grpc.RpcGetVeriBlockPublicationsReply import nodecore.api.grpc.RpcGetVeriBlockPublicationsRequest import nodecore.api.grpc.RpcTransactionAnnounce @@ -55,7 +58,10 @@ import java.util.* import nodecore.api.grpc.RpcGetVtbsForBtcBlocksReply import nodecore.api.grpc.RpcGetVtbsForBtcBlocksRequest import nodecore.p2p.PeerCapabilities +import org.veriblock.core.crypto.VbkHash import org.veriblock.core.crypto.VbkTxId +import org.veriblock.sdk.models.FullBlock +import org.veriblock.spv.serialization.MessageSerializer private val logger = createLogger {} @@ -425,9 +431,9 @@ class SpvService( return signatureIndex } - if (signatureIndex == null && maxConfirmedSigIndex > maxOf(pendingSignatureIndex) ) { - logger.debug { "signatureIndex == null, maxConfirmedSigIndex > maxOf(pendingSignatureIndex, return maxConfirmedSigIndex : $maxConfirmedSigIndex" } - return maxConfirmedSigIndex + if (signatureIndex == null && maxConfirmedSigIndex > maxOf(pendingSignatureIndex)) { + logger.debug { "signatureIndex == null, maxConfirmedSigIndex > maxOf(pendingSignatureIndex, return maxConfirmedSigIndex : $maxConfirmedSigIndex" } + return maxConfirmedSigIndex } val returnValue = maxOf(signatureIndex ?: 0L, maxConfirmedSigIndex, pendingSignatureIndex) @@ -442,13 +448,40 @@ class SpvService( val status: DownloadStatus = when { SpvState.downloadPeer == null || currentHeight == 0 || bestBlockHeight == 0 -> DownloadStatus.DISCOVERING + bestBlockHeight > 0 && bestBlockHeight - currentHeight < AMOUNT_OF_BLOCKS_WHEN_WE_CAN_START_WORKING -> DownloadStatus.READY + else -> DownloadStatus.DOWNLOADING } return DownloadStatusResponse(status, currentHeight, bestBlockHeight) } + + suspend fun getFullBlock(hash: VbkHash): FullBlock? { + // if we don't know this block, we exit early. + // but we don't need the block itself. + blockchain.getBlock(hash) ?: return null + + val request = buildMessage { + blockRequest = blockRequestBuilder + .addHeaders( + RpcBlockHeader.newBuilder() + .setHash(ByteString.copyFrom(hash.bytes)) + .build() + ) + .build() + } + + val rpcBlock = peerTable.requestMessage( + event = request + ) { if (it.block == null) -1 else 1 }.block + + val block = MessageSerializer.deserialize(rpcBlock) + logger.warn { block.toString() } + + return null + } } fun PeerTable.advertise(transaction: Transaction) { diff --git a/pop-miners/altchain-pop-miner/build.gradle.kts b/pop-miners/altchain-pop-miner/build.gradle.kts index 4095e0c1c..27987044c 100644 --- a/pop-miners/altchain-pop-miner/build.gradle.kts +++ b/pop-miners/altchain-pop-miner/build.gradle.kts @@ -65,7 +65,7 @@ dependencies { implementation("com.github.lamba92:ktor-spa:1.2.1") // Logging - implementation("io.github.microutils:kotlin-logging:1.6.26") + implementation("io.github.microutils:kotlin-logging:2.1.23") implementation("org.apache.logging.log4j:log4j-api:$log4jVersion") implementation("org.apache.logging.log4j:log4j-core:$log4jVersion") implementation("org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion") diff --git a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/net/SpvGateway.kt b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/net/SpvGateway.kt index 469eba029..cc8ccbe45 100644 --- a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/net/SpvGateway.kt +++ b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/net/SpvGateway.kt @@ -82,6 +82,10 @@ class SpvGateway( ) } + suspend fun getFullBlock(hash: VbkHash): FullBlock? { + return spvService.getFullBlock(hash) + } + fun getTransactions(ids: List): List { return spvService.getTransactions(ids) } diff --git a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/securityinheriting/SecurityInheritingMonitor.kt b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/securityinheriting/SecurityInheritingMonitor.kt index 73b97e682..b26de22b0 100644 --- a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/securityinheriting/SecurityInheritingMonitor.kt +++ b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/securityinheriting/SecurityInheritingMonitor.kt @@ -62,6 +62,8 @@ import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.locks.ReentrantLock import org.veriblock.miners.pop.util.CheckResult +import org.veriblock.sdk.alt.model.VbkBlockResponse +import org.veriblock.sdk.alt.model.VbkHeader import org.veriblock.sdk.models.VeriBlockBlock import java.time.LocalDate import kotlin.concurrent.withLock @@ -143,7 +145,7 @@ class SecurityInheritingMonitor( delay(5_000L) } - while(!isPopActive()) { + while (!isPopActive()) { delay(10_000L) } @@ -269,7 +271,7 @@ class SecurityInheritingMonitor( logger.error { "Failed to auto mine the block $blockHeight: ${e.message}" } } } else { - logger.info { "Unable to auto mine the block $blockHeight: ${(isMinerReady as CheckResult.Failure).error.message}" } + logger.info { "Unable to auto mine the block $blockHeight: ${(isMinerReady as CheckResult.Failure).error.message}" } } } } @@ -342,13 +344,13 @@ class SecurityInheritingMonitor( } } - private suspend fun getLastCommonVbkBlock(): VeriBlockBlock? { + private suspend fun getLastCommonVbkBlock(): VbkHeader? { val bestHash = chain.getBestKnownVbkBlockHash() - var cursor = chain.getVbkBlock(bestHash) + var cursor = chain.getVbkBlock(bestHash)?.header ?: return null while (!miner.gateway.isOnActiveChain(cursor.hash)) { logger.info { "Altchain's known VBK block ${cursor.hash} @${cursor.height} is not on the local known chain... Getting previous block." } - cursor = chain.getVbkBlock(cursor.previousBlock.toString()) + cursor = chain.getVbkBlock(cursor.previousBlock.toString())?.header ?: return null } @@ -367,7 +369,7 @@ class SecurityInheritingMonitor( logger.error { "${chain.name} can not find last common VBK block. Misconfiguration?" } return } - logger.debug {"${chain.name} last common VBK block: $bestKnownBlock"} + logger.debug { "${chain.name} last common VBK block: $bestKnownBlock" } if (bestKnownBlock.hash == newBlock.hash) { // return early if altchain already knows newBlock @@ -382,7 +384,7 @@ class SecurityInheritingMonitor( it.height }.toList() - logger.debug {"Context blocks: ${contextBlocks.size}. First: ${contextBlocks.first()}. Last: ${contextBlocks.last()}"} + logger.debug { "Context blocks: ${contextBlocks.size}. First: ${contextBlocks.first()}. Last: ${contextBlocks.last()}" } val popMempool = chain.getPopMempool() val mempoolContext = popMempool.vbkBlockHashes.map { it.lowercase() } @@ -451,57 +453,59 @@ class SecurityInheritingMonitor( } } + private suspend fun getLastVbkBlockIntroducingBtcContext(): VbkBlockResponse? { + val lastBtcHash = chain.getBestKnownBtcBlockHash() + val lastBtc = chain.getBtcBlock(lastBtcHash) + if (lastBtc == null) { + logger.error { "Node responded that its best BTC block hash is $lastBtcHash but RPC to fetch its content was not able to find this block. Bug in the node?" } + return null + } + + // this is height of VBK block that references last known BTC block on ALT chain + val refVbkBlockHeight = lastBtc.vbkrefs.maxOrNull() + if (refVbkBlockHeight == null) { + logger.error { "BTC block $lastBtcHash expected to be referenced by some VBK block. Node bug?" } + return null + } + + // get its hash + val refVbkHash = chain.getVbkBlockHash(refVbkBlockHeight) + if (refVbkHash == null) { + logger.error { "BTC block $lastBtcHash is referenced by VBK:${refVbkBlockHeight} but a node responded that block on this height is not found. Node bug?" } + return null + } + + // get its info + val refVbk = chain.getVbkBlock(refVbkHash) + if (refVbk == null) { + logger.error { "Expected to find $refVbkHash VBK block. Node bug?" } + return null + } + + return refVbk + } + /** * Handles the context gap and returns the amount of missing BTC blocks to be processed yet */ suspend fun handleContextGap(): Int { - val popMempool = chain.getPopMempool() - val remainingVtbs = popMempool.vtbs.mapNotNull { - chain.getVtb(it) - } - val btcContextBlockHash = chain.getBestKnownBtcBlockHash().asBtcHash() - val allPendingBtcBlocks = remainingVtbs.flatMap { it.btcBlockOfProofContext + it.btcBlockOfProof } - val allPendingBtcBlockHashes = allPendingBtcBlocks.map { it.hash.asBtcHash() }.toSet() + btcContextBlockHash - val pendingBtcBlocksWithAbsentPrevious = allPendingBtcBlocks.filter { - it.previousBlock.asBtcHash() !in allPendingBtcBlockHashes - } - //val missingBtcBlockHashes = try { - // chain.getMissingBtcBlockHashes() - //} catch (e: Exception) { - // logger.debugWarn(e) { "Unable to retrieve ${chain.name}'s missing BTC block hashes" } - // emptyList() - //} - - if (pendingBtcBlocksWithAbsentPrevious.isEmpty()) { + logger.warn { "Starting handling context gap" } + val vbk: VbkBlockResponse = getLastVbkBlockIntroducingBtcContext() ?: return 0 + val bestVbk: VbkBlockResponse = chain.getVbkBlock(chain.getBestKnownVbkBlockHash()) ?: return 0 + val maxGapSize = 1000 // vbk blocks + if (bestVbk.height <= vbk.height || (bestVbk.height - vbk.height) < maxGapSize) { + // there's no context gap return 0 } - val oldestPendingBtcBlocksWithAbsentPrevious = pendingBtcBlocksWithAbsentPrevious.minByOrNull { it.timestamp }!! - val earliestTime = LocalDate.ofEpochDay(oldestPendingBtcBlocksWithAbsentPrevious.timestamp / (3600L * 24)) - logger.info { - "The chain ${chain.name} has a context gap of ${pendingBtcBlocksWithAbsentPrevious.size} BTC blocks!" + - " Oldest missing BTC block: ${oldestPendingBtcBlocksWithAbsentPrevious.previousBlock} ($earliestTime)." + - " Retrieving corresponding publication data..." + val fullVbk = miner.gateway.getFullBlock(vbk.header.hash) + if (fullVbk == null) { + logger.info {"Cannot get full VBK block ${vbk.header.hash}"} + return 0 } - // Fetch and wait for veriblock publications (VTBs) - val vtbs = miner.gateway.getVtbsForBtcBlocks(pendingBtcBlocksWithAbsentPrevious.map { it.previousBlock.asBtcHash() }) - logger.info { "${vtbs.size} VTBs found! Submitting to ${chain.name}'s daemon..." } - - // Submit them to the blockchain - val successfulSubmissions = vtbs.map { vtb -> - chain.submitPopVtb(vtb).also { - if (!it.accepted) { - logger.debug { "VTB with ${vtb.getFirstBitcoinBlock()} was not accepted in ${chain.name}'s PoP mempool." } - } - } - }.count { it.accepted } - if (successfulSubmissions > 0) { - logger.info { "Successfully submitted $successfulSubmissions VTBs to ${chain.name}!" } - } else { - logger.info { "Failed to submit VTBs to ${chain.name}" } - } - return pendingBtcBlocksWithAbsentPrevious.size - successfulSubmissions + return 0 + // context gap of bigger size than maxGapSize } private fun handleNewBlock(block: SecurityInheritingBlock) { diff --git a/pop-miners/altchain-pop-miner/src/main/spa-client/package-lock.json b/pop-miners/altchain-pop-miner/src/main/spa-client/package-lock.json index 4742d23a0..990176f35 100644 --- a/pop-miners/altchain-pop-miner/src/main/spa-client/package-lock.json +++ b/pop-miners/altchain-pop-miner/src/main/spa-client/package-lock.json @@ -14790,6 +14790,7 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, + "hasInstallScript": true, "optional": true, "os": [ "darwin" @@ -15227,6 +15228,7 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, + "hasInstallScript": true, "optional": true, "os": [ "darwin" diff --git a/pop-miners/pop-miners-common/build.gradle.kts b/pop-miners/pop-miners-common/build.gradle.kts index fc1803614..547984ab7 100644 --- a/pop-miners/pop-miners-common/build.gradle.kts +++ b/pop-miners/pop-miners-common/build.gradle.kts @@ -46,7 +46,7 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationVersion") // Logging - implementation("io.github.microutils:kotlin-logging:1.6.26") + implementation("io.github.microutils:kotlin-logging:2.1.23") implementation("org.apache.logging.log4j:log4j-core:$log4jVersion") // Persistence diff --git a/pop-miners/veriblock-pop-miner/build.gradle.kts b/pop-miners/veriblock-pop-miner/build.gradle.kts index c6abb96c9..da8c8ffa1 100644 --- a/pop-miners/veriblock-pop-miner/build.gradle.kts +++ b/pop-miners/veriblock-pop-miner/build.gradle.kts @@ -73,7 +73,7 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:$kotlinxSerializationVersion") // Logging - implementation("io.github.microutils:kotlin-logging:1.6.26") + implementation("io.github.microutils:kotlin-logging:2.1.23") implementation("org.apache.logging.log4j:log4j-api:$log4jVersion") implementation("org.apache.logging.log4j:log4j-core:$log4jVersion") implementation("org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion") diff --git a/pop-miners/veriblock-pop-miners-common/build.gradle.kts b/pop-miners/veriblock-pop-miners-common/build.gradle.kts index d709d001a..2c27cab91 100644 --- a/pop-miners/veriblock-pop-miners-common/build.gradle.kts +++ b/pop-miners/veriblock-pop-miners-common/build.gradle.kts @@ -41,7 +41,7 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$coroutinesVersion") // Logging - implementation("io.github.microutils:kotlin-logging:1.6.26") + implementation("io.github.microutils:kotlin-logging:2.1.23") implementation("org.apache.logging.log4j:log4j-api:$log4jVersion") implementation("org.apache.logging.log4j:log4j-core:$log4jVersion") diff --git a/veriblock-core/build.gradle.kts b/veriblock-core/build.gradle.kts index cc866abeb..687a22997 100644 --- a/veriblock-core/build.gradle.kts +++ b/veriblock-core/build.gradle.kts @@ -30,7 +30,7 @@ dependencies { api("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$coroutinesVersion") // Logging - api("io.github.microutils:kotlin-logging:1.6.26") + api("io.github.microutils:kotlin-logging:2.1.23") implementation("org.apache.logging.log4j:log4j-api:$log4jVersion") implementation("org.apache.logging.log4j:log4j-core:$log4jVersion") implementation("org.slf4j:slf4j-api:$slf4jVersion") diff --git a/veriblock-core/src/main/java/org/veriblock/core/crypto/Sha256Hash.kt b/veriblock-core/src/main/java/org/veriblock/core/crypto/Sha256Hash.kt index 2f2e0e268..c94ea37db 100644 --- a/veriblock-core/src/main/java/org/veriblock/core/crypto/Sha256Hash.kt +++ b/veriblock-core/src/main/java/org/veriblock/core/crypto/Sha256Hash.kt @@ -103,9 +103,9 @@ class MerkleRoot(bytes: ByteArray) : Sha256Hash(bytes) { } } -class TruncatedMerkleRoot(bytes: ByteArray) : Sha256Hash(bytes) { +class TruncatedMerkleRoot(bytes: ByteArray) : Sha256Hash(trimBytes(bytes, TRUNCATED_MERKLE_ROOT_LENGTH)) { init { - check(bytes.size == TRUNCATED_MERKLE_ROOT_LENGTH) { + check(bytes.size == TRUNCATED_MERKLE_ROOT_LENGTH || bytes.size == TRUNCATED_MERKLE_ROOT_LENGTH * 2) { "Trying to create a truncated merkle root hash with invalid amount of bytes: ${bytes.size} (${bytes.toHex()})" } } diff --git a/veriblock-core/src/main/java/org/veriblock/core/crypto/VbkHash.kt b/veriblock-core/src/main/java/org/veriblock/core/crypto/VbkHash.kt index 02b790529..674016095 100644 --- a/veriblock-core/src/main/java/org/veriblock/core/crypto/VbkHash.kt +++ b/veriblock-core/src/main/java/org/veriblock/core/crypto/VbkHash.kt @@ -1,8 +1,13 @@ package org.veriblock.core.crypto +import com.google.gson.TypeAdapter +import com.google.gson.internal.bind.TypeAdapters +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter import org.veriblock.core.utilities.Utility import org.veriblock.core.utilities.extensions.asHexBytes import org.veriblock.core.utilities.extensions.toHex +import java.io.IOException import java.math.BigInteger import java.nio.ByteBuffer @@ -12,6 +17,8 @@ sealed class AnyVbkHash( val length: Int get() = bytes.size + constructor(hash: String) : this(hash.asHexBytes()) + abstract fun trimToPreviousBlockSize(): PreviousBlockVbkHash abstract fun trimToPreviousKeystoneSize(): PreviousKeystoneVbkHash @@ -33,19 +40,25 @@ sealed class AnyVbkHash( bytes.toHex() } -private fun AnyVbkHash.trimBytes(size: Int): ByteArray { +fun trimBytes(bytes: ByteArray, size: Int): ByteArray { return ByteArray(size).apply { System.arraycopy(bytes, bytes.size - size, this, 0, size) } } -open class VbkHash internal constructor(bytes: ByteArray) : AnyVbkHash(bytes) { +private fun AnyVbkHash.trimBytes(size: Int): ByteArray { + return trimBytes(bytes, size) +} + +open class VbkHash internal constructor(bytes: ByteArray) : AnyVbkHash(trimBytes(bytes, HASH_LENGTH)) { init { - check(bytes.size == HASH_LENGTH) { + check(bytes.size == HASH_LENGTH || bytes.size == VbkHash.HASH_LENGTH) { "Trying to create a VBK hash with invalid amount of bytes: ${bytes.size} (${bytes.toHex()})" } } + constructor(hash: String) : this(hash.asHexBytes()) + override fun trimToPreviousBlockSize(): PreviousBlockVbkHash = PreviousBlockVbkHash(trimBytes(PreviousBlockVbkHash.HASH_LENGTH)) @@ -58,13 +71,15 @@ open class VbkHash internal constructor(bytes: ByteArray) : AnyVbkHash(bytes) { } } -class PreviousBlockVbkHash(bytes: ByteArray) : AnyVbkHash(bytes) { +class PreviousBlockVbkHash(bytes: ByteArray) : AnyVbkHash(trimBytes(bytes, HASH_LENGTH)) { init { - check(bytes.size == HASH_LENGTH) { + check(bytes.size == HASH_LENGTH || bytes.size == VbkHash.HASH_LENGTH) { "Trying to create a previous block VBK hash with invalid amount of bytes: ${bytes.size} (${bytes.toHex()})" } } + constructor(hash: String) : this(hash.asHexBytes()) + override fun trimToPreviousBlockSize(): PreviousBlockVbkHash = this @@ -77,13 +92,15 @@ class PreviousBlockVbkHash(bytes: ByteArray) : AnyVbkHash(bytes) { } } -class PreviousKeystoneVbkHash(bytes: ByteArray) : AnyVbkHash(bytes) { +class PreviousKeystoneVbkHash(bytes: ByteArray) : AnyVbkHash(trimBytes(bytes, HASH_LENGTH)) { init { - check(bytes.size == HASH_LENGTH) { + check(bytes.size == HASH_LENGTH || bytes.size == VbkHash.HASH_LENGTH) { "Trying to create a previous keystone VBK hash with invalid amount of bytes: ${bytes.size} (${bytes.toHex()})" } } + constructor(hash: String) : this(hash.asHexBytes()) + override fun trimToPreviousBlockSize(): PreviousBlockVbkHash = error("Trying to trim a previous keystone VBK hash down to a previous block VBK hash") diff --git a/veriblock-core/src/main/java/org/veriblock/sdk/models/VeriBlockBlock.kt b/veriblock-core/src/main/java/org/veriblock/sdk/models/VeriBlockBlock.kt index 056d32125..3aca5f5e5 100644 --- a/veriblock-core/src/main/java/org/veriblock/sdk/models/VeriBlockBlock.kt +++ b/veriblock-core/src/main/java/org/veriblock/sdk/models/VeriBlockBlock.kt @@ -11,14 +11,15 @@ import org.veriblock.core.bitcoinj.BitcoinUtilities import org.veriblock.core.crypto.AnyVbkHash import org.veriblock.core.crypto.PreviousBlockVbkHash import org.veriblock.core.crypto.PreviousKeystoneVbkHash -import org.veriblock.core.crypto.VbkHash -import org.veriblock.core.crypto.MerkleRoot import org.veriblock.core.crypto.TruncatedMerkleRoot +import org.veriblock.core.crypto.VbkHash import org.veriblock.core.crypto.asVbkHash import org.veriblock.core.utilities.BlockUtility import org.veriblock.sdk.services.SerializeDeserializeService import java.math.BigInteger -import java.util.Arrays +import java.util.* + +annotation class SkipSerialisation open class VeriBlockBlock( val height: Int, @@ -30,6 +31,7 @@ open class VeriBlockBlock( val timestamp: Int, val difficulty: Int, var nonce: Long, + @Transient private val precomputedHash: VbkHash? = null ) { val raw: ByteArray From 0815cffd9f88d2f452d32616b79ff52b75fc8b15 Mon Sep 17 00:00:00 2001 From: Bohdan Date: Mon, 15 Aug 2022 19:15:04 +0300 Subject: [PATCH 2/2] Refactor SPV models into SDK models --- .../plugins/ethereum/EthereumFamilyChain.kt | 14 +- .../spv/standalone/commands/SpvCommands.kt | 2 - .../main/java/org/veriblock/spv/SpvContext.kt | 4 +- .../java/org/veriblock/spv/model/FullBlock.kt | 34 ---- .../java/org/veriblock/spv/model/Output.kt | 38 ----- .../spv/model/PopTransactionLight.kt | 72 --------- .../org/veriblock/spv/model/SigningResult.kt | 11 +- .../spv/model/StandardTransaction.kt | 152 +----------------- .../org/veriblock/spv/model/Transaction.kt | 42 ----- .../veriblock/spv/model/TransactionMeta.kt | 4 +- .../veriblock/spv/model/TransactionPool.kt | 15 +- .../veriblock/spv/net/PeerEventListener.kt | 2 - .../spv/serialization/MessageSerializer.kt | 147 ----------------- .../java/org/veriblock/spv/service/Model.kt | 7 +- .../service/PendingTransactionContainer.kt | 1 - .../org/veriblock/spv/service/SpvService.kt | 70 ++++---- .../spv/service/TransactionService.kt | 64 ++++---- .../task/PendingTransactionsUpdateTask.kt | 2 +- .../java/org/veriblock/spv/wallet/Ledger.kt | 16 +- .../PendingTransactionDownloadedListener.kt | 20 +-- .../admin/service/impl/AdminApiServiceTest.kt | 12 +- .../spv/lite/core/StandardTransactionTest.kt | 2 - .../spv/net/impl/PeerEventListenerTest.kt | 2 - .../spv/service/TransactionServiceTest.kt | 1 - .../pop/api/controller/WalletController.kt | 1 - .../veriblock/miners/pop/net/SpvGateway.kt | 18 +-- .../SecurityInheritingMonitor.kt | 26 ++- .../pop/serialization/MessageSerializer.kt | 1 - .../pop/shell/commands/WalletCommands.kt | 1 - .../org/veriblock/core/crypto/Sha256Hash.kt | 2 +- .../sdk/models/VeriBlockPopTransaction.kt | 6 +- .../sdk/models/VeriBlockTransaction.kt | 11 +- 32 files changed, 145 insertions(+), 655 deletions(-) delete mode 100644 nodecore-spv/src/main/java/org/veriblock/spv/model/FullBlock.kt delete mode 100644 nodecore-spv/src/main/java/org/veriblock/spv/model/Output.kt delete mode 100644 nodecore-spv/src/main/java/org/veriblock/spv/model/PopTransactionLight.kt delete mode 100644 nodecore-spv/src/main/java/org/veriblock/spv/model/Transaction.kt delete mode 100644 nodecore-spv/src/main/java/org/veriblock/spv/serialization/MessageSerializer.kt diff --git a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/ethereum/EthereumFamilyChain.kt b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/ethereum/EthereumFamilyChain.kt index df68a1802..1be879230 100644 --- a/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/ethereum/EthereumFamilyChain.kt +++ b/altchain-plugins/src/main/kotlin/org/veriblock/alt/plugins/ethereum/EthereumFamilyChain.kt @@ -325,22 +325,10 @@ class EthereumFamilyChain( } override suspend fun getVbkBlock(hash: String): VbkBlockResponse? { - val response = rpcRequest( + return rpcRequest( method="pop_getVbkBlockByHash", params = listOf(hash), version = "2.0") - - return VbkBlockResponse( - chainWork = response.chainWork, - containingEndorsements = response.containingEndorsements, - endorsedBy = response.endorsedBy, - blockOfProofEndorsements = response.blockOfProofEndorsements, - height = response.height, - header = response.header.toVbkBlock(), - status = response.status, - altrefs = response.altrefs, - stored = StoredInVbkBlockData(response.stored.vtbids) - ) } override suspend fun getVbkBlockHash(height: Int): String? { diff --git a/nodecore-spv/nodecore-spv-standalone/src/main/kotlin/org/veriblock/spv/standalone/commands/SpvCommands.kt b/nodecore-spv/nodecore-spv-standalone/src/main/kotlin/org/veriblock/spv/standalone/commands/SpvCommands.kt index de9845126..38c1e803f 100644 --- a/nodecore-spv/nodecore-spv-standalone/src/main/kotlin/org/veriblock/spv/standalone/commands/SpvCommands.kt +++ b/nodecore-spv/nodecore-spv-standalone/src/main/kotlin/org/veriblock/spv/standalone/commands/SpvCommands.kt @@ -3,7 +3,6 @@ package org.veriblock.spv.standalone.commands import com.google.gson.GsonBuilder import com.google.gson.JsonPrimitive import com.google.gson.JsonSerializer -import kotlinx.coroutines.runBlocking import org.jline.utils.AttributedStyle import org.veriblock.core.WalletException import org.veriblock.core.utilities.Utility @@ -17,7 +16,6 @@ import org.veriblock.shell.command import org.veriblock.shell.core.failure import org.veriblock.shell.core.success import org.veriblock.spv.SpvContext -import org.veriblock.spv.model.Output import org.veriblock.spv.model.asLightAddress fun CommandFactory.spvCommands( diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/SpvContext.kt b/nodecore-spv/src/main/java/org/veriblock/spv/SpvContext.kt index cfe332a60..b14e252ec 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/SpvContext.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/SpvContext.kt @@ -65,7 +65,7 @@ class SpvContext( val addressManager: AddressManager val transactionService: TransactionService val pendingTransactionContainer: PendingTransactionContainer - val pendingTransactionDownloadedListener: PendingTransactionDownloadedListener +// val pendingTransactionDownloadedListener: PendingTransactionDownloadedListener private val addressState: ConcurrentHashMap = ConcurrentHashMap() @@ -96,7 +96,7 @@ class SpvContext( addressManager = AddressManager() val walletFile = File(directory, filePrefix + FILE_EXTENSION) addressManager.load(walletFile) - pendingTransactionDownloadedListener = PendingTransactionDownloadedListener(this) +// pendingTransactionDownloadedListener = PendingTransactionDownloadedListener(this) val externalPeerEndpoints = config.connectDirectlyTo.map { try { diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/model/FullBlock.kt b/nodecore-spv/src/main/java/org/veriblock/spv/model/FullBlock.kt deleted file mode 100644 index a5a1e5dca..000000000 --- a/nodecore-spv/src/main/java/org/veriblock/spv/model/FullBlock.kt +++ /dev/null @@ -1,34 +0,0 @@ -// VeriBlock Blockchain Project -// Copyright 2017-2018 VeriBlock, Inc -// Copyright 2018-2021 Xenios SEZC -// All rights reserved. -// https://www.veriblock.org -// Distributed under the MIT software license, see the accompanying -// file LICENSE or http://www.opensource.org/licenses/mit-license.php. -package org.veriblock.spv.model - -import org.veriblock.core.crypto.PreviousBlockVbkHash -import org.veriblock.core.crypto.PreviousKeystoneVbkHash -import org.veriblock.core.crypto.MerkleRoot -import org.veriblock.core.crypto.TruncatedMerkleRoot -import org.veriblock.sdk.models.VeriBlockBlock - -class FullBlock( - height: Int, - version: Short, - previousBlock: PreviousBlockVbkHash, - previousKeystone: PreviousKeystoneVbkHash, - secondPreviousKeystone: PreviousKeystoneVbkHash, - merkleRoot: TruncatedMerkleRoot, - timestamp: Int, - difficulty: Int, - nonce: Long -) : VeriBlockBlock( - height, version, previousBlock, previousKeystone, secondPreviousKeystone, merkleRoot, timestamp, difficulty, nonce -) { - var normalTransactions: List? = null - - var popTransactions: List? = null - - var metaPackage: BlockMetaPackage? = null -} diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/model/Output.kt b/nodecore-spv/src/main/java/org/veriblock/spv/model/Output.kt deleted file mode 100644 index 7a74168ca..000000000 --- a/nodecore-spv/src/main/java/org/veriblock/spv/model/Output.kt +++ /dev/null @@ -1,38 +0,0 @@ -// VeriBlock Blockchain Project -// Copyright 2017-2018 VeriBlock, Inc -// Copyright 2018-2021 Xenios SEZC -// All rights reserved. -// https://www.veriblock.org -// Distributed under the MIT software license, see the accompanying -// file LICENSE or http://www.opensource.org/licenses/mit-license.php. -package org.veriblock.spv.model - -import org.veriblock.sdk.models.Coin -import org.veriblock.sdk.services.SerializeDeserializeService -import java.io.OutputStream -import java.util.Objects - -class Output( - val address: AddressLight, - val amount: Coin -) { - fun serializeToStream(stream: OutputStream) { - address.serializeToStream(stream) - SerializeDeserializeService.serialize(amount, stream) - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - if (other !is Output) { - return false - } - return address == other.address && - amount == other.amount - } - - override fun hashCode(): Int { - return Objects.hash(address, amount) - } -} diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/model/PopTransactionLight.kt b/nodecore-spv/src/main/java/org/veriblock/spv/model/PopTransactionLight.kt deleted file mode 100644 index a728dfad9..000000000 --- a/nodecore-spv/src/main/java/org/veriblock/spv/model/PopTransactionLight.kt +++ /dev/null @@ -1,72 +0,0 @@ -// VeriBlock Blockchain Project -// Copyright 2017-2018 VeriBlock, Inc -// Copyright 2018-2021 Xenios SEZC -// All rights reserved. -// https://www.veriblock.org -// Distributed under the MIT software license, see the accompanying -// file LICENSE or http://www.opensource.org/licenses/mit-license.php. -package org.veriblock.spv.model - -import nodecore.api.grpc.RpcSignedTransaction -import org.veriblock.core.utilities.SerializerUtility -import org.veriblock.sdk.models.BitcoinBlock -import org.veriblock.sdk.models.BitcoinTransaction -import org.veriblock.sdk.models.MerklePath -import org.veriblock.core.crypto.Sha256Hash -import org.veriblock.core.crypto.VbkTxId -import org.veriblock.core.params.NetworkParameters -import org.veriblock.sdk.models.VeriBlockBlock -import org.veriblock.sdk.services.SerializeDeserializeService -import java.io.ByteArrayOutputStream -import java.io.IOException -import java.io.OutputStream -import java.util.ArrayList - -class PopTransactionLight( - txId: VbkTxId, - val endorsedBlock: VeriBlockBlock, - val bitcoinTx: BitcoinTransaction, - val bitcoinMerklePath: MerklePath, - val blockOfProof: BitcoinBlock -) : StandardTransaction(txId) { - private val blockOfProofContext: MutableList = ArrayList() - - fun getContextBitcoinBlocks(): List = - blockOfProofContext - - fun addContextBitcoinBlocks(contextBitcoinBlock: BitcoinBlock) { - blockOfProofContext.add(contextBitcoinBlock) - } - - override fun toByteArray(networkParameters: NetworkParameters): ByteArray { - return calculateHash() - } - - override fun getSignedMessageBuilder(networkParameters: NetworkParameters): RpcSignedTransaction.Builder { - TODO() // SPV-48 - } - - private fun calculateHash(): ByteArray { - ByteArrayOutputStream().use { stream -> - serializeToStream(stream) - return stream.toByteArray() - } - } - - override val transactionTypeIdentifier: TransactionTypeIdentifier - get() = TransactionTypeIdentifier.PROOF_OF_PROOF - - @Throws(IOException::class) - private fun serializeToStream(stream: OutputStream) { - stream.write(transactionTypeIdentifier.id.toInt()) - inputAddress!!.serializeToStream(stream) - SerializeDeserializeService.serialize(endorsedBlock, stream) - SerializeDeserializeService.serialize(bitcoinTx, stream) - SerializeDeserializeService.serialize(bitcoinMerklePath, stream) - SerializeDeserializeService.serialize(blockOfProof, stream) - SerializerUtility.writeVariableLengthValueToStream(stream, getContextBitcoinBlocks().size) - for (block in getContextBitcoinBlocks()) { - SerializeDeserializeService.serialize(block, stream) - } - } -} diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/model/SigningResult.kt b/nodecore-spv/src/main/java/org/veriblock/spv/model/SigningResult.kt index af63be5f2..5d8148ed5 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/model/SigningResult.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/model/SigningResult.kt @@ -7,11 +7,6 @@ package org.veriblock.spv.model class SigningResult( - private val succeeded: Boolean, - val signature: ByteArray?, - val publicKey: ByteArray? -) { - fun succeeded(): Boolean { - return succeeded - } -} + val signature: ByteArray, + val publicKey: ByteArray +) diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/model/StandardTransaction.kt b/nodecore-spv/src/main/java/org/veriblock/spv/model/StandardTransaction.kt index f442cc977..448332ded 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/model/StandardTransaction.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/model/StandardTransaction.kt @@ -20,6 +20,7 @@ import org.veriblock.core.crypto.Sha256Hash import org.veriblock.core.crypto.VbkTxId import org.veriblock.core.crypto.asVbkTxId import org.veriblock.core.params.NetworkParameters +import org.veriblock.sdk.models.VeriBlockTransaction import org.veriblock.sdk.models.asCoin import org.veriblock.sdk.services.SerializeDeserializeService import java.io.ByteArrayOutputStream @@ -29,150 +30,7 @@ import java.util.ArrayList private val logger = createLogger {} -open class StandardTransaction : Transaction { - var inputAmount: Coin? = null - private val outputs: MutableList = ArrayList() - private var signatureIndex: Long = 0 - private var transactionFee: Long = 0 - override var data: ByteArray? = null - - constructor(txId: VbkTxId) : super(txId) - - constructor( - inputAddress: String, - inputAmount: Long, - outputs: List, - signatureIndex: Long, - networkParameters: NetworkParameters - ) : this( - null, inputAddress, inputAmount, outputs, signatureIndex, ByteArray(0), networkParameters - ) - - constructor( - txId: VbkTxId?, - inputAddress: String, - inputAmount: Long, - outputs: List, - signatureIndex: Long, - data: ByteArray?, - networkParameters: NetworkParameters - ) { - var totalOutput = 0L - for (o in outputs) { - totalOutput += o.amount.atomicUnits - } - val fee = inputAmount - totalOutput - - // Only for Alt Chain Endorsement Transactions - this.data = data - this.signatureIndex = signatureIndex - addAllOutput(outputs) - this.inputAmount = inputAmount.asCoin() - this.inputAddress = StandardAddress(inputAddress) - transactionFee = fee - if (txId == null) { - this.txId = calculateTxId(networkParameters) - } else { - this.txId = txId - } - } - - override fun toByteArray(networkParameters: NetworkParameters): ByteArray { - ByteArrayOutputStream().use { stream -> - serializeToStream(stream, networkParameters) - return stream.toByteArray() - } - } - - override fun getSignedMessageBuilder(networkParameters: NetworkParameters): RpcSignedTransaction.Builder { - val transaction = getTransactionMessageBuilder(networkParameters).build() - val builder = RpcSignedTransaction.newBuilder() - builder.transaction = transaction - builder.signatureIndex = signatureIndex - builder.publicKey = ByteString.copyFrom(publicKey) - builder.signature = ByteString.copyFrom(signature) - return builder - } - - private fun getTransactionMessageBuilder(networkParameters: NetworkParameters): RpcTransaction.Builder { - val builder = RpcTransaction.newBuilder() - builder.timestamp = Utility.getCurrentTimeSeconds() - builder.transactionFee = transactionFee - builder.txId = txId.toString().asHexByteString() - if (transactionTypeIdentifier == TransactionTypeIdentifier.STANDARD) { - builder.type = RpcTransaction.Type.STANDARD - } else if (transactionTypeIdentifier == TransactionTypeIdentifier.MULTISIG) { - builder.type = RpcTransaction.Type.MULTISIG - } - builder.sourceAmount = inputAmount!!.atomicUnits - builder.sourceAddress = ByteString.copyFrom(inputAddress!!.toByteArray()) - builder.data = ByteString.copyFrom(data) - builder.size = toByteArray(networkParameters).size - for (output in getOutputs()) { - val outputBuilder = builder.addOutputsBuilder() - outputBuilder.address = ByteString.copyFrom(output.address.toByteArray()) - outputBuilder.amount = output.amount.atomicUnits - } - return builder - } - - @Throws(IOException::class) - private fun serializeToStream(stream: OutputStream, networkParameters: NetworkParameters) { - val magicByte = networkParameters.transactionPrefix - if (magicByte != null) { - stream.write(magicByte.toInt()) - } - - // Write type - stream.write(transactionTypeIdentifier.id.toInt()) - - // Write source address - inputAddress!!.serializeToStream(stream) - - // Write source amount - SerializeDeserializeService.serialize(inputAmount!!, stream) - - // Write destinations - stream.write(getOutputs().size) - for (output in getOutputs()) { - output.serializeToStream(stream) - } - SerializerUtility.writeVariableLengthValueToStream(stream, signatureIndex) - SerializerUtility.writeVariableLengthValueToStream(stream, data) - } - - override fun getOutputs(): List { - return outputs - } - - fun addOutput(o: Output) { - outputs.add(o) - } - - fun addAllOutput(o: Collection) { - outputs.addAll(o) - } - - override fun getSignatureIndex(): Long = - signatureIndex - - fun setSignatureIndex(signatureIndex: Long) { - this.signatureIndex = signatureIndex - } - - override fun getTransactionFee(): Long = - transactionFee - - override val transactionTypeIdentifier: TransactionTypeIdentifier - get() = TransactionTypeIdentifier.STANDARD - - private fun calculateTxId( - networkParameters: NetworkParameters - ): VbkTxId { - return calculateTxIDBytes(toByteArray(networkParameters)).asVbkTxId() - } - - private fun calculateTxIDBytes(rawTx: ByteArray): ByteArray { - return Crypto().SHA256ReturnBytes(rawTx) - } -} +class StandardTransaction( + val tx: VeriBlockTransaction, + val meta: TransactionMeta +) diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/model/Transaction.kt b/nodecore-spv/src/main/java/org/veriblock/spv/model/Transaction.kt deleted file mode 100644 index 93759a4d8..000000000 --- a/nodecore-spv/src/main/java/org/veriblock/spv/model/Transaction.kt +++ /dev/null @@ -1,42 +0,0 @@ -// VeriBlock Blockchain Project -// Copyright 2017-2018 VeriBlock, Inc -// Copyright 2018-2021 Xenios SEZC -// All rights reserved. -// https://www.veriblock.org -// Distributed under the MIT software license, see the accompanying -// file LICENSE or http://www.opensource.org/licenses/mit-license.php. -package org.veriblock.spv.model - -import nodecore.api.grpc.RpcSignedTransaction -import org.veriblock.core.crypto.Sha256Hash -import org.veriblock.core.crypto.VbkTxId -import org.veriblock.core.params.NetworkParameters - -abstract class Transaction { - lateinit var txId: VbkTxId - var inputAddress: AddressLight? = null - var transactionMeta: TransactionMeta? = null - var signature: ByteArray? = null - var publicKey: ByteArray? = null - - constructor() - - constructor(txId: VbkTxId) { - this.txId = txId - transactionMeta = TransactionMeta(txId) - } - - abstract fun getOutputs(): List - abstract fun getSignatureIndex(): Long - abstract fun getTransactionFee(): Long - abstract fun toByteArray(networkParameters: NetworkParameters): ByteArray? - abstract fun getSignedMessageBuilder(networkParameters: NetworkParameters): RpcSignedTransaction.Builder? - - abstract val data: ByteArray? - abstract val transactionTypeIdentifier: TransactionTypeIdentifier - - fun addSignature(signature: ByteArray?, publicKey: ByteArray?) { - this.signature = signature - this.publicKey = publicKey - } -} diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/model/TransactionMeta.kt b/nodecore-spv/src/main/java/org/veriblock/spv/model/TransactionMeta.kt index cc4efe2af..f982d8220 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/model/TransactionMeta.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/model/TransactionMeta.kt @@ -14,9 +14,7 @@ import org.veriblock.spv.util.SpvEventBus import java.util.ArrayList import java.util.HashSet -class TransactionMeta( - val txId: VbkTxId -) { +class TransactionMeta { private val appearsInBlock: MutableList = ArrayList() var appearsAtChainHeight = -1 var depth = 0 diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/model/TransactionPool.kt b/nodecore-spv/src/main/java/org/veriblock/spv/model/TransactionPool.kt index 3d5fe3c5d..39a663b9b 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/model/TransactionPool.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/model/TransactionPool.kt @@ -19,11 +19,10 @@ import kotlin.concurrent.withLock class TransactionPool { private class WeakPoolReference( + val id: VbkTxId, meta: TransactionMeta, queue: ReferenceQueue? - ) : WeakReference(meta, queue) { - var hash: Sha256Hash? = meta.txId - } + ) : WeakReference(meta, queue) private val lock = ReentrantLock(true) private val referenceQueue = ReferenceQueue() @@ -53,20 +52,20 @@ class TransactionPool { return transactionMeta } } - val tx = TransactionMeta(txId) - pool[txId] = WeakPoolReference(tx, referenceQueue) + val tx = TransactionMeta() + pool[txId] = WeakPoolReference(txId, tx, referenceQueue) tx } - fun insert(meta: TransactionMeta) = lock.withLock { - pool[meta.txId] = WeakPoolReference(meta, referenceQueue) + fun insert(id: VbkTxId, meta: TransactionMeta) = lock.withLock { + pool[id] = WeakPoolReference(id, meta, referenceQueue) } private fun purge() = lock.withLock { var reference: Reference? = referenceQueue.poll() while (reference != null) { val txReference = reference as WeakPoolReference - pool.remove(txReference.hash) + pool.remove(txReference.id) reference = referenceQueue.poll() } } diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/net/PeerEventListener.kt b/nodecore-spv/src/main/java/org/veriblock/spv/net/PeerEventListener.kt index 57b2c299f..b24eaf1c4 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/net/PeerEventListener.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/net/PeerEventListener.kt @@ -51,9 +51,7 @@ import org.veriblock.sdk.models.VeriBlockBlock import org.veriblock.sdk.services.SerializeDeserializeService import org.veriblock.spv.SpvContext import org.veriblock.spv.SpvState -import org.veriblock.spv.model.Transaction import org.veriblock.spv.model.TransactionTypeIdentifier -import org.veriblock.spv.serialization.MessageSerializer import org.veriblock.spv.service.Blockchain import org.veriblock.spv.service.NetworkBlock import org.veriblock.spv.service.PendingTransactionContainer diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/serialization/MessageSerializer.kt b/nodecore-spv/src/main/java/org/veriblock/spv/serialization/MessageSerializer.kt deleted file mode 100644 index 7f525509f..000000000 --- a/nodecore-spv/src/main/java/org/veriblock/spv/serialization/MessageSerializer.kt +++ /dev/null @@ -1,147 +0,0 @@ -// VeriBlock Blockchain Project -// Copyright 2017-2018 VeriBlock, Inc -// Copyright 2018-2021 Xenios SEZC -// All rights reserved. -// https://www.veriblock.org -// Distributed under the MIT software license, see the accompanying -// file LICENSE or http://www.opensource.org/licenses/mit-license.php. -package org.veriblock.spv.serialization - -import com.google.protobuf.InvalidProtocolBufferException -import nodecore.api.grpc.RpcBlock -import nodecore.api.grpc.RpcBlockHeader -import nodecore.api.grpc.RpcEvent -import nodecore.api.grpc.RpcSignedMultisigTransaction -import nodecore.api.grpc.RpcSignedTransaction -import nodecore.api.grpc.RpcTransactionUnion -import nodecore.api.grpc.utilities.ByteStringAddressUtility -import nodecore.api.grpc.utilities.ByteStringUtility -import nodecore.api.grpc.utilities.extensions.asVbkPreviousBlockHash -import nodecore.api.grpc.utilities.extensions.asVbkPreviousKeystoneHash -import org.veriblock.core.utilities.createLogger -import org.veriblock.sdk.models.BitcoinTransaction -import org.veriblock.sdk.models.MerklePath -import org.veriblock.core.crypto.asVbkHash -import org.veriblock.core.crypto.asBtcHash -import org.veriblock.core.crypto.asTruncatedMerkleRoot -import org.veriblock.core.crypto.asVbkTxId -import org.veriblock.sdk.models.VeriBlockBlock -import org.veriblock.sdk.models.asCoin -import org.veriblock.sdk.services.SerializeDeserializeService -import org.veriblock.spv.model.BlockMetaPackage -import org.veriblock.spv.model.FullBlock -import org.veriblock.spv.model.MultisigTransaction -import org.veriblock.spv.model.OutputFactory.create -import org.veriblock.spv.model.PopTransactionLight -import org.veriblock.spv.model.StandardTransaction -import org.veriblock.spv.model.asLightAddress - -private val logger = createLogger {} - -object MessageSerializer { - fun deserialize(blockHeaderMessage: RpcBlockHeader, trustHash: Boolean = false): VeriBlockBlock { - return if (trustHash) { - SerializeDeserializeService.parseVeriBlockBlock(blockHeaderMessage.header.toByteArray(), blockHeaderMessage.hash.toByteArray().asVbkHash()) - } else { - SerializeDeserializeService.parseVeriBlockBlock(blockHeaderMessage.header.toByteArray()) - } - } - - @JvmStatic - fun deserializeNormalTransaction(transactionUnionMessage: RpcTransactionUnion): StandardTransaction { - return when (transactionUnionMessage.transactionCase) { - RpcTransactionUnion.TransactionCase.SIGNED -> deserializeStandardTransaction( - transactionUnionMessage.signed - ) - RpcTransactionUnion.TransactionCase.SIGNED_MULTISIG -> deserializeMultisigTransaction( - transactionUnionMessage.signedMultisig - ) - else -> - // Should be impossible - error("Unhandled transaction type: ${transactionUnionMessage.transactionCase}") - } - } - - fun deserializePopTransaction(transactionUnionMessage: RpcTransactionUnion): PopTransactionLight { - val signed = transactionUnionMessage.signed - val txMessage = signed.transaction - val tx = PopTransactionLight( - txId = txMessage.txId.toByteArray().asVbkTxId(), - endorsedBlock = SerializeDeserializeService.parseVeriBlockBlock(txMessage.endorsedBlockHeader.toByteArray()), - bitcoinTx = BitcoinTransaction(txMessage.bitcoinTransaction.toByteArray()), - bitcoinMerklePath = MerklePath(txMessage.merklePath), - blockOfProof = SerializeDeserializeService.parseBitcoinBlock(txMessage.bitcoinBlockHeaderOfProof.header.toByteArray()) - ) - tx.inputAddress = ByteStringAddressUtility.parseProperAddressTypeAutomatically(txMessage.sourceAddress).asLightAddress() - txMessage.contextBitcoinBlockHeadersList.map { - SerializeDeserializeService.parseBitcoinBlock(it.header.toByteArray()) - }.forEach { - tx.addContextBitcoinBlocks(it) - } - return tx - } - - fun deserialize(blockMessage: RpcBlock): FullBlock { - val block = FullBlock( - blockMessage.number, - blockMessage.version.toShort(), - blockMessage.previousHash.asVbkPreviousBlockHash(), - blockMessage.secondPreviousHash.asVbkPreviousKeystoneHash(), - blockMessage.thirdPreviousHash.asVbkPreviousKeystoneHash(), - ByteStringUtility.byteStringToHex(blockMessage.merkleRoot).asTruncatedMerkleRoot(), - blockMessage.timestamp, - blockMessage.encodedDifficulty, - blockMessage.winningNonce - ) - block.normalTransactions = blockMessage.regularTransactionsList.map { - deserializeNormalTransaction(it) - } - block.popTransactions = blockMessage.popTransactionsList.map { - deserializePopTransaction(it) - } - block.metaPackage = BlockMetaPackage( - blockMessage.blockContentMetapackage.hash.toByteArray().asBtcHash() - ) - return block - } - - private fun deserializeStandardTransaction(signedTransaction: RpcSignedTransaction): StandardTransaction { - val txMessage = signedTransaction.transaction - val tx = StandardTransaction(txMessage.txId.toByteArray().asVbkTxId()) - tx.inputAddress = ByteStringAddressUtility.parseProperAddressTypeAutomatically(txMessage.sourceAddress).asLightAddress() - tx.inputAmount = txMessage.sourceAmount.asCoin() - txMessage.outputsList.map { - create(ByteStringAddressUtility.parseProperAddressTypeAutomatically(it.address), it.amount) - }.forEach { - tx.addOutput(it) - } - tx.setSignatureIndex(signedTransaction.signatureIndex) - tx.data = txMessage.data.toByteArray() - return tx - } - - private fun deserializeMultisigTransaction(signedTransaction: RpcSignedMultisigTransaction): StandardTransaction { - val txMessage = signedTransaction.transaction - val tx: StandardTransaction = MultisigTransaction(txMessage.txId.toByteArray().asVbkTxId()) - tx.inputAddress = ByteStringAddressUtility.parseProperAddressTypeAutomatically(txMessage.sourceAddress).asLightAddress() - tx.inputAmount = txMessage.sourceAmount.asCoin() - txMessage.outputsList.map { - create(ByteStringAddressUtility.parseProperAddressTypeAutomatically(it.address), it.amount) - }.forEach { - tx.addOutput(it) - } - tx.setSignatureIndex(signedTransaction.signatureIndex) - tx.data = txMessage.data.toByteArray() - return tx - } - - @JvmStatic - fun deserialize(raw: ByteArray?): RpcEvent? { - try { - return RpcEvent.parseFrom(raw) - } catch (e: InvalidProtocolBufferException) { - logger.error("Unable to parse message", e) - } - return null - } -} diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/service/Model.kt b/nodecore-spv/src/main/java/org/veriblock/spv/service/Model.kt index 24bfb663a..7d0ec3aa7 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/service/Model.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/service/Model.kt @@ -1,15 +1,14 @@ package org.veriblock.spv.service import nodecore.p2p.Peer -import org.veriblock.core.crypto.Sha256Hash import org.veriblock.core.crypto.VbkTxId import org.veriblock.sdk.models.Address import org.veriblock.sdk.models.Coin +import org.veriblock.sdk.models.Output import org.veriblock.sdk.models.VeriBlockBlock +import org.veriblock.sdk.models.VeriBlockTransaction import org.veriblock.spv.model.AddressLight -import org.veriblock.spv.model.Output import org.veriblock.spv.model.StandardTransaction -import org.veriblock.spv.model.Transaction enum class BlockchainState { LOADING, @@ -78,7 +77,7 @@ data class WalletBalance( ) data class AltChainEndorsement( - val transaction: StandardTransaction, + val transaction: VeriBlockTransaction, val signatureIndex: Long ) diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/service/PendingTransactionContainer.kt b/nodecore-spv/src/main/java/org/veriblock/spv/service/PendingTransactionContainer.kt index d98e60f63..212d06b35 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/service/PendingTransactionContainer.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/service/PendingTransactionContainer.kt @@ -12,7 +12,6 @@ import org.veriblock.core.utilities.createLogger import org.veriblock.sdk.models.Address import org.veriblock.sdk.models.VeriBlockBlock import org.veriblock.spv.SpvContext -import org.veriblock.spv.model.Transaction import org.veriblock.spv.util.SpvEventBus import org.veriblock.spv.util.Threading diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/service/SpvService.kt b/nodecore-spv/src/main/java/org/veriblock/spv/service/SpvService.kt index 673500310..6d1439daf 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/service/SpvService.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/service/SpvService.kt @@ -8,22 +8,27 @@ package org.veriblock.spv.service import com.google.protobuf.ByteString -import kotlinx.coroutines.flow.asFlow -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.toList import nodecore.api.grpc.RpcAdvertiseTransaction import nodecore.api.grpc.RpcBlockHeader -import nodecore.api.grpc.RpcBlockHeadersByHashesRequest -import nodecore.api.grpc.RpcBlockInfo import nodecore.api.grpc.RpcGetVeriBlockPublicationsReply import nodecore.api.grpc.RpcGetVeriBlockPublicationsRequest +import nodecore.api.grpc.RpcGetVtbsForBtcBlocksReply +import nodecore.api.grpc.RpcGetVtbsForBtcBlocksRequest import nodecore.api.grpc.RpcTransactionAnnounce +import nodecore.p2p.PeerCapabilities import nodecore.p2p.PeerTable import nodecore.p2p.buildMessage -import org.veriblock.core.* +import org.veriblock.core.AddressCreationException +import org.veriblock.core.EndorsementCreationException +import org.veriblock.core.ImportException +import org.veriblock.core.SendCoinsException +import org.veriblock.core.WalletException +import org.veriblock.core.WalletLockedException import org.veriblock.core.crypto.AnyVbkHash +import org.veriblock.core.crypto.PreviousBlockVbkHash import org.veriblock.core.crypto.Sha256Hash +import org.veriblock.core.crypto.VbkHash +import org.veriblock.core.crypto.VbkTxId import org.veriblock.core.types.Pair import org.veriblock.core.utilities.createLogger import org.veriblock.core.utilities.debugError @@ -33,6 +38,10 @@ import org.veriblock.core.utilities.extensions.toHex import org.veriblock.core.wallet.AddressManager import org.veriblock.core.wallet.AddressPubKey import org.veriblock.sdk.models.Address +import org.veriblock.sdk.models.FullBlock +import org.veriblock.sdk.models.Output +import org.veriblock.sdk.models.VeriBlockPopTransaction +import org.veriblock.sdk.models.VeriBlockTransaction import org.veriblock.sdk.models.asCoin import org.veriblock.sdk.services.SerializeDeserializeService import org.veriblock.spv.SpvConstants @@ -44,24 +53,14 @@ import org.veriblock.spv.model.BlockHeader import org.veriblock.spv.model.DownloadStatus import org.veriblock.spv.model.DownloadStatusResponse import org.veriblock.spv.model.LedgerContext -import org.veriblock.spv.model.Output -import org.veriblock.spv.model.StandardTransaction import org.veriblock.spv.model.StoredVeriBlockBlock -import org.veriblock.spv.model.Transaction import org.veriblock.spv.model.TransactionTypeIdentifier import org.veriblock.spv.model.asLightAddress import org.veriblock.spv.net.AMOUNT_OF_BLOCKS_WHEN_WE_CAN_START_WORKING import org.veriblock.spv.service.TransactionService.Companion.predictAltChainEndorsementTransactionSize import java.io.File import java.io.IOException -import java.util.* -import nodecore.api.grpc.RpcGetVtbsForBtcBlocksReply -import nodecore.api.grpc.RpcGetVtbsForBtcBlocksRequest -import nodecore.p2p.PeerCapabilities -import org.veriblock.core.crypto.VbkHash -import org.veriblock.core.crypto.VbkTxId -import org.veriblock.sdk.models.FullBlock -import org.veriblock.spv.serialization.MessageSerializer + private val logger = createLogger {} @@ -145,7 +144,7 @@ class SpvService( pendingTransactionContainer.addTransaction(it) peerTable.advertise(it) }.map { - it.txId + it.id }.toList() } @@ -163,7 +162,7 @@ class SpvService( } } - suspend fun submitTransactions(transactions: List) { + suspend fun submitTransactions(transactions: List) { for (transaction in transactions) { pendingTransactionContainer.addTransaction(transaction) peerTable.advertise(transaction) @@ -204,9 +203,8 @@ class SpvService( val privateKeyLength = privateKey[0].toInt() val privateKeyBytes = privateKey.copyOfRange(1, privateKeyLength + 1) val publicKeyBytes = privateKey.copyOfRange(privateKeyLength + 1, privateKey.size) - val importedAddress = addressManager.importKeyPair(publicKeyBytes, privateKeyBytes) + return addressManager.importKeyPair(publicKeyBytes, privateKeyBytes) ?: throw ImportException("The private key ${privateKey.toHex()} is invalid or corrupted!") - return importedAddress } fun encryptWallet(passphrase: String) { @@ -339,7 +337,7 @@ class SpvService( val tx = transactionService.createUnsignedAltChainEndorsementTransaction( sourceAddress.address, fee, publicationData, signatureIndex ) - return AltChainEndorsement((tx as StandardTransaction), signatureIndex) + return AltChainEndorsement(tx, signatureIndex) } catch (e: Exception) { logger.debugWarn(e) { "Failed to create alt chain endorsement" } throw EndorsementCreationException("Failed to create alt chain endorsement") @@ -458,7 +456,7 @@ class SpvService( return DownloadStatusResponse(status, currentHeight, bestBlockHeight) } - suspend fun getFullBlock(hash: VbkHash): FullBlock? { + suspend fun getFullBlock(hash: PreviousBlockVbkHash): FullBlock? { // if we don't know this block, we exit early. // but we don't need the block itself. blockchain.getBlock(hash) ?: return null @@ -477,26 +475,18 @@ class SpvService( event = request ) { if (it.block == null) -1 else 1 }.block - val block = MessageSerializer.deserialize(rpcBlock) - logger.warn { block.toString() } + // TODO(warchant): Deserialize RpcBlock -> FullBlock - return null } } -fun PeerTable.advertise(transaction: Transaction) { +private fun PeerTable.advertiseTx(id: ByteArray, type: RpcTransactionAnnounce.Type) { val advertise = buildMessage { advertiseTx = RpcAdvertiseTransaction.newBuilder() .addTransactions( RpcTransactionAnnounce.newBuilder() - .setType( - if (transaction.transactionTypeIdentifier === TransactionTypeIdentifier.PROOF_OF_PROOF) { - RpcTransactionAnnounce.Type.PROOF_OF_PROOF - } else { - RpcTransactionAnnounce.Type.NORMAL - } - ) - .setTxId(ByteString.copyFrom(transaction.txId.bytes)) + .setType(type) + .setTxId(ByteString.copyFrom(id)) .build() ) .build() @@ -509,3 +499,11 @@ fun PeerTable.advertise(transaction: Transaction) { } } } + +fun PeerTable.advertise(transaction: VeriBlockTransaction) { + this.advertiseTx(transaction.id.bytes, RpcTransactionAnnounce.Type.NORMAL) +} + +fun PeerTable.advertise(transaction: VeriBlockPopTransaction) { + this.advertiseTx(transaction.id.bytes, RpcTransactionAnnounce.Type.PROOF_OF_PROOF) +} diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/service/TransactionService.kt b/nodecore-spv/src/main/java/org/veriblock/spv/service/TransactionService.kt index 3605ed1ba..91fdbef24 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/service/TransactionService.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/service/TransactionService.kt @@ -7,8 +7,6 @@ // file LICENSE or http://www.opensource.org/licenses/mit-license.php. package org.veriblock.spv.service -import com.google.protobuf.ByteString -import nodecore.api.grpc.RpcTransaction import org.veriblock.core.types.Pair import org.veriblock.core.utilities.AddressUtility import org.veriblock.core.utilities.Utility @@ -16,12 +14,14 @@ import org.veriblock.sdk.models.Coin import org.veriblock.core.crypto.Sha256Hash import org.veriblock.core.params.NetworkParameters import org.veriblock.core.wallet.AddressManager +import org.veriblock.sdk.models.Address +import org.veriblock.sdk.models.Output +import org.veriblock.sdk.models.VeriBlockPopTransaction +import org.veriblock.sdk.models.VeriBlockTransaction import org.veriblock.sdk.models.asCoin import org.veriblock.spv.model.AddressCoinsIndex -import org.veriblock.spv.model.Output import org.veriblock.spv.model.SigningResult import org.veriblock.spv.model.StandardTransaction -import org.veriblock.spv.model.Transaction import java.util.ArrayList class TransactionService( @@ -46,11 +46,11 @@ class TransactionService( fun createTransactionsByOutputList( addressCoinsIndexList: List, outputList: List - ): List { - val transactions: MutableList = ArrayList() + ): List { + val transactions: MutableList = ArrayList() var sortedOutputs = outputList.sortedBy { it.amount.atomicUnits }.toMutableList() val sortedAddressCoinsIndexList = addressCoinsIndexList.filter { it.coins > 0 }.sortedBy { it.coins } - val totalOutputAmount = sortedOutputs.map { it.amount.atomicUnits }.sum() + val totalOutputAmount = sortedOutputs.sumOf { it.amount.atomicUnits } for (sourceAddressesIndex in sortedAddressCoinsIndexList) { val fee = calculateFee(sourceAddressesIndex.address, totalOutputAmount, sortedOutputs, sourceAddressesIndex.index) val fulfillAndForPay = splitOutPutsAccordingBalance( @@ -117,7 +117,7 @@ class TransactionService( inputAmount: Long, outputs: List, signatureIndex: Long - ): Transaction { + ): VeriBlockTransaction { require(AddressUtility.isValidStandardAddress(inputAddress)) { "createStandardTransaction cannot be called with an invalid inputAddress ($inputAddress)!" } @@ -137,10 +137,20 @@ class TransactionService( "createStandardTransaction cannot be called with an output total which is larger than the inputAmount" + " (outputTotal = $outputTotal, inputAmount = $inputAmount)!" } - val transaction: Transaction = StandardTransaction(inputAddress, inputAmount, outputs, signatureIndex, networkParameters) - val signingResult = signTransaction(transaction.txId, inputAddress) - if (signingResult.succeeded()) { - transaction.addSignature(signingResult.signature, signingResult.publicKey) + val transaction = VeriBlockTransaction( + networkByte=networkParameters.transactionPrefix, + sourceAddress = Address(inputAddress), + sourceAmount = Coin(inputAmount), + outputs = outputs, + signatureIndex = signatureIndex, + signature = ByteArray(0), + publicKey = ByteArray(0), + publicationData = null + ) + val signingResult = signTransaction(transaction.id, inputAddress) + if (signingResult != null) { + transaction.signature = signingResult.signature + transaction.publicKey = signingResult.publicKey } return transaction } @@ -148,13 +158,14 @@ class TransactionService( // TODO(warchant): use Address instead of String for all addresses fun createUnsignedAltChainEndorsementTransaction( inputAddress: String, fee: Long, publicationData: ByteArray?, signatureIndex: Long - ): Transaction { + ): VeriBlockTransaction { require(AddressUtility.isValidStandardAddress(inputAddress)) { "createAltChainEndorsementTransaction cannot be called with an invalid inputAddress ($inputAddress)!" } require(Utility.isPositive(fee)) { "createAltChainEndorsementTransaction cannot be called with a non-positiveinputAmount ($fee)!" } + return VeriBlockTransaction() return StandardTransaction(null, inputAddress, fee, emptyList(), signatureIndex, publicationData, networkParameters) } @@ -191,12 +202,12 @@ class TransactionService( return totalSize } - fun signTransaction(txId: Sha256Hash, address: String): SigningResult { + fun signTransaction(txId: Sha256Hash, address: String): SigningResult? { val signature = addressManager.signMessage(txId.bytes, address) - ?: return SigningResult(false, null, null) + ?: return null val publicKey = addressManager.getPublicKeyForAddress(address) - ?: return SigningResult(false, null, null) - return SigningResult(true, signature, publicKey.encoded) + ?: return null + return SigningResult(signature, publicKey.encoded) } companion object { @@ -225,25 +236,6 @@ class TransactionService( totalSize += dataLength return totalSize } - - @JvmStatic - fun getRegularTransactionMessageBuilder(tx: StandardTransaction): RpcTransaction.Builder { - val builder = RpcTransaction.newBuilder() - builder.transactionFee = tx.getTransactionFee() - builder.txId = ByteString.copyFrom(tx.txId.bytes) - builder.type = RpcTransaction.Type.STANDARD - builder.sourceAmount = tx.inputAmount!!.atomicUnits - builder.sourceAddress = ByteString.copyFrom(tx.inputAddress!!.toByteArray()) - builder.data = ByteString.copyFrom(tx.data) - // builder.setTimestamp(getTimeStamp()); - // builder.setSize(tx.getSize()); - for (output in tx.getOutputs()) { - val outputBuilder = builder.addOutputsBuilder() - outputBuilder.address = ByteString.copyFrom(output.address.toByteArray()) - outputBuilder.amount = output.amount.atomicUnits - } - return builder - } } } diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/service/task/PendingTransactionsUpdateTask.kt b/nodecore-spv/src/main/java/org/veriblock/spv/service/task/PendingTransactionsUpdateTask.kt index b0e698ac4..bf40cb98b 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/service/task/PendingTransactionsUpdateTask.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/service/task/PendingTransactionsUpdateTask.kt @@ -50,7 +50,7 @@ suspend fun SpvContext.requestPendingTransactions() { } else { val transaction = pendingTransactionContainer.getTransaction(txId) if (transaction != null) { - peerTable.advertise(transaction) + peerTable.advertise(transaction.) } } } catch (e: Exception) { diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/wallet/Ledger.kt b/nodecore-spv/src/main/java/org/veriblock/spv/wallet/Ledger.kt index 26706b093..6105b6767 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/wallet/Ledger.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/wallet/Ledger.kt @@ -8,11 +8,11 @@ package org.veriblock.spv.wallet import org.veriblock.sdk.models.Coin +import org.veriblock.sdk.models.VeriBlockTransaction import org.veriblock.spv.model.StandardTransaction import org.veriblock.spv.model.TransactionMeta import java.util.ArrayList import java.util.HashMap -import java.util.function.Consumer class Ledger { private val entries: MutableMap = HashMap() @@ -52,21 +52,21 @@ class Ledger { private fun createLedgerEntriesFrom(tx: StandardTransaction): List { val ledgerEntries = ArrayList() - val status = if (tx.transactionMeta!!.state === TransactionMeta.MetaState.CONFIRMED) { + val status = if (tx.meta.state === TransactionMeta.MetaState.CONFIRMED) { LedgerEntry.Status.CONFIRMED } else { LedgerEntry.Status.PENDING } - if (entries.containsKey(tx.inputAddress!!.get())) { + if (entries.containsKey(tx.tx.sourceAddress.address)) { ledgerEntries.add( - LedgerEntry(tx.inputAddress!!.get(), tx.txId, tx.inputAmount!!, Coin.ZERO, tx.getSignatureIndex(), 0, status) + LedgerEntry(tx.tx.sourceAddress.address, tx.tx.id, tx.tx.sourceAmount, Coin.ZERO, tx.tx.signatureIndex, 0, status) ) } - for (i in tx.getOutputs().indices) { - val o = tx.getOutputs()[i] - if (entries.containsKey(o.address.get())) { + for (i in tx.tx.outputs.indices) { + val o = tx.tx.outputs[i] + if (entries.containsKey(o.address.address)) { ledgerEntries.add( - LedgerEntry(o.address.get(), tx.txId, Coin.ZERO, o.amount, -1, i, status) + LedgerEntry(o.address.address, tx.tx.id, Coin.ZERO, o.amount, -1, i, status) ) } } diff --git a/nodecore-spv/src/main/java/org/veriblock/spv/wallet/PendingTransactionDownloadedListener.kt b/nodecore-spv/src/main/java/org/veriblock/spv/wallet/PendingTransactionDownloadedListener.kt index 14c16699f..602e5d458 100644 --- a/nodecore-spv/src/main/java/org/veriblock/spv/wallet/PendingTransactionDownloadedListener.kt +++ b/nodecore-spv/src/main/java/org/veriblock/spv/wallet/PendingTransactionDownloadedListener.kt @@ -18,17 +18,17 @@ class PendingTransactionDownloadedListener( fun loadTransactions(toLoad: List) { for (tx in toLoad) { - transactions[tx.txId] = tx - spvContext.transactionPool.insert(tx.transactionMeta!!) + transactions[tx.tx.id] = tx + spvContext.transactionPool.insert(tx.tx.id, tx.meta) } } fun commitTx(tx: StandardTransaction) = lock.withLock { - if (transactions.containsKey(tx.txId)) { + if (transactions.containsKey(tx.tx.id)) { return } - tx.transactionMeta!!.setState(TransactionMeta.MetaState.PENDING) - transactions[tx.txId] = tx + tx.meta.setState(TransactionMeta.MetaState.PENDING) + transactions[tx.tx.id] = tx ledger.record(tx) } @@ -40,20 +40,20 @@ class PendingTransactionDownloadedListener( Collections.unmodifiableCollection(transactions.values) private fun isTransactionRelevant(tx: StandardTransaction): Boolean { - if (transactions.containsKey(tx.txId)) { + if (transactions.containsKey(tx.tx.id)) { return true } - return if (keyRing.contains(tx.inputAddress!!.get())) { + return if (keyRing.contains(tx.tx.sourceAddress.address)) { true } else { - tx.getOutputs().any { - keyRing.contains(it.address.get()) + tx.tx.outputs.any { + keyRing.contains(it.address.address) } } } private fun addTransaction(tx: StandardTransaction) = lock.withLock { - transactions.putIfAbsent(tx.txId, tx) + transactions.putIfAbsent(tx.tx.id, tx) ledger.record(tx) //save(); } diff --git a/nodecore-spv/src/test/java/org/veriblock/spv/admin/service/impl/AdminApiServiceTest.kt b/nodecore-spv/src/test/java/org/veriblock/spv/admin/service/impl/AdminApiServiceTest.kt index e37e82b2f..efbca5e60 100644 --- a/nodecore-spv/src/test/java/org/veriblock/spv/admin/service/impl/AdminApiServiceTest.kt +++ b/nodecore-spv/src/test/java/org/veriblock/spv/admin/service/impl/AdminApiServiceTest.kt @@ -25,15 +25,13 @@ import org.veriblock.core.wallet.AddressManager import org.veriblock.core.wallet.AddressPubKey import org.veriblock.sdk.models.Address import org.veriblock.sdk.models.Coin +import org.veriblock.sdk.models.Output import org.veriblock.sdk.models.asCoin import org.veriblock.spv.SpvConfig import org.veriblock.spv.SpvContext import org.veriblock.spv.model.LedgerContext import org.veriblock.spv.model.LedgerValue -import org.veriblock.spv.model.Output import org.veriblock.spv.model.StandardAddress -import org.veriblock.spv.model.StandardTransaction -import org.veriblock.spv.model.Transaction import org.veriblock.spv.model.asLightAddress import org.veriblock.spv.service.SpvService import org.veriblock.spv.service.Blockchain @@ -92,7 +90,7 @@ class AdminApiServiceTest { address.asLightAddress(), listOf( Output( - "VDBt3GuwPe1tA5m4duTPkBq5vF22rw".asLightAddress(), + Address("VDBt3GuwPe1tA5m4duTPkBq5vF22rw"), 100.asCoin() ) ) @@ -150,7 +148,7 @@ class AdminApiServiceTest { "VcspPDtJNpNmLV8qFTqb2F5157JNHS".asLightAddress(), listOf( Output( - "VDBt3GuwPe1tA5m4duTPkBq5vF22rw".asLightAddress(), + Address("VDBt3GuwPe1tA5m4duTPkBq5vF22rw"), 100.asCoin() ) ) @@ -176,7 +174,7 @@ class AdminApiServiceTest { address.asLightAddress(), listOf( Output( - "VDBt3GuwPe1tA5m4duTPkBq5vF22rw".asLightAddress(), + Address("VDBt3GuwPe1tA5m4duTPkBq5vF22rw"), 100.asCoin() ) ) @@ -196,7 +194,7 @@ class AdminApiServiceTest { "VcspPDtJNpNmLV8qFTqb2F5157JNHS".asLightAddress(), listOf( Output( - "VDBt3GuwPe1tA5m4duTPkBq5vF22rw".asLightAddress(), + Output("VDBt3GuwPe1tA5m4duTPkBq5vF22rw"), 100.asCoin() ) ) diff --git a/nodecore-spv/src/test/java/org/veriblock/spv/lite/core/StandardTransactionTest.kt b/nodecore-spv/src/test/java/org/veriblock/spv/lite/core/StandardTransactionTest.kt index d409cb618..2ab89a463 100644 --- a/nodecore-spv/src/test/java/org/veriblock/spv/lite/core/StandardTransactionTest.kt +++ b/nodecore-spv/src/test/java/org/veriblock/spv/lite/core/StandardTransactionTest.kt @@ -10,8 +10,6 @@ import org.veriblock.core.utilities.Utility import org.veriblock.sdk.models.asCoin import org.veriblock.spv.SpvConfig import org.veriblock.spv.SpvContext -import org.veriblock.spv.model.Output -import org.veriblock.spv.model.StandardTransaction import org.veriblock.spv.model.asStandardAddress import java.io.File diff --git a/nodecore-spv/src/test/java/org/veriblock/spv/net/impl/PeerEventListenerTest.kt b/nodecore-spv/src/test/java/org/veriblock/spv/net/impl/PeerEventListenerTest.kt index 8a593808e..efc8722d1 100644 --- a/nodecore-spv/src/test/java/org/veriblock/spv/net/impl/PeerEventListenerTest.kt +++ b/nodecore-spv/src/test/java/org/veriblock/spv/net/impl/PeerEventListenerTest.kt @@ -18,8 +18,6 @@ import org.veriblock.core.params.defaultTestNetParameters import org.veriblock.sdk.models.asCoin import org.veriblock.spv.SpvConfig import org.veriblock.spv.SpvContext -import org.veriblock.spv.model.Output -import org.veriblock.spv.model.StandardTransaction import org.veriblock.spv.model.asStandardAddress import org.veriblock.spv.net.PeerEventListener import org.veriblock.spv.service.PendingTransactionContainer diff --git a/nodecore-spv/src/test/java/org/veriblock/spv/service/TransactionServiceTest.kt b/nodecore-spv/src/test/java/org/veriblock/spv/service/TransactionServiceTest.kt index 9f622de79..c1d3f2ebf 100644 --- a/nodecore-spv/src/test/java/org/veriblock/spv/service/TransactionServiceTest.kt +++ b/nodecore-spv/src/test/java/org/veriblock/spv/service/TransactionServiceTest.kt @@ -12,7 +12,6 @@ import org.veriblock.sdk.models.asCoinDecimal import org.veriblock.spv.SpvConfig import org.veriblock.spv.SpvContext import org.veriblock.spv.model.AddressCoinsIndex -import org.veriblock.spv.model.Output import org.veriblock.spv.model.StandardAddress class TransactionServiceTest : TestCase() { diff --git a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/api/controller/WalletController.kt b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/api/controller/WalletController.kt index 83d86a995..0984996e8 100644 --- a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/api/controller/WalletController.kt +++ b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/api/controller/WalletController.kt @@ -20,7 +20,6 @@ import org.veriblock.miners.pop.api.dto.WithdrawRequest import org.veriblock.miners.pop.api.dto.WithdrawResponse import org.veriblock.miners.pop.service.AltchainPopMinerService import org.veriblock.sdk.models.asCoin -import org.veriblock.spv.model.Output import org.veriblock.spv.model.asStandardAddress class WalletController( diff --git a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/net/SpvGateway.kt b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/net/SpvGateway.kt index cc8ccbe45..846445129 100644 --- a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/net/SpvGateway.kt +++ b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/net/SpvGateway.kt @@ -17,6 +17,7 @@ import nodecore.p2p.NoPeersException import org.veriblock.core.contracts.Balance import org.veriblock.core.crypto.AnyVbkHash import org.veriblock.core.crypto.BtcHash +import org.veriblock.core.crypto.PreviousBlockVbkHash import org.veriblock.core.crypto.asVbkHash import org.veriblock.core.params.NetworkParameters import org.veriblock.core.utilities.createLogger @@ -26,13 +27,13 @@ import org.veriblock.miners.pop.serialization.deserialize import org.veriblock.miners.pop.serialization.deserializeStandardTransaction import org.veriblock.sdk.models.* import org.veriblock.sdk.services.SerializeDeserializeService -import org.veriblock.spv.model.StandardTransaction import org.veriblock.spv.service.NetworkState import org.veriblock.spv.service.SpvService import org.veriblock.spv.service.TransactionInfo import org.veriblock.core.crypto.VbkHash import org.veriblock.core.crypto.VbkTxId + private val logger = createLogger {} class SpvGateway( @@ -82,7 +83,7 @@ class SpvGateway( ) } - suspend fun getFullBlock(hash: VbkHash): FullBlock? { + suspend fun getFullBlock(hash: PreviousBlockVbkHash): FullBlock? { return spvService.getFullBlock(hash) } @@ -198,17 +199,14 @@ class SpvGateway( private fun signTransaction( addressManager: AddressManager, - unsignedTransaction: StandardTransaction - ): StandardTransaction { - val sourceAddress = unsignedTransaction.inputAddress!!.get() + unsignedTransaction: VeriBlockTransaction + ): VeriBlockTransaction { + val sourceAddress = unsignedTransaction.sourceAddress.address requireNotNull(addressManager.get(sourceAddress)) { "The address $sourceAddress is not contained in the specified wallet file!" } - val transactionId = unsignedTransaction.txId.bytes - val signature = addressManager.signMessage(transactionId, sourceAddress) - val publicKey = addressManager.getPublicKeyForAddress(sourceAddress).encoded - - unsignedTransaction.addSignature(signature, publicKey) + unsignedTransaction.signature = addressManager.signMessage(unsignedTransaction.id.bytes, sourceAddress) + unsignedTransaction.publicKey = addressManager.getPublicKeyForAddress(sourceAddress).encoded return unsignedTransaction } diff --git a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/securityinheriting/SecurityInheritingMonitor.kt b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/securityinheriting/SecurityInheritingMonitor.kt index b26de22b0..c835a98a6 100644 --- a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/securityinheriting/SecurityInheritingMonitor.kt +++ b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/securityinheriting/SecurityInheritingMonitor.kt @@ -30,8 +30,8 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch -import nodecore.api.grpc.RpcVeriBlockPublication import org.veriblock.core.MineException +import org.veriblock.core.crypto.PreviousBlockVbkHash import org.veriblock.core.crypto.asBtcHash import org.veriblock.core.crypto.asVbkHash import org.veriblock.core.utilities.Configuration @@ -40,7 +40,6 @@ import org.veriblock.core.utilities.createLogger import org.veriblock.core.utilities.debugError import org.veriblock.core.utilities.debugInfo import org.veriblock.core.utilities.debugWarn -import org.veriblock.core.utilities.extensions.asHexBytes import org.veriblock.miners.pop.core.ApmContext import org.veriblock.miners.pop.util.Threading import org.veriblock.miners.pop.EventBus @@ -64,8 +63,8 @@ import java.util.concurrent.locks.ReentrantLock import org.veriblock.miners.pop.util.CheckResult import org.veriblock.sdk.alt.model.VbkBlockResponse import org.veriblock.sdk.alt.model.VbkHeader +import org.veriblock.sdk.models.FullBlock import org.veriblock.sdk.models.VeriBlockBlock -import java.time.LocalDate import kotlin.concurrent.withLock private val logger = createLogger {} @@ -498,12 +497,25 @@ class SecurityInheritingMonitor( return 0 } - val fullVbk = miner.gateway.getFullBlock(vbk.header.hash) - if (fullVbk == null) { - logger.info {"Cannot get full VBK block ${vbk.header.hash}"} - return 0 + var cursorHash: PreviousBlockVbkHash = vbk.header.hash.trimToPreviousBlockSize() + while(true) { + val fullVbk: FullBlock? = miner.gateway.getFullBlock(cursorHash) + if (fullVbk == null) { + logger.error { "Cannot get full block $cursorHash" } + return 0 + } + + fullVbk.popTransactions.forEach { tx -> + VeriBlockPublication(tx, + + ) + } + + cursorHash = fullVbk.previousBlock } + + return 0 // context gap of bigger size than maxGapSize } diff --git a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/serialization/MessageSerializer.kt b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/serialization/MessageSerializer.kt index 7e024668a..922c53bb2 100644 --- a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/serialization/MessageSerializer.kt +++ b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/serialization/MessageSerializer.kt @@ -34,7 +34,6 @@ import org.veriblock.sdk.models.VeriBlockPublication import org.veriblock.sdk.models.VeriBlockTransaction import org.veriblock.sdk.models.asCoin import org.veriblock.sdk.services.SerializeDeserializeService -import org.veriblock.spv.model.StandardTransaction private val logger = createLogger {} diff --git a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/shell/commands/WalletCommands.kt b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/shell/commands/WalletCommands.kt index fb8df638a..e4501ff44 100644 --- a/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/shell/commands/WalletCommands.kt +++ b/pop-miners/altchain-pop-miner/src/main/kotlin/org/veriblock/miners/pop/shell/commands/WalletCommands.kt @@ -18,7 +18,6 @@ import org.veriblock.shell.CommandParameter import org.veriblock.shell.CommandParameterMappers import org.veriblock.shell.command import org.veriblock.shell.core.success -import org.veriblock.spv.model.Output import org.veriblock.spv.model.asStandardAddress fun CommandFactory.walletCommands( diff --git a/veriblock-core/src/main/java/org/veriblock/core/crypto/Sha256Hash.kt b/veriblock-core/src/main/java/org/veriblock/core/crypto/Sha256Hash.kt index c94ea37db..a070ba52e 100644 --- a/veriblock-core/src/main/java/org/veriblock/core/crypto/Sha256Hash.kt +++ b/veriblock-core/src/main/java/org/veriblock/core/crypto/Sha256Hash.kt @@ -105,7 +105,7 @@ class MerkleRoot(bytes: ByteArray) : Sha256Hash(bytes) { class TruncatedMerkleRoot(bytes: ByteArray) : Sha256Hash(trimBytes(bytes, TRUNCATED_MERKLE_ROOT_LENGTH)) { init { - check(bytes.size == TRUNCATED_MERKLE_ROOT_LENGTH || bytes.size == TRUNCATED_MERKLE_ROOT_LENGTH * 2) { + check(bytes.size == TRUNCATED_MERKLE_ROOT_LENGTH || bytes.size == 24) { "Trying to create a truncated merkle root hash with invalid amount of bytes: ${bytes.size} (${bytes.toHex()})" } } diff --git a/veriblock-core/src/main/java/org/veriblock/sdk/models/VeriBlockPopTransaction.kt b/veriblock-core/src/main/java/org/veriblock/sdk/models/VeriBlockPopTransaction.kt index 5e30bce07..e41842c30 100644 --- a/veriblock-core/src/main/java/org/veriblock/sdk/models/VeriBlockPopTransaction.kt +++ b/veriblock-core/src/main/java/org/veriblock/sdk/models/VeriBlockPopTransaction.kt @@ -20,11 +20,11 @@ class VeriBlockPopTransaction( val merklePath: MerklePath, val blockOfProof: BitcoinBlock, val blockOfProofContext: List, - val signature: ByteArray, - val publicKey: ByteArray, + var signature: ByteArray, + var publicKey: ByteArray, val networkByte: Byte? ) { - val id: Sha256Hash = getId(this) + val id by lazy { getId(this) } init { check(signature.isNotEmpty()) { diff --git a/veriblock-core/src/main/java/org/veriblock/sdk/models/VeriBlockTransaction.kt b/veriblock-core/src/main/java/org/veriblock/sdk/models/VeriBlockTransaction.kt index 5ea6c96b4..e7048eb5b 100644 --- a/veriblock-core/src/main/java/org/veriblock/sdk/models/VeriBlockTransaction.kt +++ b/veriblock-core/src/main/java/org/veriblock/sdk/models/VeriBlockTransaction.kt @@ -15,7 +15,7 @@ import java.util.Arrays import java.util.Collections open class VeriBlockTransaction( - type: Byte, + type: Byte = 1, /* vbk tx == 1 */ sourceAddress: Address, sourceAmount: Coin, outputs: List?, @@ -25,15 +25,17 @@ open class VeriBlockTransaction( publicKey: ByteArray, networkByte: Byte? ) { - val id: VbkTxId + val id: VbkTxId by lazy { + SerializeDeserializeService.getId(this) + } val type: Byte val sourceAddress: Address val sourceAmount: Coin val outputs: List val signatureIndex: Long val publicationData: PublicationData? - val signature: ByteArray - val publicKey: ByteArray + var signature: ByteArray + var publicKey: ByteArray val networkByte: Byte? init { @@ -55,7 +57,6 @@ open class VeriBlockTransaction( this.signature = signature this.publicKey = publicKey this.networkByte = networkByte - id = SerializeDeserializeService.getId(this) } override fun equals(other: Any?): Boolean {