diff --git a/.ci/api-current.txt b/.ci/api-current.txt index a75bc444bf..8f6dcc619f 100644 --- a/.ci/api-current.txt +++ b/.ci/api-current.txt @@ -5907,7 +5907,6 @@ public final class net.corda.core.transactions.LedgerTransaction extends net.cor public (java.util.List>, java.util.List>, java.util.List>, java.util.List, net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt) @DeprecatedConstructorForDeserialization public (java.util.List>, java.util.List>, java.util.List>, java.util.List, net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt, net.corda.core.node.NetworkParameters) - public (java.util.List, java.util.List, java.util.List, java.util.List, net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.contracts.TimeWindow, net.corda.core.contracts.PrivacySalt, net.corda.core.node.NetworkParameters, java.util.List, java.util.Map, kotlin.jvm.internal.DefaultConstructorMarker) @NotNull public final java.util.List> commandsOfType(Class) @NotNull diff --git a/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt b/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt index b16ad3bb24..d0323d123e 100644 --- a/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt +++ b/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt @@ -28,9 +28,7 @@ fun LedgerTransaction.prepareVerify(extraAttachments: List) = this.i * * @param inputVersions A map linking each contract class name to the advertised version of the JAR that defines it. Used for downgrade protection. */ -class Verifier(val ltx: LedgerTransaction, - private val transactionClassLoader: ClassLoader, - private val inputVersions: Map) { +class Verifier(val ltx: LedgerTransaction, private val transactionClassLoader: ClassLoader) { private val inputStates: List> = ltx.inputs.map { it.state } private val allStates: List> = inputStates + ltx.references.map { it.state } + ltx.outputs diff --git a/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt index eabc125549..01d1058eb8 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt @@ -58,12 +58,7 @@ private constructor( */ override val networkParameters: NetworkParameters?, /** Referenced states, which are like inputs but won't be consumed. */ - override val references: List>, - /** - * The versions of the app JARs attached to the transactions that defined the inputs, grouped by contract class name. - * This is used to stop adversaries downgrading apps to versions that have exploitable bugs. - */ - private val inputVersions: Map + override val references: List> //DOCEND 1 ) : FullTransaction() { // These are not part of the c'tor above as that defines LedgerTransaction's serialisation format @@ -94,10 +89,9 @@ private constructor( references: List>, componentGroups: List? = null, serializedInputs: List? = null, - serializedReferences: List? = null, - inputVersions: Map + serializedReferences: List? = null ): LedgerTransaction { - return LedgerTransaction(inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, networkParameters, references, inputVersions).apply { + return LedgerTransaction(inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, networkParameters, references).apply { this.componentGroups = componentGroups this.serializedInputs = serializedInputs this.serializedReferences = serializedReferences @@ -139,7 +133,7 @@ private constructor( // Switch thread local deserialization context to using a cached attachments classloader. This classloader enforces various rules // like no-overlap, package namespace ownership and (in future) deterministic Java. return AttachmentsClassLoaderBuilder.withAttachmentsClassloaderContext(this.attachments + extraAttachments, getParamsWithGoo(), id) { transactionClassLoader -> - Verifier(createLtxForVerification(), transactionClassLoader, inputVersions) + Verifier(createLtxForVerification(), transactionClassLoader) } } @@ -196,8 +190,7 @@ private constructor( timeWindow = this.timeWindow, privacySalt = this.privacySalt, networkParameters = this.networkParameters, - references = deserializedReferences, - inputVersions = this.inputVersions + references = deserializedReferences ) } else { // This branch is only present for backwards compatibility. @@ -560,7 +553,7 @@ private constructor( notary: Party?, timeWindow: TimeWindow?, privacySalt: PrivacySalt - ) : this(inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, null, emptyList(), emptyMap()) + ) : this(inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, null, emptyList()) @Deprecated("LedgerTransaction should not be created directly, use WireTransaction.toLedgerTransaction instead.") @DeprecatedConstructorForDeserialization(1) @@ -574,7 +567,7 @@ private constructor( timeWindow: TimeWindow?, privacySalt: PrivacySalt, networkParameters: NetworkParameters - ) : this(inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, networkParameters, emptyList(), emptyMap()) + ) : this(inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, networkParameters, emptyList()) @Deprecated("LedgerTransactions should not be created directly, use WireTransaction.toLedgerTransaction instead.") fun copy(inputs: List>, @@ -596,8 +589,7 @@ private constructor( timeWindow = timeWindow, privacySalt = privacySalt, networkParameters = networkParameters, - references = references, - inputVersions = emptyMap() + references = references ) } @@ -622,8 +614,7 @@ private constructor( timeWindow = timeWindow, privacySalt = privacySalt, networkParameters = networkParameters, - references = references, - inputVersions = emptyMap() + references = references ) } } diff --git a/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt index c6b9bdd59e..b13f8ec6b1 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt @@ -190,19 +190,6 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr val resolvedNetworkParameters = resolveParameters(networkParametersHash) ?: throw TransactionResolutionException.UnknownParametersException(id, networkParametersHash!!) - // For each contract referenced in the inputs, figure out the highest version being used. The outputs must be - // at least that version or higher, to prevent adversaries from downgrading the app to an old version that has - // known bugs they can then exploit. This is part of the version ratchet that ensures apps can only ever be - // upgraded, not downgraded. We don't use resolvedInputs here to keep it lazy. TODO: why? - // We do this resolution now instead of in LedgerTransaction because here we have the function to map - // StateRefs to their attachments directly. - val appVersionsInInputs: Map = serializedResolvedInputs - .map { it.toStateAndRef() } - .groupBy { it.state.contract } - .mapValues { (_ , statesAndRefs) -> - statesAndRefs.map { resolveContractAttachment(it.ref).contractVersion }.max() ?: DEFAULT_CORDAPP_VERSION - } - val ltx = LedgerTransaction.create( resolvedInputs, outputs, @@ -216,8 +203,7 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr resolvedReferences, componentGroups, serializedResolvedInputs, - serializedResolvedReferences, - appVersionsInInputs + serializedResolvedReferences ) checkTransactionSize(ltx, resolvedNetworkParameters.maxTransactionSize, serializedResolvedInputs, serializedResolvedReferences) diff --git a/core/src/test/kotlin/net/corda/core/transactions/TransactionTests.kt b/core/src/test/kotlin/net/corda/core/transactions/TransactionTests.kt index 994c30e925..2adc215584 100644 --- a/core/src/test/kotlin/net/corda/core/transactions/TransactionTests.kt +++ b/core/src/test/kotlin/net/corda/core/transactions/TransactionTests.kt @@ -139,8 +139,7 @@ class TransactionTests { timeWindow, privacySalt, testNetworkParameters(), - emptyList(), - inputVersions = emptyMap() + emptyList() ) transaction.verify() @@ -192,8 +191,7 @@ class TransactionTests { timeWindow, privacySalt, testNetworkParameters(notaries = listOf(NotaryInfo(DUMMY_NOTARY, true))), - emptyList(), - inputVersions = emptyMap() + emptyList() ) assertFailsWith { buildTransaction().verify() } diff --git a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt index a6945a069f..52ede9cae9 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt @@ -461,11 +461,9 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) { // We need to declare this here, if we do it inside [expectEvents] kotlin throws an internal compiler error(!). val aliceTxExpectations = sequence( - //TODO investigate missing event after introduction of signature constraints non-downgrade rule - /* expect { tx: SignedTransaction -> require(tx.id == bobsFakeCash[0].id) - },*/ + }, expect { tx: SignedTransaction -> require(tx.id == bobsFakeCash[2].id) }, @@ -475,12 +473,10 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) { ) aliceTxStream.expectEvents { aliceTxExpectations } val aliceMappingExpectations = sequence( - //TODO investigate missing event after introduction of signature constraints non-downgrade rule - /* expect { (stateMachineRunId, transactionId) -> require(stateMachineRunId == aliceSmId) require(transactionId == bobsFakeCash[0].id) - },*/ + }, expect { (stateMachineRunId, transactionId) -> require(stateMachineRunId == aliceSmId) require(transactionId == bobsFakeCash[2].id)