CORDA-1511: Kryo only used for node checkpoints and so moved out of serialization module and into node (#3228)

This commit is contained in:
Shams Asari
2018-05-24 12:18:07 +01:00
committed by GitHub
parent 76918de656
commit 3136e973a7
37 changed files with 150 additions and 153 deletions

5
.idea/compiler.xml generated
View File

@ -40,6 +40,9 @@
<module name="corda-test-common_test" target="1.8" /> <module name="corda-test-common_test" target="1.8" />
<module name="corda-test-utils_main" target="1.8" /> <module name="corda-test-utils_main" target="1.8" />
<module name="corda-test-utils_test" target="1.8" /> <module name="corda-test-utils_test" target="1.8" />
<module name="corda-utils_integrationTest" target="1.8" />
<module name="corda-utils_main" target="1.8" />
<module name="corda-utils_test" target="1.8" />
<module name="corda-webserver_integrationTest" target="1.8" /> <module name="corda-webserver_integrationTest" target="1.8" />
<module name="corda-webserver_main" target="1.8" /> <module name="corda-webserver_main" target="1.8" />
<module name="corda-webserver_test" target="1.8" /> <module name="corda-webserver_test" target="1.8" />
@ -68,6 +71,8 @@
<module name="example-code_integrationTest" target="1.8" /> <module name="example-code_integrationTest" target="1.8" />
<module name="example-code_main" target="1.8" /> <module name="example-code_main" target="1.8" />
<module name="example-code_test" target="1.8" /> <module name="example-code_test" target="1.8" />
<module name="experimental-blobinspector_main" target="1.8" />
<module name="experimental-blobinspector_test" target="1.8" />
<module name="experimental-kryo-hook_main" target="1.8" /> <module name="experimental-kryo-hook_main" target="1.8" />
<module name="experimental-kryo-hook_test" target="1.8" /> <module name="experimental-kryo-hook_test" target="1.8" />
<module name="experimental_main" target="1.8" /> <module name="experimental_main" target="1.8" />

View File

@ -3,9 +3,9 @@ package net.corda.core.utilities
import com.esotericsoftware.kryo.KryoException import com.esotericsoftware.kryo.KryoException
import net.corda.core.crypto.random63BitValue import net.corda.core.crypto.random63BitValue
import net.corda.core.serialization.* import net.corda.core.serialization.*
import net.corda.serialization.internal.KRYO_CHECKPOINT_CONTEXT import net.corda.node.serialization.kryo.KRYO_CHECKPOINT_CONTEXT
import net.corda.node.serialization.kryo.kryoMagic
import net.corda.serialization.internal.SerializationContextImpl import net.corda.serialization.internal.SerializationContextImpl
import net.corda.serialization.internal.kryo.kryoMagic
import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.SerializationEnvironmentRule
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule import org.junit.Rule

View File

@ -5,7 +5,11 @@ import net.corda.core.serialization.EncodingWhitelist
import net.corda.core.serialization.SerializationEncoding import net.corda.core.serialization.SerializationEncoding
import net.corda.core.utilities.ByteSequence import net.corda.core.utilities.ByteSequence
import net.corda.serialization.internal.SerializationFactoryImpl import net.corda.serialization.internal.SerializationFactoryImpl
import net.corda.serialization.internal.amqp.* import net.corda.serialization.internal.amqp.CompositeType
import net.corda.serialization.internal.amqp.DeserializationInput
import net.corda.serialization.internal.amqp.RestrictedType
import net.corda.serialization.internal.amqp.TypeNotation
import net.corda.serialization.internal.amqp.amqpMagic
import org.apache.qpid.proton.amqp.Binary import org.apache.qpid.proton.amqp.Binary
import org.apache.qpid.proton.amqp.DescribedType import org.apache.qpid.proton.amqp.DescribedType
import org.apache.qpid.proton.amqp.Symbol import org.apache.qpid.proton.amqp.Symbol

View File

@ -27,19 +27,16 @@ import net.corda.serialization.internal.CordaSerializationMagic
import net.corda.serialization.internal.SerializationFactoryImpl import net.corda.serialization.internal.SerializationFactoryImpl
import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme
import net.corda.serialization.internal.amqp.amqpMagic import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.kryo.AbstractKryoSerializationScheme
import net.corda.serialization.internal.kryo.kryoMagic
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
import java.nio.file.StandardCopyOption.REPLACE_EXISTING import java.nio.file.StandardCopyOption.REPLACE_EXISTING
import java.time.Instant import java.time.Instant
import java.util.concurrent.Executors import java.util.concurrent.Executors
import java.util.concurrent.TimeoutException import java.util.concurrent.TimeoutException
import kotlin.streams.toList
import kotlin.collections.HashSet
import kotlin.collections.component1 import kotlin.collections.component1
import kotlin.collections.component2 import kotlin.collections.component2
import kotlin.collections.set import kotlin.collections.set
import kotlin.streams.toList
/** /**
* Class to bootstrap a local network of Corda nodes on the same filesystem. * Class to bootstrap a local network of Corda nodes on the same filesystem.
@ -338,22 +335,12 @@ class NetworkBootstrapper {
private fun initialiseSerialization() { private fun initialiseSerialization() {
_contextSerializationEnv.set(SerializationEnvironmentImpl( _contextSerializationEnv.set(SerializationEnvironmentImpl(
SerializationFactoryImpl().apply { SerializationFactoryImpl().apply {
registerScheme(KryoParametersSerializationScheme)
registerScheme(AMQPParametersSerializationScheme) registerScheme(AMQPParametersSerializationScheme)
}, },
AMQP_P2P_CONTEXT) AMQP_P2P_CONTEXT)
) )
} }
private object KryoParametersSerializationScheme : AbstractKryoSerializationScheme() {
override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean {
return magic == kryoMagic && target == SerializationContext.UseCase.P2P
}
override fun rpcClientKryoPool(context: SerializationContext) = throw UnsupportedOperationException()
override fun rpcServerKryoPool(context: SerializationContext) = throw UnsupportedOperationException()
}
private object AMQPParametersSerializationScheme : AbstractAMQPSerializationScheme(emptyList()) { private object AMQPParametersSerializationScheme : AbstractAMQPSerializationScheme(emptyList()) {
override fun rpcClientSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException() override fun rpcClientSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException()
override fun rpcServerSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException() override fun rpcServerSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException()

View File

@ -11,10 +11,10 @@ import net.corda.core.serialization.serialize
import net.corda.node.serialization.amqp.AMQPServerSerializationScheme import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
import net.corda.nodeapi.internal.config.SSLConfiguration import net.corda.nodeapi.internal.config.SSLConfiguration
import net.corda.nodeapi.internal.createDevKeyStores import net.corda.nodeapi.internal.createDevKeyStores
import net.corda.serialization.internal.AllWhitelist
import net.corda.serialization.internal.SerializationContextImpl import net.corda.serialization.internal.SerializationContextImpl
import net.corda.serialization.internal.SerializationFactoryImpl import net.corda.serialization.internal.SerializationFactoryImpl
import net.corda.serialization.internal.amqp.amqpMagic import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.AllWhitelist
import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.TestIdentity import net.corda.testing.core.TestIdentity
@ -352,13 +352,15 @@ class X509UtilitiesTest {
@Test @Test
fun `serialize - deserialize X509CertPath`() { fun `serialize - deserialize X509CertPath`() {
val factory = SerializationFactoryImpl().apply { registerScheme(AMQPServerSerializationScheme()) } val factory = SerializationFactoryImpl().apply { registerScheme(AMQPServerSerializationScheme()) }
val context = SerializationContextImpl(amqpMagic, val context = SerializationContextImpl(
amqpMagic,
javaClass.classLoader, javaClass.classLoader,
AllWhitelist, AllWhitelist,
emptyMap(), emptyMap(),
true, true,
SerializationContext.UseCase.P2P, SerializationContext.UseCase.P2P,
null) null
)
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val rootCACert = X509Utilities.createSelfSignedCACertificate(ALICE_NAME.x500Principal, rootCAKey) val rootCACert = X509Utilities.createSelfSignedCACertificate(ALICE_NAME.x500Principal, rootCAKey)
val certificate = X509Utilities.createCertificate(CertificateType.TLS, rootCACert, rootCAKey, BOB_NAME.x500Principal, BOB.publicKey) val certificate = X509Utilities.createCertificate(CertificateType.TLS, rootCACert, rootCAKey, BOB_NAME.x500Principal, BOB.publicKey)

View File

@ -71,6 +71,10 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
// Kryo: object graph serialization.
compile "com.esotericsoftware:kryo:4.0.0"
compile "de.javakaffee:kryo-serializers:0.41"
compile "com.google.guava:guava:$guava_version" compile "com.google.guava:guava:$guava_version"
// For caches rather than guava // For caches rather than guava

View File

@ -28,6 +28,7 @@ import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.internal.security.RPCSecurityManagerImpl import net.corda.node.internal.security.RPCSecurityManagerImpl
import net.corda.node.internal.security.RPCSecurityManagerWithAdditionalUser import net.corda.node.internal.security.RPCSecurityManagerWithAdditionalUser
import net.corda.node.serialization.amqp.AMQPServerSerializationScheme import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
import net.corda.node.serialization.kryo.KRYO_CHECKPOINT_CONTEXT
import net.corda.node.serialization.kryo.KryoServerSerializationScheme import net.corda.node.serialization.kryo.KryoServerSerializationScheme
import net.corda.node.services.Permissions import net.corda.node.services.Permissions
import net.corda.node.services.api.NodePropertiesStore import net.corda.node.services.api.NodePropertiesStore

View File

@ -1,4 +1,4 @@
package net.corda.serialization.internal.kryo package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.* import com.esotericsoftware.kryo.*
import com.esotericsoftware.kryo.io.Input import com.esotericsoftware.kryo.io.Input
@ -13,6 +13,7 @@ import net.corda.core.serialization.SerializationContext
import net.corda.core.utilities.contextLogger import net.corda.core.utilities.contextLogger
import net.corda.serialization.internal.AttachmentsClassLoader import net.corda.serialization.internal.AttachmentsClassLoader
import net.corda.serialization.internal.MutableClassWhitelist import net.corda.serialization.internal.MutableClassWhitelist
import net.corda.serialization.internal.TransientClassWhiteList
import net.corda.serialization.internal.amqp.hasAnnotationInHierarchy import net.corda.serialization.internal.amqp.hasAnnotationInHierarchy
import java.io.PrintWriter import java.io.PrintWriter
import java.lang.reflect.Modifier import java.lang.reflect.Modifier
@ -146,43 +147,6 @@ class CordaClassResolver(serializationContext: SerializationContext) : DefaultCl
} }
} }
class BuiltInExceptionsWhitelist : ClassWhitelist {
companion object {
private val packageName = "^(?:java|kotlin)(?:[.]|$)".toRegex()
}
override fun hasListed(type: Class<*>) = Throwable::class.java.isAssignableFrom(type) && packageName.containsMatchIn(type.`package`.name)
}
sealed class AbstractMutableClassWhitelist(private val whitelist: MutableSet<String>, private val delegate: ClassWhitelist) : MutableClassWhitelist {
override fun hasListed(type: Class<*>): Boolean {
/**
* There are certain delegates like [net.corda.serialization.internal.AllButBlacklisted]
* which may throw when asked whether the type is listed.
* In such situations - it may be a good idea to ask [delegate] first before making a check against own [whitelist].
*/
return delegate.hasListed(type) || (type.name in whitelist)
}
override fun add(entry: Class<*>) {
whitelist += entry.name
}
}
// TODO: Need some concept of from which class loader
class GlobalTransientClassWhiteList(delegate: ClassWhitelist) : AbstractMutableClassWhitelist(whitelist, delegate) {
companion object {
private val whitelist: MutableSet<String> = Collections.synchronizedSet(mutableSetOf())
}
}
/**
* A whitelist that can be customised via the [net.corda.core.serialization.SerializationWhitelist],
* since it implements [MutableClassWhitelist].
*/
class TransientClassWhiteList(delegate: ClassWhitelist) : AbstractMutableClassWhitelist(Collections.synchronizedSet(mutableSetOf()), delegate)
/** /**
* This class is not currently used, but can be installed to log a large number of missing entries from the whitelist * This class is not currently used, but can be installed to log a large number of missing entries from the whitelist
* and was used to track down the initial set. * and was used to track down the initial set.

View File

@ -1,4 +1,4 @@
package net.corda.serialization.internal.kryo package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.Kryo import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.io.Output import com.esotericsoftware.kryo.io.Output

View File

@ -1,4 +1,4 @@
package net.corda.serialization.internal.kryo package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.Kryo import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.Serializer import com.esotericsoftware.kryo.Serializer

View File

@ -1,4 +1,4 @@
package net.corda.serialization.internal.kryo package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.* import com.esotericsoftware.kryo.*
import com.esotericsoftware.kryo.factories.ReflectionSerializerFactory import com.esotericsoftware.kryo.factories.ReflectionSerializerFactory

View File

@ -1,4 +1,4 @@
package net.corda.serialization.internal.kryo package net.corda.node.serialization.kryo
import co.paralleluniverse.fibers.Fiber import co.paralleluniverse.fibers.Fiber
import co.paralleluniverse.io.serialization.kryo.KryoSerializer import co.paralleluniverse.io.serialization.kryo.KryoSerializer
@ -12,10 +12,10 @@ import com.esotericsoftware.kryo.serializers.ClosureSerializer
import net.corda.core.internal.uncheckedCast import net.corda.core.internal.uncheckedCast
import net.corda.core.serialization.ClassWhitelist import net.corda.core.serialization.ClassWhitelist
import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationDefaults
import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.SerializedBytes
import net.corda.core.utilities.ByteSequence import net.corda.core.utilities.ByteSequence
import net.corda.serialization.internal.* import net.corda.serialization.internal.*
import net.corda.serialization.internal.SectionId
import java.security.PublicKey import java.security.PublicKey
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@ -130,3 +130,14 @@ abstract class AbstractKryoSerializationScheme : SerializationScheme {
} }
} }
} }
val KRYO_CHECKPOINT_CONTEXT = SerializationContextImpl(
kryoMagic,
SerializationDefaults.javaClass.classLoader,
QuasarWhitelist,
emptyMap(),
true,
SerializationContext.UseCase.Checkpoint,
null,
AlwaysAcceptEncodingWhitelist
)

View File

@ -3,8 +3,6 @@ package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.pool.KryoPool import com.esotericsoftware.kryo.pool.KryoPool
import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationContext
import net.corda.serialization.internal.CordaSerializationMagic import net.corda.serialization.internal.CordaSerializationMagic
import net.corda.serialization.internal.kryo.AbstractKryoSerializationScheme
import net.corda.serialization.internal.kryo.kryoMagic
class KryoServerSerializationScheme : AbstractKryoSerializationScheme() { class KryoServerSerializationScheme : AbstractKryoSerializationScheme() {
override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean { override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean {
@ -12,7 +10,5 @@ class KryoServerSerializationScheme : AbstractKryoSerializationScheme() {
} }
override fun rpcClientKryoPool(context: SerializationContext): KryoPool = throw UnsupportedOperationException() override fun rpcClientKryoPool(context: SerializationContext): KryoPool = throw UnsupportedOperationException()
override fun rpcServerKryoPool(context: SerializationContext): KryoPool = throw UnsupportedOperationException() override fun rpcServerKryoPool(context: SerializationContext): KryoPool = throw UnsupportedOperationException()
}
}

View File

@ -1,6 +1,6 @@
@file:JvmName("KryoStreams") @file:JvmName("KryoStreams")
package net.corda.serialization.internal.kryo package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.io.Input import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output import com.esotericsoftware.kryo.io.Output

View File

@ -1,4 +1,4 @@
package net.corda.serialization.internal.kryo package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.Kryo import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.KryoException import com.esotericsoftware.kryo.KryoException

View File

@ -1,9 +1,9 @@
package net.corda.node.internal.serialization.testutils package net.corda.node.internal.serialization.testutils
import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationContext
import net.corda.serialization.internal.AllWhitelist
import net.corda.serialization.internal.SerializationContextImpl import net.corda.serialization.internal.SerializationContextImpl
import net.corda.serialization.internal.amqp.amqpMagic import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.AllWhitelist
val serializationProperties: MutableMap<Any, Any> = mutableMapOf() val serializationProperties: MutableMap<Any, Any> = mutableMapOf()
@ -14,4 +14,5 @@ val serializationContext = SerializationContextImpl(
properties = serializationProperties, properties = serializationProperties,
objectReferencesEnabled = false, objectReferencesEnabled = false,
useCase = SerializationContext.UseCase.Testing, useCase = SerializationContext.UseCase.Testing,
encoding = null) encoding = null
)

View File

@ -1,4 +1,4 @@
package net.corda.serialization.internal.kryo package net.corda.node.serialization.kryo
import net.corda.core.internal.declaredField import net.corda.core.internal.declaredField
import net.corda.serialization.internal.ByteBufferOutputStream import net.corda.serialization.internal.ByteBufferOutputStream
@ -28,7 +28,7 @@ class KryoStreamsTest {
fun `substitute output works`() { fun `substitute output works`() {
assertArrayEquals(byteArrayOf(100, -101), kryoOutput { assertArrayEquals(byteArrayOf(100, -101), kryoOutput {
write(100) write(100)
substitute(::NegOutputStream) substitute(KryoStreamsTest::NegOutputStream)
write(101) write(101)
}) })
} }
@ -37,7 +37,7 @@ class KryoStreamsTest {
fun `substitute input works`() { fun `substitute input works`() {
kryoInput(byteArrayOf(100, 101).inputStream()) { kryoInput(byteArrayOf(100, 101).inputStream()) {
assertEquals(100, read()) assertEquals(100, read())
substitute(::NegInputStream) substitute(KryoStreamsTest::NegInputStream)
assertEquals(-101, read().toByte()) assertEquals(-101, read().toByte())
assertEquals(-1, read()) assertEquals(-1, read())
} }

View File

@ -1,4 +1,4 @@
package net.corda.serialization.internal.kryo package net.corda.node.serialization.kryo
import com.esotericsoftware.kryo.Kryo import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.KryoException import com.esotericsoftware.kryo.KryoException
@ -33,6 +33,7 @@ import org.slf4j.LoggerFactory
import java.io.InputStream import java.io.InputStream
import java.time.Instant import java.time.Instant
import java.util.* import java.util.*
import kotlin.collections.ArrayList
import kotlin.test.* import kotlin.test.*
class TestScheme : AbstractKryoSerializationScheme() { class TestScheme : AbstractKryoSerializationScheme() {
@ -93,7 +94,7 @@ class KryoTests(private val compression: CordaSerializationEncoding?) {
fun `serialised form is stable when the same object instance is added to the deserialised object graph`() { fun `serialised form is stable when the same object instance is added to the deserialised object graph`() {
val noReferencesContext = context.withoutReferences() val noReferencesContext = context.withoutReferences()
val obj : ByteSequence = Ints.toByteArray(0x01234567).sequence() val obj : ByteSequence = Ints.toByteArray(0x01234567).sequence()
val originalList : ArrayList<ByteSequence> = arrayListOf(obj) val originalList : ArrayList<ByteSequence> = ArrayList<ByteSequence>().apply { this += obj }
val deserialisedList = originalList.serialize(factory, noReferencesContext).deserialize(factory, noReferencesContext) val deserialisedList = originalList.serialize(factory, noReferencesContext).deserialize(factory, noReferencesContext)
originalList += obj originalList += obj
deserialisedList += obj deserialisedList += obj
@ -106,8 +107,14 @@ class KryoTests(private val compression: CordaSerializationEncoding?) {
val instant = Instant.ofEpochMilli(123) val instant = Instant.ofEpochMilli(123)
val instantCopy = Instant.ofEpochMilli(123) val instantCopy = Instant.ofEpochMilli(123)
assertThat(instant).isNotSameAs(instantCopy) assertThat(instant).isNotSameAs(instantCopy)
val listWithCopies = arrayListOf(instant, instantCopy) val listWithCopies = ArrayList<Instant>().apply {
val listWithSameInstances = arrayListOf(instant, instant) this += instant
this += instantCopy
}
val listWithSameInstances = ArrayList<Instant>().apply {
this += instant
this += instant
}
assertThat(listWithSameInstances.serialize(factory, noReferencesContext)).isEqualTo(listWithCopies.serialize(factory, noReferencesContext)) assertThat(listWithSameInstances.serialize(factory, noReferencesContext)).isEqualTo(listWithCopies.serialize(factory, noReferencesContext))
} }

View File

@ -12,9 +12,6 @@ dependencies {
compile "org.apache.activemq:artemis-commons:${artemis_version}" compile "org.apache.activemq:artemis-commons:${artemis_version}"
// Kryo: object graph serialization.
compile "com.esotericsoftware:kryo:4.0.0"
compile "de.javakaffee:kryo-serializers:0.41"
compile "org.ow2.asm:asm:$asm_version" compile "org.ow2.asm:asm:$asm_version"
// For AMQP serialisation. // For AMQP serialisation.

View File

@ -15,7 +15,7 @@ internal val serializeOutputStreamPool = LazyPool(
shouldReturnToPool = { it.size() < 256 * 1024 }, // Discard if it grew too large shouldReturnToPool = { it.size() < 256 * 1024 }, // Discard if it grew too large
newInstance = { ByteBufferOutputStream(64 * 1024) }) newInstance = { ByteBufferOutputStream(64 * 1024) })
internal fun <T> byteArrayOutput(task: (ByteBufferOutputStream) -> T): ByteArray { fun <T> byteArrayOutput(task: (ByteBufferOutputStream) -> T): ByteArray {
return serializeOutputStreamPool.run { underlying -> return serializeOutputStreamPool.run { underlying ->
task(underlying) task(underlying)
underlying.toByteArray() // Must happen after close, to allow ZIP footer to be written for example. underlying.toByteArray() // Must happen after close, to allow ZIP footer to be written for example.

View File

@ -1,6 +1,7 @@
package net.corda.serialization.internal package net.corda.serialization.internal
import net.corda.core.serialization.ClassWhitelist import net.corda.core.serialization.ClassWhitelist
import java.util.*
interface MutableClassWhitelist : ClassWhitelist { interface MutableClassWhitelist : ClassWhitelist {
fun add(entry: Class<*>) fun add(entry: Class<*>)
@ -9,3 +10,41 @@ interface MutableClassWhitelist : ClassWhitelist {
object AllWhitelist : ClassWhitelist { object AllWhitelist : ClassWhitelist {
override fun hasListed(type: Class<*>): Boolean = true override fun hasListed(type: Class<*>): Boolean = true
} }
class BuiltInExceptionsWhitelist : ClassWhitelist {
companion object {
private val packageName = "^(?:java|kotlin)(?:[.]|$)".toRegex()
}
override fun hasListed(type: Class<*>): Boolean {
return Throwable::class.java.isAssignableFrom(type) && packageName.containsMatchIn(type.`package`.name)
}
}
sealed class AbstractMutableClassWhitelist(private val whitelist: MutableSet<String>, private val delegate: ClassWhitelist) : MutableClassWhitelist {
override fun hasListed(type: Class<*>): Boolean {
/**
* There are certain delegates like [net.corda.serialization.internal.AllButBlacklisted]
* which may throw when asked whether the type is listed.
* In such situations - it may be a good idea to ask [delegate] first before making a check against own [whitelist].
*/
return delegate.hasListed(type) || (type.name in whitelist)
}
override fun add(entry: Class<*>) {
whitelist += entry.name
}
}
/**
* A whitelist that can be customised via the [net.corda.core.serialization.SerializationWhitelist],
* since it implements [MutableClassWhitelist].
*/
class TransientClassWhiteList(delegate: ClassWhitelist) : AbstractMutableClassWhitelist(Collections.synchronizedSet(mutableSetOf()), delegate)
// TODO: Need some concept of from which class loader
class GlobalTransientClassWhiteList(delegate: ClassWhitelist) : AbstractMutableClassWhitelist(whitelist, delegate) {
companion object {
private val whitelist: MutableSet<String> = Collections.synchronizedSet(mutableSetOf())
}
}

