mirror of
https://github.com/corda/corda.git
synced 2025-06-13 20:58:19 +00:00
Merge branch 'master' into tudor_merge_os_24_10
# Conflicts: # core/src/main/kotlin/net/corda/core/internal/JarSignatureCollector.kt # core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt # core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt # core/src/main/kotlin/net/corda/core/utilities/KotlinUtils.kt # core/src/test/kotlin/net/corda/core/contracts/PackageOwnershipVerificationTests.kt # core/src/test/kotlin/net/corda/core/internal/JarSignatureCollectorTest.kt # node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt # node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt # testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TestDSL.kt # testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TransactionDSLInterpreter.kt # testing/test-utils/src/main/kotlin/net/corda/testing/internal/MockCordappProvider.kt
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
package net.corda.nodeapi.internal
|
||||
|
||||
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
||||
import io.github.classgraph.ClassGraph
|
||||
import net.corda.core.contracts.Contract
|
||||
import net.corda.core.contracts.ContractClassName
|
||||
import net.corda.core.contracts.UpgradedContract
|
||||
@ -28,15 +28,13 @@ class ContractsJarFile(private val file: Path) : ContractsJar {
|
||||
override val hash: SecureHash by lazy(LazyThreadSafetyMode.NONE, file::hash)
|
||||
|
||||
override fun scan(): List<ContractClassName> {
|
||||
val scanResult = FastClasspathScanner()
|
||||
// A set of a single element may look odd, but if this is removed "Path" which itself is an `Iterable`
|
||||
// is getting broken into pieces to scan individually, which doesn't yield desired effect.
|
||||
.overrideClasspath(singleton(file))
|
||||
.scan()
|
||||
val scanResult = ClassGraph().overrideClasspath(singleton(file)).enableAllInfo().scan()
|
||||
|
||||
val contractClassNames = coreContractClasses
|
||||
.flatMap { scanResult.getNamesOfClassesImplementing(it.qualifiedName) }
|
||||
.toSet()
|
||||
val contractClassNames = scanResult.use {
|
||||
coreContractClasses
|
||||
.flatMap { scanResult.getClassesImplementing(it.qualifiedName).names }
|
||||
.toSet()
|
||||
}
|
||||
|
||||
return URLClassLoader(arrayOf(file.toUri().toURL()), Contract::class.java.classLoader).use { cl ->
|
||||
contractClassNames.mapNotNull {
|
||||
|
@ -2,7 +2,7 @@ package net.corda.nodeapi.internal
|
||||
|
||||
import com.github.benmanes.caffeine.cache.CacheLoader
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import net.corda.core.internal.buildNamed
|
||||
import net.corda.core.internal.NamedCacheFactory
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
@ -10,11 +10,10 @@ import java.util.concurrent.atomic.AtomicLong
|
||||
/**
|
||||
* A class allowing the deduplication of a strictly incrementing sequence number.
|
||||
*/
|
||||
class DeduplicationChecker(cacheExpiry: Duration, name: String = "DeduplicationChecker") {
|
||||
class DeduplicationChecker(cacheExpiry: Duration, name: String = "DeduplicationChecker", cacheFactory: NamedCacheFactory) {
|
||||
// dedupe identity -> watermark cache
|
||||
private val watermarkCache = Caffeine.newBuilder()
|
||||
.expireAfterAccess(cacheExpiry.toNanos(), TimeUnit.NANOSECONDS)
|
||||
.buildNamed("${name}_watermark", WatermarkCacheLoader)
|
||||
private val watermarkCache = cacheFactory.buildNamed(Caffeine.newBuilder()
|
||||
.expireAfterAccess(cacheExpiry.toNanos(), TimeUnit.NANOSECONDS), "${name}_watermark", WatermarkCacheLoader)
|
||||
|
||||
private object WatermarkCacheLoader : CacheLoader<Any, AtomicLong> {
|
||||
override fun load(key: Any) = AtomicLong(-1)
|
||||
|
@ -30,9 +30,9 @@ object DevIdentityGenerator {
|
||||
/** Install a node key store for the given node directory using the given legal name. */
|
||||
fun installKeyStoreWithNodeIdentity(nodeDir: Path, legalName: CordaX500Name): Party {
|
||||
val certificatesDirectory = nodeDir / "certificates"
|
||||
val signingCertStore = FileBasedCertificateStoreSupplier(certificatesDirectory / "nodekeystore.jks", "cordacadevpass")
|
||||
val p2pKeyStore = FileBasedCertificateStoreSupplier(certificatesDirectory / "sslkeystore.jks", "cordacadevpass")
|
||||
val p2pTrustStore = FileBasedCertificateStoreSupplier(certificatesDirectory / "truststore.jks", "trustpass")
|
||||
val signingCertStore = FileBasedCertificateStoreSupplier(certificatesDirectory / "nodekeystore.jks", DEV_CA_KEY_STORE_PASS, DEV_CA_KEY_STORE_PASS)
|
||||
val p2pKeyStore = FileBasedCertificateStoreSupplier(certificatesDirectory / "sslkeystore.jks", DEV_CA_KEY_STORE_PASS, DEV_CA_KEY_STORE_PASS)
|
||||
val p2pTrustStore = FileBasedCertificateStoreSupplier(certificatesDirectory / "truststore.jks", DEV_CA_TRUST_STORE_PASS, DEV_CA_TRUST_STORE_PRIVATE_KEY_PASS)
|
||||
val p2pSslConfig = SslConfiguration.mutual(p2pKeyStore, p2pTrustStore)
|
||||
|
||||
certificatesDirectory.createDirectories()
|
||||
@ -77,13 +77,16 @@ object DevIdentityGenerator {
|
||||
publicKey)
|
||||
}
|
||||
val distServKeyStoreFile = (nodeDir / "certificates").createDirectories() / "distributedService.jks"
|
||||
X509KeyStore.fromFile(distServKeyStoreFile, "cordacadevpass", createNew = true).update {
|
||||
X509KeyStore.fromFile(distServKeyStoreFile, DEV_CA_KEY_STORE_PASS, createNew = true).update {
|
||||
setCertificate("$DISTRIBUTED_NOTARY_ALIAS_PREFIX-composite-key", compositeKeyCert)
|
||||
setPrivateKey(
|
||||
"$DISTRIBUTED_NOTARY_ALIAS_PREFIX-private-key",
|
||||
keyPair.private,
|
||||
listOf(serviceKeyCert, DEV_INTERMEDIATE_CA.certificate, DEV_ROOT_CA.certificate),
|
||||
"cordacadevkeypass")
|
||||
DEV_CA_KEY_STORE_PASS // Unfortunately we have to use the same password for private key due to Artemis limitation, for more details please see:
|
||||
// org.apache.activemq.artemis.core.remoting.impl.ssl.SSLSupport.loadKeyManagerFactory
|
||||
// where it is calling `KeyManagerFactory.init()` with store password
|
||||
/*DEV_CA_PRIVATE_KEY_PASS*/)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,8 @@ fun CertificateStore.registerDevSigningCertificates(legalName: CordaX500Name,
|
||||
devNodeCa: CertificateAndKeyPair = createDevNodeCa(intermediateCa, legalName)) {
|
||||
|
||||
update {
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_CA, devNodeCa.keyPair.private, listOf(devNodeCa.certificate, intermediateCa.certificate, rootCert))
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_CA, devNodeCa.keyPair.private, listOf(devNodeCa.certificate, intermediateCa.certificate, rootCert),
|
||||
this@registerDevSigningCertificates.entryPassword)
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +40,8 @@ fun CertificateStore.registerDevP2pCertificates(legalName: CordaX500Name,
|
||||
update {
|
||||
val tlsKeyPair = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val tlsCert = X509Utilities.createCertificate(CertificateType.TLS, devNodeCa.certificate, devNodeCa.keyPair, legalName.x500Principal, tlsKeyPair.public)
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_TLS, tlsKeyPair.private, listOf(tlsCert, devNodeCa.certificate, intermediateCa.certificate, rootCert))
|
||||
setPrivateKey(X509Utilities.CORDA_CLIENT_TLS, tlsKeyPair.private, listOf(tlsCert, devNodeCa.certificate, intermediateCa.certificate, rootCert),
|
||||
this@registerDevP2pCertificates.entryPassword)
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,15 +49,14 @@ fun CertificateStore.storeLegalIdentity(alias: String, keyPair: KeyPair = Crypto
|
||||
val identityCertPath = query {
|
||||
val nodeCaCertPath = getCertificateChain(X509Utilities.CORDA_CLIENT_CA)
|
||||
// Assume key password = store password.
|
||||
val nodeCaCertAndKeyPair = getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA)
|
||||
val nodeCaCertAndKeyPair = getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, this@storeLegalIdentity.entryPassword)
|
||||
// Create new keys and store in keystore.
|
||||
val identityCert = X509Utilities.createCertificate(CertificateType.LEGAL_IDENTITY, nodeCaCertAndKeyPair.certificate, nodeCaCertAndKeyPair.keyPair, nodeCaCertAndKeyPair.certificate.subjectX500Principal, keyPair.public)
|
||||
// TODO: X509Utilities.validateCertificateChain()
|
||||
// Assume key password = store password.
|
||||
listOf(identityCert) + nodeCaCertPath
|
||||
}
|
||||
update {
|
||||
setPrivateKey(alias, keyPair.private, identityCertPath)
|
||||
setPrivateKey(alias, keyPair.private, identityCertPath, this@storeLegalIdentity.entryPassword)
|
||||
}
|
||||
return PartyAndCertificate(X509Utilities.buildCertPath(identityCertPath))
|
||||
}
|
||||
@ -96,6 +97,9 @@ const val DEV_CA_KEY_STORE_FILE: String = "cordadevcakeys.jks"
|
||||
const val DEV_CA_KEY_STORE_PASS: String = "cordacadevpass"
|
||||
const val DEV_CA_TRUST_STORE_FILE: String = "cordatruststore.jks"
|
||||
const val DEV_CA_TRUST_STORE_PASS: String = "trustpass"
|
||||
const val DEV_CA_TRUST_STORE_PRIVATE_KEY_PASS: String = "trustpasskeypass"
|
||||
|
||||
val DEV_CERTIFICATES: List<X509Certificate> get() = listOf(DEV_INTERMEDIATE_CA.certificate, DEV_ROOT_CA.certificate)
|
||||
|
||||
// We need a class so that we can get hold of the class loader
|
||||
internal object DevCaHelper {
|
||||
@ -104,6 +108,8 @@ internal object DevCaHelper {
|
||||
}
|
||||
}
|
||||
|
||||
fun loadDevCaKeyStore(classLoader: ClassLoader = DevCaHelper::class.java.classLoader): CertificateStore = CertificateStore.fromResource("certificates/$DEV_CA_KEY_STORE_FILE", DEV_CA_KEY_STORE_PASS, classLoader)
|
||||
fun loadDevCaKeyStore(classLoader: ClassLoader = DevCaHelper::class.java.classLoader): CertificateStore = CertificateStore.fromResource(
|
||||
"certificates/$DEV_CA_KEY_STORE_FILE", DEV_CA_KEY_STORE_PASS, DEV_CA_PRIVATE_KEY_PASS, classLoader)
|
||||
|
||||
fun loadDevCaTrustStore(classLoader: ClassLoader = DevCaHelper::class.java.classLoader): CertificateStore = CertificateStore.fromResource("certificates/$DEV_CA_TRUST_STORE_FILE", DEV_CA_TRUST_STORE_PASS, classLoader)
|
||||
fun loadDevCaTrustStore(classLoader: ClassLoader = DevCaHelper::class.java.classLoader): CertificateStore = CertificateStore.fromResource(
|
||||
"certificates/$DEV_CA_TRUST_STORE_FILE", DEV_CA_TRUST_STORE_PASS, DEV_CA_TRUST_STORE_PRIVATE_KEY_PASS, classLoader)
|
||||
|
@ -2,4 +2,3 @@ package net.corda.nodeapi.internal
|
||||
|
||||
// TODO: Add to Corda node.conf to allow customisation
|
||||
const val NODE_INFO_DIRECTORY = "additional-node-infos"
|
||||
const val PLATFORM_VERSION = 4
|
||||
|
@ -14,17 +14,18 @@ interface CertificateStore : Iterable<Pair<String, X509Certificate>> {
|
||||
|
||||
companion object {
|
||||
|
||||
fun of(store: X509KeyStore, password: String): CertificateStore = DelegatingCertificateStore(store, password)
|
||||
fun of(store: X509KeyStore, password: String, entryPassword: String): CertificateStore = DelegatingCertificateStore(store, password, entryPassword)
|
||||
|
||||
fun fromFile(storePath: Path, password: String, createNew: Boolean): CertificateStore = DelegatingCertificateStore(X509KeyStore.fromFile(storePath, password, createNew), password)
|
||||
fun fromFile(storePath: Path, password: String, entryPassword: String, createNew: Boolean): CertificateStore = DelegatingCertificateStore(X509KeyStore.fromFile(storePath, password, createNew), password, entryPassword)
|
||||
|
||||
fun fromInputStream(stream: InputStream, password: String): CertificateStore = DelegatingCertificateStore(X509KeyStore.fromInputStream(stream, password), password)
|
||||
fun fromInputStream(stream: InputStream, password: String, entryPassword: String): CertificateStore = DelegatingCertificateStore(X509KeyStore.fromInputStream(stream, password), password, entryPassword)
|
||||
|
||||
fun fromResource(storeResourceName: String, password: String, classLoader: ClassLoader = Thread.currentThread().contextClassLoader): CertificateStore = fromInputStream(classLoader.getResourceAsStream(storeResourceName), password)
|
||||
fun fromResource(storeResourceName: String, password: String, entryPassword: String, classLoader: ClassLoader = Thread.currentThread().contextClassLoader): CertificateStore = fromInputStream(classLoader.getResourceAsStream(storeResourceName), password, entryPassword)
|
||||
}
|
||||
|
||||
val value: X509KeyStore
|
||||
val password: String
|
||||
val entryPassword: String
|
||||
|
||||
fun writeTo(stream: OutputStream) = value.internal.store(stream, password.toCharArray())
|
||||
|
||||
@ -79,4 +80,4 @@ interface CertificateStore : Iterable<Pair<String, X509Certificate>> {
|
||||
}
|
||||
}
|
||||
|
||||
private class DelegatingCertificateStore(override val value: X509KeyStore, override val password: String) : CertificateStore
|
||||
private class DelegatingCertificateStore(override val value: X509KeyStore, override val password: String, override val entryPassword: String) : CertificateStore
|
@ -18,7 +18,7 @@ interface CertificateStoreSupplier {
|
||||
}
|
||||
|
||||
// TODO replace reference to FileBasedCertificateStoreSupplier with CertificateStoreSupplier, after coming up with a way of passing certificate stores to Artemis.
|
||||
class FileBasedCertificateStoreSupplier(val path: Path, val password: String) : CertificateStoreSupplier {
|
||||
class FileBasedCertificateStoreSupplier(val path: Path, val storePassword: String, val entryPassword: String) : CertificateStoreSupplier {
|
||||
|
||||
override fun get(createNew: Boolean) = CertificateStore.fromFile(path, password, createNew)
|
||||
override fun get(createNew: Boolean) = CertificateStore.fromFile(path, storePassword, entryPassword, createNew)
|
||||
}
|
@ -151,7 +151,7 @@ private fun Config.getSingleValue(path: String, type: KType, onUnknownKeys: (Set
|
||||
|
||||
private fun ConfigException.Missing.relative(path: String, nestedPath: String?): ConfigException.Missing {
|
||||
return when {
|
||||
nestedPath != null -> throw ConfigException.Missing("$nestedPath.$path")
|
||||
nestedPath != null -> throw ConfigException.Missing("$nestedPath.$path", this)
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
@ -53,17 +53,17 @@ class X509KeyStore private constructor(val internal: KeyStore, private val store
|
||||
return uncheckedCast(certArray.asList())
|
||||
}
|
||||
|
||||
fun getCertificateAndKeyPair(alias: String, keyPassword: String = storePassword): CertificateAndKeyPair {
|
||||
fun getCertificateAndKeyPair(alias: String, keyPassword: String): CertificateAndKeyPair {
|
||||
val cert = getCertificate(alias)
|
||||
val publicKey = Crypto.toSupportedPublicKey(cert.publicKey)
|
||||
return CertificateAndKeyPair(cert, KeyPair(publicKey, getPrivateKey(alias, keyPassword)))
|
||||
}
|
||||
|
||||
fun getPrivateKey(alias: String, keyPassword: String = storePassword): PrivateKey {
|
||||
fun getPrivateKey(alias: String, keyPassword: String): PrivateKey {
|
||||
return internal.getSupportedKey(alias, keyPassword)
|
||||
}
|
||||
|
||||
fun setPrivateKey(alias: String, key: PrivateKey, certificates: List<X509Certificate>, keyPassword: String = storePassword) {
|
||||
fun setPrivateKey(alias: String, key: PrivateKey, certificates: List<X509Certificate>, keyPassword: String) {
|
||||
internal.setKeyEntry(alias, key, keyPassword.toCharArray(), certificates.toTypedArray())
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ import net.corda.core.node.services.AttachmentId
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.internal.SerializationEnvironmentImpl
|
||||
import net.corda.core.serialization.internal.SerializationEnvironment
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.utilities.days
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
@ -34,6 +34,7 @@ import java.time.Instant
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.jar.JarInputStream
|
||||
import kotlin.collections.component1
|
||||
import kotlin.collections.component2
|
||||
import kotlin.collections.set
|
||||
@ -64,7 +65,7 @@ internal constructor(private val initSerEnv: Boolean,
|
||||
"java",
|
||||
"-jar",
|
||||
"corda.jar",
|
||||
"--just-generate-node-info"
|
||||
"generate-node-info"
|
||||
)
|
||||
|
||||
private const val LOGS_DIR_NAME = "logs"
|
||||
@ -125,8 +126,8 @@ internal constructor(private val initSerEnv: Boolean,
|
||||
}
|
||||
return clusteredNotaries.groupBy { it.first }.map { (k, vs) ->
|
||||
val cs = vs.map { it.second.config }
|
||||
if (cs.any { it.hasPath("notary.bftSMaRt") }) {
|
||||
require(cs.all { it.hasPath("notary.bftSMaRt") }) { "Mix of BFT and non-BFT notaries with service name $k" }
|
||||
if (cs.any { isBFTNotary(it) }) {
|
||||
require(cs.all { isBFTNotary(it) }) { "Mix of BFT and non-BFT notaries with service name $k" }
|
||||
NotaryCluster.BFT(k) to vs.map { it.second.directory }
|
||||
} else {
|
||||
NotaryCluster.CFT(k) to vs.map { it.second.directory }
|
||||
@ -134,6 +135,12 @@ internal constructor(private val initSerEnv: Boolean,
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
private fun isBFTNotary(config: Config): Boolean {
|
||||
// TODO: pass a commandline parameter to the bootstrapper instead. Better yet, a notary config map
|
||||
// specifying the notary identities and the type (single-node, CFT, BFT) of each notary to set up.
|
||||
return config.getString ("notary.className").contains("BFT", true)
|
||||
}
|
||||
|
||||
private fun generateServiceIdentitiesForNotaryClusters(configs: Map<Path, Config>) {
|
||||
notaryClusters(configs).forEach { (cluster, directories) ->
|
||||
when (cluster) {
|
||||
@ -161,16 +168,23 @@ internal constructor(private val initSerEnv: Boolean,
|
||||
}
|
||||
|
||||
/** Entry point for the tool */
|
||||
fun bootstrap(directory: Path, copyCordapps: Boolean) {
|
||||
fun bootstrap(directory: Path, copyCordapps: Boolean, minimumPlatformVersion: Int) {
|
||||
require(minimumPlatformVersion <= PLATFORM_VERSION) { "Minimum platform version cannot be greater than $PLATFORM_VERSION" }
|
||||
// Don't accidently include the bootstrapper jar as a CorDapp!
|
||||
val bootstrapperJar = javaClass.location.toPath()
|
||||
val cordappJars = directory.list { paths ->
|
||||
paths.filter { it.toString().endsWith(".jar") && !it.isSameAs(bootstrapperJar) && it.fileName.toString() != "corda.jar" }.toList()
|
||||
}
|
||||
bootstrap(directory, cordappJars, copyCordapps, fromCordform = false)
|
||||
bootstrap(directory, cordappJars, copyCordapps, fromCordform = false, minimumPlatformVersion = minimumPlatformVersion)
|
||||
}
|
||||
|
||||
private fun bootstrap(directory: Path, cordappJars: List<Path>, copyCordapps: Boolean, fromCordform: Boolean) {
|
||||
private fun bootstrap(
|
||||
directory: Path,
|
||||
cordappJars: List<Path>,
|
||||
copyCordapps: Boolean,
|
||||
fromCordform: Boolean,
|
||||
minimumPlatformVersion: Int = PLATFORM_VERSION
|
||||
) {
|
||||
directory.createDirectories()
|
||||
println("Bootstrapping local test network in $directory")
|
||||
if (!fromCordform) {
|
||||
@ -208,8 +222,8 @@ internal constructor(private val initSerEnv: Boolean,
|
||||
println("Gathering notary identities")
|
||||
val notaryInfos = gatherNotaryInfos(nodeInfoFiles, configs)
|
||||
println("Generating contract implementations whitelist")
|
||||
val newWhitelist = generateWhitelist(existingNetParams, readExcludeWhitelist(directory), cordappJars.map(contractsJarConverter))
|
||||
val newNetParams = installNetworkParameters(notaryInfos, newWhitelist, existingNetParams, nodeDirs)
|
||||
val newWhitelist = generateWhitelist(existingNetParams, readExcludeWhitelist(directory), cordappJars.filter { !isSigned(it) }.map(contractsJarConverter))
|
||||
val newNetParams = installNetworkParameters(notaryInfos, newWhitelist, existingNetParams, nodeDirs, minimumPlatformVersion)
|
||||
if (newNetParams != existingNetParams) {
|
||||
println("${if (existingNetParams == null) "New" else "Updated"} $newNetParams")
|
||||
} else {
|
||||
@ -336,10 +350,13 @@ internal constructor(private val initSerEnv: Boolean,
|
||||
throw IllegalStateException(msg.toString())
|
||||
}
|
||||
|
||||
private fun installNetworkParameters(notaryInfos: List<NotaryInfo>,
|
||||
whitelist: Map<String, List<AttachmentId>>,
|
||||
existingNetParams: NetworkParameters?,
|
||||
nodeDirs: List<Path>): NetworkParameters {
|
||||
private fun installNetworkParameters(
|
||||
notaryInfos: List<NotaryInfo>,
|
||||
whitelist: Map<String, List<AttachmentId>>,
|
||||
existingNetParams: NetworkParameters?,
|
||||
nodeDirs: List<Path>,
|
||||
minimumPlatformVersion: Int
|
||||
): NetworkParameters {
|
||||
// TODO Add config for minimumPlatformVersion, maxMessageSize and maxTransactionSize
|
||||
val netParams = if (existingNetParams != null) {
|
||||
if (existingNetParams.whitelistedContractImplementations == whitelist && existingNetParams.notaries == notaryInfos) {
|
||||
@ -354,7 +371,7 @@ internal constructor(private val initSerEnv: Boolean,
|
||||
}
|
||||
} else {
|
||||
NetworkParameters(
|
||||
minimumPlatformVersion = 4,
|
||||
minimumPlatformVersion = minimumPlatformVersion,
|
||||
notaries = notaryInfos,
|
||||
modifiedTime = Instant.now(),
|
||||
maxMessageSize = 10485760,
|
||||
@ -382,7 +399,7 @@ internal constructor(private val initSerEnv: Boolean,
|
||||
|
||||
// We need to to set serialization env, because generation of parameters is run from Cordform.
|
||||
private fun initialiseSerialization() {
|
||||
_contextSerializationEnv.set(SerializationEnvironmentImpl(
|
||||
_contextSerializationEnv.set(SerializationEnvironment.with(
|
||||
SerializationFactoryImpl().apply {
|
||||
registerScheme(AMQPParametersSerializationScheme)
|
||||
},
|
||||
@ -398,4 +415,10 @@ internal constructor(private val initSerEnv: Boolean,
|
||||
return magic == amqpMagic && target == SerializationContext.UseCase.P2P
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSigned(file: Path): Boolean = file.read {
|
||||
JarInputStream(it).use {
|
||||
JarSignatureCollector.collectSigningParties(it).isNotEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.corda.nodeapi.internal.persistence
|
||||
|
||||
import co.paralleluniverse.strands.Strand
|
||||
import net.corda.core.internal.NamedCacheFactory
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import rx.Observable
|
||||
@ -38,7 +39,8 @@ enum class TransactionIsolationLevel {
|
||||
/**
|
||||
* The JDBC constant value of the same name but prefixed with TRANSACTION_ defined in [java.sql.Connection].
|
||||
*/
|
||||
val jdbcValue: Int = java.sql.Connection::class.java.getField("TRANSACTION_$name").get(null) as Int
|
||||
val jdbcString = "TRANSACTION_$name"
|
||||
val jdbcValue: Int = java.sql.Connection::class.java.getField(jdbcString).get(null) as Int
|
||||
}
|
||||
|
||||
private val _contextDatabase = InheritableThreadLocal<CordaPersistence>()
|
||||
@ -51,6 +53,7 @@ class CordaPersistence(
|
||||
databaseConfig: DatabaseConfig,
|
||||
schemas: Set<MappedSchema>,
|
||||
val jdbcUrl: String,
|
||||
cacheFactory: NamedCacheFactory,
|
||||
attributeConverters: Collection<AttributeConverter<*, *>> = emptySet()
|
||||
) : Closeable {
|
||||
companion object {
|
||||
@ -60,9 +63,10 @@ class CordaPersistence(
|
||||
private val defaultIsolationLevel = databaseConfig.transactionIsolationLevel
|
||||
val hibernateConfig: HibernateConfiguration by lazy {
|
||||
transaction {
|
||||
HibernateConfiguration(schemas, databaseConfig, attributeConverters, jdbcUrl)
|
||||
HibernateConfiguration(schemas, databaseConfig, attributeConverters, jdbcUrl, cacheFactory)
|
||||
}
|
||||
}
|
||||
|
||||
val entityManagerFactory get() = hibernateConfig.sessionFactoryForRegisteredSchemas
|
||||
|
||||
data class Boundary(val txId: UUID, val success: Boolean)
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.corda.nodeapi.internal.persistence
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import net.corda.core.internal.buildNamed
|
||||
import net.corda.core.internal.NamedCacheFactory
|
||||
import net.corda.core.internal.castIfPossible
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.core.utilities.contextLogger
|
||||
@ -31,6 +31,7 @@ class HibernateConfiguration(
|
||||
private val databaseConfig: DatabaseConfig,
|
||||
private val attributeConverters: Collection<AttributeConverter<*, *>>,
|
||||
private val jdbcUrl: String,
|
||||
cacheFactory: NamedCacheFactory,
|
||||
val cordappClassLoader: ClassLoader? = null
|
||||
) {
|
||||
companion object {
|
||||
@ -58,7 +59,7 @@ class HibernateConfiguration(
|
||||
}
|
||||
}
|
||||
|
||||
private val sessionFactories = Caffeine.newBuilder().maximumSize(databaseConfig.mappedSchemaCacheSize).buildNamed<Set<MappedSchema>, SessionFactory>("HibernateConfiguration_sessionFactories")
|
||||
private val sessionFactories = cacheFactory.buildNamed<Set<MappedSchema>, SessionFactory>(Caffeine.newBuilder(), "HibernateConfiguration_sessionFactories")
|
||||
|
||||
val sessionFactoryForRegisteredSchemas = schemas.let {
|
||||
logger.info("Init HibernateConfiguration for schemas: $it")
|
||||
|
@ -159,7 +159,9 @@ internal fun initialiseTrustStoreAndEnableCrlChecking(trustStore: CertificateSto
|
||||
return CertPathTrustManagerParameters(pkixParams)
|
||||
}
|
||||
|
||||
fun KeyManagerFactory.init(keyStore: CertificateStore) = init(keyStore.value.internal, keyStore.password.toCharArray())
|
||||
// As per Javadoc in: https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/KeyManagerFactory.html `init` method
|
||||
// 2nd parameter `password` - the password for recovering keys in the KeyStore
|
||||
fun KeyManagerFactory.init(keyStore: CertificateStore) = init(keyStore.value.internal, keyStore.entryPassword.toCharArray())
|
||||
|
||||
fun TrustManagerFactory.init(trustStore: CertificateStore) = init(trustStore.value.internal)
|
||||
|
||||
@ -167,5 +169,5 @@ internal fun x500toHostName(x500Name: CordaX500Name): String {
|
||||
val secureHash = SecureHash.sha256(x500Name.toString())
|
||||
// RFC 1035 specifies a limit 255 bytes for hostnames with each label being 63 bytes or less. Due to this, the string
|
||||
// representation of the SHA256 hash is truncated to 32 characters.
|
||||
return String.format(HOSTNAME_FORMAT, secureHash.toString().substring(0..32).toLowerCase())
|
||||
return String.format(HOSTNAME_FORMAT, secureHash.toString().take(32).toLowerCase())
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.transactions.LedgerTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.node.VersionInfo
|
||||
import net.corda.node.cordapp.CordappLoader
|
||||
import net.corda.node.internal.cordapp.CordappProviderImpl
|
||||
import net.corda.node.internal.cordapp.JarScanningCordappLoader
|
||||
@ -25,16 +24,13 @@ import net.corda.testing.core.SerializationEnvironmentRule
|
||||
import net.corda.testing.core.TestIdentity
|
||||
import net.corda.testing.internal.MockCordappConfigProvider
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
import net.corda.testing.node.internal.TestCordappDirectories
|
||||
import net.corda.testing.node.internal.cordappsForPackages
|
||||
import net.corda.testing.node.internal.getTimestampAsDirectoryName
|
||||
import net.corda.testing.node.internal.packageInDirectory
|
||||
import net.corda.testing.services.MockAttachmentStorage
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
|
||||
class AttachmentsClassLoaderStaticContractTests {
|
||||
private companion object {
|
||||
@ -108,22 +104,11 @@ class AttachmentsClassLoaderStaticContractTests {
|
||||
@Test
|
||||
fun `verify that contract DummyContract is in classPath`() {
|
||||
val contractClass = Class.forName("net.corda.nodeapi.internal.AttachmentsClassLoaderStaticContractTests\$AttachmentDummyContract")
|
||||
val contract = contractClass.newInstance() as Contract
|
||||
|
||||
assertNotNull(contract)
|
||||
assertThat(contractClass.newInstance()).isInstanceOf(Contract::class.java)
|
||||
}
|
||||
|
||||
private fun cordappLoaderForPackages(packages: Iterable<String>): CordappLoader {
|
||||
|
||||
val cordapps = cordappsForPackages(packages)
|
||||
return testDirectory().let { directory ->
|
||||
cordapps.packageInDirectory(directory)
|
||||
JarScanningCordappLoader.fromDirectories(listOf(directory), VersionInfo.UNKNOWN)
|
||||
}
|
||||
private fun cordappLoaderForPackages(packages: Collection<String>): CordappLoader {
|
||||
val dirs = cordappsForPackages(packages).map { TestCordappDirectories.getJarDirectory(it) }
|
||||
return JarScanningCordappLoader.fromDirectories(dirs)
|
||||
}
|
||||
|
||||
private fun testDirectory(): Path {
|
||||
|
||||
return Paths.get("build", getTimestampAsDirectoryName())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -235,8 +235,9 @@ class X509UtilitiesTest {
|
||||
signingCertStore.get(createNew = true).also { it.registerDevSigningCertificates(MEGA_CORP.name, rootCa.certificate, intermediateCa, nodeCa) }
|
||||
p2pSslConfig.keyStore.get(createNew = true).also { it.registerDevP2pCertificates(MEGA_CORP.name, rootCa.certificate, intermediateCa, nodeCa) }
|
||||
// Load back server certificate
|
||||
val serverKeyStore = signingCertStore.get().value
|
||||
val (serverCert, serverKeyPair) = serverKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA)
|
||||
val certStore = signingCertStore.get()
|
||||
val serverKeyStore = certStore.value
|
||||
val (serverCert, serverKeyPair) = serverKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, certStore.entryPassword)
|
||||
|
||||
serverCert.checkValidity()
|
||||
serverCert.verify(intermediateCa.certificate.publicKey)
|
||||
@ -244,7 +245,7 @@ class X509UtilitiesTest {
|
||||
|
||||
// Load back SSL certificate
|
||||
val sslKeyStoreReloaded = p2pSslConfig.keyStore.get()
|
||||
val (sslCert) = sslKeyStoreReloaded.query { getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_TLS, p2pSslConfig.keyStore.password) }
|
||||
val (sslCert) = sslKeyStoreReloaded.query { getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_TLS, sslKeyStoreReloaded.entryPassword) }
|
||||
|
||||
sslCert.checkValidity()
|
||||
sslCert.verify(serverCert.publicKey)
|
||||
|
@ -11,6 +11,7 @@ import net.corda.core.serialization.serialize
|
||||
import net.corda.node.services.config.NotaryConfig
|
||||
import net.corda.nodeapi.internal.DEV_ROOT_CA
|
||||
import net.corda.nodeapi.internal.NODE_INFO_DIRECTORY
|
||||
import net.corda.core.internal.PLATFORM_VERSION
|
||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||
import net.corda.nodeapi.internal.config.parseAs
|
||||
import net.corda.nodeapi.internal.config.toConfig
|
||||
@ -217,7 +218,7 @@ class NetworkBootstrapperTest {
|
||||
|
||||
private fun bootstrap(copyCordapps: Boolean = true) {
|
||||
providedCordaJar = (rootDir / "corda.jar").let { if (it.exists()) it.readAll() else null }
|
||||
bootstrapper.bootstrap(rootDir, copyCordapps)
|
||||
bootstrapper.bootstrap(rootDir, copyCordapps, PLATFORM_VERSION)
|
||||
}
|
||||
|
||||
private fun createNodeConfFile(nodeDirName: String, config: FakeNodeConfig) {
|
||||
|
@ -0,0 +1,37 @@
|
||||
package net.corda.nodeapi.internal.protonwrapper.netty
|
||||
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.nodeapi.internal.config.CertificateStore
|
||||
import net.corda.testing.internal.configureTestSSL
|
||||
import org.junit.Test
|
||||
import javax.net.ssl.KeyManagerFactory
|
||||
import javax.net.ssl.SNIHostName
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class SSLHelperTest {
|
||||
@Test
|
||||
fun `ensure SNI header in correct format`() {
|
||||
val legalName = CordaX500Name("Test", "London", "GB")
|
||||
val sslConfig = configureTestSSL(legalName)
|
||||
|
||||
val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
|
||||
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
||||
|
||||
val keyStore = sslConfig.keyStore
|
||||
keyManagerFactory.init(CertificateStore.fromFile(keyStore.path, keyStore.storePassword, keyStore.entryPassword, false))
|
||||
val trustStore = sslConfig.trustStore
|
||||
trustManagerFactory.init(initialiseTrustStoreAndEnableCrlChecking(CertificateStore.fromFile(trustStore.path, trustStore.storePassword, trustStore.entryPassword, false), false))
|
||||
|
||||
val sslHandler = createClientSslHelper(NetworkHostAndPort("localhost", 1234), setOf(legalName), keyManagerFactory, trustManagerFactory)
|
||||
val legalNameHash = SecureHash.sha256(legalName.toString()).toString().take(32).toLowerCase()
|
||||
|
||||
// These hardcoded values must not be changed, something is broken if you have to change these hardcoded values.
|
||||
assertEquals("O=Test, L=London, C=GB", legalName.toString())
|
||||
assertEquals("f3df3c01a5f5aa5b9d394680cde3a414", legalNameHash)
|
||||
assertEquals(1, sslHandler.engine().sslParameters.serverNames.size)
|
||||
assertEquals("$legalNameHash.corda.net", (sslHandler.engine().sslParameters.serverNames.first() as SNIHostName).asciiName)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user