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:
Tudor Malene 2019-02-16 17:46:23 +00:00 committed by Tommy Lillehagen
parent 092d66ac45
commit e5c7355d43

View File

@ -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)
} }