CORDA-2475 Adjust attachments query logic to return correct results (#4612)

* CORDA-2475 Adjust attachments query logic to return correct results sets for signed/unsigned jars.

* Updates following PR review feedback by RP.
This commit is contained in:
josecoll
2019-01-22 22:57:43 +00:00
committed by GitHub
parent 197a13611d
commit 100a6fcb56
7 changed files with 129 additions and 40 deletions

View File

@ -1,10 +1,9 @@
package net.corda.core.node.services
import net.corda.core.CordaInternal
import net.corda.core.DoNotImplement
import net.corda.core.contracts.Attachment
import net.corda.core.contracts.ContractAttachment
import net.corda.core.crypto.SecureHash
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
import net.corda.core.node.services.vault.AttachmentQueryCriteria
import net.corda.core.node.services.vault.AttachmentSort
import java.io.IOException
@ -79,22 +78,15 @@ interface AttachmentStorage {
}
/**
* Find the Attachment Id of the contract attachment with the highest version for a given contract class name
* from trusted upload sources. If both a signed and unsigned attachment exist, prefer the signed one.
* Find the Attachment Id(s) of the contract attachments with the highest version for a given contract class name
* from trusted upload sources.
* Return highest version of both signed and unsigned attachment ids (signed first, unsigned second), otherwise return a
* single signed or unsigned version id, or an empty list if none meet the criteria.
*
* @param contractClassName The fully qualified name of the contract class.
* @param minContractVersion The minimum contract version that should be returned.
* @return the [AttachmentId] of the contract, or null if none meet the criteria.
* @return the [AttachmentId]s of the contract attachments (signed always first in list), or an empty list if none meet the criteria.
*/
fun getContractAttachmentWithHighestContractVersion(contractClassName: String, minContractVersion: Int): AttachmentId?
/**
* Find the Attachment Ids of the contract attachments for a given contract class name
* from trusted upload sources.
*
* @param contractClassName The fully qualified name of the contract class.
* @return the [AttachmentId]s of the contract attachments, or an empty set if none meet the criteria.
*/
fun getContractAttachments(contractClassName: String): Set<AttachmentId>
fun getLatestContractAttachments(contractClassName: String, minContractVersion: Int = DEFAULT_CORDAPP_VERSION): List<AttachmentId>
}

View File

@ -288,7 +288,7 @@ open class TransactionBuilder(
val outputHashConstraints = outputStates?.filter { it.constraint is HashAttachmentConstraint } ?: emptyList()
val outputSignatureConstraints = outputStates?.filter { it.constraint is SignatureAttachmentConstraint } ?: emptyList()
if (inputsHashConstraints.isNotEmpty() && (outputHashConstraints.isNotEmpty() || outputSignatureConstraints.isNotEmpty())) {
val attachmentIds = services.attachments.getContractAttachments(contractClassName)
val attachmentIds = services.attachments.getLatestContractAttachments(contractClassName)
// only switchover if we have both signed and unsigned attachments for the given contract class name
if (attachmentIds.isNotEmpty() && attachmentIds.size == 2) {
val attachmentsToUse = attachmentIds.map {
@ -465,7 +465,7 @@ open class TransactionBuilder(
require(isReference || constraints.none { it is HashAttachmentConstraint })
val minimumRequiredContractClassVersion = stateRefs?.map { services.loadContractAttachment(it).contractVersion }?.max() ?: DEFAULT_CORDAPP_VERSION
return services.attachments.getContractAttachmentWithHighestContractVersion(contractClassName, minimumRequiredContractClassVersion)
return services.attachments.getLatestContractAttachments(contractClassName, minimumRequiredContractClassVersion).firstOrNull()
?: throw MissingContractAttachments(states, minimumRequiredContractClassVersion)
}

View File

@ -59,8 +59,8 @@ class TransactionBuilderTest {
doReturn(setOf(DummyContract.PROGRAM_ID)).whenever(attachment).allContracts
doReturn("app").whenever(attachment).uploader
doReturn(emptyList<Party>()).whenever(attachment).signerKeys
doReturn(contractAttachmentId).whenever(attachmentStorage)
.getContractAttachmentWithHighestContractVersion("net.corda.testing.contracts.DummyContract", DEFAULT_CORDAPP_VERSION)
doReturn(listOf(contractAttachmentId)).whenever(attachmentStorage)
.getLatestContractAttachments("net.corda.testing.contracts.DummyContract")
}
@Test
@ -146,8 +146,8 @@ class TransactionBuilderTest {
doReturn(attachments).whenever(services).attachments
doReturn(signedAttachment).whenever(attachments).openAttachment(contractAttachmentId)
doReturn(contractAttachmentId).whenever(attachments)
.getContractAttachmentWithHighestContractVersion("net.corda.testing.contracts.DummyContract", DEFAULT_CORDAPP_VERSION)
doReturn(listOf(contractAttachmentId)).whenever(attachments)
.getLatestContractAttachments("net.corda.testing.contracts.DummyContract")
val outputState = TransactionState(data = DummyState(), contract = DummyContract.PROGRAM_ID, notary = notary)
val builder = TransactionBuilder()