From 47a57285fbcbdcf5d463756ab73eb9418fe6357b Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Thu, 7 Mar 2024 10:06:23 +0000 Subject: [PATCH] ENT-9659: Using signers component group for `WireTransaction.requiredSigningKeys` The previous solution of using `Command.signers` has the risk of not being deserialisable if the correct CorDapp is not installed on the node. --- .../core/transactions/WireTransaction.kt | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) 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 83ecf55704..021b09e97b 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt @@ -8,6 +8,7 @@ import net.corda.core.contracts.CommandWithParties import net.corda.core.contracts.ComponentGroupEnum import net.corda.core.contracts.ComponentGroupEnum.COMMANDS_GROUP import net.corda.core.contracts.ComponentGroupEnum.OUTPUTS_GROUP +import net.corda.core.contracts.ComponentGroupEnum.SIGNERS_GROUP import net.corda.core.contracts.ContractState import net.corda.core.contracts.PrivacySalt import net.corda.core.contracts.StateRef @@ -24,11 +25,13 @@ import net.corda.core.internal.Emoji import net.corda.core.internal.SerializedStateAndRef import net.corda.core.internal.SerializedTransactionState import net.corda.core.internal.createComponentGroups +import net.corda.core.internal.deserialiseComponentGroup import net.corda.core.internal.flatMapToSet import net.corda.core.internal.getGroup import net.corda.core.internal.isUploaderTrusted import net.corda.core.internal.lazyMapped import net.corda.core.internal.mapToSet +import net.corda.core.internal.uncheckedCast import net.corda.core.internal.verification.VerificationSupport import net.corda.core.internal.verification.toVerifyingServiceHub import net.corda.core.node.NetworkParameters @@ -106,13 +109,20 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr /** Public keys that need to be fulfilled by signatures in order for the transaction to be valid. */ val requiredSigningKeys: Set get() { - val commandKeys = commands.flatMap { it.signers }.toSet() - // TODO: prevent notary field from being set if there are no inputs and no time-window. - return if (notary != null && (inputs.isNotEmpty() || references.isNotEmpty() || timeWindow != null)) { - commandKeys + notary.owningKey + val keys = LinkedHashSet() + val signersGroup: List> = uncheckedCast(deserialiseComponentGroup(componentGroups, List::class, SIGNERS_GROUP)) + if (signersGroup.isNotEmpty()) { + signersGroup.forEach { keys.addAll(it) } } else { - commandKeys + // On the very odd chance we're dealing with a pre-3.x transaction, use the commands to get the signers. However, this has + // risk of not being deserialisable if the correct CorDapp is not installed. This is why this is only used as a last resort. + commands.flatMapTo(keys) { it.signers } } + // TODO: prevent notary field from being set if there are no inputs and no time-window. + if (notary != null && (inputs.isNotEmpty() || references.isNotEmpty() || timeWindow != null)) { + keys += notary.owningKey + } + return keys } /**