mirror of
https://github.com/corda/corda.git
synced 2025-05-28 13:14:24 +00:00
CORDA-2550 use cordapp classloader for explicit upgrades (#4766)
CORDA-2550 use cordapp classloader for explicit upgrades CORDA-2550 Fix api break CORDA-2550 Fix api break CORDA-2550 Fix api break CORDA-2550 Address code review comments CORDA-2550 Fix error CORDA-2550 Remove redundant field. CORDA-2550 Remove redundant field. CORDA-2550 remove unnecessary copy method CORDA-2550 remove unnecessary copy method
This commit is contained in:
parent
092d66ac45
commit
e5c7355d43
@ -15,6 +15,8 @@ import net.corda.core.node.ServicesForResolution
|
||||
import net.corda.core.serialization.*
|
||||
import net.corda.core.serialization.internal.AttachmentsClassLoaderBuilder
|
||||
import net.corda.core.transactions.ContractUpgradeFilteredTransaction.FilteredComponent
|
||||
import net.corda.core.transactions.ContractUpgradeLedgerTransaction.Companion.loadUpgradedContract
|
||||
import net.corda.core.transactions.ContractUpgradeLedgerTransaction.Companion.retrieveAppClassLoader
|
||||
import net.corda.core.transactions.ContractUpgradeWireTransaction.Companion.calculateUpgradedState
|
||||
import net.corda.core.transactions.ContractUpgradeWireTransaction.Component.*
|
||||
import net.corda.core.transactions.WireTransaction.Companion.resolveStateRefBinaryComponent
|
||||
@ -112,16 +114,16 @@ data class ContractUpgradeWireTransaction(
|
||||
?: throw AttachmentResolutionException(upgradedContractAttachmentId)
|
||||
val hashToResolve = networkParametersHash ?: services.networkParametersService.defaultHash
|
||||
val resolvedNetworkParameters = services.networkParametersService.lookup(hashToResolve) ?: throw TransactionResolutionException(id)
|
||||
return ContractUpgradeLedgerTransaction(
|
||||
return ContractUpgradeLedgerTransaction.create(
|
||||
resolvedInputs,
|
||||
notary,
|
||||
legacyContractAttachment,
|
||||
upgradedContractClassName,
|
||||
upgradedContractAttachment,
|
||||
id,
|
||||
privacySalt,
|
||||
sigs,
|
||||
resolvedNetworkParameters
|
||||
resolvedNetworkParameters,
|
||||
loadUpgradedContract(upgradedContractClassName, retrieveAppClassLoader(services))
|
||||
)
|
||||
}
|
||||
|
||||
@ -231,22 +233,63 @@ data class ContractUpgradeFilteredTransaction(
|
||||
* *participants* fields, so full resolution is needed for signature verification.
|
||||
*/
|
||||
@KeepForDJVM
|
||||
data class ContractUpgradeLedgerTransaction(
|
||||
class ContractUpgradeLedgerTransaction
|
||||
private constructor(
|
||||
override val inputs: List<StateAndRef<ContractState>>,
|
||||
override val notary: Party,
|
||||
val legacyContractAttachment: Attachment,
|
||||
val upgradedContractClassName: ContractClassName,
|
||||
val upgradedContractAttachment: Attachment,
|
||||
override val id: SecureHash,
|
||||
val privacySalt: PrivacySalt,
|
||||
override val sigs: List<TransactionSignature>,
|
||||
override val networkParameters: NetworkParameters
|
||||
override val networkParameters: NetworkParameters,
|
||||
private val upgradedContract: UpgradedContract<ContractState, *>
|
||||
) : FullTransaction(), TransactionWithSignatures {
|
||||
/** ContractUpgradeLedgerTransactions do not contain reference input states. */
|
||||
override val references: List<StateAndRef<ContractState>> = emptyList()
|
||||
/** The legacy contract class name is determined by the first input state. */
|
||||
private val legacyContractClassName = inputs.first().state.contract
|
||||
private val upgradedContract: UpgradedContract<ContractState, *> = loadUpgradedContract()
|
||||
|
||||
val upgradedContractClassName: ContractClassName
|
||||
get() = upgradedContract::class.java.name
|
||||
|
||||
companion object {
|
||||
|
||||
@CordaInternal
|
||||
internal fun create(
|
||||
inputs: List<StateAndRef<ContractState>>,
|
||||
notary: Party,
|
||||
legacyContractAttachment: Attachment,
|
||||
upgradedContractAttachment: Attachment,
|
||||
id: SecureHash,
|
||||
privacySalt: PrivacySalt,
|
||||
sigs: List<TransactionSignature>,
|
||||
networkParameters: NetworkParameters,
|
||||
upgradedContract: UpgradedContract<ContractState, *>
|
||||
): ContractUpgradeLedgerTransaction {
|
||||
return ContractUpgradeLedgerTransaction(inputs, notary, legacyContractAttachment, upgradedContractAttachment, id, privacySalt, sigs, networkParameters, upgradedContract)
|
||||
}
|
||||
|
||||
// TODO - this has to use a classloader created from the upgraded attachment.
|
||||
@CordaInternal
|
||||
internal fun loadUpgradedContract(upgradedContractClassName: ContractClassName, classLoader: ClassLoader): UpgradedContract<ContractState, *> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return classLoader
|
||||
.loadClass(upgradedContractClassName)
|
||||
.asSubclass(Contract::class.java)
|
||||
.getConstructor()
|
||||
.newInstance() as UpgradedContract<ContractState, *>
|
||||
}
|
||||
|
||||
// This is a "hack" to retrieve the CordappsClassloader from the services without having access to all classes.
|
||||
@CordaInternal
|
||||
internal fun retrieveAppClassLoader(services: ServicesForResolution): ClassLoader {
|
||||
val cordappLoader = services.cordappProvider::class.java.getMethod("getCordappLoader").invoke(services.cordappProvider)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return cordappLoader::class.java.getMethod("getAppClassLoader").invoke(cordappLoader) as ClassLoader
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
checkNotaryWhitelisted()
|
||||
@ -297,13 +340,47 @@ data class ContractUpgradeLedgerTransaction(
|
||||
return keys.map { it.toBase58String() }
|
||||
}
|
||||
|
||||
// TODO: load contract from the CorDapp classloader
|
||||
private fun loadUpgradedContract(): UpgradedContract<ContractState, *> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return this::class.java.classLoader
|
||||
.loadClass(upgradedContractClassName)
|
||||
.asSubclass(Contract::class.java)
|
||||
.getConstructor()
|
||||
.newInstance() as UpgradedContract<ContractState, *>
|
||||
operator fun component1(): List<StateAndRef<ContractState>> = inputs
|
||||
operator fun component2(): Party = notary
|
||||
operator fun component3(): Attachment = legacyContractAttachment
|
||||
operator fun component4(): ContractClassName = upgradedContract::class.java.name
|
||||
operator fun component5(): Attachment = upgradedContractAttachment
|
||||
operator fun component6(): SecureHash = id
|
||||
operator fun component7(): PrivacySalt = privacySalt
|
||||
operator fun component8(): List<TransactionSignature> = sigs
|
||||
operator fun component9(): NetworkParameters = networkParameters
|
||||
|
||||
override fun equals(other: Any?): Boolean = this === other || other is ContractUpgradeLedgerTransaction && this.id == other.id
|
||||
|
||||
override fun hashCode(): Int = id.hashCode()
|
||||
|
||||
override fun toString(): String {
|
||||
return "ContractUpgradeLedgerTransaction(inputs=$inputs, notary=$notary, legacyContractAttachment=$legacyContractAttachment, upgradedContractAttachment=$upgradedContractAttachment, id=$id, privacySalt=$privacySalt, sigs=$sigs, networkParameters=$networkParameters, upgradedContract=$upgradedContract, references=$references, legacyContractClassName='$legacyContractClassName', outputs=$outputs)"
|
||||
}
|
||||
|
||||
@Deprecated("ContractUpgradeLedgerTransaction should not be created directly, use ContractUpgradeWireTransaction.resolve instead.")
|
||||
constructor(
|
||||
inputs: List<StateAndRef<ContractState>>,
|
||||
notary: Party,
|
||||
legacyContractAttachment: Attachment,
|
||||
upgradedContractClassName: ContractClassName,
|
||||
upgradedContractAttachment: Attachment,
|
||||
id: SecureHash,
|
||||
privacySalt: PrivacySalt,
|
||||
sigs: List<TransactionSignature>,
|
||||
networkParameters: NetworkParameters
|
||||
) : this(inputs, notary, legacyContractAttachment, upgradedContractAttachment, id, privacySalt, sigs, networkParameters, loadUpgradedContract(upgradedContractClassName, ContractUpgradeLedgerTransaction::class.java.classLoader))
|
||||
|
||||
@Deprecated("ContractUpgradeLedgerTransaction should not be created directly, use ContractUpgradeWireTransaction.resolve instead.")
|
||||
fun copy(
|
||||
inputs: List<StateAndRef<ContractState>> = this.inputs,
|
||||
notary: Party = this.notary,
|
||||
legacyContractAttachment: Attachment = this.legacyContractAttachment,
|
||||
upgradedContractClassName: ContractClassName = this.upgradedContract::class.java.name,
|
||||
upgradedContractAttachment: Attachment = this.upgradedContractAttachment,
|
||||
id: SecureHash = this.id,
|
||||
privacySalt: PrivacySalt = this.privacySalt,
|
||||
sigs: List<TransactionSignature> = this.sigs,
|
||||
networkParameters: NetworkParameters = this.networkParameters
|
||||
) = ContractUpgradeLedgerTransaction(inputs, notary, legacyContractAttachment, upgradedContractClassName, upgradedContractAttachment, id, privacySalt, sigs, networkParameters)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user