View File

@ -5,9 +5,6 @@ package net.corda.serialization.internal
import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationDefaults import net.corda.core.serialization.SerializationDefaults
import net.corda.serialization.internal.amqp.amqpMagic import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.kryo.BuiltInExceptionsWhitelist
import net.corda.serialization.internal.kryo.GlobalTransientClassWhiteList
import net.corda.serialization.internal.kryo.kryoMagic
/* /*
* Serialisation contexts for the client. * Serialisation contexts for the client.
@ -16,10 +13,12 @@ import net.corda.serialization.internal.kryo.kryoMagic
*/ */
val AMQP_RPC_CLIENT_CONTEXT = SerializationContextImpl(amqpMagic, val AMQP_RPC_CLIENT_CONTEXT = SerializationContextImpl(
amqpMagic,
SerializationDefaults.javaClass.classLoader, SerializationDefaults.javaClass.classLoader,
GlobalTransientClassWhiteList(BuiltInExceptionsWhitelist()), GlobalTransientClassWhiteList(BuiltInExceptionsWhitelist()),
emptyMap(), emptyMap(),
true, true,
SerializationContext.UseCase.RPCClient, SerializationContext.UseCase.RPCClient,
null) null
)

View File

@ -1,6 +1,5 @@
package net.corda.serialization.internal package net.corda.serialization.internal
import com.esotericsoftware.kryo.KryoException
import net.corda.core.serialization.SerializationWhitelist import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.SimpleString
@ -30,7 +29,6 @@ object DefaultWhitelist : SerializationWhitelist {
mapOf(Unit to Unit).javaClass, // SingletonMap mapOf(Unit to Unit).javaClass, // SingletonMap
NetworkHostAndPort::class.java, NetworkHostAndPort::class.java,
SimpleString::class.java, SimpleString::class.java,
KryoException::class.java, // TODO: Will be removed when we migrate away from Kryo
StringBuffer::class.java, StringBuffer::class.java,
Unit::class.java, Unit::class.java,
java.io.ByteArrayInputStream::class.java, java.io.ByteArrayInputStream::class.java,

View File

@ -1,6 +1,5 @@
package net.corda.serialization.internal package net.corda.serialization.internal
import net.corda.core.internal.VisibleForTesting
import net.corda.core.serialization.SerializationEncoding import net.corda.core.serialization.SerializationEncoding
import net.corda.core.utilities.ByteSequence import net.corda.core.utilities.ByteSequence
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
@ -54,5 +53,4 @@ enum class CordaSerializationEncoding : SerializationEncoding, OrdinalWriter {
abstract fun wrap(stream: InputStream): InputStream abstract fun wrap(stream: InputStream): InputStream
} }
@VisibleForTesting const val encodingNotPermittedFormat = "Encoding not permitted: %s"
internal val encodingNotPermittedFormat = "Encoding not permitted: %s"

