mirror of
https://github.com/corda/corda.git
synced 2025-06-18 15:18:16 +00:00
Simple deserialisation fixes. (#1243)
* Fix typo: prefered -> preferred * Simplify KryoVerifierSerializationScheme and resolve warning. * Add a custom serialiser for PrivacySeed so that we can avoid invoking RNG.
This commit is contained in:
@ -39,7 +39,7 @@ interface SerializationContext {
|
|||||||
/**
|
/**
|
||||||
* When serializing, use the format this header sequence represents.
|
* When serializing, use the format this header sequence represents.
|
||||||
*/
|
*/
|
||||||
val preferedSerializationVersion: ByteSequence
|
val preferredSerializationVersion: ByteSequence
|
||||||
/**
|
/**
|
||||||
* The class loader to use for deserialization.
|
* The class loader to use for deserialization.
|
||||||
*/
|
*/
|
||||||
|
@ -11,7 +11,7 @@ import net.corda.nodeapi.internal.serialization.amqp.SerializationOutput
|
|||||||
import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory
|
import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
internal val AMQP_ENABLED get() = SerializationDefaults.P2P_CONTEXT.preferedSerializationVersion == AmqpHeaderV1_0
|
internal val AMQP_ENABLED get() = SerializationDefaults.P2P_CONTEXT.preferredSerializationVersion == AmqpHeaderV1_0
|
||||||
|
|
||||||
abstract class AbstractAMQPSerializationScheme : SerializationScheme {
|
abstract class AbstractAMQPSerializationScheme : SerializationScheme {
|
||||||
internal companion object {
|
internal companion object {
|
||||||
|
@ -6,11 +6,11 @@ import com.esotericsoftware.kryo.io.Input
|
|||||||
import com.esotericsoftware.kryo.io.Output
|
import com.esotericsoftware.kryo.io.Output
|
||||||
import com.esotericsoftware.kryo.serializers.CompatibleFieldSerializer
|
import com.esotericsoftware.kryo.serializers.CompatibleFieldSerializer
|
||||||
import com.esotericsoftware.kryo.serializers.FieldSerializer
|
import com.esotericsoftware.kryo.serializers.FieldSerializer
|
||||||
import com.esotericsoftware.kryo.util.MapReferenceResolver
|
|
||||||
import de.javakaffee.kryoserializers.ArraysAsListSerializer
|
import de.javakaffee.kryoserializers.ArraysAsListSerializer
|
||||||
import de.javakaffee.kryoserializers.BitSetSerializer
|
import de.javakaffee.kryoserializers.BitSetSerializer
|
||||||
import de.javakaffee.kryoserializers.UnmodifiableCollectionsSerializer
|
import de.javakaffee.kryoserializers.UnmodifiableCollectionsSerializer
|
||||||
import de.javakaffee.kryoserializers.guava.*
|
import de.javakaffee.kryoserializers.guava.*
|
||||||
|
import net.corda.core.contracts.PrivacySalt
|
||||||
import net.corda.core.crypto.composite.CompositeKey
|
import net.corda.core.crypto.composite.CompositeKey
|
||||||
import net.corda.core.identity.PartyAndCertificate
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.node.CordaPluginRegistry
|
import net.corda.core.node.CordaPluginRegistry
|
||||||
@ -110,6 +110,9 @@ object DefaultKryoCustomizer {
|
|||||||
register(NotaryChangeWireTransaction::class.java, NotaryChangeWireTransactionSerializer)
|
register(NotaryChangeWireTransaction::class.java, NotaryChangeWireTransactionSerializer)
|
||||||
register(PartyAndCertificate::class.java, PartyAndCertificateSerializer)
|
register(PartyAndCertificate::class.java, PartyAndCertificateSerializer)
|
||||||
|
|
||||||
|
// Don't deserialize PrivacySalt via its default constructor.
|
||||||
|
register(PrivacySalt::class.java, PrivacySaltSerializer)
|
||||||
|
|
||||||
val customization = KryoSerializationCustomization(this)
|
val customization = KryoSerializationCustomization(this)
|
||||||
pluginRegistries.forEach { it.customizeSerialization(customization) }
|
pluginRegistries.forEach { it.customizeSerialization(customization) }
|
||||||
}
|
}
|
||||||
@ -153,4 +156,18 @@ object DefaultKryoCustomizer {
|
|||||||
return list.toNonEmptySet()
|
return list.toNonEmptySet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/*
|
||||||
|
* Avoid deserialising PrivacySalt via its default constructor
|
||||||
|
* because the random number generator may not be available.
|
||||||
|
*/
|
||||||
|
private object PrivacySaltSerializer : Serializer<PrivacySalt>() {
|
||||||
|
override fun write(kryo: Kryo, output: Output, obj: PrivacySalt) {
|
||||||
|
output.writeBytesWithLength(obj.bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(kryo: Kryo, input: Input, type: Class<PrivacySalt>): PrivacySalt {
|
||||||
|
return PrivacySalt(input.readBytesWithLength())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -28,7 +28,7 @@ object NotSupportedSeralizationScheme : SerializationScheme {
|
|||||||
override fun <T : Any> serialize(obj: T, context: SerializationContext): SerializedBytes<T> = doThrow()
|
override fun <T : Any> serialize(obj: T, context: SerializationContext): SerializedBytes<T> = doThrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
data class SerializationContextImpl(override val preferedSerializationVersion: ByteSequence,
|
data class SerializationContextImpl(override val preferredSerializationVersion: ByteSequence,
|
||||||
override val deserializationClassLoader: ClassLoader,
|
override val deserializationClassLoader: ClassLoader,
|
||||||
override val whitelist: ClassWhitelist,
|
override val whitelist: ClassWhitelist,
|
||||||
override val properties: Map<Any, Any>,
|
override val properties: Map<Any, Any>,
|
||||||
@ -52,7 +52,7 @@ data class SerializationContextImpl(override val preferedSerializationVersion: B
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun withPreferredSerializationVersion(versionHeader: ByteSequence) = copy(preferedSerializationVersion = versionHeader)
|
override fun withPreferredSerializationVersion(versionHeader: ByteSequence) = copy(preferredSerializationVersion = versionHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val HEADER_SIZE: Int = 8
|
private const val HEADER_SIZE: Int = 8
|
||||||
@ -81,7 +81,7 @@ open class SerializationFactoryImpl : SerializationFactory {
|
|||||||
override fun <T : Any> deserialize(byteSequence: ByteSequence, clazz: Class<T>, context: SerializationContext): T = schemeFor(byteSequence, context.useCase).deserialize(byteSequence, clazz, context)
|
override fun <T : Any> deserialize(byteSequence: ByteSequence, clazz: Class<T>, context: SerializationContext): T = schemeFor(byteSequence, context.useCase).deserialize(byteSequence, clazz, context)
|
||||||
|
|
||||||
override fun <T : Any> serialize(obj: T, context: SerializationContext): SerializedBytes<T> {
|
override fun <T : Any> serialize(obj: T, context: SerializationContext): SerializedBytes<T> {
|
||||||
return schemeFor(context.preferedSerializationVersion, context.useCase).serialize(obj, context)
|
return schemeFor(context.preferredSerializationVersion, context.useCase).serialize(obj, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun registerScheme(scheme: SerializationScheme) {
|
fun registerScheme(scheme: SerializationScheme) {
|
||||||
|
@ -5,6 +5,7 @@ import com.esotericsoftware.kryo.KryoSerializable
|
|||||||
import com.esotericsoftware.kryo.io.Input
|
import com.esotericsoftware.kryo.io.Input
|
||||||
import com.esotericsoftware.kryo.io.Output
|
import com.esotericsoftware.kryo.io.Output
|
||||||
import com.google.common.primitives.Ints
|
import com.google.common.primitives.Ints
|
||||||
|
import net.corda.core.contracts.PrivacySalt
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.serialization.*
|
import net.corda.core.serialization.*
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
@ -16,7 +17,9 @@ import net.corda.testing.TestDependencyInjectionBase
|
|||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import org.junit.rules.ExpectedException
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -28,6 +31,9 @@ class KryoTests : TestDependencyInjectionBase() {
|
|||||||
private lateinit var factory: SerializationFactory
|
private lateinit var factory: SerializationFactory
|
||||||
private lateinit var context: SerializationContext
|
private lateinit var context: SerializationContext
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val expectedEx: ExpectedException = ExpectedException.none()
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
factory = SerializationFactoryImpl().apply { registerScheme(KryoServerSerializationScheme(this)) }
|
factory = SerializationFactoryImpl().apply { registerScheme(KryoServerSerializationScheme(this)) }
|
||||||
@ -157,6 +163,26 @@ class KryoTests : TestDependencyInjectionBase() {
|
|||||||
override fun toString(): String = "Cyclic($value)"
|
override fun toString(): String = "Cyclic($value)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `serialize - deserialize PrivacySalt`() {
|
||||||
|
val expected = PrivacySalt(byteArrayOf(
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||||
|
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
|
||||||
|
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
|
||||||
|
31, 32
|
||||||
|
))
|
||||||
|
val serializedBytes = expected.serialize(factory, context)
|
||||||
|
val actual = serializedBytes.deserialize(factory, context)
|
||||||
|
assertEquals(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `all-zero PrivacySalt not allowed`() {
|
||||||
|
expectedEx.expect(IllegalArgumentException::class.java)
|
||||||
|
expectedEx.expectMessage("Privacy salt should not be all zeros.")
|
||||||
|
PrivacySalt(ByteArray(32))
|
||||||
|
}
|
||||||
|
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
private object TestSingleton
|
private object TestSingleton
|
||||||
|
|
||||||
|
@ -111,8 +111,8 @@ class TestSerializationContext : SerializationContext {
|
|||||||
|
|
||||||
override fun toString(): String = stackTrace?.joinToString("\n") ?: "null"
|
override fun toString(): String = stackTrace?.joinToString("\n") ?: "null"
|
||||||
|
|
||||||
override val preferedSerializationVersion: ByteSequence
|
override val preferredSerializationVersion: ByteSequence
|
||||||
get() = delegate!!.preferedSerializationVersion
|
get() = delegate!!.preferredSerializationVersion
|
||||||
override val deserializationClassLoader: ClassLoader
|
override val deserializationClassLoader: ClassLoader
|
||||||
get() = delegate!!.deserializationClassLoader
|
get() = delegate!!.deserializationClassLoader
|
||||||
override val whitelist: ClassWhitelist
|
override val whitelist: ClassWhitelist
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.corda.verifier
|
package net.corda.verifier
|
||||||
|
|
||||||
import com.esotericsoftware.kryo.pool.KryoPool
|
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import com.typesafe.config.ConfigParseOptions
|
import com.typesafe.config.ConfigParseOptions
|
||||||
@ -98,15 +97,10 @@ class Verifier {
|
|||||||
|
|
||||||
class KryoVerifierSerializationScheme(serializationFactory: SerializationFactory) : AbstractKryoSerializationScheme(serializationFactory) {
|
class KryoVerifierSerializationScheme(serializationFactory: SerializationFactory) : AbstractKryoSerializationScheme(serializationFactory) {
|
||||||
override fun canDeserializeVersion(byteSequence: ByteSequence, target: SerializationContext.UseCase): Boolean {
|
override fun canDeserializeVersion(byteSequence: ByteSequence, target: SerializationContext.UseCase): Boolean {
|
||||||
return byteSequence.equals(KryoHeaderV0_1) && target == SerializationContext.UseCase.P2P
|
return byteSequence == KryoHeaderV0_1 && target == SerializationContext.UseCase.P2P
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun rpcClientKryoPool(context: SerializationContext): KryoPool {
|
override fun rpcClientKryoPool(context: SerializationContext) = throw UnsupportedOperationException()
|
||||||
throw UnsupportedOperationException()
|
override fun rpcServerKryoPool(context: SerializationContext) = throw UnsupportedOperationException()
|
||||||
}
|
|
||||||
|
|
||||||
override fun rpcServerKryoPool(context: SerializationContext): KryoPool {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user