From c3e8284f280713b758b4456155aaf15fd41943f6 Mon Sep 17 00:00:00 2001 From: Jose Coll Date: Mon, 17 Jul 2023 09:48:37 +0100 Subject: [PATCH] ENT-9927 Ledger Recovery tweaks (#7409) --- .../net/corda/core/flows/FinalityFlow.kt | 4 +-- .../corda/core/flows/SendTransactionFlow.kt | 30 +++++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/flows/FinalityFlow.kt b/core/src/main/kotlin/net/corda/core/flows/FinalityFlow.kt index 46902c19b2..36b5174ad8 100644 --- a/core/src/main/kotlin/net/corda/core/flows/FinalityFlow.kt +++ b/core/src/main/kotlin/net/corda/core/flows/FinalityFlow.kt @@ -283,7 +283,7 @@ class FinalityFlow private constructor(val transaction: SignedTransaction, try { logger.debug { "Sending transaction to party sessions: $sessions." } val (participantSessions, observerSessions) = deriveSessions(sessions) - subFlow(SendTransactionFlow(tx, participantSessions, observerSessions, statesToRecord)) + subFlow(SendTransactionFlow(tx, participantSessions, observerSessions, statesToRecord, true)) } catch (e: UnexpectedFlowEndException) { throw UnexpectedFlowEndException( "One of the sessions ${sessions.map { it.counterparty }} has finished prematurely and we're trying to send them a transaction." + @@ -367,7 +367,7 @@ class FinalityFlow private constructor(val transaction: SignedTransaction, oldV3Broadcast(tx, oldParticipants.toSet()) try { logger.debug { "Sending transaction to party sessions $sessions." } - subFlow(SendTransactionFlow(tx, sessions.toSet(), emptySet(), statesToRecord)) + subFlow(SendTransactionFlow(tx, sessions.toSet(), emptySet(), statesToRecord, true)) } catch (e: UnexpectedFlowEndException) { throw UnexpectedFlowEndException( "One of the sessions ${sessions.map { it.counterparty }} has finished prematurely and we're trying to send them the finalised transaction. " + diff --git a/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt b/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt index 0daa48633f..93ed7d0c97 100644 --- a/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt +++ b/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt @@ -6,6 +6,7 @@ import net.corda.core.contracts.StateAndRef import net.corda.core.crypto.SecureHash import net.corda.core.identity.CordaX500Name import net.corda.core.internal.* +import net.corda.core.node.ServicesForResolution import net.corda.core.node.StatesToRecord import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.SerializedBytes @@ -78,20 +79,37 @@ class MaybeSerializedSignedTransaction(override val id: SecureHash, val serializ * @param participantSessions the target parties which are participants to the transaction. * @param observerSessions the target parties which are observers to the transaction. * @param senderStatesToRecord the [StatesToRecord] relevancy information of the sender. + * @param recordMetaDataEvenIfNotFullySigned whether to store recovery metadata when a txn is not fully signed. */ open class SendTransactionFlow(val stx: SignedTransaction, val participantSessions: Set, val observerSessions: Set, - val senderStatesToRecord: StatesToRecord) : DataVendingFlow(participantSessions + observerSessions, stx, - TransactionMetadata(DUMMY_PARTICIPANT_NAME, - DistributionList(senderStatesToRecord, - (participantSessions.map { it.counterparty.name to StatesToRecord.ONLY_RELEVANT}).toMap() + - (observerSessions.map { it.counterparty.name to StatesToRecord.ALL_VISIBLE}).toMap() - ))) { + val senderStatesToRecord: StatesToRecord, + private val recordMetaDataEvenIfNotFullySigned: Boolean = false) + : DataVendingFlow(participantSessions + observerSessions, stx, + makeMetaData(stx, recordMetaDataEvenIfNotFullySigned, senderStatesToRecord, participantSessions, observerSessions)) { + constructor(otherSide: FlowSession, stx: SignedTransaction) : this(stx, setOf(otherSide), emptySet(), StatesToRecord.NONE) + // Note: DUMMY_PARTICIPANT_NAME to be substituted with actual "ourIdentity.name" in flow call() companion object { val DUMMY_PARTICIPANT_NAME = CordaX500Name("Transaction Participant", "London", "GB") + + fun makeMetaData(stx: SignedTransaction, recordMetaDataEvenIfNotFullySigned: Boolean, senderStatesToRecord: StatesToRecord, participantSessions: Set, observerSessions: Set): TransactionMetadata? { + return if (recordMetaDataEvenIfNotFullySigned || isFullySigned(stx)) + TransactionMetadata(DUMMY_PARTICIPANT_NAME, + DistributionList(senderStatesToRecord, + (participantSessions.map { it.counterparty.name to StatesToRecord.ONLY_RELEVANT}).toMap() + + (observerSessions.map { it.counterparty.name to StatesToRecord.ALL_VISIBLE}).toMap())) + else null + } + + private fun isFullySigned(stx: SignedTransaction): Boolean { + val serviceHub = (currentTopLevel?.serviceHub as? ServicesForResolution) + return if (serviceHub != null) + stx.resolveTransactionWithSignatures(serviceHub).getMissingSigners().isEmpty() + else false + } } }