View File

@ -8,7 +8,6 @@ import net.corda.core.internal.copyBytes
import net.corda.core.serialization.* import net.corda.core.serialization.*
import net.corda.core.utilities.ByteSequence import net.corda.core.utilities.ByteSequence
import net.corda.serialization.internal.amqp.amqpMagic import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.kryo.kryoMagic
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.NotSerializableException import java.io.NotSerializableException
import java.util.* import java.util.*
@ -98,7 +97,7 @@ open class SerializationFactoryImpl(
constructor() : this(ConcurrentHashMap()) constructor() : this(ConcurrentHashMap())
companion object { companion object {
val magicSize = sequenceOf(kryoMagic, amqpMagic).map { it.size }.distinct().single() val magicSize = amqpMagic.size
} }
private val creator: List<StackTraceElement> = Exception().stackTrace.asList() private val creator: List<StackTraceElement> = Exception().stackTrace.asList()
@ -114,7 +113,7 @@ open class SerializationFactoryImpl(
return schemes.computeIfAbsent(lookupKey) { return schemes.computeIfAbsent(lookupKey) {
registeredSchemes.filter { it.canDeserializeVersion(magic, target) }.forEach { return@computeIfAbsent it } // XXX: Not single? registeredSchemes.filter { it.canDeserializeVersion(magic, target) }.forEach { return@computeIfAbsent it } // XXX: Not single?
logger.warn("Cannot find serialization scheme for: [$lookupKey, " + logger.warn("Cannot find serialization scheme for: [$lookupKey, " +
"${if (magic == amqpMagic) "AMQP" else if (magic == kryoMagic) "Kryo" else "UNKNOWN MAGIC"}] registeredSchemes are: $registeredSchemes") "${if (magic == amqpMagic) "AMQP" else "UNKNOWN MAGIC"}] registeredSchemes are: $registeredSchemes")
throw UnsupportedOperationException("Serialization scheme $lookupKey not supported.") throw UnsupportedOperationException("Serialization scheme $lookupKey not supported.")
} to magic } to magic
} }
@ -144,15 +143,12 @@ open class SerializationFactoryImpl(
registeredSchemes += scheme registeredSchemes += scheme
} }
val alreadyRegisteredSchemes: Collection<SerializationScheme> get() = Collections.unmodifiableCollection(registeredSchemes)
override fun toString(): String { override fun toString(): String {
return "${this.javaClass.name} registeredSchemes=$registeredSchemes ${creator.joinToString("\n")}" return "${this.javaClass.name} registeredSchemes=$registeredSchemes ${creator.joinToString("\n")}"
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
return other is SerializationFactoryImpl && return other is SerializationFactoryImpl && other.registeredSchemes == this.registeredSchemes
other.registeredSchemes == this.registeredSchemes
} }
override fun hashCode(): Int = registeredSchemes.hashCode() override fun hashCode(): Int = registeredSchemes.hashCode()

