CORDA-2871: Add a callback to ServicesForResolution to allow the Node to modify a LedgerTransaction object.

This commit is contained in:
Chris Rankin
2019-07-18 16:48:17 +01:00
parent 840e717ccf
commit d02d17fb4e
4 changed files with 21 additions and 5 deletions

View File

@ -10,6 +10,7 @@ import net.corda.core.flows.ContractUpgradeFlow
import net.corda.core.node.services.* import net.corda.core.node.services.*
import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializeAsToken
import net.corda.core.transactions.FilteredTransaction import net.corda.core.transactions.FilteredTransaction
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import java.security.PublicKey import java.security.PublicKey
@ -71,6 +72,12 @@ interface ServicesForResolution {
*/ */
@Throws(TransactionResolutionException::class, AttachmentResolutionException::class) @Throws(TransactionResolutionException::class, AttachmentResolutionException::class)
fun loadContractAttachment(stateRef: StateRef): Attachment fun loadContractAttachment(stateRef: StateRef): Attachment
/**
* Provides a callback for the Node to customise the [LedgerTransaction].
*/
@JvmDefault
fun specialise(ltx: LedgerTransaction): LedgerTransaction = ltx
} }
/** /**

View File

@ -70,8 +70,8 @@ open class TransactionBuilder(
private fun defaultLockId() = (Strand.currentStrand() as? FlowStateMachine<*>)?.id?.uuid ?: UUID.randomUUID() private fun defaultLockId() = (Strand.currentStrand() as? FlowStateMachine<*>)?.id?.uuid ?: UUID.randomUUID()
private val log = contextLogger() private val log = contextLogger()
private val ID_PATTERN = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*" private const val ID_PATTERN = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*"
private val FQCP = Pattern.compile("$ID_PATTERN(/$ID_PATTERN)+") private val FQCP: Pattern = Pattern.compile("$ID_PATTERN(/$ID_PATTERN)+")
private fun isValidJavaClass(identifier: String) = FQCP.matcher(identifier).matches() private fun isValidJavaClass(identifier: String) = FQCP.matcher(identifier).matches()
} }

View File

@ -99,7 +99,8 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class) @Throws(AttachmentResolutionException::class, TransactionResolutionException::class)
@DeleteForDJVM @DeleteForDJVM
fun toLedgerTransaction(services: ServicesForResolution): LedgerTransaction { fun toLedgerTransaction(services: ServicesForResolution): LedgerTransaction {
return toLedgerTransactionInternal( return services.specialise(
toLedgerTransactionInternal(
resolveIdentity = { services.identityService.partyFromKey(it) }, resolveIdentity = { services.identityService.partyFromKey(it) },
resolveAttachment = { services.attachments.openAttachment(it) }, resolveAttachment = { services.attachments.openAttachment(it) },
resolveStateRefAsSerialized = { resolveStateRefBinaryComponent(it, services) }, resolveStateRefAsSerialized = { resolveStateRefBinaryComponent(it, services) },
@ -109,6 +110,7 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
}, },
// `as?` is used due to [MockServices] not implementing [ServiceHubCoreInternal] // `as?` is used due to [MockServices] not implementing [ServiceHubCoreInternal]
isAttachmentTrusted = { (services as? ServiceHubCoreInternal)?.attachmentTrustCalculator?.calculate(it) ?: true } isAttachmentTrusted = { (services as? ServiceHubCoreInternal)?.attachmentTrustCalculator?.calculate(it) ?: true }
)
) )
} }
@ -129,7 +131,7 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
* @throws AttachmentResolutionException if a required attachment was not found using [resolveAttachment]. * @throws AttachmentResolutionException if a required attachment was not found using [resolveAttachment].
* @throws TransactionResolutionException if an input was not found not using [resolveStateRef]. * @throws TransactionResolutionException if an input was not found not using [resolveStateRef].
*/ */
@Deprecated("Use toLedgerTransaction(ServicesForTransaction) instead") @Deprecated("Use toLedgerTransaction(ServicesForResolution) instead")
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class) @Throws(AttachmentResolutionException::class, TransactionResolutionException::class)
fun toLedgerTransaction( fun toLedgerTransaction(
resolveIdentity: (PublicKey) -> Party?, resolveIdentity: (PublicKey) -> Party?,

View File

@ -10,6 +10,7 @@ import net.corda.core.node.services.IdentityService
import net.corda.core.node.services.NetworkParametersService import net.corda.core.node.services.NetworkParametersService
import net.corda.core.node.services.TransactionStorage import net.corda.core.node.services.TransactionStorage
import net.corda.core.transactions.ContractUpgradeWireTransaction import net.corda.core.transactions.ContractUpgradeWireTransaction
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.NotaryChangeWireTransaction import net.corda.core.transactions.NotaryChangeWireTransaction
import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction
import net.corda.core.transactions.WireTransaction.Companion.resolveStateRefBinaryComponent import net.corda.core.transactions.WireTransaction.Companion.resolveStateRefBinaryComponent
@ -35,7 +36,7 @@ data class ServicesForResolutionImpl(
return stateRefs.groupBy { it.txhash }.flatMap { return stateRefs.groupBy { it.txhash }.flatMap {
val stx = validatedTransactions.getTransaction(it.key) ?: throw TransactionResolutionException(it.key) val stx = validatedTransactions.getTransaction(it.key) ?: throw TransactionResolutionException(it.key)
val baseTx = stx.resolveBaseTransaction(this) val baseTx = stx.resolveBaseTransaction(this)
it.value.map { StateAndRef(baseTx.outputs[it.index], it) } it.value.map { ref -> StateAndRef(baseTx.outputs[ref.index], ref) }
}.toSet() }.toSet()
} }
@ -69,4 +70,10 @@ data class ServicesForResolutionImpl(
} }
return inner(stateRef, null) return inner(stateRef, null)
} }
override fun specialise(ltx: LedgerTransaction): LedgerTransaction {
// Specialise the LedgerTransaction here so that
// contracts are verified inside the DJVM!
return ltx
}
} }