Required changes for running tx.verify in conclave

This commit is contained in:
vanjatomic 2022-02-21 09:31:24 +00:00
parent d30b354b19
commit 046c441cbe
8 changed files with 102 additions and 4 deletions

View File

@ -3,6 +3,7 @@ package net.corda.core.contracts
import net.corda.core.KeepForDJVM
import net.corda.core.crypto.CompositeKey
import net.corda.core.identity.Party
import net.corda.core.serialization.ConstructorForDeserialization
import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.exactAdd
import java.math.BigDecimal
@ -39,7 +40,9 @@ interface TokenizableAssetInfo {
*/
@KeepForDJVM
@CordaSerializable
data class Amount<T : Any>(val quantity: Long, val displayTokenSize: BigDecimal, val token: T) : Comparable<Amount<T>> {
data class Amount<T : Any>
@ConstructorForDeserialization
constructor(val quantity: Long, val displayTokenSize: BigDecimal, val token: T) : Comparable<Amount<T>> {
// TODO Proper lookup of currencies in a locale and context sensitive fashion is not supported and is left to the application.
companion object {
/**

View File

@ -4,6 +4,7 @@ package net.corda.core.contracts
import net.corda.core.KeepForDJVM
import net.corda.core.identity.Party
import net.corda.core.internal.requiredContractClassName
import net.corda.core.serialization.ConstructorForDeserialization
import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.loggerFor
@ -15,7 +16,10 @@ typealias ContractClassName = String
* This is the definitive state that is stored on the ledger and used in transaction outputs.
*/
@CordaSerializable
data class TransactionState<out T : ContractState> @JvmOverloads constructor(
data class TransactionState<out T : ContractState>
@ConstructorForDeserialization
constructor(
/** The custom contract state */
val data: T,
/**

View File

@ -3,6 +3,7 @@ package net.corda.core.contracts
import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM
import net.corda.core.internal.VisibleForTesting
import net.corda.core.serialization.ConstructorForDeserialization
import net.corda.core.serialization.CordaSerializable
import java.util.*
@ -20,7 +21,20 @@ import java.util.*
*/
@CordaSerializable
@KeepForDJVM
data class UniqueIdentifier @JvmOverloads @DeleteForDJVM constructor(val externalId: String? = null, val id: UUID = UUID.randomUUID()) : Comparable<UniqueIdentifier> {
data class UniqueIdentifier
@ConstructorForDeserialization
constructor(val externalId: String?, val id: UUID) : Comparable<UniqueIdentifier> {
@DeleteForDJVM
constructor(externalId: String? = null) : this(externalId, UUID.randomUUID())
@DeleteForDJVM
constructor(id: UUID = UUID.randomUUID()) : this(null, id)
@DeleteForDJVM
constructor() : this(null, UUID.randomUUID())
override fun toString(): String = if (externalId != null) "${externalId}_$id" else id.toString()
companion object {

View File

@ -4,6 +4,7 @@ import net.corda.core.contracts.ContractState
import net.corda.core.internal.PlatformVersionSwitches
import net.corda.core.internal.cordapp.targetPlatformVersion
import net.corda.core.internal.warnOnce
import net.corda.core.utilities.SgxSupport
import org.slf4j.LoggerFactory
import java.net.URL
import java.util.concurrent.ConcurrentHashMap
@ -26,6 +27,9 @@ object StateContractValidationEnforcementRule {
private val targetVersionCache = ConcurrentHashMap<URL, Int>()
fun shouldEnforce(state: ContractState): Boolean {
if(SgxSupport.isInsideEnclave) {
return true
}
val jarLocation = state::class.java.protectionDomain.codeSource.location
if (jarLocation == null) {

View File

@ -30,6 +30,7 @@ import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.serialization.internal.AttachmentURLStreamHandlerFactory.toUrl
import net.corda.core.serialization.withWhitelist
import net.corda.core.utilities.SgxSupport
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.debug
import java.io.IOException
@ -353,7 +354,11 @@ object AttachmentsClassLoaderBuilder {
val cache = attachmentsClassLoaderCache ?: fallBackCache
val serializationContext = cache.computeIfAbsent(AttachmentsClassLoaderKey(attachmentIds, params), Function { key ->
// Create classloader and load serializers, whitelisted classes
val transactionClassLoader = AttachmentsClassLoader(attachments, key.params, txId, isAttachmentTrusted, parent)
val transactionClassLoader = if(SgxSupport.isInsideEnclave) {
SerializationFactory.defaultFactory.defaultContext.deserializationClassLoader
} else {
AttachmentsClassLoader(attachments, key.params, txId, isAttachmentTrusted, parent)
}
val serializers = try {
createInstancesOfClassesImplementing(transactionClassLoader, SerializationCustomSerializer::class.java,
JDK1_2_CLASS_FILE_FORMAT_MAJOR_VERSION..JDK8_CLASS_FILE_FORMAT_MAJOR_VERSION)

View File

@ -222,6 +222,52 @@ private constructor(
// All states must also deserialize using the correct SerializationContext.
).also(LedgerTransaction::checkBaseInvariants)
}
/**
* This factory function will create an instance of [LedgerTransaction]
* that will be used for contract verification. See [BasicVerifier] and
* [DeterministicVerifier][net.corda.node.internal.djvm.DeterministicVerifier].
*/
@CordaInternal
fun createForConclaveVerify(
inputs: List<StateAndRef<ContractState>>,
outputs: List<TransactionState<ContractState>>,
commands: List<CommandWithParties<CommandData>>,
attachments: List<Attachment>,
id: SecureHash,
notary: Party?,
timeWindow: TimeWindow?,
privacySalt: PrivacySalt,
networkParameters: NetworkParameters?,
references: List<StateAndRef<ContractState>>,
componentGroups: List<ComponentGroup>?,
serializedInputs: List<SerializedStateAndRef>?,
serializedReferences: List<SerializedStateAndRef>?,
digestService: DigestService): LedgerTransaction {
return LedgerTransaction(
inputs = protect(inputs),
outputs = protect(outputs),
commands = protect(commands),
attachments = protect(attachments),
id = id,
notary = notary,
timeWindow = timeWindow,
privacySalt = privacySalt,
networkParameters = networkParameters,
references = protect(references),
componentGroups = componentGroups,
serializedInputs = serializedInputs,
serializedReferences = serializedReferences,
isAttachmentTrusted = { true },
verifierFactory = ::BasicVerifier,
attachmentsClassLoaderCache = null,
digestService = digestService
// This check accesses input states and must run on the LedgerTransaction
// instance that is verified, not on the outer LedgerTransaction shell.
// All states must also deserialize using the correct SerializationContext.
).also(LedgerTransaction::checkBaseInvariants)
}
}
val inputStates: List<ContractState> get() = inputs.map { it.state.data }

View File

@ -194,6 +194,7 @@ fun registerCustomSerializers(factory: SerializerFactory) {
register(net.corda.serialization.internal.amqp.custom.BitSetSerializer(this))
register(net.corda.serialization.internal.amqp.custom.EnumSetSerializer(this))
register(net.corda.serialization.internal.amqp.custom.ContractAttachmentSerializer(this))
register(net.corda.serialization.internal.amqp.custom.PairSerializer(this))
}
registerNonDeterministicSerializers(factory)
}

View File

@ -0,0 +1,21 @@
package net.corda.serialization.internal.amqp.custom
import net.corda.core.KeepForDJVM
import net.corda.serialization.internal.amqp.CustomSerializer
import net.corda.serialization.internal.amqp.SerializerFactory
class PairSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<Pair<*, *>, PairSerializer.PairProxy>(
Pair::class.java,
PairProxy::class.java,
factory
) {
override fun toProxy(obj: Pair<*, *>): PairProxy = PairProxy(obj.first, obj.second)
override fun fromProxy(proxy: PairProxy): Pair<*, *> = Pair(proxy.first, proxy.second)
@KeepForDJVM
data class PairProxy(val first: Any?, val second: Any?)
}