Merge remote-tracking branch 'remotes/open/master' into merges/may-14-15-21

# Conflicts:
#	.idea/compiler.xml
#	constants.properties
#	experimental/behave/src/main/kotlin/net/corda/behave/network/Network.kt
#	experimental/behave/src/main/kotlin/net/corda/behave/node/Distribution.kt
#	experimental/behave/src/test/kotlin/net/corda/behave/service/PostreSQLServiceTests.kt
#	node-api/src/main/kotlin/net/corda/nodeapi/internal/bridging/AMQPBridgeManager.kt
#	node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/CordaPersistence.kt
#	node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt
#	node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/AMQPChannelHandler.kt
#	node-api/src/main/kotlin/net/corda/nodeapi/internal/protonwrapper/netty/AMQPClient.kt
#	node/src/integration-test/kotlin/net/corda/node/AuthDBTests.kt
#	node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt
#	node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt
#	node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt
#	node/src/main/kotlin/net/corda/node/services/messaging/MessagingExecutor.kt
#	node/src/main/kotlin/net/corda/node/services/persistence/AbstractPartyToX500NameAsStringConverter.kt
#	node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionMappingStorage.kt
#	node/src/main/kotlin/net/corda/node/utilities/AddOrRemove.kt
#	node/src/test/kotlin/net/corda/node/services/config/NodeConfigurationImplTest.kt
#	samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt
#	samples/irs-demo/web/src/test/kotlin/net/corda/irs/web/IrsDemoWebApplicationTests.kt
#	samples/simm-valuation-demo/src/integration-test/kotlin/net/corda/vega/SimmValuationTest.kt
#	testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt
#	testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalTestUtils.kt
#	testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt
#	testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeConfig.kt
#	webserver/src/integration-test/kotlin/net/corda/webserver/WebserverDriverTests.kt
This commit is contained in:
sollecitom
2018-05-14 15:56:43 +01:00
475 changed files with 1987 additions and 1521 deletions

View File

