CORDA-2178 Signature constraints minimum platform version checking (#4161)

* Minimum platform version checking for new signature constraints feature.

* Fix broken JUnit

* NP safety checking on network parameters.

* Warning and auto-downgrade of signed states that do not meet the minimum network platform version.
This commit is contained in:
josecoll 2018-11-09 12:27:28 +00:00 committed by GitHub
parent 99e9864975
commit 74c80aafd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 34 additions and 5 deletions

View File

@ -20,12 +20,15 @@ import org.slf4j.MDC
const val PLATFORM_VERSION = 4
fun ServicesForResolution.ensureMinimumPlatformVersion(requiredMinPlatformVersion: Int, feature: String) {
val currentMinPlatformVersion = networkParameters.minimumPlatformVersion
if (currentMinPlatformVersion < requiredMinPlatformVersion) {
checkMinimumPlatformVersion(networkParameters.minimumPlatformVersion, requiredMinPlatformVersion, feature)
}
fun checkMinimumPlatformVersion(minimumPlatformVersion: Int, requiredMinPlatformVersion: Int, feature: String) {
if (minimumPlatformVersion < requiredMinPlatformVersion) {
throw ZoneVersionTooLowException(
"$feature requires all nodes on the Corda compatibility zone to be running at least platform version " +
"$requiredMinPlatformVersion. The current zone is only enforcing a minimum platform version of " +
"$currentMinPlatformVersion. Please contact your zone operator."
"$minimumPlatformVersion. Please contact your zone operator."
)
}
}

View File

@ -7,6 +7,7 @@ import net.corda.core.crypto.isFulfilledBy
import net.corda.core.identity.Party
import net.corda.core.internal.AttachmentWithContext
import net.corda.core.internal.castIfPossible
import net.corda.core.internal.checkMinimumPlatformVersion
import net.corda.core.internal.uncheckedCast
import net.corda.core.node.NetworkParameters
import net.corda.core.serialization.CordaSerializable
@ -148,6 +149,8 @@ data class LedgerTransaction @JvmOverloads constructor(
val contractAttachment = uniqueAttachmentsForStateContract.first()
val constraintAttachment = AttachmentWithContext(contractAttachment, state.contract, networkParameters?.whitelistedContractImplementations)
if (state.constraint is SignatureAttachmentConstraint)
checkMinimumPlatformVersion(networkParameters?.minimumPlatformVersion ?: 1, 4, "Signature constraints")
if (!state.constraint.isSatisfiedBy(constraintAttachment)) {
throw TransactionVerificationException.ContractConstraintRejection(id, state.contract)
}

View File

@ -56,6 +56,10 @@ open class TransactionBuilder @JvmOverloads constructor(
private val inputsWithTransactionState = arrayListOf<TransactionState<ContractState>>()
private val referencesWithTransactionState = arrayListOf<TransactionState<ContractState>>()
companion object {
private val log = contextLogger()
}
/**
* Creates a copy of the builder.
*/
@ -165,7 +169,21 @@ open class TransactionBuilder @JvmOverloads constructor(
return when {
attachmentSigners.isEmpty() -> HashAttachmentConstraint(attachmentId)
else -> makeSignatureAttachmentConstraint(attachmentSigners)
else -> {
// Auto downgrade: signature constraints only available with a corda network minimum platform version of >= 4
if (services.networkParameters.minimumPlatformVersion < 4) {
log.warn("Signature constraints not available on network requiring a minimum platform version of ${services.networkParameters.minimumPlatformVersion}")
if (useWhitelistedByZoneAttachmentConstraint(state.contract, services.networkParameters)) {
log.warn("Reverting back to using whitelisted zone constraints")
WhitelistedByZoneAttachmentConstraint
}
else {
log.warn("Reverting back to using hash constraints")
HashAttachmentConstraint(attachmentId)
}
}
else makeSignatureAttachmentConstraint(attachmentSigners)
}
}
}

View File

@ -8,6 +8,7 @@ import net.corda.core.crypto.CompositeKey
import net.corda.core.crypto.SecureHash
import net.corda.core.identity.Party
import net.corda.core.internal.AbstractAttachment
import net.corda.core.internal.PLATFORM_VERSION
import net.corda.core.node.ServicesForResolution
import net.corda.core.node.ZoneVersionTooLowException
import net.corda.core.node.services.AttachmentStorage
@ -40,7 +41,7 @@ class TransactionBuilderTest {
val cordappProvider = rigorousMock<CordappProvider>()
doReturn(cordappProvider).whenever(services).cordappProvider
doReturn(contractAttachmentId).whenever(cordappProvider).getContractAttachmentID(DummyContract.PROGRAM_ID)
doReturn(testNetworkParameters()).whenever(services).networkParameters
doReturn(testNetworkParameters(minimumPlatformVersion = PLATFORM_VERSION)).whenever(services).networkParameters
val attachmentStorage = rigorousMock<AttachmentStorage>()
doReturn(attachmentStorage).whenever(services).attachments

View File

@ -88,6 +88,10 @@ and the smoothest to deploy: no restarts or contract upgrade transactions are ne
When CorDapp is build using :ref:`corda-gradle-plugin <cordapp_build_system_signing_cordapp_jar_ref>` the JAR is signed
by Corda development key by default, an external keystore can be configured or signing can be disabled.
.. warning:: CorDapps can only use signature constraints when participating in a Corda network using a minimum platform version of 4.
An auto downgrade rule applies to signed CorDapps built and tested with Corda 4 but running on a Corda network of a lower version:
if the associated contract class is whitelisted in the network parameters then zone constraints are applied, otherwise hash constraints are used.
**Defaults.** The default constraint type is either a zone constraint, if the network parameters in effect when the
transaction is built contain an entry for that contract class, or a hash constraint if not.