From e2ddd14c09e95f0994e8e77da9f43a2d2f0f6545 Mon Sep 17 00:00:00 2001 From: hyperschwartz Date: Wed, 27 Apr 2022 12:45:07 -0700 Subject: [PATCH] Remove home-grown Asset proto, switch to figure tech asset. --- buildSrc/src/main/kotlin/Dependencies.kt | 5 ++ proto/src/main/proto/asset_protos.proto | 32 ---------- server/build.gradle.kts | 1 + .../MockAssetOnboardingServiceContainer.kt | 2 +- .../invoice/clients/OnboardingApiClient.kt | 2 +- .../services/AssetOnboardingService.kt | 2 +- .../invoice/services/EventHandlerService.kt | 6 +- .../invoice/services/InvoiceService.kt | 1 - .../services/mock/AssetOnboardingMocker.kt | 4 +- .../services/mock/MockOnboardingApiClient.kt | 4 +- .../invoice/util/extension/AssetExtensions.kt | 60 ++++++------------- .../invoice/util/provenance/ProvenanceUtil.kt | 7 --- .../mock/TestAssetOnboardingMocker.kt | 2 +- .../util/extension/AssetExtensionsTest.kt | 27 ++++----- 14 files changed, 48 insertions(+), 107 deletions(-) delete mode 100644 proto/src/main/proto/asset_protos.proto diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 2f9177a..9ad8c2e 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -6,6 +6,7 @@ import org.gradle.plugin.use.PluginDependenciesSpec object Versions { const val Arrow = "1.0.1" + const val AssetModel = "0.1.2" const val BouncyCastle = "1.70" const val Exposed = "0.37.3" const val Feign = "10.1.0" @@ -143,6 +144,10 @@ object Dependencies { val Core = DependencySpec("io.arrow-kt:arrow-core", Versions.Arrow) } + object Asset { + val AssetModel = DependencySpec("io.provenance.model:metadata-asset-model", Versions.AssetModel) + } + val BouncyCastle = DependencySpec("org.bouncycastle:bcprov-jdk15on", Versions.BouncyCastle) } diff --git a/proto/src/main/proto/asset_protos.proto b/proto/src/main/proto/asset_protos.proto deleted file mode 100644 index cf29f55..0000000 --- a/proto/src/main/proto/asset_protos.proto +++ /dev/null @@ -1,32 +0,0 @@ -syntax = "proto3"; - -package invoice; - -option java_package = "io.provenance.invoice"; - -import "util_protos.proto"; -import "google/protobuf/any.proto"; -import "google/protobuf/descriptor.proto"; - -option java_outer_classname = "AssetProtos"; - -extend google.protobuf.EnumValueOptions { - string provenance_name = 51554; - string asset_kv_name = 51555; -} - -// Overarching asset payload -message Asset { - UUID id = 1; // Unique identifier for the asset - string type = 2; // The specific type of asset, corresponds to one of AssetType enum string names - string description = 3; // A description that should maintain constant across generated assets, containing various values that define it in a unique way - map kv = 4; // Sub-fields of the packed asset -} - -enum AssetType { - UNKNOWN_ASSET_TYPE = 0; - LOAN = 1 [(provenance_name) = "PROVENANCE_LOAN", (asset_kv_name) = "loan"]; - TITLE = 2 [(provenance_name) = "PROVENANCE_TITLE", (asset_kv_name) = "title"]; - FUND = 3 [(provenance_name) = "PROVENANCE_FUND", (asset_kv_name) = "fund"]; - NFT = 4 [(provenance_name) = "PROVENANCE_NFT", (asset_kv_name) = "nft"]; -} diff --git a/server/build.gradle.kts b/server/build.gradle.kts index c5a80eb..1b66315 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { implementation(project(":proto")) listOf( Dependencies.Arrow.Core, + Dependencies.Asset.AssetModel, Dependencies.BouncyCastle, Dependencies.Database.Exposed, Dependencies.Database.ExposedDao, diff --git a/server/src/integrationTest/kotlin/io/provenance/invoice/testhelpers/testcontainers/MockAssetOnboardingServiceContainer.kt b/server/src/integrationTest/kotlin/io/provenance/invoice/testhelpers/testcontainers/MockAssetOnboardingServiceContainer.kt index b92486f..9cfbe4b 100644 --- a/server/src/integrationTest/kotlin/io/provenance/invoice/testhelpers/testcontainers/MockAssetOnboardingServiceContainer.kt +++ b/server/src/integrationTest/kotlin/io/provenance/invoice/testhelpers/testcontainers/MockAssetOnboardingServiceContainer.kt @@ -1,7 +1,6 @@ package io.provenance.invoice.testhelpers.testcontainers import com.fasterxml.jackson.module.kotlin.readValue -import io.provenance.invoice.AssetProtos.Asset import mu.KLogging import org.mockserver.client.MockServerClient import org.mockserver.model.HttpRequest.request @@ -12,6 +11,7 @@ import org.testcontainers.utility.DockerImageName import io.provenance.invoice.config.app.ConfigurationUtil.DEFAULT_OBJECT_MAPPER import io.provenance.invoice.config.web.AppHeaders import io.provenance.invoice.services.mock.AssetOnboardingMocker +import tech.figure.asset.v1beta1.Asset class MockAssetOnboardingServiceContainer : TestContainerTemplate { private companion object : KLogging() { diff --git a/server/src/main/kotlin/io/provenance/invoice/clients/OnboardingApiClient.kt b/server/src/main/kotlin/io/provenance/invoice/clients/OnboardingApiClient.kt index d1d6fe7..1f7340a 100644 --- a/server/src/main/kotlin/io/provenance/invoice/clients/OnboardingApiClient.kt +++ b/server/src/main/kotlin/io/provenance/invoice/clients/OnboardingApiClient.kt @@ -7,7 +7,6 @@ import cosmos.tx.v1beta1.TxOuterClass.TxBody import feign.Headers import feign.Param import feign.RequestLine -import io.provenance.invoice.AssetProtos.Asset import io.provenance.invoice.config.web.AppHeaders import io.provenance.invoice.util.extension.checkNotNullI import io.provenance.invoice.util.extension.deriveDefaultInstanceI @@ -16,6 +15,7 @@ import io.provenance.invoice.util.extension.typedUnpackI import io.provenance.metadata.v1.MsgWriteRecordRequest import io.provenance.metadata.v1.MsgWriteScopeRequest import io.provenance.metadata.v1.MsgWriteSessionRequest +import tech.figure.asset.v1beta1.Asset @Headers("Content-Type: application/json") interface OnboardingApiClient { diff --git a/server/src/main/kotlin/io/provenance/invoice/services/AssetOnboardingService.kt b/server/src/main/kotlin/io/provenance/invoice/services/AssetOnboardingService.kt index 06ec775..0fdbb26 100644 --- a/server/src/main/kotlin/io/provenance/invoice/services/AssetOnboardingService.kt +++ b/server/src/main/kotlin/io/provenance/invoice/services/AssetOnboardingService.kt @@ -1,6 +1,5 @@ package io.provenance.invoice.services -import io.provenance.invoice.AssetProtos.Asset import io.provenance.invoice.clients.OnboardingApiClient import io.provenance.invoice.config.app.Qualifiers import io.provenance.metadata.v1.MsgWriteRecordRequest @@ -10,6 +9,7 @@ import mu.KLogging import org.springframework.stereotype.Service import io.provenance.invoice.util.provenance.ProvenanceAccountDetail import org.springframework.beans.factory.annotation.Qualifier +import tech.figure.asset.v1beta1.Asset @Service class AssetOnboardingService( diff --git a/server/src/main/kotlin/io/provenance/invoice/services/EventHandlerService.kt b/server/src/main/kotlin/io/provenance/invoice/services/EventHandlerService.kt index 07fa6bc..37dbe6f 100644 --- a/server/src/main/kotlin/io/provenance/invoice/services/EventHandlerService.kt +++ b/server/src/main/kotlin/io/provenance/invoice/services/EventHandlerService.kt @@ -2,7 +2,6 @@ package io.provenance.invoice.services import arrow.core.Either import arrow.core.getOrHandle -import io.provenance.invoice.AssetProtos.Asset import io.provenance.invoice.config.provenance.ObjectStore import io.provenance.invoice.factory.InvoiceCalcFactory import io.provenance.invoice.repository.FailedEventRepository @@ -13,12 +12,13 @@ import io.provenance.invoice.util.enums.InvoiceStatus import io.provenance.invoice.util.eventstream.external.StreamEvent import io.provenance.invoice.util.extension.attributeValueI import io.provenance.invoice.util.extension.attributeValueOrNullI -import io.provenance.invoice.util.extension.unpackInvoiceI +import io.provenance.invoice.util.extension.toInvoiceI import io.provenance.invoice.util.provenance.PayableContractKey import io.provenance.invoice.util.validation.InvoiceValidator import io.provenance.scope.sdk.extensions.resultHash import mu.KLogging import org.springframework.stereotype.Service +import tech.figure.asset.v1beta1.Asset import java.time.OffsetDateTime import java.util.UUID import java.util.concurrent.TimeUnit @@ -102,7 +102,7 @@ class EventHandlerService( .getDecryptedPayload(objectStore.oracleAccountDetail.keyRef) .use { signatureStream -> val messageBytes = signatureStream.readAllBytes() - val targetInvoice = Asset.parseFrom(messageBytes).unpackInvoiceI() + val targetInvoice = Asset.parseFrom(messageBytes).toInvoiceI() Either.catch { InvoiceValidator.validateInvoiceForApproval( invoiceDto = invoiceDto, diff --git a/server/src/main/kotlin/io/provenance/invoice/services/InvoiceService.kt b/server/src/main/kotlin/io/provenance/invoice/services/InvoiceService.kt index f0724b9..95a8bb5 100644 --- a/server/src/main/kotlin/io/provenance/invoice/services/InvoiceService.kt +++ b/server/src/main/kotlin/io/provenance/invoice/services/InvoiceService.kt @@ -13,7 +13,6 @@ import io.provenance.invoice.util.extension.toAssetI import io.provenance.invoice.util.extension.toProtoAnyI import io.provenance.invoice.util.extension.toUuidI import io.provenance.invoice.util.provenance.ProvenanceAccountDetail -import io.provenance.invoice.util.validation.InvoiceValidator import io.provenance.invoice.util.validation.ValidatedInvoice import org.springframework.beans.factory.annotation.Qualifier import java.math.BigDecimal diff --git a/server/src/main/kotlin/io/provenance/invoice/services/mock/AssetOnboardingMocker.kt b/server/src/main/kotlin/io/provenance/invoice/services/mock/AssetOnboardingMocker.kt index 3a705c4..b0e78c4 100644 --- a/server/src/main/kotlin/io/provenance/invoice/services/mock/AssetOnboardingMocker.kt +++ b/server/src/main/kotlin/io/provenance/invoice/services/mock/AssetOnboardingMocker.kt @@ -4,7 +4,6 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import com.google.common.io.BaseEncoding import cosmos.tx.v1beta1.TxOuterClass.TxBody -import io.provenance.invoice.AssetProtos.Asset import io.provenance.invoice.clients.OnboardingResponse import io.provenance.invoice.util.extension.toJsonProvenanceI import io.provenance.invoice.util.extension.toProtoAnyI @@ -28,6 +27,7 @@ import io.provenance.scope.encryption.ecies.ProvenanceKeyGenerator import io.provenance.scope.objectstore.client.SIGNATURE_PUBLIC_KEY_FIELD_NAME import io.provenance.scope.util.MetadataAddress import io.provenance.scope.util.toByteString +import tech.figure.asset.v1beta1.Asset import java.io.ByteArrayInputStream import java.security.PublicKey import java.util.Base64 @@ -64,7 +64,7 @@ object AssetOnboardingMocker { ): OnboardingResponse { val decodedPublicKey = ECUtils.convertBytesToPublicKey(BaseEncoding.base64().decode(publicKey)) val hash = hashAsset(asset, decodedPublicKey) - val txBody = buildTxBody(asset.id.toUuidI(), hash, address) + val txBody = buildTxBody(asset.id.value.toUuidI(), hash, address) return OnboardingResponse( json = ObjectMapper().readValue(txBody.toJsonProvenanceI()), base64 = txBody.messagesList.map { it.toByteArray().toBase64String() }, diff --git a/server/src/main/kotlin/io/provenance/invoice/services/mock/MockOnboardingApiClient.kt b/server/src/main/kotlin/io/provenance/invoice/services/mock/MockOnboardingApiClient.kt index 3b8015c..9f47e16 100644 --- a/server/src/main/kotlin/io/provenance/invoice/services/mock/MockOnboardingApiClient.kt +++ b/server/src/main/kotlin/io/provenance/invoice/services/mock/MockOnboardingApiClient.kt @@ -1,11 +1,11 @@ package io.provenance.invoice.services.mock -import io.provenance.invoice.AssetProtos.Asset import io.provenance.invoice.clients.OnboardingApiClient import io.provenance.invoice.clients.OnboardingResponse import mu.KLogging import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.stereotype.Service +import tech.figure.asset.v1beta1.Asset @Service @ConditionalOnProperty(name = ["simulated.asset_onboarding_api"], havingValue = "true") @@ -19,7 +19,7 @@ class MockOnboardingApiClient : OnboardingApiClient { override fun onboardPayable( address: String, publicKey: String, - asset: Asset + asset: Asset, ): OnboardingResponse { logger.error("Using simulated asset onboarding api client!") return AssetOnboardingMocker.mockAssetResponse( diff --git a/server/src/main/kotlin/io/provenance/invoice/util/extension/AssetExtensions.kt b/server/src/main/kotlin/io/provenance/invoice/util/extension/AssetExtensions.kt index c58379b..3a7b648 100644 --- a/server/src/main/kotlin/io/provenance/invoice/util/extension/AssetExtensions.kt +++ b/server/src/main/kotlin/io/provenance/invoice/util/extension/AssetExtensions.kt @@ -1,52 +1,28 @@ package io.provenance.invoice.util.extension -import com.google.protobuf.DescriptorProtos.EnumValueOptions -import com.google.protobuf.GeneratedMessage.GeneratedExtension -import com.google.protobuf.MessageOrBuilder -import com.google.protobuf.ProtocolMessageEnum -import io.provenance.invoice.AssetProtos -import io.provenance.invoice.AssetProtos.Asset -import io.provenance.invoice.AssetProtos.AssetOrBuilder -import io.provenance.invoice.AssetProtos.AssetType -import io.provenance.invoice.AssetProtosBuilders import io.provenance.invoice.InvoiceProtos.Invoice import io.provenance.invoice.InvoiceProtos.InvoiceOrBuilder -import io.provenance.invoice.UtilProtos -import io.provenance.invoice.util.randomProtoUuidI +import tech.figure.asset.v1beta1.Asset +import tech.figure.asset.v1beta1.AssetOrBuilder import java.math.BigDecimal -fun AssetType.provenanceNameI(): String = this.getExtensionValue(AssetProtos.provenanceName) +private const val ASSET_TYPE = "payable" +private const val INVOICE_KV_NAME = "invoice" -fun AssetType.assetKvNameI(): String = this.getExtensionValue(AssetProtos.assetKvName) - -fun InvoiceOrBuilder.toAssetI(): Asset = this.toAssetI( - assetType = AssetType.NFT, - assetDescription = "Invoice [${this.invoiceUuid.value}]", - idProvider = { invoiceUuid }, -) +fun InvoiceOrBuilder.toAssetI(): Asset = Asset.newBuilder().also { assetBuilder -> + assetBuilder.id = tech.figure.util.v1beta1.UUID.newBuilder().setValue(this.invoiceUuid.value).build() + assetBuilder.type = ASSET_TYPE + assetBuilder.description = "Invoice [${this.invoiceUuid.value}]" + assetBuilder.putKv(INVOICE_KV_NAME, this.toProtoAnyI()) +}.build() fun InvoiceOrBuilder.totalAmountI(): BigDecimal = lineItemsList.sumOf { it.quantity.toBigDecimal() * it.price.toBigDecimalOrZeroI() } -fun AssetOrBuilder.unpackInvoiceI(): Invoice = this - .checkI({ it.type == AssetType.NFT.name }) { "Cannot unpack invoice from asset. Expected invoice to be properly typed as [${AssetType.NFT.name}] but type was [$type]" } - .kvMap[AssetType.NFT.assetKvNameI()] - .checkNotNullI { "Expected the NFT to be serialized into the KV map of the asset under its KV name of [${AssetType.NFT.assetKvNameI()}]" } - .unpack(Invoice::class.java) - -private fun T.toAssetI( - assetType: AssetType, - assetDescription: String = assetType.provenanceNameI(), - idProvider: (T) -> UtilProtos.UUID = { randomProtoUuidI() }, -): Asset = this.let { message -> - AssetProtosBuilders.Asset { - id = idProvider.invoke(message) - type = assetType.name - description = assetDescription - putKv(assetType.assetKvNameI(), message.toProtoAnyI()) - } -} - -private fun T.getExtensionValue(extension: GeneratedExtension): U = - this.valueDescriptor.options.getExtension(extension) - - +fun AssetOrBuilder.toInvoiceI(): Invoice = this + .checkI( + predicate = { asset -> asset.kvCount == 1 }, + lazyMessage = { "An asset containing an invoice should only contain a single kv value, but found keys: ${this.kvMap.keys}" }, + ) + .kvMap[INVOICE_KV_NAME] + ?.unpack(Invoice::class.java) + ?: throw IllegalStateException("No key of type [$INVOICE_KV_NAME] could be found in asset kv map. Found keys: ${this.kvMap.keys}") diff --git a/server/src/main/kotlin/io/provenance/invoice/util/provenance/ProvenanceUtil.kt b/server/src/main/kotlin/io/provenance/invoice/util/provenance/ProvenanceUtil.kt index 86c24b7..f767b81 100644 --- a/server/src/main/kotlin/io/provenance/invoice/util/provenance/ProvenanceUtil.kt +++ b/server/src/main/kotlin/io/provenance/invoice/util/provenance/ProvenanceUtil.kt @@ -1,7 +1,5 @@ package io.provenance.invoice.util.provenance -import io.provenance.invoice.AssetProtos.Asset -import io.provenance.invoice.AssetProtos.AssetType import io.provenance.invoice.util.extension.tryOrNullI import io.provenance.scope.util.Bech32 import java.security.MessageDigest @@ -11,11 +9,6 @@ object ProvenanceUtil { private const val MARKER_ENCODING_PREFIX: String = "marker/" private const val MARKER_ENCODING_TRUNCATE_LENGTH: Int = 20 - fun getInvoiceDenominationForAsset(asset: Asset): String { - check(asset.type == AssetType.NFT.name) { "Provided asset with id [${asset.id.value}] is not of expected type [${AssetType.NFT.name}]" } - return "$INVOICE_DENOM_PREFIX-${asset.id.value}" - } - /** * Takes a source denomination for a marker and an account address from the target blockchain environment and * computes a marker address. diff --git a/server/src/test/kotlin/io/provenance/invoice/services/mock/TestAssetOnboardingMocker.kt b/server/src/test/kotlin/io/provenance/invoice/services/mock/TestAssetOnboardingMocker.kt index 5455013..c23a56a 100644 --- a/server/src/test/kotlin/io/provenance/invoice/services/mock/TestAssetOnboardingMocker.kt +++ b/server/src/test/kotlin/io/provenance/invoice/services/mock/TestAssetOnboardingMocker.kt @@ -25,7 +25,7 @@ class TestAssetOnboardingMocker { @Test fun testAssetOnboardingMockerResponses() { val asset = MockInvoice.defaultProto().toAssetI() - val assetUuid = asset.id.toUuidI() + val assetUuid = asset.id.value.toUuidI() val response = assertSucceeds("A valid public key and address should produce output") { AssetOnboardingMocker.mockAssetResponse( asset = asset, diff --git a/server/src/test/kotlin/io/provenance/invoice/util/extension/AssetExtensionsTest.kt b/server/src/test/kotlin/io/provenance/invoice/util/extension/AssetExtensionsTest.kt index 91de587..d6ff4a9 100644 --- a/server/src/test/kotlin/io/provenance/invoice/util/extension/AssetExtensionsTest.kt +++ b/server/src/test/kotlin/io/provenance/invoice/util/extension/AssetExtensionsTest.kt @@ -1,40 +1,39 @@ package io.provenance.invoice.util.extension import helper.assertSucceeds -import io.provenance.invoice.AssetProtos.AssetType -import io.provenance.invoice.AssetProtosBuilders import io.provenance.invoice.util.mock.MockInvoice -import io.provenance.invoice.util.randomProtoUuidI import org.junit.jupiter.api.Test +import tech.figure.asset.v1beta1.Asset +import tech.figure.util.v1beta1.UUID import kotlin.test.assertEquals import kotlin.test.assertTrue class AssetExtensionsTest { @Test - fun testUnpackInvoiceFromAsset() { + fun testAssetToInvoice() { val invoice = MockInvoice.defaultProto() - val asset = AssetProtosBuilders.Asset { - id = randomProtoUuidI() - type = AssetType.NFT.name - description = "Doesn't matter" - putKv(AssetType.NFT.assetKvNameI(), invoice.toProtoAnyI()) - } + val asset = Asset.newBuilder().also { assetBuilder -> + assetBuilder.id = UUID.newBuilder().setValue(invoice.invoiceUuid.value).build() + assetBuilder.type = "payable" + assetBuilder.description = "Invoice [${invoice.invoiceUuid.value}]" + assetBuilder.putKv("invoice", invoice.toProtoAnyI()) + }.build() val unpackedInvoice = assertSucceeds("Expected the invoice kv to successfully unpack to an Invoice proto") { - asset.unpackInvoiceI() + asset.toInvoiceI() } assertEquals(expected = invoice, actual = unpackedInvoice, "The asset's packed invoice should properly deserialize into the original") } @Test - fun testPackInvoiceAsAsset() { + fun testInvoiceToAsset() { val invoice = MockInvoice.defaultProto() val asset = invoice.toAssetI() assertTrue(actual = asset.id.isSet(), message = "Expected the newly-created asset to get an id") - assertEquals(expected = asset.type, actual = AssetType.NFT.name, message = "Expected the type to equate to the name of the NFT asset type enum") + assertEquals(expected = asset.type, actual = "payable", message = "Expected the type to equate to the payable type") assertTrue(actual = asset.description.isNotBlank(), message = "Expected the description to be established") assertEquals(expected = 1, actual = asset.kvCount, "Expected only one KV to be set") val unpackedInvoice = assertSucceeds("Expected the invoice kv to successfully unpack to an Invoice proto") { - asset.unpackInvoiceI() + asset.toInvoiceI() } assertEquals(expected = invoice, actual = unpackedInvoice, "The asset's packed invoice should properly deserialize into the original") }