@ -113,7 +113,7 @@ class ArtemisTcpTransport {
direction: ConnectionDirection,
hostAndPortList: List<NetworkHostAndPort>,
config: SSLConfiguration?,
enableSSL: Boolean = true): List<TransportConfiguration>{
enableSSL: Boolean = true): List<TransportConfiguration> {
val tcpTransports = ArrayList<TransportConfiguration>(hostAndPortList.size)
hostAndPortList.forEach {
tcpTransports.add(tcpTransport(direction, it, config, enableSSL))

View File

@ -258,22 +258,22 @@ object RPCApi {
}
}
private val TAG_FIELD_NAME = "tag"
private val RPC_ID_FIELD_NAME = "rpc-id"
private val RPC_ID_TIMESTAMP_FIELD_NAME = "rpc-id-timestamp"
private val RPC_SESSION_ID_FIELD_NAME = "rpc-session-id"
private val RPC_SESSION_ID_TIMESTAMP_FIELD_NAME = "rpc-session-id-timestamp"
private val RPC_EXTERNAL_ID_FIELD_NAME = "rpc-external-id"
private val RPC_EXTERNAL_ID_TIMESTAMP_FIELD_NAME = "rpc-external-id-timestamp"
private val RPC_EXTERNAL_SESSION_ID_FIELD_NAME = "rpc-external-session-id"
private val RPC_EXTERNAL_SESSION_ID_TIMESTAMP_FIELD_NAME = "rpc-external-session-id-timestamp"
private val RPC_IMPERSONATED_ACTOR_ID = "rpc-impersonated-actor-id"
private val RPC_IMPERSONATED_ACTOR_STORE_ID = "rpc-impersonated-actor-store-id"
private val RPC_IMPERSONATED_ACTOR_OWNING_LEGAL_IDENTITY = "rpc-impersonated-actor-owningLegalIdentity"
private val DEDUPLICATION_IDENTITY_FIELD_NAME = "deduplication-identity"
private val OBSERVABLE_ID_FIELD_NAME = "observable-id"
private val OBSERVABLE_ID_TIMESTAMP_FIELD_NAME = "observable-id-timestamp"
private val METHOD_NAME_FIELD_NAME = "method-name"
private const val TAG_FIELD_NAME = "tag"
private const val RPC_ID_FIELD_NAME = "rpc-id"
private const val RPC_ID_TIMESTAMP_FIELD_NAME = "rpc-id-timestamp"
private const val RPC_SESSION_ID_FIELD_NAME = "rpc-session-id"
private const val RPC_SESSION_ID_TIMESTAMP_FIELD_NAME = "rpc-session-id-timestamp"
private const val RPC_EXTERNAL_ID_FIELD_NAME = "rpc-external-id"
private const val RPC_EXTERNAL_ID_TIMESTAMP_FIELD_NAME = "rpc-external-id-timestamp"
private const val RPC_EXTERNAL_SESSION_ID_FIELD_NAME = "rpc-external-session-id"
private const val RPC_EXTERNAL_SESSION_ID_TIMESTAMP_FIELD_NAME = "rpc-external-session-id-timestamp"
private const val RPC_IMPERSONATED_ACTOR_ID = "rpc-impersonated-actor-id"
private const val RPC_IMPERSONATED_ACTOR_STORE_ID = "rpc-impersonated-actor-store-id"
private const val RPC_IMPERSONATED_ACTOR_OWNING_LEGAL_IDENTITY = "rpc-impersonated-actor-owningLegalIdentity"
private const val DEDUPLICATION_IDENTITY_FIELD_NAME = "deduplication-identity"
private const val OBSERVABLE_ID_FIELD_NAME = "observable-id"
private const val OBSERVABLE_ID_TIMESTAMP_FIELD_NAME = "observable-id-timestamp"
private const val METHOD_NAME_FIELD_NAME = "method-name"
fun ClientMessage.replyId(): InvocationId {

View File

@ -59,7 +59,6 @@ class ArtemisMessagingComponent {
*/
val bridgedCertificateSubject = SimpleString("sender-subject-name")
object Type {
const val KEY = "corda_p2p_message_type"
const val SESSION_INIT_VALUE = "session_init"
@ -138,5 +137,4 @@ class ArtemisMessagingComponent {
override val queueName: String = "$P2P_PREFIX${identity.toStringShort()}"
}
}

View File

@ -70,6 +70,7 @@ inline fun NodeInfo.sign(signer: (PublicKey, SerializedBytes<NodeInfo>) -> Digit
class NodeInfoAndSigned private constructor(val nodeInfo: NodeInfo, val signed: SignedNodeInfo) {
constructor(nodeInfo: NodeInfo, signer: (PublicKey, SerializedBytes<NodeInfo>) -> DigitalSignature) : this(nodeInfo, nodeInfo.sign(signer))
constructor(signedNodeInfo: SignedNodeInfo) : this(signedNodeInfo.verified(), signedNodeInfo)
operator fun component1(): NodeInfo = nodeInfo
operator fun component2(): SignedNodeInfo = signed
}

View File

@ -48,7 +48,7 @@ import kotlin.concurrent.withLock
* The Netty thread pool used by the AMQPBridges is also shared and managed by the AMQPBridgeManager.
*/
@VisibleForTesting
class AMQPBridgeManager(config: NodeSSLConfiguration, private val socksProxyConfig: SocksProxyConfig? = null, val artemisMessageClientFactory: () -> ArtemisSessionProvider) : BridgeManager {
class AMQPBridgeManager(config: NodeSSLConfiguration, private val socksProxyConfig: SocksProxyConfig? = null, private val artemisMessageClientFactory: () -> ArtemisSessionProvider) : BridgeManager {
private val lock = ReentrantLock()
private val bridgeNameToBridgeMap = mutableMapOf<String, AMQPBridge>()

View File

@ -16,6 +16,6 @@ data class User(
val password: String,
val permissions: Set<String>) {
override fun toString(): String = "${javaClass.simpleName}($username, permissions=$permissions)"
@Deprecated("Use toConfig().root().unwrapped() instead")
@Deprecated("Use toConfig().root().unwrapped() instead", ReplaceWith("toConfig().root().unwrapped()"))
fun toMap(): Map<String, Any> = toConfig().root().unwrapped()
}

View File

@ -23,7 +23,6 @@ import net.corda.nodeapi.internal.crypto.X509Utilities
import java.security.cert.X509Certificate
import java.time.Instant
const val NETWORK_PARAMS_FILE_NAME = "network-parameters"
const val NETWORK_PARAMS_UPDATE_FILE_NAME = "network-parameters-update"
@ -81,6 +80,7 @@ fun <T : Any> SignedDataWithCert<T>.verifiedNetworkMapCert(rootCert: X509Certifi
class NetworkMapAndSigned private constructor(val networkMap: NetworkMap, val signed: SignedNetworkMap) {
constructor(networkMap: NetworkMap, signer: (SerializedBytes<NetworkMap>) -> DigitalSignatureWithCert) : this(networkMap, networkMap.signWithCert(signer))
constructor(signed: SignedNetworkMap) : this(signed.verified(), signed)
operator fun component1(): NetworkMap = networkMap
operator fun component2(): SignedNetworkMap = signed
}

View File

@ -290,10 +290,8 @@ fun isH2Database(jdbcUrl: String) = jdbcUrl.startsWith("jdbc:h2:")
/** Check if any nested cause is of [SQLException] type. */
private fun Throwable.hasSQLExceptionCause(): Boolean =
if (cause == null)
false
else if (cause is SQLException)
true
else
cause?.hasSQLExceptionCause() ?: false
when (cause) {
null -> false
is SQLException -> true
else -> cause?.hasSQLExceptionCause() ?: false
}

View File

@ -176,8 +176,8 @@ class HibernateConfiguration(
}
// A tweaked version of `org.hibernate.type.descriptor.java.PrimitiveByteArrayTypeDescriptor` that truncates logged messages.
object CordaPrimitiveByteArrayTypeDescriptor : PrimitiveByteArrayTypeDescriptor() {
private val LOG_SIZE_LIMIT = 1024
private object CordaPrimitiveByteArrayTypeDescriptor : PrimitiveByteArrayTypeDescriptor() {
private const val LOG_SIZE_LIMIT = 1024
override fun extractLoggableRepresentation(value: ByteArray?): String {
return if (value == null) {

View File

@ -72,6 +72,7 @@ internal class ConnectionStateMachine(serverMode: Boolean,
transport = Engine.transport()
transport.idleTimeout = IDLE_TIMEOUT
transport.context = connection
@Suppress("UsePropertyAccessSyntax")
transport.setEmitFlowEventOnSend(true)
connection.collect(collector)
val sasl = transport.sasl()

View File

@ -15,7 +15,6 @@ import io.netty.channel.ChannelDuplexHandler
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelPromise
import io.netty.channel.socket.SocketChannel
import io.netty.handler.proxy.ProxyConnectException
import io.netty.handler.proxy.ProxyConnectionEvent
import io.netty.handler.ssl.SslHandler
import io.netty.handler.ssl.SslHandshakeCompletionEvent
@ -101,31 +100,38 @@ internal class AMQPChannelHandler(private val serverMode: Boolean,
val sslHandler = ctx.pipeline().get(SslHandler::class.java)
localCert = sslHandler.engine().session.localCertificates[0].x509
remoteCert = sslHandler.engine().session.peerCertificates[0].x509
try {
val remoteX500Name = CordaX500Name.build(remoteCert!!.subjectX500Principal)
require(allowedRemoteLegalNames == null || remoteX500Name in allowedRemoteLegalNames)
log.info("handshake completed subject: $remoteX500Name")
val remoteX500Name = try {
CordaX500Name.build(remoteCert!!.subjectX500Principal)
} catch (ex: IllegalArgumentException) {
log.error("Invalid certificate subject", ex)
log.error("Certificate subject not a valid CordaX500Name", ex)
ctx.close()
return
}
if (allowedRemoteLegalNames != null && remoteX500Name !in allowedRemoteLegalNames) {
log.error("Provided certificate subject $remoteX500Name not in expected set $allowedRemoteLegalNames")
ctx.close()
return
}
log.info("Handshake completed with subject: $remoteX500Name")
createAMQPEngine(ctx)
onOpen(Pair(ctx.channel() as SocketChannel, ConnectionChange(remoteAddress, remoteCert, true)))
} else {
log.error("Handshake failure $evt")
log.error("Handshake failure ${evt.cause().message}")
if (log.isTraceEnabled) {
log.trace("Handshake failure", evt.cause())
}
ctx.close()
}
}
}
@Suppress("OverridingDeprecatedMember")
override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
if (cause is ProxyConnectException) {
log.warn("Proxy connection failed ${cause.message}")
suppressClose = true // The pipeline gets marked as active on connection to the proxy rather than to the target, which causes excess close events
log.warn("Closing channel due to nonrecoverable exception ${cause.message}")
if (log.isTraceEnabled) {
log.trace("Pipeline uncaught exception", cause)
}
ctx.close()
}
override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {

View File

@ -30,6 +30,7 @@ import net.corda.nodeapi.internal.protonwrapper.messages.impl.SendableMessageImp
import rx.Observable
import rx.subjects.PublishSubject
import java.net.InetSocketAddress
import java.lang.Long.min
import java.security.KeyStore
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantLock
@ -74,7 +75,9 @@ class AMQPClient(val targets: List<NetworkHostAndPort>,
}
val log = contextLogger()
const val RETRY_INTERVAL = 1000L
const val MIN_RETRY_INTERVAL = 1000L
const val MAX_RETRY_INTERVAL = 60000L
const val BACKOFF_MULTIPLIER = 2L
const val NUM_CLIENT_THREADS = 2
}
@ -87,6 +90,13 @@ class AMQPClient(val targets: List<NetworkHostAndPort>,
// Offset into the list of targets, so that we can implement round-robin reconnect logic.
private var targetIndex = 0
private var currentTarget: NetworkHostAndPort = targets.first()
private var retryInterval = MIN_RETRY_INTERVAL
private fun nextTarget() {
targetIndex = (targetIndex + 1).rem(targets.size)
log.info("Retry connect to ${targets[targetIndex]}")
retryInterval = min(MAX_RETRY_INTERVAL, retryInterval * BACKOFF_MULTIPLIER)
}
private val connectListener = object : ChannelFutureListener {
override fun operationComplete(future: ChannelFuture) {
@ -95,10 +105,9 @@ class AMQPClient(val targets: List<NetworkHostAndPort>,
if (!stopping) {
workerGroup?.schedule({
log.info("Retry connect to $currentTarget")
targetIndex = (targetIndex + 1).rem(targets.size)
nextTarget()
restart()
}, RETRY_INTERVAL, TimeUnit.MILLISECONDS)
}, retryInterval, TimeUnit.MILLISECONDS)
}
} else {
log.info("Connected to $currentTarget")
@ -116,10 +125,9 @@ class AMQPClient(val targets: List<NetworkHostAndPort>,
clientChannel = null
if (!stopping) {
workerGroup?.schedule({
log.info("Retry connect")
targetIndex = (targetIndex + 1).rem(targets.size)
nextTarget()
restart()
}, RETRY_INTERVAL, TimeUnit.MILLISECONDS)
}, retryInterval, TimeUnit.MILLISECONDS)
}
}
}
@ -162,7 +170,10 @@ class AMQPClient(val targets: List<NetworkHostAndPort>,
parent.userName,
parent.password,
parent.trace,
{ parent._onConnection.onNext(it.second) },
{
parent.retryInterval = MIN_RETRY_INTERVAL // reset to fast reconnect if we connect properly
parent._onConnection.onNext(it.second)
},
{ parent._onConnection.onNext(it.second) },
{ rcv -> parent._onReceive.onNext(rcv) }))
}

View File

@ -100,7 +100,7 @@ class AMQPServer(val hostName: String,
parent.password,
parent.trace,
{
parent.clientChannels.put(it.first.remoteAddress(), it.first)
parent.clientChannels[it.first.remoteAddress()] = it.first
parent._onConnection.onNext(it.second)
},
{
@ -204,5 +204,4 @@ class AMQPServer(val hostName: String,
private val _onConnection = PublishSubject.create<ConnectionChange>().toSerialized()
val onConnection: Observable<ConnectionChange>
get() = _onConnection
}

View File

@ -12,22 +12,111 @@ package net.corda.nodeapi.internal.protonwrapper.netty
import io.netty.handler.ssl.SslHandler
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.toHex
import net.corda.nodeapi.ArtemisTcpTransport
import net.corda.nodeapi.internal.crypto.toBc
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier
import org.bouncycastle.asn1.x509.Extension
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier
import java.net.Socket
import java.security.KeyStore
import java.security.SecureRandom
import java.security.cert.CertPathBuilder
import java.security.cert.PKIXBuilderParameters
import java.security.cert.PKIXRevocationChecker
import java.security.cert.X509CertSelector
import java.security.cert.*
import java.util.*
import javax.net.ssl.*
internal class LoggingTrustManagerWrapper(val wrapped: X509ExtendedTrustManager) : X509ExtendedTrustManager() {
companion object {
val log = contextLogger()
}
private fun certPathToString(certPath: Array<out X509Certificate>?): String {
if (certPath == null) {
return "<empty certpath>"
}
val certs = certPath.map {
val bcCert = it.toBc()
val subject = bcCert.subject.toString()
val issuer = bcCert.issuer.toString()
val keyIdentifier = try {
SubjectKeyIdentifier.getInstance(bcCert.getExtension(Extension.subjectKeyIdentifier).parsedValue).keyIdentifier.toHex()
} catch (ex: Exception) {
"null"
}
val authorityKeyIdentifier = try {
AuthorityKeyIdentifier.getInstance(bcCert.getExtension(Extension.authorityKeyIdentifier).parsedValue).keyIdentifier.toHex()
} catch (ex: Exception) {
"null"
}
" $subject[$keyIdentifier] issued by $issuer[$authorityKeyIdentifier]"
}
return certs.joinToString("\r\n")
}
private fun certPathToStringFull(chain: Array<out X509Certificate>?): String {
if (chain == null) {
return "<empty certpath>"
}
return chain.map { it.toString() }.joinToString(", ")
}
private fun logErrors(chain: Array<out X509Certificate>?, block: () -> Unit) {
try {
block()
} catch (ex: CertificateException) {
log.error("Bad certificate path ${ex.message}:\r\n${certPathToStringFull(chain)}")
throw ex
}
}
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?, socket: Socket?) {
log.info("Check Client Certpath:\r\n${certPathToString(chain)}")
logErrors(chain) { wrapped.checkClientTrusted(chain, authType, socket) }
}
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?, engine: SSLEngine?) {
log.info("Check Client Certpath:\r\n${certPathToString(chain)}")
logErrors(chain) { wrapped.checkClientTrusted(chain, authType, engine) }
}
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {
log.info("Check Client Certpath:\r\n${certPathToString(chain)}")
logErrors(chain) { wrapped.checkClientTrusted(chain, authType) }
}
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?, socket: Socket?) {
log.info("Check Server Certpath:\r\n${certPathToString(chain)}")
logErrors(chain) { wrapped.checkServerTrusted(chain, authType, socket) }
}
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?, engine: SSLEngine?) {
log.info("Check Server Certpath:\r\n${certPathToString(chain)}")
logErrors(chain) { wrapped.checkServerTrusted(chain, authType, engine) }
}
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {
log.info("Check Server Certpath:\r\n${certPathToString(chain)}")
logErrors(chain) { wrapped.checkServerTrusted(chain, authType) }
}
override fun getAcceptedIssuers(): Array<X509Certificate> = wrapped.acceptedIssuers
}
internal fun createClientSslHelper(target: NetworkHostAndPort,
keyManagerFactory: KeyManagerFactory,
trustManagerFactory: TrustManagerFactory): SslHandler {
val sslContext = SSLContext.getInstance("TLS")
val keyManagers = keyManagerFactory.keyManagers
val trustManagers = trustManagerFactory.trustManagers
val trustManagers = trustManagerFactory.trustManagers.filterIsInstance(X509ExtendedTrustManager::class.java).map { LoggingTrustManagerWrapper(it) }.toTypedArray()
sslContext.init(keyManagers, trustManagers, SecureRandom())
val sslEngine = sslContext.createSSLEngine(target.host, target.port)
sslEngine.useClientMode = true
@ -41,7 +130,7 @@ internal fun createServerSslHelper(keyManagerFactory: KeyManagerFactory,
trustManagerFactory: TrustManagerFactory): SslHandler {
val sslContext = SSLContext.getInstance("TLS")
val keyManagers = keyManagerFactory.keyManagers
val trustManagers = trustManagerFactory.trustManagers
val trustManagers = trustManagerFactory.trustManagers.filterIsInstance(X509ExtendedTrustManager::class.java).map { LoggingTrustManagerWrapper(it) }.toTypedArray()
sslContext.init(keyManagers, trustManagers, SecureRandom())
val sslEngine = sslContext.createSSLEngine()
sslEngine.useClientMode = false

View File

@ -1,4 +1,5 @@
@file:JvmName("ByteBufferStreams")
package net.corda.nodeapi.internal.serialization
import net.corda.core.internal.LazyPool
@ -10,9 +11,9 @@ import java.nio.ByteBuffer
import kotlin.math.min
internal val serializeOutputStreamPool = LazyPool(
clear = ByteBufferOutputStream::reset,
shouldReturnToPool = { it.size() < 256 * 1024 }, // Discard if it grew too large
newInstance = { ByteBufferOutputStream(64 * 1024) })
clear = ByteBufferOutputStream::reset,
shouldReturnToPool = { it.size() < 256 * 1024 }, // Discard if it grew too large
newInstance = { ByteBufferOutputStream(64 * 1024) })
internal fun <T> byteArrayOutput(task: (ByteBufferOutputStream) -> T): ByteArray {
return serializeOutputStreamPool.run { underlying ->

View File

@ -56,7 +56,7 @@ class SerializeAsTokenContextImpl(override val serviceHub: ServiceHub, init: Ser
if (className !in classNameToSingleton) {
// Only allowable if we are in SerializeAsTokenContext init (readOnly == false)
if (readOnly) {
throw UnsupportedOperationException("Attempt to write token for lazy registered ${className}. All tokens should be registered during context construction.")
throw UnsupportedOperationException("Attempt to write token for lazy registered $className. All tokens should be registered during context construction.")
}
classNameToSingleton[className] = toBeTokenized
}

View File

@ -22,7 +22,7 @@ import java.lang.reflect.Type
* [ByteArray] is automatically marshalled to/from the Proton-J wrapper, [Binary].
*/
class AMQPPrimitiveSerializer(clazz: Class<*>) : AMQPSerializer<Any> {
override val typeDescriptor = Symbol.valueOf(SerializerFactory.primitiveTypeName(clazz)!!)
override val typeDescriptor = Symbol.valueOf(SerializerFactory.primitiveTypeName(clazz)!!)!!
override val type: Type = clazz
// NOOP since this is a primitive type.

View File

@ -78,6 +78,7 @@ abstract class AbstractAMQPSerializationScheme(
val List<Cordapp>.customSerializers get() = flatMap { it.serializationCustomSerializers }.toSet()
}
// Parameter "context" is unused directy but passed in by reflection. Removing it will cause failures.
private fun registerCustomSerializers(context: SerializationContext, factory: SerializerFactory) {
with(factory) {
register(publicKeySerializer)

View File

@ -1,4 +1,5 @@
@file:JvmName("AMQPSerializerFactories")
package net.corda.nodeapi.internal.serialization.amqp
import net.corda.core.serialization.SerializationContext

View File

@ -9,6 +9,7 @@
*/
@file:JvmName("AMQPStreams")
package net.corda.nodeapi.internal.serialization.amqp
import net.corda.nodeapi.internal.serialization.ByteBufferInputStream

View File

@ -42,7 +42,7 @@ open class ArraySerializer(override val type: Type, factory: SerializerFactory)
"${type.componentType().typeName}$arrayType"
}
override val typeDescriptor by lazy {
override val typeDescriptor: Symbol by lazy {
Symbol.valueOf("$DESCRIPTOR_DOMAIN:${factory.fingerPrinter.fingerprint(type)}")
}
internal val elementType: Type by lazy { type.componentType() }
@ -105,7 +105,7 @@ abstract class PrimArraySerializer(type: Type, factory: SerializerFactory) : Arr
companion object {
// We don't need to handle the unboxed byte type as that is coercible to a byte array, but
// the other 7 primitive types we do
val primTypes: Map<Type, (SerializerFactory) -> PrimArraySerializer> = mapOf(
private val primTypes: Map<Type, (SerializerFactory) -> PrimArraySerializer> = mapOf(
IntArray::class.java to { f -> PrimIntArraySerializer(f) },
CharArray::class.java to { f -> PrimCharArraySerializer(f) },
BooleanArray::class.java to { f -> PrimBooleanArraySerializer(f) },

View File

@ -24,10 +24,10 @@ import kotlin.collections.LinkedHashSet
/**
* Serialization / deserialization of predefined set of supported [Collection] types covering mostly [List]s and [Set]s.
*/
class CollectionSerializer(val declaredType: ParameterizedType, factory: SerializerFactory) : AMQPSerializer<Any> {
class CollectionSerializer(private val declaredType: ParameterizedType, factory: SerializerFactory) : AMQPSerializer<Any> {
override val type: Type = declaredType as? DeserializedParameterizedType
?: DeserializedParameterizedType.make(SerializerFactory.nameForType(declaredType))
override val typeDescriptor by lazy {
override val typeDescriptor: Symbol by lazy {
Symbol.valueOf("$DESCRIPTOR_DOMAIN:${factory.fingerPrinter.fingerprint(type)}")
}
@ -63,10 +63,8 @@ class CollectionSerializer(val declaredType: ParameterizedType, factory: Seriali
(declaredType as? ParameterizedType)
?: DeserializedParameterizedType(collectionClass, arrayOf(SerializerFactory.AnyType))
private fun findMostSuitableCollectionType(actualClass: Class<*>): Class<out Collection<*>> =
supportedTypes.keys.findLast { it.isAssignableFrom(actualClass) }!!
}
private val concreteBuilder: (List<*>) -> Collection<*> = findConcreteType(declaredType.rawType as Class<*>)

View File

@ -69,7 +69,7 @@ class CorDappCustomSerializer(
override val type = types[CORDAPP_TYPE]
val proxyType = types[PROXY_TYPE]
override val typeDescriptor = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${nameForType(type)}")
override val typeDescriptor: Symbol = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${nameForType(type)}")
val descriptor: Descriptor = Descriptor(typeDescriptor)
private val proxySerializer: ObjectSerializer by lazy { ObjectSerializer(proxyType, factory) }

View File

@ -74,7 +74,7 @@ abstract class CustomSerializer<T : Any> : AMQPSerializer<T>, SerializerFor {
override fun isSerializerFor(clazz: Class<*>): Boolean = clazz == this.clazz
override val type: Type get() = clazz
override val typeDescriptor by lazy {
override val typeDescriptor: Symbol by lazy {
Symbol.valueOf("$DESCRIPTOR_DOMAIN:${SerializerFingerPrinter().fingerprintForDescriptors(superClassSerializer.typeDescriptor.toString(), nameForType(clazz))}")
}
private val typeNotation: TypeNotation = RestrictedType(
@ -110,7 +110,7 @@ abstract class CustomSerializer<T : Any> : AMQPSerializer<T>, SerializerFor {
*/
abstract class CustomSerializerImp<T : Any>(protected val clazz: Class<T>, protected val withInheritance: Boolean) : CustomSerializer<T>() {
override val type: Type get() = clazz
override val typeDescriptor = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${nameForType(clazz)}")
override val typeDescriptor: Symbol = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${nameForType(clazz)}")
override fun writeClassInfo(output: SerializationOutput) {}
override val descriptor: Descriptor = Descriptor(typeDescriptor)
override fun isSerializerFor(clazz: Class<*>): Boolean = if (withInheritance) this.clazz.isAssignableFrom(clazz) else this.clazz == clazz

View File

@ -18,7 +18,6 @@ import net.corda.core.utilities.ByteSequence
import net.corda.nodeapi.internal.serialization.*
import org.apache.qpid.proton.amqp.Binary
import org.apache.qpid.proton.amqp.DescribedType
import org.apache.qpid.proton.amqp.UnsignedByte
import org.apache.qpid.proton.amqp.UnsignedInteger
import org.apache.qpid.proton.codec.Data
import java.io.InputStream
@ -42,28 +41,6 @@ class DeserializationInput @JvmOverloads constructor(private val serializerFacto
private val objectHistory: MutableList<Any> = mutableListOf()
companion object {
private const val BYTES_NEEDED_TO_PEEK: Int = 23
fun peekSize(bytes: ByteArray): Int {
// There's an 8 byte header, and then a 0 byte plus descriptor followed by constructor
val eighth = bytes[8].toInt()
check(eighth == 0x0) { "Expected to find a descriptor in the AMQP stream" }
// We should always have an Envelope, so the descriptor should be a 64-bit long (0x80)
val ninth = UnsignedByte.valueOf(bytes[9]).toInt()
check(ninth == 0x80) { "Expected to find a ulong in the AMQP stream" }
// Skip 8 bytes
val eighteenth = UnsignedByte.valueOf(bytes[18]).toInt()
check(eighteenth == 0xd0 || eighteenth == 0xc0) { "Expected to find a list8 or list32 in the AMQP stream" }
val size = if (eighteenth == 0xc0) {
// Next byte is size
UnsignedByte.valueOf(bytes[19]).toInt() - 3 // Minus three as PEEK_SIZE assumes 4 byte unsigned integer.
} else {
// Next 4 bytes is size
UnsignedByte.valueOf(bytes[19]).toInt().shl(24) + UnsignedByte.valueOf(bytes[20]).toInt().shl(16) + UnsignedByte.valueOf(bytes[21]).toInt().shl(8) + UnsignedByte.valueOf(bytes[22]).toInt()
}
return size + BYTES_NEEDED_TO_PEEK
}
@VisibleForTesting
@Throws(NotSerializableException::class)
fun <T> withDataBytes(byteSequence: ByteSequence, encodingWhitelist: EncodingWhitelist, task: (ByteBuffer) -> T): T {
@ -150,13 +127,12 @@ class DeserializationInput @JvmOverloads constructor(private val serializerFacto
envelope)
}
internal fun readObjectOrNull(obj: Any?, schema: SerializationSchemas, type: Type, context: SerializationContext,
offset: Int = 0
internal fun readObjectOrNull(obj: Any?, schema: SerializationSchemas, type: Type, context: SerializationContext
): Any? {
return if (obj == null) null else readObject(obj, schema, type, context, offset)
return if (obj == null) null else readObject(obj, schema, type, context)
}
internal fun readObject(obj: Any, schemas: SerializationSchemas, type: Type, context: SerializationContext, debugIndent: Int = 0): Any =
internal fun readObject(obj: Any, schemas: SerializationSchemas, type: Type, context: SerializationContext): Any =
if (obj is DescribedType && ReferencedObject.DESCRIPTOR == obj.descriptor) {
// It must be a reference to an instance that has already been read, cheaply and quickly returning it by reference.
val objectIndex = (obj.described as UnsignedInteger).toInt()

View File

@ -38,7 +38,7 @@ class DeserializedParameterizedType(private val rawType: Class<*>, private val p
private val _typeName: String = makeTypeName()
private fun makeTypeName(): String {
val paramsJoined = params.map { it.typeName }.joinToString(", ")
val paramsJoined = params.joinToString(", ") { it.typeName }
return "${rawType.name}<$paramsJoined>"
}
@ -155,14 +155,14 @@ class DeserializedParameterizedType(private val rawType: Class<*>, private val p
}
override fun equals(other: Any?): Boolean {
if (other is ParameterizedType) {
return if (other is ParameterizedType) {
if (this === other) {
return true
true
} else {
return this.ownerType == other.ownerType && this.rawType == other.rawType && Arrays.equals(this.actualTypeArguments, other.actualTypeArguments)
this.ownerType == other.ownerType && this.rawType == other.rawType && Arrays.equals(this.actualTypeArguments, other.actualTypeArguments)
}
} else {
return false
false
}
}
}

View File

@ -101,7 +101,7 @@ abstract class EvolutionSerializer(
val constructorArgs = arrayOfNulls<Any?>(constructor.parameters.size)
constructor.parameters.withIndex().forEach {
readersAsSerialized.get(it.value.name!!)?.apply {
readersAsSerialized[it.value.name!!]?.apply {
this.resultsIndex = it.index
} ?: if (!it.value.type.isMarkedNullable) {
throw NotSerializableException(

View File

@ -104,7 +104,7 @@ class SerializerFingerPrinter : FingerPrinter {
// serialise the object in the first place (and thus the cache lookup fails). This is also
// true of Any, where we need Example<A, B> and Example<?, ?> to have the same fingerprint
return if ((type in alreadySeen)
&& (type !is SerializerFactory.AnyType)
&& (type !== SerializerFactory.AnyType)
&& (type !is TypeVariable<*>)
&& (type !is WildcardType)) {
hasher.putUnencodedChars(ALREADY_SEEN_HASH)

View File

@ -33,7 +33,7 @@ open class ObjectSerializer(val clazz: Type, factory: SerializerFactory) : AMQPS
private val logger = contextLogger()
}
open internal val propertySerializers: PropertySerializers by lazy {
internal open val propertySerializers: PropertySerializers by lazy {
propertiesForSerialization(kotlinConstructor, clazz, factory)
}
@ -42,12 +42,12 @@ open class ObjectSerializer(val clazz: Type, factory: SerializerFactory) : AMQPS
private val typeName = nameForType(clazz)
override val typeDescriptor = Symbol.valueOf(
"$DESCRIPTOR_DOMAIN:${factory.fingerPrinter.fingerprint(type)}")
"$DESCRIPTOR_DOMAIN:${factory.fingerPrinter.fingerprint(type)}")!!
// We restrict to only those annotated or whitelisted
private val interfaces = interfacesForSerialization(clazz, factory)
open internal val typeNotation: TypeNotation by lazy {
internal open val typeNotation: TypeNotation by lazy {
CompositeType(typeName, null, generateProvides(), Descriptor(typeDescriptor), generateFields())
}

View File

@ -89,7 +89,7 @@ class PrivatePropertyReader(val field: Field, parentType: Type) : PropertyReader
// So this used to report as an error, but given we serialise exceptions all the time it
// provides for very scary log files so move this to trace level
loggerFor<PropertySerializer>().let { logger ->
logger.trace("Using kotlin introspection on internal type ${field}")
logger.trace("Using kotlin introspection on internal type $field")
logger.trace("Unexpected internal Kotlin error", e)
}
true

View File

@ -134,18 +134,18 @@ open class SerializationOutput @JvmOverloads constructor(
// assigned to them first as they will be first read from the stream on receiving end.
// Skip for primitive types as they are too small and overhead of referencing them will be much higher than their content
if (suitableForObjectReference(obj.javaClass)) {
objectHistory.put(obj, objectHistory.size)
objectHistory[obj] = objectHistory.size
}
} else {
data.writeReferencedObject(ReferencedObject(retrievedRefCount))
}
}
open internal fun writeTypeNotations(vararg typeNotation: TypeNotation): Boolean {
internal open fun writeTypeNotations(vararg typeNotation: TypeNotation): Boolean {
return schemaHistory.addAll(typeNotation)
}
open internal fun requireSerializer(type: Type) {
internal open fun requireSerializer(type: Type) {
if (type != SerializerFactory.AnyType && type != Object::class.java) {
val serializer = serializerFactory.get(null, type)
if (serializer !in serializerHistory) {

View File

@ -154,7 +154,7 @@ open class SerializerFactory(
return if (actualClass.typeParameters.isNotEmpty()) {
// The actual class can never have type variables resolved, due to the JVM's use of type erasure, so let's try and resolve them
// Search for declared type in the inheritance hierarchy and then see if that fills in all the variables
val implementationChain: List<Type>? = findPathToDeclared(actualClass, declaredType, mutableListOf<Type>())
val implementationChain: List<Type>? = findPathToDeclared(actualClass, declaredType, mutableListOf())
if (implementationChain != null) {
val start = implementationChain.last()
val rest = implementationChain.dropLast(1).drop(1)
@ -315,6 +315,7 @@ open class SerializerFactory(
return if (declaredSuperClass == null
|| !customSerializer.isSerializerFor(declaredSuperClass)
|| !customSerializer.revealSubclassesInSchema) {
@Suppress("UNCHECKED_CAST")
customSerializer as? AMQPSerializer<Any>
} else {
// Make a subclass serializer for the subclass and return that...

View File

@ -22,7 +22,7 @@ import java.lang.reflect.Type
*/
class SingletonSerializer(override val type: Class<*>, val singleton: Any, factory: SerializerFactory) : AMQPSerializer<Any> {
override val typeDescriptor = Symbol.valueOf(
"$DESCRIPTOR_DOMAIN:${factory.fingerPrinter.fingerprint(type)}")
"$DESCRIPTOR_DOMAIN:${factory.fingerPrinter.fingerprint(type)}")!!
private val interfaces = interfacesForSerialization(type, factory)

View File

@ -82,7 +82,7 @@ abstract class Transform : DescribedType {
*/
class UnknownTransform : Transform() {
companion object : DescribedTypeConstructor<UnknownTransform> {
val typeName = "UnknownTransform"
const val typeName = "UnknownTransform"
override fun newInstance(obj: Any?) = UnknownTransform()
@ -100,7 +100,7 @@ class UnknownTransform : Transform() {
*/
class UnknownTestTransform(val a: Int, val b: Int, val c: Int) : Transform() {
companion object : DescribedTypeConstructor<UnknownTestTransform> {
val typeName = "UnknownTest"
const val typeName = "UnknownTest"
override fun newInstance(obj: Any?): UnknownTestTransform {
val described = obj as List<*>
@ -127,7 +127,7 @@ class EnumDefaultSchemaTransform(val old: String, val new: String) : Transform()
/**
* Value encoded into the schema that identifies a transform as this type
*/
val typeName = "EnumDefault"
const val typeName = "EnumDefault"
override fun newInstance(obj: Any?): EnumDefaultSchemaTransform {
val described = obj as List<*>
@ -164,7 +164,7 @@ class RenameSchemaTransform(val from: String, val to: String) : Transform() {
/**
* Value encoded into the schema that identifies a transform as this type
*/
val typeName = "Rename"
const val typeName = "Rename"
override fun newInstance(obj: Any?): RenameSchemaTransform {
val described = obj as List<*>
@ -223,9 +223,7 @@ data class TransformsSchema(val types: Map<String, EnumMap<TransformTypes, Mutab
// we're explicitly rejecting repeated annotations, whilst it's fine and we'd just
// ignore them it feels like a good thing to alert the user to since this is
// more than likely a typo in their code so best make it an actual error
if (transforms.computeIfAbsent(transform.enum) { mutableListOf() }
.filter { t == it }
.isNotEmpty()) {
if (transforms.computeIfAbsent(transform.enum) { mutableListOf() }.any { t == it }) {
throw NotSerializableException(
"Repeated unique transformation annotation of type ${t.name}")
}

View File

@ -12,6 +12,7 @@ package net.corda.nodeapi.internal.serialization.amqp.custom
import net.corda.nodeapi.internal.serialization.amqp.CustomSerializer
import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory
import java.lang.reflect.Method
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.ZoneOffset
@ -24,7 +25,7 @@ class ZonedDateTimeSerializer(factory: SerializerFactory) : CustomSerializer.Pro
// Java deserialization of `ZonedDateTime` uses a private method. We will resolve this somewhat statically
// so that any change to internals of `ZonedDateTime` is detected early.
companion object {
val ofLenient = ZonedDateTime::class.java.getDeclaredMethod("ofLenient", LocalDateTime::class.java, ZoneOffset::class.java, ZoneId::class.java)
val ofLenient: Method = ZonedDateTime::class.java.getDeclaredMethod("ofLenient", LocalDateTime::class.java, ZoneOffset::class.java, ZoneId::class.java)
init {
ofLenient.isAccessible = true

View File

@ -134,14 +134,14 @@ fun String.stripGenerics(): String = if (this.endsWith('>')) {
this.substring(0, this.indexOf('<'))
} else this
fun AMQPField.getTypeAsClass(classloader: ClassLoader) = typeStrToType[Pair(type, mandatory)] ?: when (type) {
fun AMQPField.getTypeAsClass(classloader: ClassLoader) = (typeStrToType[Pair(type, mandatory)] ?: when (type) {
"string" -> String::class.java
"binary" -> ByteArray::class.java
"*" -> if (requires.isEmpty()) Any::class.java else {
classloader.loadClass(requires[0].stripGenerics())
}
else -> classloader.loadClass(type.stripGenerics())
}
})!!
fun AMQPField.validateType(classloader: ClassLoader) =
when (type) {

View File

@ -16,7 +16,7 @@ import com.esotericsoftware.kryo.serializers.ClosureSerializer
import java.io.Serializable
object CordaClosureSerializer : ClosureSerializer() {
val ERROR_MESSAGE = "Unable to serialize Java Lambda expression, unless explicitly declared e.g., Runnable r = (Runnable & Serializable) () -> System.out.println(\"Hello world!\");"
const val ERROR_MESSAGE = "Unable to serialize Java Lambda expression, unless explicitly declared e.g., Runnable r = (Runnable & Serializable) () -> System.out.println(\"Hello world!\");"
override fun write(kryo: Kryo, output: Output, target: Any) {
if (!isSerializable(target)) {
@ -31,7 +31,7 @@ object CordaClosureSerializer : ClosureSerializer() {
}
object CordaClosureBlacklistSerializer : ClosureSerializer() {
val ERROR_MESSAGE = "Java 8 Lambda expressions are not supported for serialization."
const val ERROR_MESSAGE = "Java 8 Lambda expressions are not supported for serialization."
override fun write(kryo: Kryo, output: Output, target: Any) {
throw IllegalArgumentException(ERROR_MESSAGE)

View File

@ -226,6 +226,7 @@ object DefaultKryoCustomizer {
if (kryo.serializationContext() != null) {
val attachmentHash = SecureHash.SHA256(input.readBytes(32))
val contract = input.readString()
@Suppress("UNCHECKED_CAST")
val additionalContracts = kryo.readClassAndObject(input) as Set<ContractClassName>
val uploader = input.readString()
val context = kryo.serializationContext()!!
@ -243,6 +244,7 @@ object DefaultKryoCustomizer {
} else {
val attachment = GeneratedAttachment(input.readBytesWithLength())
val contract = input.readString()
@Suppress("UNCHECKED_CAST")
val additionalContracts = kryo.readClassAndObject(input) as Set<ContractClassName>
val uploader = input.readString()
return ContractAttachment(attachment, contract, additionalContracts, uploader)

View File

@ -9,6 +9,7 @@
*/
@file:JvmName("KryoStreams")
package net.corda.nodeapi.internal.serialization.kryo
import com.esotericsoftware.kryo.io.Input

View File

@ -53,7 +53,7 @@ public final class ForbiddenLambdaSerializationTests {
assertThat(throwable).isNotNull();
assertThat(throwable).isInstanceOf(IllegalArgumentException.class);
if (ctx != SerializationContext.UseCase.RPCServer && ctx != SerializationContext.UseCase.Storage) {
assertThat(throwable).hasMessage(CordaClosureBlacklistSerializer.INSTANCE.getERROR_MESSAGE());
assertThat(throwable).hasMessage(CordaClosureBlacklistSerializer.ERROR_MESSAGE);
} else {
assertThat(throwable).hasMessageContaining("RPC not allowed to deserialise internal classes");
}
@ -75,7 +75,7 @@ public final class ForbiddenLambdaSerializationTests {
assertThat(throwable).isInstanceOf(IllegalArgumentException.class);
assertThat(throwable).isInstanceOf(IllegalArgumentException.class);
if (ctx != SerializationContext.UseCase.RPCServer && ctx != SerializationContext.UseCase.Storage) {
assertThat(throwable).hasMessage(CordaClosureBlacklistSerializer.INSTANCE.getERROR_MESSAGE());
assertThat(throwable).hasMessage(CordaClosureBlacklistSerializer.ERROR_MESSAGE);
} else {
assertThat(throwable).hasMessageContaining("RPC not allowed to deserialise internal classes");
}

View File

@ -61,7 +61,7 @@ public final class LambdaCheckpointSerializationTest {
assertThat(throwable).isNotNull();
assertThat(throwable).isInstanceOf(IllegalArgumentException.class);
assertThat(throwable).hasMessage(CordaClosureSerializer.INSTANCE.getERROR_MESSAGE());
assertThat(throwable).hasMessage(CordaClosureSerializer.ERROR_MESSAGE);
}
private <T> SerializedBytes<T> serialize(final T target) {

View File

@ -12,7 +12,6 @@ package net.corda.nodeapi.internal.serialization.amqp;
import net.corda.nodeapi.internal.serialization.AllWhitelist;
import net.corda.nodeapi.internal.serialization.amqp.testutils.TestSerializationContext;
import net.corda.nodeapi.internal.serialization.amqp.testutils.TestSerializationContextKt;
import org.assertj.core.api.Assertions;
import org.junit.Ignore;
import org.junit.Test;

View File

@ -1,7 +1,6 @@
package net.corda.nodeapi.internal.serialization.amqp;
import com.google.common.collect.ImmutableList;
import kotlin.Suppress;
import net.corda.core.contracts.ContractState;
import net.corda.core.identity.AbstractParty;
import net.corda.core.serialization.SerializedBytes;

View File

@ -10,22 +10,17 @@
package net.corda.nodeapi.internal.serialization.amqp;
import com.google.common.collect.ImmutableList;
import net.corda.core.contracts.ContractState;
import net.corda.core.identity.AbstractParty;
import net.corda.core.serialization.ConstructorForDeserialization;
import net.corda.nodeapi.internal.serialization.AllWhitelist;
import net.corda.core.serialization.SerializedBytes;
import net.corda.nodeapi.internal.serialization.amqp.testutils.TestSerializationContext;
import org.apache.qpid.proton.codec.DecoderImpl;
import org.apache.qpid.proton.codec.EncoderImpl;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import javax.annotation.Nonnull;
import java.io.NotSerializableException;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Objects;
import static org.junit.Assert.assertTrue;

View File

@ -11,7 +11,7 @@ import java.util.Map;
public class TestSerializationContext {
static private Map<Object, Object> serializationProperties = new HashMap<Object, Object>();
private static Map<Object, Object> serializationProperties = new HashMap<>();
public static SerializationContext testSerializationContext = new SerializationContextImpl(
ByteSequence.of(new byte[] { 'c', 'o', 'r', 'd', 'a', (byte)0, (byte)0, (byte)1}),

View File

@ -46,7 +46,7 @@ class AttachmentsClassLoaderStaticContractTests {
class AttachmentDummyContract : Contract {
companion object {
private val ATTACHMENT_PROGRAM_ID = "net.corda.nodeapi.internal.AttachmentsClassLoaderStaticContractTests\$AttachmentDummyContract"
private const val ATTACHMENT_PROGRAM_ID = "net.corda.nodeapi.internal.AttachmentsClassLoaderStaticContractTests\$AttachmentDummyContract"
}
data class State(val magicNumber: Int = 0) : ContractState {

View File

@ -20,7 +20,12 @@ import net.corda.core.internal.declaredField
import net.corda.core.internal.toWireTransaction
import net.corda.core.node.ServiceHub
import net.corda.core.node.services.AttachmentStorage
import net.corda.core.serialization.*
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.MissingAttachmentsException
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationFactory
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
import net.corda.core.utilities.ByteSequence
import net.corda.core.utilities.OpaqueBytes
import net.corda.node.internal.cordapp.CordappLoader
@ -38,10 +43,12 @@ import net.corda.testing.internal.kryoSpecific
import net.corda.testing.internal.rigorousMock
import net.corda.testing.services.MockAttachmentStorage
import org.apache.commons.io.IOUtils
import org.junit.Assert.*
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.net.URL
import java.net.URLClassLoader
@ -135,6 +142,7 @@ class AttachmentsClassLoaderTests {
}
@Test
@Suppress("DEPRECATION")
fun `test overlapping file exception`() {
val storage = attachments
val att0 = attachmentId
@ -147,7 +155,8 @@ class AttachmentsClassLoaderTests {
}
@Test
fun `basic`() {
@Suppress("DEPRECATION")
fun basic() {
val storage = attachments
val att0 = attachmentId
val att1 = storage.importAttachment(fakeAttachment("file1.txt", "some data").inputStream())
@ -159,6 +168,7 @@ class AttachmentsClassLoaderTests {
}
@Test
@Suppress("DEPRECATION")
fun `Check platform independent path handling in attachment jars`() {
val storage = MockAttachmentStorage()
@ -179,6 +189,7 @@ class AttachmentsClassLoaderTests {
}
@Test
@Suppress("DEPRECATION")
fun `loading class AnotherDummyContract`() {
val storage = attachments
val att0 = attachmentId
@ -200,6 +211,7 @@ class AttachmentsClassLoaderTests {
}
@Test
@Suppress("DEPRECATION")
fun `testing Kryo with ClassLoader (with top level class name)`() {
val contract = createContract2Cash()
@ -222,6 +234,7 @@ class AttachmentsClassLoaderTests {
class Data(val contract: Contract)
@Test
@Suppress("DEPRECATION")
fun `testing Kryo with ClassLoader (without top level class name)`() {
val data = Data(createContract2Cash())

View File

@ -28,7 +28,6 @@ import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Rule
import org.junit.Test
import java.security.KeyPair
import java.security.PrivateKey
import java.security.PublicKey
import java.security.SignatureException

View File

@ -28,32 +28,32 @@ import kotlin.reflect.full.primaryConstructor
class ConfigParsingTest {
@Test
fun `String`() {
fun String() {
testPropertyType<StringData, StringListData, String>("hello world!", "bye")
}
@Test
fun `Int`() {
fun Int() {
testPropertyType<IntData, IntListData, Int>(1, 2)
}
@Test
fun `Long`() {
fun Long() {
testPropertyType<LongData, LongListData, Long>(Long.MAX_VALUE, Long.MIN_VALUE)
}
@Test
fun `Double`() {
fun Double() {
testPropertyType<DoubleData, DoubleListData, Double>(1.2, 3.4)
}
@Test
fun `Boolean`() {
fun Boolean() {
testPropertyType<BooleanData, BooleanListData, Boolean>(true, false)
}
@Test
fun `Enum`() {
fun Enum() {
testPropertyType<EnumData, EnumListData, TestEnum>(TestEnum.Value2, TestEnum.Value1, valuesToString = true)
}
@ -66,17 +66,17 @@ class ConfigParsingTest {
}
@Test
fun `LocalDate`() {
fun LocalDate() {
testPropertyType<LocalDateData, LocalDateListData, LocalDate>(LocalDate.now(), LocalDate.now().plusDays(1), valuesToString = true)
}
@Test
fun `Instant`() {
fun Instant() {
testPropertyType<InstantData, InstantListData, Instant>(Instant.now(), Instant.now().plusMillis(100), valuesToString = true)
}
@Test
fun `NetworkHostAndPort`() {
fun NetworkHostAndPort() {
testPropertyType<NetworkHostAndPortData, NetworkHostAndPortListData, NetworkHostAndPort>(
NetworkHostAndPort("localhost", 2223),
NetworkHostAndPort("localhost", 2225),
@ -84,18 +84,18 @@ class ConfigParsingTest {
}
@Test
fun `Path`() {
fun Path() {
val path = "tmp" / "test"
testPropertyType<PathData, PathListData, Path>(path, path / "file", valuesToString = true)
}
@Test
fun `URL`() {
fun URL() {
testPropertyType<URLData, URLListData, URL>(URL("http://localhost:1234"), URL("http://localhost:1235"), valuesToString = true)
}
@Test
fun `UUID`() {
fun UUID() {
testPropertyType<UUIDData, UUIDListData, UUID>(UUID.randomUUID(), UUID.randomUUID(), valuesToString = true)
}
@ -146,7 +146,7 @@ class ConfigParsingTest {
}
@Test
fun `Set`() {
fun Set() {
val data = StringSetData(setOf("a", "b"))
assertThat(config("values" to listOf("a", "a", "b")).parseAs<StringSetData>()).isEqualTo(data)
assertThat(data.toConfig()).isEqualTo(config("values" to listOf("a", "b")))

View File

@ -24,7 +24,6 @@ import rx.schedulers.TestScheduler
import java.nio.file.Path
import java.time.Duration
import java.util.concurrent.TimeUnit
import kotlin.streams.toList
class NodeInfoFilesCopierTest {
companion object {
@ -123,7 +122,7 @@ class NodeInfoFilesCopierTest {
}
@Test
fun `clear`() {
fun clear() {
// Configure 2 nodes.
nodeInfoFilesCopier.addConfig(node1RootPath)
nodeInfoFilesCopier.addConfig(node2RootPath)

View File

@ -65,7 +65,7 @@ class MapsSerializationTest {
val wrongPayloadType = WrongPayloadType(payload)
assertThatThrownBy { wrongPayloadType.serialize() }
.isInstanceOf(IllegalArgumentException::class.java).hasMessageContaining(
"Map type class java.util.HashMap is unstable under iteration. Suggested fix: use java.util.LinkedHashMap instead.")
"Map type class java.util.HashMap is unstable under iteration. Suggested fix: use java.util.LinkedHashMap instead.")
}
@CordaSerializable

View File

@ -50,7 +50,6 @@ class PrivateKeySerializationTest(private val privateKey: PrivateKey, private va
fun `failed with wrong UseCase`() {
assertThatThrownBy { privateKey.serialize(context = SerializationDefaults.P2P_CONTEXT) }
.isInstanceOf(IllegalStateException::class.java)
.hasMessageContaining("UseCase '${P2P}' is not within")
.hasMessageContaining("UseCase '$P2P' is not within")
}
}

View File

@ -407,6 +407,7 @@ class EnumEvolvabilityTests {
val f = sf.javaClass.getDeclaredField("transformsCache")
f.isAccessible = true
@Suppress("UNCHECKED_CAST")
val transformsCache = f.get(sf) as ConcurrentHashMap<String, EnumMap<TransformTypes, MutableList<Transform>>>
assertEquals(0, transformsCache.size)

View File

@ -25,7 +25,7 @@ class ErrorMessagesTests {
val VERBOSE get() = false
}
private fun errMsg(property:String, testname: String) =
private fun errMsg(property: String, testname: String) =
"Property '$property' or its getter is non public, this renders class 'class $testname\$C' unserializable -> class $testname\$C"
// Java allows this to be set at the class level yet Kotlin doesn't for some reason

View File

@ -17,7 +17,7 @@ import net.corda.nodeapi.internal.serialization.AllWhitelist
import net.corda.nodeapi.internal.serialization.amqp.testutils.TestSerializationOutput
import net.corda.nodeapi.internal.serialization.amqp.testutils.serializeAndReturnSchema
class FingerPrinterTesting : FingerPrinter {
class FingerPrinterTesting : FingerPrinter {
private var index = 0
private val cache = mutableMapOf<Type, String>()
@ -39,18 +39,19 @@ class FingerPrinterTestingTests {
companion object {
const val VERBOSE = true
}
@Test
fun testingTest() {
val fpt = FingerPrinterTesting()
assertEquals ("0", fpt.fingerprint(Integer::class.java))
assertEquals ("1", fpt.fingerprint(String::class.java))
assertEquals ("0", fpt.fingerprint(Integer::class.java))
assertEquals ("1", fpt.fingerprint(String::class.java))
assertEquals("0", fpt.fingerprint(Integer::class.java))
assertEquals("1", fpt.fingerprint(String::class.java))
assertEquals("0", fpt.fingerprint(Integer::class.java))
assertEquals("1", fpt.fingerprint(String::class.java))
}
@Test
fun worksAsReplacement() {
data class C (val a: Int, val b: Long)
data class C(val a: Int, val b: Long)
val factory = SerializerFactory(
AllWhitelist,
@ -60,8 +61,7 @@ class FingerPrinterTestingTests {
val blob = TestSerializationOutput(VERBOSE, factory).serializeAndReturnSchema(C(1, 2L))
assertEquals (1, blob.schema.types.size)
assertEquals ("<descriptor name=\"net.corda:0\"/>", blob.schema.types[0].descriptor.toString())
assertEquals(1, blob.schema.types.size)
assertEquals("<descriptor name=\"net.corda:0\"/>", blob.schema.types[0].descriptor.toString())
}
}

View File

@ -31,7 +31,7 @@ class OverridePKSerializerTest {
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput,
context: SerializationContext
) : PublicKey {
): PublicKey {
throw SerializerTestException("Custom read call")
}

View File

@ -10,9 +10,10 @@ import org.junit.Test
class RoundTripTests {
@Test
fun mutableBecomesImmutable() {
data class C(val l : MutableList<String>)
data class C(val l: MutableList<String>)
val factory = testDefaultFactoryNoEvolution()
val bytes = SerializationOutput(factory).serialize(C(mutableListOf ("a", "b", "c")))
val bytes = SerializationOutput(factory).serialize(C(mutableListOf("a", "b", "c")))
val newC = DeserializationInput(factory).deserialize(bytes)
Assertions.assertThatThrownBy {
@ -23,15 +24,16 @@ class RoundTripTests {
@Test
fun mutableStillMutable() {
class C {
val l : MutableList<String>
val l: MutableList<String>
@Suppress("Unused")
constructor (l : MutableList<String>) {
constructor (l: MutableList<String>) {
this.l = l.toMutableList()
}
}
val factory = testDefaultFactoryNoEvolution()
val bytes = SerializationOutput(factory).serialize(C(mutableListOf ("a", "b", "c")))
val bytes = SerializationOutput(factory).serialize(C(mutableListOf("a", "b", "c")))
val newC = DeserializationInput(factory).deserialize(bytes)
newC.l.add("d")
@ -39,14 +41,14 @@ class RoundTripTests {
@Test
fun mutableStillMutable2() {
data class C (val l : MutableList<String>){
data class C(val l: MutableList<String>) {
@ConstructorForDeserialization
@Suppress("Unused")
constructor (l : Collection<String>) : this (l.toMutableList())
constructor (l: Collection<String>) : this(l.toMutableList())
}
val factory = testDefaultFactoryNoEvolution()
val bytes = SerializationOutput(factory).serialize(C(mutableListOf ("a", "b", "c")))
val bytes = SerializationOutput(factory).serialize(C(mutableListOf("a", "b", "c")))
val newC = DeserializationInput(factory).deserialize(bytes)
newC.l.add("d")
@ -54,10 +56,11 @@ class RoundTripTests {
@Test
fun mutableBecomesImmutable4() {
data class C(val l : List<String>)
data class C(val l: List<String>)
val factory = testDefaultFactoryNoEvolution()
val bytes = SerializationOutput(factory).serialize(C(listOf ("a", "b", "c")))
val bytes = SerializationOutput(factory).serialize(C(listOf("a", "b", "c")))
val newC = DeserializationInput(factory).deserialize(bytes)
val newC2 = newC.copy (l = (newC.l + "d"))
val newC2 = newC.copy(l = (newC.l + "d"))
}
}

View File

@ -17,7 +17,13 @@ import com.nhaarman.mockito_kotlin.whenever
import net.corda.client.rpc.RPCException
import net.corda.core.CordaException
import net.corda.core.CordaRuntimeException
import net.corda.core.contracts.*
import net.corda.core.contracts.Amount
import net.corda.core.contracts.Contract
import net.corda.core.contracts.ContractAttachment
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.PrivacySalt
import net.corda.core.contracts.StateRef
import net.corda.core.contracts.TransactionState
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.secureRandomBytes
@ -26,25 +32,47 @@ import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.AbstractAttachment
import net.corda.core.internal.x500Name
import net.corda.core.serialization.*
import net.corda.core.serialization.ConstructorForDeserialization
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.EncodingWhitelist
import net.corda.core.serialization.MissingAttachmentsException
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationFactory
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.utilities.OpaqueBytes
import net.corda.nodeapi.internal.DEV_INTERMEDIATE_CA
import net.corda.nodeapi.internal.crypto.ContentSignerBuilder
import net.corda.nodeapi.internal.serialization.*
import net.corda.nodeapi.internal.serialization.AllWhitelist
import net.corda.nodeapi.internal.serialization.CordaSerializationEncoding
import net.corda.nodeapi.internal.serialization.EmptyWhitelist
import net.corda.nodeapi.internal.serialization.GeneratedAttachment
import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.Companion.isPrimitive
import net.corda.nodeapi.internal.serialization.amqp.testutils.*
import net.corda.nodeapi.internal.serialization.carpenter.ClassCarpenterImpl
import net.corda.nodeapi.internal.serialization.amqp.testutils.deserialize
import net.corda.nodeapi.internal.serialization.amqp.testutils.serialize
import net.corda.nodeapi.internal.serialization.amqp.testutils.testDefaultFactory
import net.corda.nodeapi.internal.serialization.amqp.testutils.testDefaultFactoryNoEvolution
import net.corda.nodeapi.internal.serialization.amqp.testutils.testSerializationContext
import net.corda.nodeapi.internal.serialization.encodingNotPermittedFormat
import net.corda.testing.contracts.DummyContract
import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.core.TestIdentity
import net.corda.testing.internal.rigorousMock
import org.apache.activemq.artemis.api.core.SimpleString
import org.apache.qpid.proton.amqp.*
import org.apache.qpid.proton.amqp.Decimal128
import org.apache.qpid.proton.amqp.Decimal32
import org.apache.qpid.proton.amqp.Decimal64
import org.apache.qpid.proton.amqp.Symbol
import org.apache.qpid.proton.amqp.UnsignedByte
import org.apache.qpid.proton.amqp.UnsignedInteger
import org.apache.qpid.proton.amqp.UnsignedLong
import org.apache.qpid.proton.amqp.UnsignedShort
import org.apache.qpid.proton.codec.DecoderImpl
import org.apache.qpid.proton.codec.EncoderImpl
import org.assertj.core.api.Assertions.*
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.assertj.core.api.Assertions.catchThrowable
import org.bouncycastle.cert.X509v2CRLBuilder
import org.bouncycastle.cert.jcajce.JcaX509CRLConverter
import org.bouncycastle.jce.provider.BouncyCastleProvider
@ -60,7 +88,20 @@ import java.io.NotSerializableException
import java.math.BigDecimal
import java.math.BigInteger
import java.security.cert.X509CRL
import java.time.*
import java.time.DayOfWeek
import java.time.Duration
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.Month
import java.time.MonthDay
import java.time.OffsetDateTime
import java.time.OffsetTime
import java.time.Period
import java.time.Year
import java.time.YearMonth
import java.time.ZonedDateTime
import java.time.temporal.ChronoUnit
import java.util.*
import kotlin.reflect.full.superclasses
@ -243,7 +284,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi
}
EncoderImpl(decoder)
DeserializationInput.withDataBytes(bytes, encodingWhitelist) {
decoder.setByteBuffer(it)
decoder.byteBuffer = it
// Check that a vanilla AMQP decoder can deserialize without schema.
val result = decoder.readObject() as Envelope
assertNotNull(result)
@ -899,7 +940,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi
@Test
fun `test generic in constructor serialize`() {
val obj = GenericSubclass(OtherGeneric<String>())
val obj = GenericSubclass(OtherGeneric())
serdes(obj)
}
@ -1196,7 +1237,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi
factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.BigDecimalSerializer)
factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.CurrencySerializer)
val c = C(Amount<Currency>(100, BigDecimal("1.5"), Currency.getInstance("USD")))
val c = C(Amount(100, BigDecimal("1.5"), Currency.getInstance("USD")))
// were the issue not fixed we'd blow up here
SerializationOutput(factory, compression).serialize(c)

View File

@ -17,8 +17,8 @@ val TESTING_CONTEXT = SerializationContextImpl(amqpMagic,
// Test factory that lets us count the number of serializer registration attempts
class TestSerializerFactory(
wl : ClassWhitelist,
cl : ClassLoader
wl: ClassWhitelist,
cl: ClassLoader
) : SerializerFactory(wl, cl) {
var registerCount = 0
@ -83,16 +83,17 @@ class TestSerializationFactory : SerializationFactory() {
class SerializationSchemaTests {
@Test
fun onlyRegisterCustomSerializersOnce() {
@CordaSerializable data class C(val a: Int)
@CordaSerializable
data class C(val a: Int)
val c = C(1)
val testSerializationFactory = TestSerializationFactory()
val expectedCustomSerializerCount = 40
assertEquals (0, testFactory.registerCount)
c.serialize (testSerializationFactory, TESTING_CONTEXT)
assertEquals (expectedCustomSerializerCount, testFactory.registerCount)
c.serialize (testSerializationFactory, TESTING_CONTEXT)
assertEquals (expectedCustomSerializerCount, testFactory.registerCount)
assertEquals(0, testFactory.registerCount)
c.serialize(testSerializationFactory, TESTING_CONTEXT)
assertEquals(expectedCustomSerializerCount, testFactory.registerCount)
c.serialize(testSerializationFactory, TESTING_CONTEXT)
assertEquals(expectedCustomSerializerCount, testFactory.registerCount)
}
}

View File

@ -78,7 +78,6 @@ class StaticInitialisationOfSerializedObjectTest {
assertEquals(1, serialisersByType.size)
}
@Test
fun deserializeTest() {
data class D(val c: C2)
@ -109,8 +108,7 @@ class StaticInitialisationOfSerializedObjectTest {
// Version of a serializer factory that will allow the class carpenter living on the
// factory to have a different whitelist applied to it than the factory
class TestSerializerFactory(wl1: ClassWhitelist, wl2: ClassWhitelist) :
SerializerFactory(wl1, ClassCarpenterImpl(ClassLoader.getSystemClassLoader(), wl2)) {
}
SerializerFactory(wl1, ClassCarpenterImpl(ClassLoader.getSystemClassLoader(), wl2))
// This time have the serialization factory and the carpenter use different whitelists
@Test

View File

@ -27,7 +27,7 @@ class TestClassLoader(private var exclude: List<String>) : ClassLoader() {
}
interface TestInterface {
fun runThing() : Int
fun runThing(): Int
}
// Create a custom serialization factory where we need to be able to both specify a carpenter
@ -63,10 +63,10 @@ class CarpenterExceptionTests {
val a1 = CLA().loadClass(A::class.java.name)
val a2 = CLB().loadClass(A::class.java.name)
assertTrue (TypeToken.of(a1).isSubtypeOf(a2))
assertTrue (a1 is Type)
assertTrue (a2 is Type)
assertTrue (a3 is Type)
assertTrue(TypeToken.of(a1).isSubtypeOf(a2))
assertTrue(a1 is Type)
assertTrue(a2 is Type)
assertTrue(a3 is Type)
assertEquals(a1, a2)
assertEquals(a1, a3)
assertEquals(a2, a3)
@ -74,11 +74,11 @@ class CarpenterExceptionTests {
@Test
fun carpenterExceptionRethrownAsNotSerializableException() {
data class C2 (val i: Int) : TestInterface {
data class C2(val i: Int) : TestInterface {
override fun runThing() = 1
}
data class C1 (val i: Int, val c: C2)
data class C1(val i: Int, val c: C2)
// We need two factories to ensure when we deserialize the blob we don't just use the serializer
// we built to serialise things

View File

@ -50,7 +50,7 @@ fun Schema.mangleNames(names: List<String>): Schema {
* rather than have it create its own
*/
class SerializerFactoryExternalCarpenter(classCarpenter: ClassCarpenter)
: SerializerFactory (classCarpenter.whitelist, classCarpenter)
: SerializerFactory(classCarpenter.whitelist, classCarpenter)
open class AmqpCarpenterBase(whitelist: ClassWhitelist) {
var cc = ClassCarpenterImpl(whitelist = whitelist)

View File

@ -63,7 +63,8 @@ class ClassCarpenterWhitelistTest {
// it's marked as CordaSerializable
@Test
fun notWhitelistedButAnnotated() {
@CordaSerializable data class A(val a: Int)
@CordaSerializable
data class A(val a: Int)
class WL : ClassWhitelist {
override fun hasListed(type: Class<*>) = false

View File

@ -108,6 +108,5 @@ class MultiMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase(AllWhi
assertEquals(pinochio.getMethod("getA").invoke(p), amqpObj.a)
assertEquals(pinochio.getMethod("getB").invoke(p), amqpObj.b)
}
}