View File

@ -5,9 +5,6 @@ package net.corda.serialization.internal
import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationDefaults import net.corda.core.serialization.SerializationDefaults
import net.corda.serialization.internal.amqp.amqpMagic import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.kryo.BuiltInExceptionsWhitelist
import net.corda.serialization.internal.kryo.GlobalTransientClassWhiteList
import net.corda.serialization.internal.kryo.kryoMagic
/* /*
* Serialisation contexts for the server. * Serialisation contexts for the server.
@ -20,19 +17,23 @@ import net.corda.serialization.internal.kryo.kryoMagic
*/ */
val AMQP_STORAGE_CONTEXT = SerializationContextImpl(amqpMagic, val AMQP_STORAGE_CONTEXT = SerializationContextImpl(
amqpMagic,
SerializationDefaults.javaClass.classLoader, SerializationDefaults.javaClass.classLoader,
AllButBlacklisted, AllButBlacklisted,
emptyMap(), emptyMap(),
true, true,
SerializationContext.UseCase.Storage, SerializationContext.UseCase.Storage,
null, null,
AlwaysAcceptEncodingWhitelist) AlwaysAcceptEncodingWhitelist
)
val AMQP_RPC_SERVER_CONTEXT = SerializationContextImpl(amqpMagic, val AMQP_RPC_SERVER_CONTEXT = SerializationContextImpl(
amqpMagic,
SerializationDefaults.javaClass.classLoader, SerializationDefaults.javaClass.classLoader,
GlobalTransientClassWhiteList(BuiltInExceptionsWhitelist()), GlobalTransientClassWhiteList(BuiltInExceptionsWhitelist()),
emptyMap(), emptyMap(),
true, true,
SerializationContext.UseCase.RPCServer, SerializationContext.UseCase.RPCServer,
null) null
)

