Moved AttachmentsClassLoader out of core (#1504)

This commit is contained in:
Shams Asari 2017-09-14 15:40:39 +01:00 committed by josecoll
parent 094187cfa1
commit 943e873ff0
6 changed files with 53 additions and 34 deletions

View File

@ -1,7 +1,8 @@
package net.corda.core.serialization
package net.corda.nodeapi.internal
import net.corda.core.contracts.Attachment
import net.corda.core.crypto.SecureHash
import net.corda.core.serialization.CordaSerializable
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.FileNotFoundException

View File

@ -6,7 +6,7 @@ import com.esotericsoftware.kryo.io.Output
import com.esotericsoftware.kryo.serializers.FieldSerializer
import com.esotericsoftware.kryo.util.DefaultClassResolver
import com.esotericsoftware.kryo.util.Util
import net.corda.core.serialization.AttachmentsClassLoader
import net.corda.nodeapi.internal.AttachmentsClassLoader
import net.corda.core.serialization.ClassWhitelist
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializationContext

View File

@ -13,7 +13,7 @@ import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.TransactionSignature
import net.corda.core.identity.Party
import net.corda.core.serialization.AttachmentsClassLoader
import net.corda.nodeapi.internal.AttachmentsClassLoader
import net.corda.core.serialization.MissingAttachmentsException
import net.corda.core.serialization.SerializeAsTokenContext
import net.corda.core.serialization.SerializedBytes

View File

@ -16,6 +16,7 @@ import net.corda.core.internal.LazyPool
import net.corda.core.serialization.*
import net.corda.core.utilities.ByteSequence
import net.corda.core.utilities.OpaqueBytes
import net.corda.nodeapi.internal.AttachmentsClassLoader
import java.io.ByteArrayOutputStream
import java.io.NotSerializableException
import java.util.*

View File

@ -14,6 +14,7 @@ import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.ByteSequence
import net.corda.core.utilities.OpaqueBytes
import net.corda.nodeapi.internal.AttachmentsClassLoader
import net.corda.nodeapi.internal.serialization.SerializeAsTokenContextImpl
import net.corda.nodeapi.internal.serialization.attachmentsClassLoaderEnabledPropertyName
import net.corda.nodeapi.internal.serialization.withTokenContext
@ -41,11 +42,11 @@ interface DummyContractBackdoor {
fun inspectState(state: ContractState): Int
}
class AttachmentClassLoaderTests : TestDependencyInjectionBase() {
class AttachmentsClassLoaderTests : TestDependencyInjectionBase() {
companion object {
val ISOLATED_CONTRACTS_JAR_PATH: URL = AttachmentClassLoaderTests::class.java.getResource("isolated.jar")
val ISOLATED_CONTRACTS_JAR_PATH: URL = AttachmentsClassLoaderTests::class.java.getResource("isolated.jar")
private val ISOLATED_CONTRACT_CLASS_NAME = "net.corda.finance.contracts.isolated.AnotherDummyContract"
private val ATTACHMENT_PROGRAM_ID = "net.corda.nodeapi.AttachmentClassLoaderTests.AttachmentDummyContract"
private val ATTACHMENT_PROGRAM_ID = "net.corda.nodeapi.AttachmentsClassLoaderTests.AttachmentDummyContract"
private fun SerializationContext.withAttachmentStorage(attachmentStorage: AttachmentStorage): SerializationContext {
val serviceHub = mock<ServiceHub>()
@ -195,7 +196,7 @@ class AttachmentClassLoaderTests : TestDependencyInjectionBase() {
@Test
fun `verify that contract DummyContract is in classPath`() {
val contractClass = Class.forName("net.corda.nodeapi.AttachmentClassLoaderTests\$AttachmentDummyContract")
val contractClass = Class.forName("net.corda.nodeapi.AttachmentsClassLoaderTests\$AttachmentDummyContract")
val contract = contractClass.newInstance() as Contract
assertNotNull(contract)
@ -332,34 +333,36 @@ class AttachmentClassLoaderTests : TestDependencyInjectionBase() {
}
@Test
fun `test deserialize of WireTransaction where contract cannot be found`() = kryoSpecific<AttachmentClassLoaderTests>("Kryo verifies/loads attachments on deserialization, whereas AMQP currently does not") {
val child = ClassLoaderForTests()
val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, child)
val contract = contractClass.newInstance() as DummyContractBackdoor
val tx = contract.generateInitial(MEGA_CORP.ref(0), 42, DUMMY_NOTARY)
val storage = MockAttachmentStorage()
fun `test deserialize of WireTransaction where contract cannot be found`() {
kryoSpecific<AttachmentsClassLoaderTests>("Kryo verifies/loads attachments on deserialization, whereas AMQP currently does not") {
val child = ClassLoaderForTests()
val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, child)
val contract = contractClass.newInstance() as DummyContractBackdoor
val tx = contract.generateInitial(MEGA_CORP.ref(0), 42, DUMMY_NOTARY)
val storage = MockAttachmentStorage()
// todo - think about better way to push attachmentStorage down to serializer
val attachmentRef = importJar(storage)
val bytes = run {
// todo - think about better way to push attachmentStorage down to serializer
val attachmentRef = importJar(storage)
val bytes = run {
tx.addAttachment(storage.openAttachment(attachmentRef)!!.id)
tx.addAttachment(storage.openAttachment(attachmentRef)!!.id)
val wireTransaction = tx.toWireTransaction()
val wireTransaction = tx.toWireTransaction()
wireTransaction.serialize(context = SerializationFactory.defaultFactory.defaultContext.withAttachmentStorage(storage))
}
// use empty attachmentStorage
val e = assertFailsWith(MissingAttachmentsException::class) {
val mockAttStorage = MockAttachmentStorage()
bytes.deserialize(context = SerializationFactory.defaultFactory.defaultContext.withAttachmentStorage(mockAttStorage))
if(mockAttStorage.openAttachment(attachmentRef) == null) {
throw MissingAttachmentsException(listOf(attachmentRef))
wireTransaction.serialize(context = SerializationFactory.defaultFactory.defaultContext.withAttachmentStorage(storage))
}
// use empty attachmentStorage
val e = assertFailsWith(MissingAttachmentsException::class) {
val mockAttStorage = MockAttachmentStorage()
bytes.deserialize(context = SerializationFactory.defaultFactory.defaultContext.withAttachmentStorage(mockAttStorage))
if(mockAttStorage.openAttachment(attachmentRef) == null) {
throw MissingAttachmentsException(listOf(attachmentRef))
}
}
assertEquals(attachmentRef, e.ids.single())
}
assertEquals(attachmentRef, e.ids.single())
}
@Test
@ -371,7 +374,12 @@ class AttachmentClassLoaderTests : TestDependencyInjectionBase() {
val attachmentRef = importJar(storage)
val outboundContext = SerializationFactory.defaultFactory.defaultContext.withClassLoader(child)
// We currently ignore annotations in attachments, so manually whitelist.
val inboundContext = SerializationFactory.defaultFactory.defaultContext.withWhitelisted(contract.javaClass).withAttachmentStorage(storage).withAttachmentsClassLoader(listOf(attachmentRef))
val inboundContext = SerializationFactory
.defaultFactory
.defaultContext
.withWhitelisted(contract.javaClass)
.withAttachmentStorage(storage)
.withAttachmentsClassLoader(listOf(attachmentRef))
// Serialize with custom context to avoid populating the default context with the specially loaded class
val serialized = contract.serialize(context = outboundContext)
@ -393,7 +401,12 @@ class AttachmentClassLoaderTests : TestDependencyInjectionBase() {
// Then deserialize with the attachment class loader associated with the attachment
val e = assertFailsWith(MissingAttachmentsException::class) {
// We currently ignore annotations in attachments, so manually whitelist.
val inboundContext = SerializationFactory.defaultFactory.defaultContext.withWhitelisted(contract.javaClass).withAttachmentStorage(storage).withAttachmentsClassLoader(listOf(attachmentRef))
val inboundContext = SerializationFactory
.defaultFactory
.defaultContext
.withWhitelisted(contract.javaClass)
.withAttachmentStorage(storage)
.withAttachmentsClassLoader(listOf(attachmentRef))
serialized.deserialize(context = inboundContext)
}
assertEquals(attachmentRef, e.ids.single())

View File

@ -5,9 +5,13 @@ import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output
import com.esotericsoftware.kryo.util.MapReferenceResolver
import net.corda.core.node.services.AttachmentStorage
import net.corda.core.serialization.*
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationFactory
import net.corda.core.serialization.SerializedBytes
import net.corda.core.utilities.ByteSequence
import net.corda.nodeapi.AttachmentClassLoaderTests
import net.corda.nodeapi.AttachmentsClassLoaderTests
import net.corda.nodeapi.internal.AttachmentsClassLoader
import net.corda.testing.node.MockAttachmentStorage
import org.junit.Rule
import org.junit.Test
@ -156,7 +160,7 @@ class CordaClassResolverTests {
CordaClassResolver(emptyWhitelistContext).getRegistration(DefaultSerializable::class.java)
}
private fun importJar(storage: AttachmentStorage) = AttachmentClassLoaderTests.ISOLATED_CONTRACTS_JAR_PATH.openStream().use { storage.importAttachment(it) }
private fun importJar(storage: AttachmentStorage) = AttachmentsClassLoaderTests.ISOLATED_CONTRACTS_JAR_PATH.openStream().use { storage.importAttachment(it) }
@Test(expected = KryoException::class)
fun `Annotation does not work in conjunction with AttachmentClassLoader annotation`() {