mirror of
https://github.com/corda/corda.git
synced 2025-05-30 14:14:29 +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.*
|
||||||
import net.corda.core.serialization.internal.AttachmentsClassLoaderBuilder
|
import net.corda.core.serialization.internal.AttachmentsClassLoaderBuilder
|
||||||
import net.corda.core.transactions.ContractUpgradeFilteredTransaction.FilteredComponent
|
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.Companion.calculateUpgradedState
|
||||||
import net.corda.core.transactions.ContractUpgradeWireTransaction.Component.*
|
import net.corda.core.transactions.ContractUpgradeWireTransaction.Component.*
|
||||||
import net.corda.core.transactions.WireTransaction.Companion.resolveStateRefBinaryComponent
|
import net.corda.core.transactions.WireTransaction.Companion.resolveStateRefBinaryComponent
|
||||||
@ -112,16 +114,16 @@ data class ContractUpgradeWireTransaction(
|
|||||||
?: throw AttachmentResolutionException(upgradedContractAttachmentId)
|
?: throw AttachmentResolutionException(upgradedContractAttachmentId)
|
||||||
val hashToResolve = networkParametersHash ?: services.networkParametersService.defaultHash
|
val hashToResolve = networkParametersHash ?: services.networkParametersService.defaultHash
|
||||||
val resolvedNetworkParameters = services.networkParametersService.lookup(hashToResolve) ?: throw TransactionResolutionException(id)
|
val resolvedNetworkParameters = services.networkParametersService.lookup(hashToResolve) ?: throw TransactionResolutionException(id)
|
||||||
return ContractUpgradeLedgerTransaction(
|
return ContractUpgradeLedgerTransaction.create(
|
||||||
resolvedInputs,
|
resolvedInputs,
|
||||||
notary,
|
notary,
|
||||||
legacyContractAttachment,
|
legacyContractAttachment,
|
||||||
upgradedContractClassName,
|
|
||||||
upgradedContractAttachment,
|
upgradedContractAttachment,
|
||||||
id,
|
id,
|
||||||
privacySalt,
|
privacySalt,
|
||||||
sigs,
|
sigs,
|
||||||
resolvedNetworkParameters
|
resolvedNetworkParameters,
|
||||||
|
loadUpgradedContract(upgradedContractClassName, retrieveAppClassLoader(services))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,22 +233,63 @@ data class ContractUpgradeFilteredTransaction(
|
|||||||
* *participants* fields, so full resolution is needed for signature verification.
|
* *participants* fields, so full resolution is needed for signature verification.
|
||||||
*/
|
*/
|
||||||
@KeepForDJVM
|
@KeepForDJVM
|
||||||
data class ContractUpgradeLedgerTransaction(
|
class ContractUpgradeLedgerTransaction
|
||||||
|
private constructor(
|
||||||
override val inputs: List<StateAndRef<ContractState>>,
|
override val inputs: List<StateAndRef<ContractState>>,
|
||||||
override val notary: Party,
|
override val notary: Party,
|
||||||
val legacyContractAttachment: Attachment,
|
val legacyContractAttachment: Attachment,
|
||||||
val upgradedContractClassName: ContractClassName,
|
|
||||||
val upgradedContractAttachment: Attachment,
|
val upgradedContractAttachment: Attachment,
|
||||||
override val id: SecureHash,
|
override val id: SecureHash,
|
||||||
val privacySalt: PrivacySalt,
|
val privacySalt: PrivacySalt,
|
||||||
override val sigs: List<TransactionSignature>,
|
override val sigs: List<TransactionSignature>,
|
||||||
override val networkParameters: NetworkParameters
|
override val networkParameters: NetworkParameters,
|
||||||
|
private val upgradedContract: UpgradedContract<ContractState, *>
|
||||||
) : FullTransaction(), TransactionWithSignatures {
|
) : FullTransaction(), TransactionWithSignatures {
|
||||||
/** ContractUpgradeLedgerTransactions do not contain reference input states. */
|
/** ContractUpgradeLedgerTransactions do not contain reference input states. */
|
||||||
override val references: List<StateAndRef<ContractState>> = emptyList()
|
override val references: List<StateAndRef<ContractState>> = emptyList()
|
||||||
/** The legacy contract class name is determined by the first input state. */
|
/** The legacy contract class name is determined by the first input state. */
|
||||||
private val legacyContractClassName = inputs.first().state.contract
|
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 {
|
init {
|
||||||
checkNotaryWhitelisted()
|
checkNotaryWhitelisted()
|
||||||
@ -297,13 +340,47 @@ data class ContractUpgradeLedgerTransaction(
|
|||||||
return keys.map { it.toBase58String() }
|
return keys.map { it.toBase58String() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: load contract from the CorDapp classloader
|
operator fun component1(): List<StateAndRef<ContractState>> = inputs
|
||||||
private fun loadUpgradedContract(): UpgradedContract<ContractState, *> {
|
operator fun component2(): Party = notary
|
||||||
@Suppress("UNCHECKED_CAST")
|
operator fun component3(): Attachment = legacyContractAttachment
|
||||||
return this::class.java.classLoader
|
operator fun component4(): ContractClassName = upgradedContract::class.java.name
|
||||||
.loadClass(upgradedContractClassName)
|
operator fun component5(): Attachment = upgradedContractAttachment
|
||||||
.asSubclass(Contract::class.java)
|
operator fun component6(): SecureHash = id
|
||||||
.getConstructor()
|
operator fun component7(): PrivacySalt = privacySalt
|
||||||
.newInstance() as UpgradedContract<ContractState, *>
|
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