View File

@ -1,38 +1,19 @@
@file:JvmName("SharedContexts")
package net.corda.serialization.internal package net.corda.serialization.internal
import net.corda.core.serialization.* import net.corda.core.serialization.*
import net.corda.serialization.internal.amqp.amqpMagic import net.corda.serialization.internal.amqp.amqpMagic
import net.corda.serialization.internal.kryo.BuiltInExceptionsWhitelist
import net.corda.serialization.internal.kryo.GlobalTransientClassWhiteList
import net.corda.serialization.internal.kryo.kryoMagic
/* val AMQP_P2P_CONTEXT = SerializationContextImpl(
* Serialisation contexts shared by the server and client. amqpMagic,
*
* NOTE: The [KRYO_STORAGE_CONTEXT] and [AMQP_STORAGE_CONTEXT]
* CANNOT always be instantiated outside of the server and so
* MUST be kept separate from these ones!
*/
val KRYO_CHECKPOINT_CONTEXT = SerializationContextImpl(kryoMagic,
SerializationDefaults.javaClass.classLoader,
QuasarWhitelist,
emptyMap(),
true,
SerializationContext.UseCase.Checkpoint,
null,
AlwaysAcceptEncodingWhitelist)
val AMQP_P2P_CONTEXT = SerializationContextImpl(amqpMagic,
SerializationDefaults.javaClass.classLoader, SerializationDefaults.javaClass.classLoader,
GlobalTransientClassWhiteList(BuiltInExceptionsWhitelist()), GlobalTransientClassWhiteList(BuiltInExceptionsWhitelist()),
emptyMap(), emptyMap(),
true, true,
SerializationContext.UseCase.P2P, SerializationContext.UseCase.P2P,
null) null
)
internal object AlwaysAcceptEncodingWhitelist : EncodingWhitelist { object AlwaysAcceptEncodingWhitelist : EncodingWhitelist {
override fun acceptEncoding(encoding: SerializationEncoding) = true override fun acceptEncoding(encoding: SerializationEncoding) = true
} }

