ENT-3256 Small performance enhancement and OS preparation for ENT changes (#4857)

This commit is contained in:
Rick Parker 2019-03-07 14:47:51 +00:00 committed by GitHub
parent 96b23eea6f
commit 1c38ecee7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 48 additions and 21 deletions

View File

@ -436,7 +436,7 @@ object Crypto {
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
}
require(clearData.isNotEmpty()) { "Signing of an empty array is not permitted!" }
val signature = Signature.getInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName])
val signature = Instances.getSignatureInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName])
// Note that deterministic signature schemes, such as EdDSA, original SPHINCS-256 and RSA PKCS#1, do not require
// extra randomness, but we have to ensure that non-deterministic algorithms (i.e., ECDSA) use non-blocking
// SecureRandom implementation. Also, SPHINCS-256 implementation in BouncyCastle 1.60 fails with
@ -640,7 +640,7 @@ object Crypto {
require(isSupportedSignatureScheme(signatureScheme)) {
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
}
val signature = Signature.getInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName])
val signature = Instances.getSignatureInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName])
signature.initVerify(publicKey)
signature.update(clearData)
return signature.verify(signatureData)

View File

@ -0,0 +1,12 @@
package net.corda.core.crypto.internal
import java.security.Provider
import java.security.Signature
/**
* This is a collection of crypto related getInstance methods that tend to be quite inefficient and we want to be able to
* optimise them en masse.
*/
object Instances {
fun getSignatureInstance(algorithm: String, provider: Provider?) = Signature.getInstance(algorithm, provider)
}

View File

@ -387,7 +387,17 @@ val Class<*>.location: URL get() = protectionDomain.codeSource.location
/** Convenience method to get the package name of a class literal. */
val KClass<*>.packageName: String get() = java.packageName
val Class<*>.packageName: String get() = requireNotNull(`package`?.name) { "$this not defined inside a package" }
val Class<*>.packageName: String get() = requireNotNull(this.packageNameOrNull) { "$this not defined inside a package" }
val Class<*>.packageNameOrNull: String? // This intentionally does not go via `package` as that code path is slow and contended and just ends up doing this.
get() {
val name = this.getName()
val i = name.lastIndexOf('.')
if (i != -1) {
return name.substring(0, i)
} else {
return null
}
}
inline val Class<*>.isAbstractClass: Boolean get() = Modifier.isAbstract(modifiers)

View File

