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:
szymonsztuka
2018-12-06 11:28:53 +00:00
committed by GitHub
parent 2833013119
commit d2d13c1dfc
22 changed files with 130 additions and 54 deletions

View File

@ -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(

View File

@ -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)
}
}

View File

@ -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")

View File

@ -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>

View File

@ -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();

View File

@ -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
}