View File

@ -4,10 +4,10 @@ import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationFactory import net.corda.core.serialization.SerializationFactory
import java.util.* import java.util.*
internal fun checkUseCase(allowedUseCases: EnumSet<SerializationContext.UseCase>) { fun checkUseCase(allowedUseCases: EnumSet<SerializationContext.UseCase>) {
val currentContext: SerializationContext = SerializationFactory.currentFactory?.currentContext val currentContext: SerializationContext = SerializationFactory.currentFactory?.currentContext
?: throw IllegalStateException("Current context is not set") ?: throw IllegalStateException("Current context is not set")
if (!allowedUseCases.contains(currentContext.useCase)) { if (!allowedUseCases.contains(currentContext.useCase)) {
throw IllegalStateException("UseCase '${currentContext.useCase}' is not within '$allowedUseCases'") throw IllegalStateException("UseCase '${currentContext.useCase}' is not within '$allowedUseCases'")
} }
} }

View File

@ -8,10 +8,7 @@ import net.corda.core.internal.objectOrNewInstance
import net.corda.core.internal.uncheckedCast import net.corda.core.internal.uncheckedCast
import net.corda.core.serialization.* import net.corda.core.serialization.*
import net.corda.core.utilities.ByteSequence import net.corda.core.utilities.ByteSequence
import net.corda.serialization.internal.CordaSerializationMagic import net.corda.serialization.internal.*
import net.corda.serialization.internal.DefaultWhitelist
import net.corda.serialization.internal.MutableClassWhitelist
import net.corda.serialization.internal.SerializationScheme
import java.lang.reflect.Modifier import java.lang.reflect.Modifier
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap

View File

@ -1,17 +1,17 @@
package net.corda.serialization.internal; package net.corda.serialization.internal;
import com.google.common.collect.Maps;
import net.corda.core.serialization.SerializationContext; import net.corda.core.serialization.SerializationContext;
import net.corda.core.serialization.SerializationFactory; import net.corda.core.serialization.SerializationFactory;
import net.corda.core.serialization.SerializedBytes; import net.corda.core.serialization.SerializedBytes;
import net.corda.node.serialization.kryo.CordaClosureSerializer;
import net.corda.node.serialization.kryo.KryoSerializationSchemeKt;
import net.corda.testing.core.SerializationEnvironmentRule; import net.corda.testing.core.SerializationEnvironmentRule;
import net.corda.serialization.internal.kryo.CordaClosureSerializer;
import net.corda.serialization.internal.kryo.KryoSerializationSchemeKt;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collections;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -26,7 +26,15 @@ public final class LambdaCheckpointSerializationTest {
@Before @Before
public void setup() { public void setup() {
factory = testSerialization.getSerializationFactory(); factory = testSerialization.getSerializationFactory();
context = new SerializationContextImpl(KryoSerializationSchemeKt.getKryoMagic(), this.getClass().getClassLoader(), AllWhitelist.INSTANCE, Maps.newHashMap(), true, SerializationContext.UseCase.Checkpoint, null); context = new SerializationContextImpl(
KryoSerializationSchemeKt.getKryoMagic(),
getClass().getClassLoader(),
AllWhitelist.INSTANCE,
Collections.emptyMap(),
true,
SerializationContext.UseCase.Checkpoint,
null
);
} }
@Test @Test

View File

@ -14,9 +14,9 @@ import net.corda.core.node.services.AttachmentStorage
import net.corda.core.serialization.ClassWhitelist import net.corda.core.serialization.ClassWhitelist
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationContext
import net.corda.serialization.internal.kryo.CordaClassResolver import net.corda.node.serialization.kryo.CordaClassResolver
import net.corda.serialization.internal.kryo.CordaKryo import net.corda.node.serialization.kryo.CordaKryo
import net.corda.serialization.internal.kryo.kryoMagic import net.corda.node.serialization.kryo.kryoMagic
import net.corda.testing.internal.rigorousMock import net.corda.testing.internal.rigorousMock
import net.corda.testing.services.MockAttachmentStorage import net.corda.testing.services.MockAttachmentStorage
import org.junit.Rule import org.junit.Rule

View File

@ -3,11 +3,11 @@ package net.corda.serialization.internal
import com.esotericsoftware.kryo.Kryo import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.util.DefaultClassResolver import com.esotericsoftware.kryo.util.DefaultClassResolver
import net.corda.core.serialization.* import net.corda.core.serialization.*
import net.corda.node.serialization.kryo.kryoMagic
import net.corda.node.services.statemachine.DataSessionMessage import net.corda.node.services.statemachine.DataSessionMessage
import net.corda.serialization.internal.amqp.DeserializationInput import net.corda.serialization.internal.amqp.DeserializationInput
import net.corda.serialization.internal.amqp.Envelope import net.corda.serialization.internal.amqp.Envelope
import net.corda.serialization.internal.amqp.SerializerFactory import net.corda.serialization.internal.amqp.SerializerFactory
import net.corda.serialization.internal.kryo.kryoMagic
import net.corda.testing.internal.amqpSpecific import net.corda.testing.internal.amqpSpecific
import net.corda.testing.internal.kryoSpecific import net.corda.testing.internal.kryoSpecific
import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.SerializationEnvironmentRule

View File

@ -6,8 +6,8 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.deserialize import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.node.serialization.kryo.kryoMagic
import net.corda.node.services.statemachine.DataSessionMessage import net.corda.node.services.statemachine.DataSessionMessage
import net.corda.serialization.internal.kryo.kryoMagic
import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.internal.amqpSpecific import net.corda.testing.internal.amqpSpecific
import net.corda.testing.internal.kryoSpecific import net.corda.testing.internal.kryoSpecific

View File

@ -5,10 +5,10 @@ import com.esotericsoftware.kryo.KryoException
import com.esotericsoftware.kryo.io.Output import com.esotericsoftware.kryo.io.Output
import net.corda.core.serialization.* import net.corda.core.serialization.*
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.serialization.internal.kryo.CordaClassResolver import net.corda.node.serialization.kryo.CordaClassResolver
import net.corda.serialization.internal.kryo.CordaKryo import net.corda.node.serialization.kryo.CordaKryo
import net.corda.serialization.internal.kryo.DefaultKryoCustomizer import net.corda.node.serialization.kryo.DefaultKryoCustomizer
import net.corda.serialization.internal.kryo.kryoMagic import net.corda.node.serialization.kryo.kryoMagic
import net.corda.testing.internal.rigorousMock import net.corda.testing.internal.rigorousMock
import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.SerializationEnvironmentRule
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat

View File

@ -4,8 +4,8 @@ import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.util.DefaultClassResolver import com.esotericsoftware.kryo.util.DefaultClassResolver
import net.corda.core.serialization.deserialize import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.node.serialization.kryo.kryoMagic
import net.corda.node.services.statemachine.DataSessionMessage import net.corda.node.services.statemachine.DataSessionMessage
import net.corda.serialization.internal.kryo.kryoMagic
import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.internal.kryoSpecific import net.corda.testing.internal.kryoSpecific
import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertArrayEquals

View File

@ -3,8 +3,8 @@ package net.corda.serialization.internal.amqp
import net.corda.core.serialization.* import net.corda.core.serialization.*
import net.corda.core.utilities.ByteSequence import net.corda.core.utilities.ByteSequence
import net.corda.serialization.internal.* import net.corda.serialization.internal.*
import net.corda.serialization.internal.kryo.BuiltInExceptionsWhitelist import net.corda.serialization.internal.BuiltInExceptionsWhitelist
import net.corda.serialization.internal.kryo.GlobalTransientClassWhiteList import net.corda.serialization.internal.GlobalTransientClassWhiteList
import org.junit.Test import org.junit.Test
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import kotlin.test.assertEquals import kotlin.test.assertEquals

View File

@ -6,6 +6,7 @@ import net.corda.client.rpc.internal.serialization.amqp.AMQPClientSerializationS
import net.corda.core.DoNotImplement import net.corda.core.DoNotImplement
import net.corda.core.serialization.internal.* import net.corda.core.serialization.internal.*
import net.corda.node.serialization.amqp.AMQPServerSerializationScheme import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
import net.corda.node.serialization.kryo.KRYO_CHECKPOINT_CONTEXT
import net.corda.node.serialization.kryo.KryoServerSerializationScheme import net.corda.node.serialization.kryo.KryoServerSerializationScheme
import net.corda.serialization.internal.* import net.corda.serialization.internal.*
import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.SerializationEnvironmentRule