@ -43,7 +43,7 @@ class StatePointerSearch(val state: ContractState) {
val fieldsWithObjects = fields.mapNotNull { field ->
// Ignore classes which have not been loaded.
// Assumption: all required state classes are already loaded.
val packageName = field.type.`package`?.name
val packageName = field.type.packageNameOrNull
if (packageName == null) {
null
} else {
@ -72,7 +72,7 @@ class StatePointerSearch(val state: ContractState) {
is StatePointer<*> -> statePointers.add(obj)
is Iterable<*> -> handleIterable(obj)
else -> {
val packageName = obj.javaClass.`package`.name
val packageName = obj.javaClass.packageNameOrNull ?: ""
val isBlackListed = blackListedPackages.any { packageName.startsWith(it) }
if (isBlackListed.not()) fieldQueue.addAllFields(obj)
}

View File

@ -2,6 +2,7 @@ package net.corda.nodeapi.internal.crypto
import net.corda.core.crypto.Crypto.SPHINCS256_SHA256
import net.corda.core.crypto.SignatureScheme
import net.corda.core.crypto.internal.Instances
import org.bouncycastle.asn1.x509.AlgorithmIdentifier
import org.bouncycastle.operator.ContentSigner
import java.io.OutputStream
@ -17,7 +18,7 @@ import java.security.Signature
object ContentSignerBuilder {
fun build(signatureScheme: SignatureScheme, privateKey: PrivateKey, provider: Provider, random: SecureRandom? = null): ContentSigner {
val sigAlgId = signatureScheme.signatureOID
val sig = Signature.getInstance(signatureScheme.signatureName, provider).apply {
val sig = Instances.getSignatureInstance(signatureScheme.signatureName, provider).apply {
// TODO special handling for Sphincs due to a known BouncyCastle's Sphincs bug we reported.
// It is fixed in BC 161b12, so consider updating the below if-statement after updating BouncyCastle.
if (random != null && signatureScheme != SPHINCS256_SHA256) {

View File

@ -35,7 +35,6 @@ import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.minutes
import net.corda.node.CordaClock
import net.corda.node.VersionInfo
import net.corda.nodeapi.internal.cordapp.CordappLoader
import net.corda.node.internal.classloading.requireAnnotation
import net.corda.node.internal.cordapp.*
import net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy
@ -74,6 +73,7 @@ import net.corda.node.utilities.*
import net.corda.nodeapi.internal.NodeInfoAndSigned
import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.config.CertificateStore
import net.corda.nodeapi.internal.cordapp.CordappLoader
import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_CLIENT_CA
@ -184,7 +184,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
@Suppress("LeakingThis")
val vaultService = makeVaultService(keyManagementService, servicesForResolution, database, cordappLoader).tokenize()
val nodeProperties = NodePropertiesPersistentStore(StubbedNodeUniqueIdProvider::value, database, cacheFactory)
val flowLogicRefFactory = FlowLogicRefFactoryImpl(cordappLoader.appClassLoader)
open val flowLogicRefFactory = FlowLogicRefFactoryImpl(cordappLoader.appClassLoader)
// TODO Cancelling parameters updates - if we do that, how we ensure that no one uses cancelled parameters in the transactions?
val networkMapUpdater = NetworkMapUpdater(
networkMapCache,

View File

@ -1,8 +1,8 @@
package net.corda.node.services.statemachine
import net.corda.core.internal.VisibleForTesting
import com.google.common.primitives.Primitives
import net.corda.core.flows.*
import net.corda.core.internal.VisibleForTesting
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SingletonSerializeAsToken
import java.lang.reflect.ParameterizedType
@ -32,7 +32,7 @@ data class FlowLogicRefImpl internal constructor(val flowLogicClassName: String,
* in response to a potential malicious use or buggy update to an app etc.
*/
// TODO: Replace with a per app classloader/cordapp provider/cordapp loader - this will do for now
class FlowLogicRefFactoryImpl(private val classloader: ClassLoader) : SingletonSerializeAsToken(), FlowLogicRefFactory {
open class FlowLogicRefFactoryImpl(private val classloader: ClassLoader) : SingletonSerializeAsToken(), FlowLogicRefFactory {
override fun create(flowClass: Class<out FlowLogic<*>>, vararg args: Any?): FlowLogicRef {
if (!flowClass.isAnnotationPresent(SchedulableFlow::class.java)) {
throw IllegalFlowLogicException(flowClass, "because it's not a schedulable flow")
@ -63,17 +63,7 @@ class FlowLogicRefFactoryImpl(private val classloader: ClassLoader) : SingletonS
// to avoid requiring only a single constructor.
val argTypes = args.map { it?.javaClass }
val constructor = try {
flowClass.kotlin.constructors.single { ctor ->
// Get the types of the arguments, always boxed (as that's what we get in the invocation).
val ctorTypes = ctor.javaConstructor!!.parameterTypes.map { Primitives.wrap(it) }
if (argTypes.size != ctorTypes.size)
return@single false
for ((argType, ctorType) in argTypes.zip(ctorTypes)) {
if (argType == null) continue // Try and find a match based on the other arguments.
if (!ctorType.isAssignableFrom(argType)) return@single false
}
true
}
findConstructor(flowClass, argTypes)
} catch (e: IllegalArgumentException) {
throw IllegalFlowLogicException(flowClass, "due to ambiguous match against the constructors: $argTypes")
} catch (e: NoSuchElementException) {
@ -85,6 +75,20 @@ class FlowLogicRefFactoryImpl(private val classloader: ClassLoader) : SingletonS
return createKotlin(flowClass, argsMap)
}
protected open fun findConstructor(flowClass: Class<out FlowLogic<*>>, argTypes: List<Class<Any>?>): KFunction<FlowLogic<*>> {
return flowClass.kotlin.constructors.single { ctor ->
// Get the types of the arguments, always boxed (as that's what we get in the invocation).
val ctorTypes = ctor.javaConstructor!!.parameterTypes.map { Primitives.wrap(it) }
if (argTypes.size != ctorTypes.size)
return@single false
for ((argType, ctorType) in argTypes.zip(ctorTypes)) {
if (argType == null) continue // Try and find a match based on the other arguments.
if (!ctorType.isAssignableFrom(argType)) return@single false
}
true
}
}
/**
* Create a [FlowLogicRef] by trying to find a Kotlin constructor that matches the given args.
*