mirror of
https://github.com/corda/corda.git
synced 2025-06-19 15:43:52 +00:00
Attachment query with contract version, related to CORDA-2150, CORDA-2157 (#4357)
TransactionBuilder loads attachment using attachment storage instead of CordappLoader, contract class version is now Integer (format and stored in db as Integer).
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
package net.corda.node.internal.cordapp
|
||||
|
||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
||||
import net.corda.core.internal.cordapp.CordappImpl
|
||||
import net.corda.core.internal.cordapp.CordappImpl.Info.Companion.UNKNOWN_VALUE
|
||||
import java.util.jar.Attributes
|
||||
@ -34,7 +35,7 @@ operator fun Manifest.get(key: String): String? = mainAttributes.getValue(key)
|
||||
fun Manifest.toCordappInfo(defaultShortName: String): CordappImpl.Info {
|
||||
val shortName = this["Name"] ?: defaultShortName
|
||||
val vendor = this["Implementation-Vendor"] ?: UNKNOWN_VALUE
|
||||
val version = this["Implementation-Version"] ?: UNKNOWN_VALUE
|
||||
val version = this["Implementation-Version"] ?: DEFAULT_CORDAPP_VERSION.toString()
|
||||
val minPlatformVersion = this["Min-Platform-Version"]?.toIntOrNull() ?: 1
|
||||
val targetPlatformVersion = this["Target-Platform-Version"]?.toIntOrNull() ?: minPlatformVersion
|
||||
return CordappImpl.Info(
|
||||
|
@ -212,7 +212,7 @@ object DefaultKryoCustomizer {
|
||||
kryo.writeClassAndObject(output, obj.additionalContracts)
|
||||
output.writeString(obj.uploader)
|
||||
kryo.writeClassAndObject(output, obj.signerKeys)
|
||||
output.writeString(obj.version)
|
||||
output.writeInt(obj.version)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@ -223,7 +223,7 @@ object DefaultKryoCustomizer {
|
||||
val additionalContracts = kryo.readClassAndObject(input) as Set<ContractClassName>
|
||||
val uploader = input.readString()
|
||||
val signers = kryo.readClassAndObject(input) as List<PublicKey>
|
||||
val version = input.readString()
|
||||
val version = input.readInt()
|
||||
val context = kryo.serializationContext()!!
|
||||
val attachmentStorage = context.serviceHub.attachments
|
||||
|
||||
@ -242,7 +242,7 @@ object DefaultKryoCustomizer {
|
||||
val additionalContracts = kryo.readClassAndObject(input) as Set<ContractClassName>
|
||||
val uploader = input.readString()
|
||||
val signers = kryo.readClassAndObject(input) as List<PublicKey>
|
||||
val version = input.readString()
|
||||
val version = input.readInt()
|
||||
return ContractAttachment(attachment, contract, additionalContracts, uploader, signers, version)
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,8 @@ import com.google.common.hash.Hashing
|
||||
import com.google.common.hash.HashingInputStream
|
||||
import com.google.common.io.CountingInputStream
|
||||
import net.corda.core.CordaRuntimeException
|
||||
import net.corda.core.contracts.Attachment
|
||||
import net.corda.core.contracts.ContractAttachment
|
||||
import net.corda.core.contracts.ContractClassName
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.cordapp.CORDAPP_CONTRACT_VERSION
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.internal.*
|
||||
@ -19,6 +18,7 @@ import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
||||
import net.corda.core.node.services.vault.AttachmentSort
|
||||
import net.corda.core.serialization.*
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
||||
import net.corda.node.services.vault.HibernateAttachmentQueryCriteriaParser
|
||||
import net.corda.node.utilities.NonInvalidatingCache
|
||||
import net.corda.node.utilities.NonInvalidatingWeightBasedCache
|
||||
@ -34,7 +34,6 @@ import java.nio.file.Paths
|
||||
import java.security.PublicKey
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import java.util.jar.Attributes.Name.IMPLEMENTATION_VERSION
|
||||
import java.util.jar.JarInputStream
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
import javax.persistence.*
|
||||
@ -109,9 +108,9 @@ class NodeAttachmentService(
|
||||
foreignKey = ForeignKey(name = "FK__signers__attachments"))
|
||||
var signers: List<PublicKey>? = null,
|
||||
|
||||
// Assumption: only Contract Attachments are versioned.
|
||||
@Column(name = "version", nullable = true)
|
||||
var version: String? = null
|
||||
// Assumption: only Contract Attachments are versioned, version unknown or value for other attachments other than Contract Attachment defaults to 1
|
||||
@Column(name = "version", nullable = false)
|
||||
var version: Int = DEFAULT_CORDAPP_VERSION
|
||||
)
|
||||
|
||||
@VisibleForTesting
|
||||
@ -235,7 +234,7 @@ class NodeAttachmentService(
|
||||
val contracts = attachment.contractClassNames
|
||||
if (contracts != null && contracts.isNotEmpty()) {
|
||||
ContractAttachment(it, contracts.first(), contracts.drop(1).toSet(), attachment.uploader, attachment.signers?.toList()
|
||||
?: emptyList(), attachment.version ?: UNKNOWN_VERSION)
|
||||
?: emptyList(), attachment.version)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
@ -356,7 +355,11 @@ class NodeAttachmentService(
|
||||
|
||||
private fun getVersion(attachmentBytes: ByteArray) =
|
||||
JarInputStream(attachmentBytes.inputStream()).use {
|
||||
it.manifest?.mainAttributes?.getValue(IMPLEMENTATION_VERSION) ?: "1.0"
|
||||
try {
|
||||
it.manifest?.mainAttributes?.getValue(CORDAPP_CONTRACT_VERSION)?.toInt() ?: DEFAULT_CORDAPP_VERSION
|
||||
} catch (e: NumberFormatException) {
|
||||
DEFAULT_CORDAPP_VERSION
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("OverridingDeprecatedMember")
|
||||
|
@ -1,14 +1,14 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"
|
||||
logicalFilePath="migration/node-services.changelog-init.xml">
|
||||
|
||||
<changeSet author="R3.Corda" id="add_version_column">
|
||||
<addColumn tableName="node_attachments">
|
||||
<column name="version" type="NVARCHAR(64)"/>
|
||||
<column name="version" type="INT"/>
|
||||
</addColumn>
|
||||
<sql>update node_attachments set version = 1</sql>
|
||||
<addNotNullConstraint tableName="node_attachments" columnName="version" columnDataType="INT"/>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
@ -581,8 +581,8 @@ public class VaultQueryJavaTests {
|
||||
Pair<Path, PublicKey> anotherSignedContractJarAndKey = INSTANCE.makeTestSignedContractJar(path, "com.example.AnotherContract");
|
||||
Path anotherSignedContractJar = anotherSignedContractJarAndKey.component1();
|
||||
|
||||
Path contractJarV2 = INSTANCE.makeTestContractJar(path, "com.example.MyContract", false, "2.0");
|
||||
Pair<Path, PublicKey> signedContractJarAndKeyV2 = INSTANCE.makeTestSignedContractJar(path, "com.example.MyContract", "2.0");
|
||||
Path contractJarV2 = INSTANCE.makeTestContractJar(path, "com.example.MyContract", false, 2);
|
||||
Pair<Path, PublicKey> signedContractJarAndKeyV2 = INSTANCE.makeTestSignedContractJar(path, "com.example.MyContract", 2);
|
||||
Path signedContractJarV2 = signedContractJarAndKeyV2.component1();
|
||||
|
||||
storage.importAttachment(Files.newInputStream(sampleJar),"uploaderA", "sample.jar");
|
||||
@ -616,15 +616,15 @@ public class VaultQueryJavaTests {
|
||||
|
||||
// version
|
||||
FieldInfo version = getField("version", NodeAttachmentService.DBAttachment.class);
|
||||
ColumnPredicate<List<String>> version2Predicate = equal(version, asList("2.0")).component2();
|
||||
ColumnPredicate<Integer> version2Predicate = equal(version, 2).component2();
|
||||
|
||||
AttachmentsQueryCriteria criteria4 = new AttachmentsQueryCriteria().withContractClassNames(contractClassNamesPredicate).isSigned(isSignedPredicate).withVersions(version2Predicate);
|
||||
AttachmentsQueryCriteria criteria4 = new AttachmentsQueryCriteria().withContractClassNames(contractClassNamesPredicate).isSigned(isSignedPredicate).withVersion(version2Predicate);
|
||||
assertThat(storage.queryAttachments(criteria4).size()).isEqualTo(1);
|
||||
|
||||
ColumnPredicate<List<String>> version1Predicate = equal(version, asList("1.0")).component2();
|
||||
ColumnPredicate<Integer> version1Predicate = equal(version, 1).component2();
|
||||
ColumnPredicate<List<String>> manyContractClassNamesPredicate = equal(contractClassNames, asList("com.example.MyContract", "com.example.AnotherContract")).component2();
|
||||
|
||||
AttachmentsQueryCriteria criteria5 = new AttachmentsQueryCriteria().withContractClassNames(manyContractClassNamesPredicate).isSigned(isSignedPredicate).withVersions(version1Predicate);
|
||||
AttachmentsQueryCriteria criteria5 = new AttachmentsQueryCriteria().withContractClassNames(manyContractClassNamesPredicate).isSigned(isSignedPredicate).withVersion(version1Predicate);
|
||||
assertThat(storage.queryAttachments(criteria5).size()).isEqualTo(2);
|
||||
|
||||
selfCleaningDir.close();
|
||||
|
@ -9,6 +9,7 @@ import net.corda.testing.core.internal.ContractJarTestUtils.makeTestJar
|
||||
import net.corda.testing.core.internal.ContractJarTestUtils.makeTestSignedContractJar
|
||||
import net.corda.testing.core.internal.SelfCleaningDir
|
||||
import net.corda.core.contracts.ContractAttachment
|
||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.flows.FlowLogic
|
||||
@ -209,8 +210,8 @@ class NodeAttachmentServiceTest {
|
||||
val contractJar = makeTestContractJar(file.path, "com.example.MyContract")
|
||||
val (signedContractJar, publicKey) = makeTestSignedContractJar(file.path, "com.example.MyContract")
|
||||
val (anotherSignedContractJar, _) = makeTestSignedContractJar(file.path,"com.example.AnotherContract")
|
||||
val contractJarV2 = makeTestContractJar(file.path,"com.example.MyContract", version = "2.0")
|
||||
val (signedContractJarV2, publicKeyV2) = makeTestSignedContractJar(file.path,"com.example.MyContract", version = "2.0")
|
||||
val contractJarV2 = makeTestContractJar(file.path,"com.example.MyContract", version = 2)
|
||||
val (signedContractJarV2, _) = makeTestSignedContractJar(file.path,"com.example.MyContract", version = 2)
|
||||
|
||||
sampleJar.read { storage.importAttachment(it, "uploaderA", "sample.jar") }
|
||||
contractJar.read { storage.importAttachment(it, "uploaderB", "contract.jar") }
|
||||
@ -238,7 +239,7 @@ class NodeAttachmentServiceTest {
|
||||
1,
|
||||
storage.queryAttachments(AttachmentsQueryCriteria(
|
||||
contractClassNamesCondition = Builder.equal(listOf("com.example.MyContract")),
|
||||
versionCondition = Builder.equal(listOf("2.0")),
|
||||
versionCondition = Builder.equal(2),
|
||||
isSignedCondition = Builder.equal(true))).size
|
||||
)
|
||||
|
||||
@ -246,9 +247,33 @@ class NodeAttachmentServiceTest {
|
||||
2,
|
||||
storage.queryAttachments(AttachmentsQueryCriteria(
|
||||
contractClassNamesCondition = Builder.equal(listOf("com.example.MyContract", "com.example.AnotherContract")),
|
||||
versionCondition = Builder.equal(listOf("1.0")),
|
||||
versionCondition = Builder.equal(1),
|
||||
isSignedCondition = Builder.equal(true))).size
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
2,storage.queryAttachments(AttachmentsQueryCriteria(
|
||||
contractClassNamesCondition = Builder.equal(listOf("com.example.MyContract")),
|
||||
versionCondition = Builder.greaterThanOrEqual(1),
|
||||
isSignedCondition = Builder.equal(true)),
|
||||
AttachmentSort(listOf(AttachmentSort.AttachmentSortColumn(AttachmentSort.AttachmentSortAttribute.VERSION)))).size
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
1,storage.queryAttachments(AttachmentsQueryCriteria(
|
||||
contractClassNamesCondition = Builder.equal(listOf("com.example.MyContract")),
|
||||
versionCondition = Builder.greaterThanOrEqual(2),
|
||||
isSignedCondition = Builder.equal(true)),
|
||||
AttachmentSort(listOf(AttachmentSort.AttachmentSortColumn(AttachmentSort.AttachmentSortAttribute.VERSION)))).size
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
0,storage.queryAttachments(AttachmentsQueryCriteria(
|
||||
contractClassNamesCondition = Builder.equal(listOf("com.example.MyContract")),
|
||||
versionCondition = Builder.greaterThanOrEqual(10),
|
||||
isSignedCondition = Builder.equal(true)),
|
||||
AttachmentSort(listOf(AttachmentSort.AttachmentSortColumn(AttachmentSort.AttachmentSortAttribute.VERSION)))).size
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,7 +347,7 @@ class NodeAttachmentServiceTest {
|
||||
val bytes = testJar.readAll()
|
||||
val corruptBytes = "arggghhhh".toByteArray()
|
||||
System.arraycopy(corruptBytes, 0, bytes, 0, corruptBytes.size)
|
||||
val corruptAttachment = NodeAttachmentService.DBAttachment(attId = id.toString(), content = bytes, version = "1.0")
|
||||
val corruptAttachment = NodeAttachmentService.DBAttachment(attId = id.toString(), content = bytes, version = DEFAULT_CORDAPP_VERSION)
|
||||
session.merge(corruptAttachment)
|
||||
id
|
||||
}
|
||||
|
Reference in New Issue
Block a user