mirror of
https://github.com/corda/corda.git
synced 2025-06-17 22:58:19 +00:00
Merge branch 'master' into shams-master-merge-081217
# Conflicts: # node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/KeyStoreWrapper.kt # node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt # node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt # node/src/test/kotlin/net/corda/node/services/identity/InMemoryIdentityServiceTests.kt # node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt # samples/irs-demo/src/integration-test/kotlin/net/corda/test/spring/SpringDriver.kt # testing/node-driver/src/integration-test/kotlin/net/corda/testing/driver/DriverTests.kt # testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt # testing/node-driver/src/main/kotlin/net/corda/testing/driver/DriverDSL.kt # testing/node-driver/src/main/kotlin/net/corda/testing/internal/DriverDSLImpl.kt # testing/node-driver/src/main/kotlin/net/corda/testing/internal/NodeBasedTest.kt # testing/node-driver/src/main/kotlin/net/corda/testing/internal/RPCDriver.kt # testing/node-driver/src/main/kotlin/net/corda/testing/internal/demorun/DemoRunner.kt # testing/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt # verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt
This commit is contained in:
@ -0,0 +1,63 @@
|
||||
package net.corda.node
|
||||
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.node.services.config.configureDevKeyAndTrustStores
|
||||
import net.corda.nodeapi.config.SSLConfiguration
|
||||
import net.corda.nodeapi.internal.crypto.*
|
||||
import net.corda.testing.ALICE_NAME
|
||||
import net.corda.testing.driver.driver
|
||||
import org.junit.Test
|
||||
import java.nio.file.Path
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class NodeKeystoreCheckTest {
|
||||
@Test
|
||||
fun `node should throw exception if cert path doesn't chain to the trust root`() {
|
||||
driver(startNodesInProcess = true) {
|
||||
// This will fail because there are no keystore configured.
|
||||
assertFailsWith(IllegalArgumentException::class) {
|
||||
startNode(customOverrides = mapOf("devMode" to false)).getOrThrow()
|
||||
}.apply {
|
||||
assertTrue(message?.startsWith("Identity certificate not found. ") ?: false)
|
||||
}
|
||||
|
||||
// Create keystores
|
||||
val keystorePassword = "password"
|
||||
val config = object : SSLConfiguration {
|
||||
override val keyStorePassword: String = keystorePassword
|
||||
override val trustStorePassword: String = keystorePassword
|
||||
override val certificatesDirectory: Path = baseDirectory(ALICE_NAME.toString()) / "certificates"
|
||||
}
|
||||
config.configureDevKeyAndTrustStores(ALICE_NAME)
|
||||
|
||||
// This should pass with correct keystore.
|
||||
val node = startNode(providedName = ALICE_NAME, customOverrides = mapOf("devMode" to false,
|
||||
"keyStorePassword" to keystorePassword,
|
||||
"trustStorePassword" to keystorePassword)).get()
|
||||
node.stop()
|
||||
|
||||
// Fiddle with node keystore.
|
||||
val keystore = loadKeyStore(config.nodeKeystore, config.keyStorePassword)
|
||||
|
||||
// Self signed root
|
||||
val badRootKeyPair = Crypto.generateKeyPair()
|
||||
val badRoot = X509Utilities.createSelfSignedCACertificate(CordaX500Name("Bad Root", "Lodnon", "GB"), badRootKeyPair)
|
||||
val nodeCA = keystore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, config.keyStorePassword)
|
||||
val badNodeCACert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, badRoot, badRootKeyPair, ALICE_NAME, nodeCA.keyPair.public)
|
||||
keystore.setKeyEntry(X509Utilities.CORDA_CLIENT_CA, nodeCA.keyPair.private, config.keyStorePassword.toCharArray(), arrayOf(badNodeCACert.cert, badRoot.cert))
|
||||
keystore.save(config.nodeKeystore, config.keyStorePassword)
|
||||
|
||||
assertFailsWith(IllegalArgumentException::class) {
|
||||
startNode(providedName = ALICE_NAME, customOverrides = mapOf("devMode" to false)).getOrThrow()
|
||||
}.apply {
|
||||
assertEquals("Client CA certificate must chain to the trusted root.", message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -17,11 +17,12 @@ import net.corda.nodeapi.internal.config.User
|
||||
import net.corda.testing.DUMMY_NOTARY
|
||||
import net.corda.testing.driver.NodeHandle
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.node.NotarySpec
|
||||
import net.corda.testing.internal.InternalDriverDSL
|
||||
import net.corda.testing.internal.performance.div
|
||||
import net.corda.testing.internal.performance.startPublishingFixedRateInjector
|
||||
import net.corda.testing.internal.performance.startReporter
|
||||
import net.corda.testing.internal.performance.startTightLoopInjector
|
||||
import net.corda.testing.node.NotarySpec
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
@ -91,7 +92,7 @@ class NodePerformanceTests {
|
||||
driver(startNodesInProcess = true) {
|
||||
val a = startNode(rpcUsers = listOf(User("A", "A", setOf(startFlow<EmptyFlow>())))).get()
|
||||
a as NodeHandle.InProcess
|
||||
val metricRegistry = startReporter(shutdownManager, a.node.services.monitoringService.metrics)
|
||||
val metricRegistry = startReporter((this as InternalDriverDSL).shutdownManager, a.node.services.monitoringService.metrics)
|
||||
a.rpcClientToNode().use("A", "A") { connection ->
|
||||
startPublishingFixedRateInjector(metricRegistry, 8, 5.minutes, 2000L / TimeUnit.SECONDS) {
|
||||
connection.proxy.startFlow(::EmptyFlow).returnValue.get()
|
||||
@ -109,7 +110,7 @@ class NodePerformanceTests {
|
||||
extraCordappPackagesToScan = listOf("net.corda.finance")
|
||||
) {
|
||||
val notary = defaultNotaryNode.getOrThrow() as NodeHandle.InProcess
|
||||
val metricRegistry = startReporter(shutdownManager, notary.node.services.monitoringService.metrics)
|
||||
val metricRegistry = startReporter((this as InternalDriverDSL).shutdownManager, notary.node.services.monitoringService.metrics)
|
||||
notary.rpcClientToNode().use("A", "A") { connection ->
|
||||
println("ISSUING")
|
||||
val doneFutures = (1..100).toList().parallelStream().map {
|
||||
|
@ -1,8 +1,9 @@
|
||||
package net.corda.node.services
|
||||
|
||||
import com.nhaarman.mockito_kotlin.doReturn
|
||||
import com.nhaarman.mockito_kotlin.whenever
|
||||
import net.corda.core.contracts.Contract
|
||||
import net.corda.core.contracts.PartyAndReference
|
||||
import net.corda.core.cordapp.CordappProvider
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.UnexpectedFlowEndException
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
@ -11,34 +12,34 @@ import net.corda.core.internal.concurrent.transpose
|
||||
import net.corda.core.internal.createDirectories
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.internal.toLedgerTransaction
|
||||
import net.corda.core.node.ServicesForResolution
|
||||
import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.serialization.SerializationFactory
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.node.internal.cordapp.CordappLoader
|
||||
import net.corda.node.internal.cordapp.CordappProviderImpl
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.DUMMY_BANK_A
|
||||
import net.corda.testing.DUMMY_NOTARY
|
||||
import net.corda.testing.driver.DriverDSL
|
||||
import net.corda.testing.driver.NodeHandle
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.MockAttachmentStorage
|
||||
import net.corda.testing.rigorousMock
|
||||
import net.corda.testing.withTestSerialization
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.net.URLClassLoader
|
||||
import java.nio.file.Files
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class AttachmentLoadingTests {
|
||||
private class Services : MockServices() {
|
||||
private val provider = CordappProviderImpl(CordappLoader.createDevMode(listOf(isolatedJAR)), attachments)
|
||||
private val cordapp get() = provider.cordapps.first()
|
||||
val attachmentId get() = provider.getCordappAttachmentId(cordapp)!!
|
||||
val appContext get() = provider.getAppContext(cordapp)
|
||||
override val cordappProvider: CordappProvider = provider
|
||||
}
|
||||
private val attachments = MockAttachmentStorage()
|
||||
private val provider = CordappProviderImpl(CordappLoader.createDevMode(listOf(isolatedJAR)), attachments)
|
||||
private val cordapp get() = provider.cordapps.first()
|
||||
private val attachmentId get() = provider.getCordappAttachmentId(cordapp)!!
|
||||
private val appContext get() = provider.getAppContext(cordapp)
|
||||
|
||||
private companion object {
|
||||
private val logger = contextLogger()
|
||||
@ -60,7 +61,7 @@ class AttachmentLoadingTests {
|
||||
|
||||
private fun DriverDSL.installIsolatedCordappTo(nodeName: CordaX500Name) {
|
||||
// Copy the app jar to the first node. The second won't have it.
|
||||
val path = (baseDirectory(nodeName.toString()) / "cordapps").createDirectories() / "isolated.jar"
|
||||
val path = (baseDirectory(nodeName) / "cordapps").createDirectories() / "isolated.jar"
|
||||
logger.info("Installing isolated jar to $path")
|
||||
isolatedJAR.openStream().buffered().use { input ->
|
||||
Files.newOutputStream(path).buffered().use { output ->
|
||||
@ -70,16 +71,17 @@ class AttachmentLoadingTests {
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var services: Services
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
services = Services()
|
||||
private val services = rigorousMock<ServicesForResolution>().also {
|
||||
doReturn(attachments).whenever(it).attachments
|
||||
doReturn(provider).whenever(it).cordappProvider
|
||||
doReturn(rigorousMock<IdentityService>().also {
|
||||
doReturn(null).whenever(it).partyFromKey(DUMMY_BANK_A.owningKey)
|
||||
}).whenever(it).identityService
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test a wire transaction has loaded the correct attachment`() = withTestSerialization {
|
||||
val appClassLoader = services.appContext.classLoader
|
||||
val appClassLoader = appContext.classLoader
|
||||
val contractClass = appClassLoader.loadClass(ISOLATED_CONTRACT_ID).asSubclass(Contract::class.java)
|
||||
val generateInitialMethod = contractClass.getDeclaredMethod("generateInitial", PartyAndReference::class.java, Integer.TYPE, Party::class.java)
|
||||
val contract = contractClass.newInstance()
|
||||
@ -89,8 +91,7 @@ class AttachmentLoadingTests {
|
||||
contract.verify(ledgerTx)
|
||||
|
||||
val actual = ledgerTx.attachments.first()
|
||||
val expected = services.attachments.openAttachment(services.attachmentId)!!
|
||||
|
||||
val expected = attachments.openAttachment(attachmentId)!!
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ import net.corda.node.services.identity.InMemoryIdentityService
|
||||
import net.corda.nodeapi.internal.NodeInfoFilesCopier
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.node.MockKeyManagementService
|
||||
import net.corda.testing.node.makeTestIdentityService
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.contentOf
|
||||
import org.junit.Before
|
||||
@ -47,7 +48,7 @@ class NodeInfoWatcherTest {
|
||||
|
||||
@Before
|
||||
fun start() {
|
||||
val identityService = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
|
||||
val identityService = makeTestIdentityService()
|
||||
keyManagementService = MockKeyManagementService(identityService, ALICE_KEY)
|
||||
nodeInfoWatcher = NodeInfoWatcher(tempFolder.root.toPath(), scheduler)
|
||||
nodeInfoPath = tempFolder.root.toPath() / CordformNode.NODE_INFO_DIRECTORY
|
||||
|
@ -4,10 +4,11 @@
|
||||
package net.corda.node
|
||||
|
||||
import net.corda.node.internal.NodeStartup
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
// Pass the arguments to the Node factory. In the Enterprise edition, this line is modified to point to a subclass.
|
||||
// It will exit the process in case of startup failure and is not intended to be used by embedders. If you want
|
||||
// to embed Node in your own container, instantiate it directly and set up the configuration objects yourself.
|
||||
NodeStartup(args).run()
|
||||
exitProcess(if (NodeStartup(args).run()) 0 else 1)
|
||||
}
|
@ -43,6 +43,7 @@ import net.corda.node.services.config.NotaryConfig
|
||||
import net.corda.node.services.config.configureWithDevSSLCertificate
|
||||
import net.corda.node.services.events.NodeSchedulerService
|
||||
import net.corda.node.services.events.ScheduledActivityObserver
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.node.services.identity.PersistentIdentityService
|
||||
import net.corda.node.services.keys.PersistentKeyManagementService
|
||||
import net.corda.node.services.messaging.MessagingService
|
||||
@ -179,28 +180,34 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
check(started == null) { "Node has already been started" }
|
||||
log.info("Generating nodeInfo ...")
|
||||
initCertificate()
|
||||
val (keyPairs, info) = initNodeInfo()
|
||||
val identityKeypair = keyPairs.first { it.public == info.legalIdentities.first().owningKey }
|
||||
val serialisedNodeInfo = info.serialize()
|
||||
val signature = identityKeypair.sign(serialisedNodeInfo)
|
||||
// TODO: Signed data might not be sufficient for multiple identities, as it only contains one signature.
|
||||
NodeInfoWatcher.saveToFile(configuration.baseDirectory, SignedData(serialisedNodeInfo, signature))
|
||||
val schemaService = NodeSchemaService(cordappLoader.cordappSchemas)
|
||||
val (identity, identityKeyPair) = obtainIdentity(notaryConfig = null)
|
||||
initialiseDatabasePersistence(schemaService, makeIdentityService(identity.certificate)) { database ->
|
||||
val persistentNetworkMapCache = PersistentNetworkMapCache(database)
|
||||
val (keyPairs, info) = initNodeInfo(persistentNetworkMapCache, identity, identityKeyPair)
|
||||
val identityKeypair = keyPairs.first { it.public == info.legalIdentities.first().owningKey }
|
||||
val serialisedNodeInfo = info.serialize()
|
||||
val signature = identityKeypair.sign(serialisedNodeInfo)
|
||||
// TODO: Signed data might not be sufficient for multiple identities, as it only contains one signature.
|
||||
NodeInfoWatcher.saveToFile(configuration.baseDirectory, SignedData(serialisedNodeInfo, signature))
|
||||
}
|
||||
}
|
||||
|
||||
open fun start(): StartedNode<AbstractNode> {
|
||||
check(started == null) { "Node has already been started" }
|
||||
log.info("Node starting up ...")
|
||||
initCertificate()
|
||||
val (keyPairs, info) = initNodeInfo()
|
||||
readNetworkParameters()
|
||||
val schemaService = NodeSchemaService(cordappLoader.cordappSchemas)
|
||||
val identityService = makeIdentityService(info)
|
||||
val (identity, identityKeyPair) = obtainIdentity(notaryConfig = null)
|
||||
val identityService = makeIdentityService(identity.certificate)
|
||||
// Do all of this in a database transaction so anything that might need a connection has one.
|
||||
val (startedImpl, schedulerService) = initialiseDatabasePersistence(schemaService, identityService) { database ->
|
||||
val networkMapCache = NetworkMapCacheImpl(PersistentNetworkMapCache(database), identityService)
|
||||
val (keyPairs, info) = initNodeInfo(networkMapCache, identity, identityKeyPair)
|
||||
identityService.loadIdentities(info.legalIdentitiesAndCerts)
|
||||
val transactionStorage = makeTransactionStorage(database)
|
||||
val stateLoader = StateLoaderImpl(transactionStorage)
|
||||
val nodeServices = makeServices(keyPairs, schemaService, transactionStorage, stateLoader, database, info, identityService)
|
||||
val nodeServices = makeServices(keyPairs, schemaService, transactionStorage, database, info, identityService, networkMapCache)
|
||||
val notaryService = makeNotaryService(nodeServices, database)
|
||||
val smm = makeStateMachineManager(database)
|
||||
val flowStarter = FlowStarterImpl(serverThread, smm)
|
||||
@ -208,7 +215,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
platformClock,
|
||||
database,
|
||||
flowStarter,
|
||||
stateLoader,
|
||||
transactionStorage,
|
||||
unfinishedSchedules = busyNodeLatch,
|
||||
serverThread = serverThread)
|
||||
if (serverThread is ExecutorService) {
|
||||
@ -245,7 +252,6 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
networkMapUpdater.subscribeToNetworkMap()
|
||||
|
||||
// If we successfully loaded network data from database, we set this future to Unit.
|
||||
services.networkMapCache.addNode(info)
|
||||
_nodeReadyFuture.captureLater(services.networkMapCache.nodeReady.map { Unit })
|
||||
|
||||
return startedImpl.apply {
|
||||
@ -269,8 +275,9 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
InteractiveShell.startShell(configuration, rpcOps, userService, _services.identityService, _services.database)
|
||||
}
|
||||
|
||||
private fun initNodeInfo(): Pair<Set<KeyPair>, NodeInfo> {
|
||||
val (identity, identityKeyPair) = obtainIdentity(notaryConfig = null)
|
||||
private fun initNodeInfo(networkMapCache: NetworkMapCacheBaseInternal,
|
||||
identity: PartyAndCertificate,
|
||||
identityKeyPair: KeyPair): Pair<Set<KeyPair>, NodeInfo> {
|
||||
val keyPairs = mutableSetOf(identityKeyPair)
|
||||
|
||||
myNotaryIdentity = configuration.notary?.let {
|
||||
@ -283,12 +290,20 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
identity
|
||||
}
|
||||
}
|
||||
val info = NodeInfo(
|
||||
|
||||
var info = NodeInfo(
|
||||
myAddresses(),
|
||||
setOf(identity, myNotaryIdentity).filterNotNull(),
|
||||
versionInfo.platformVersion,
|
||||
platformClock.instant().toEpochMilli()
|
||||
)
|
||||
// Check if we have already stored a version of 'our own' NodeInfo, this is to avoid regenerating it with
|
||||
// a different timestamp.
|
||||
networkMapCache.getNodesByLegalName(myLegalName).firstOrNull()?.let {
|
||||
if (info.copy(serial = it.serial) == it) {
|
||||
info = it
|
||||
}
|
||||
}
|
||||
return Pair(keyPairs, info)
|
||||
}
|
||||
|
||||
@ -510,7 +525,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
* Builds node internal, advertised, and plugin services.
|
||||
* Returns a list of tokenizable services to be added to the serialisation context.
|
||||
*/
|
||||
private fun makeServices(keyPairs: Set<KeyPair>, schemaService: SchemaService, transactionStorage: WritableTransactionStorage, stateLoader: StateLoader, database: CordaPersistence, info: NodeInfo, identityService: IdentityService): MutableList<Any> {
|
||||
private fun makeServices(keyPairs: Set<KeyPair>, schemaService: SchemaService, transactionStorage: WritableTransactionStorage, database: CordaPersistence, info: NodeInfo, identityService: IdentityServiceInternal, networkMapCache: NetworkMapCacheInternal): MutableList<Any> {
|
||||
checkpointStorage = DBCheckpointStorage()
|
||||
val metrics = MetricRegistry()
|
||||
attachments = NodeAttachmentService(metrics)
|
||||
@ -521,11 +536,11 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
keyManagementService,
|
||||
schemaService,
|
||||
transactionStorage,
|
||||
stateLoader,
|
||||
MonitoringService(metrics),
|
||||
cordappProvider,
|
||||
database,
|
||||
info)
|
||||
info,
|
||||
networkMapCache)
|
||||
network = makeMessagingService(database, info)
|
||||
val tokenizableServices = mutableListOf(attachments, network, services.vaultService,
|
||||
services.keyManagementService, services.identityService, platformClock,
|
||||
@ -564,6 +579,17 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
"or if you don't have one yet, fill out the config file and run corda.jar --initial-registration. " +
|
||||
"Read more at: https://docs.corda.net/permissioning.html"
|
||||
}
|
||||
|
||||
// Check all cert path chain to the trusted root
|
||||
val sslKeystore = loadKeyStore(configuration.sslKeystore, configuration.keyStorePassword)
|
||||
val identitiesKeystore = loadKeyStore(configuration.nodeKeystore, configuration.keyStorePassword)
|
||||
val trustStore = loadKeyStore(configuration.trustStoreFile, configuration.trustStorePassword)
|
||||
val sslRoot = sslKeystore.getCertificateChain(X509Utilities.CORDA_CLIENT_TLS).last()
|
||||
val clientCARoot = identitiesKeystore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA).last()
|
||||
val trustRoot = trustStore.getCertificate(X509Utilities.CORDA_ROOT_CA)
|
||||
|
||||
require(sslRoot == trustRoot) { "TLS certificate must chain to the trusted root." }
|
||||
require(clientCARoot == trustRoot) { "Client CA certificate must chain to the trusted root." }
|
||||
}
|
||||
|
||||
// Specific class so that MockNode can catch it.
|
||||
@ -605,7 +631,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun makeKeyManagementService(identityService: IdentityService, keyPairs: Set<KeyPair>): KeyManagementService {
|
||||
protected open fun makeKeyManagementService(identityService: IdentityServiceInternal, keyPairs: Set<KeyPair>): KeyManagementService {
|
||||
return PersistentKeyManagementService(identityService, keyPairs)
|
||||
}
|
||||
|
||||
@ -639,12 +665,12 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeIdentityService(info: NodeInfo): PersistentIdentityService {
|
||||
private fun makeIdentityService(identityCert: X509Certificate): PersistentIdentityService {
|
||||
val trustStore = KeyStoreWrapper(configuration.trustStoreFile, configuration.trustStorePassword)
|
||||
val caKeyStore = KeyStoreWrapper(configuration.nodeKeystore, configuration.keyStorePassword)
|
||||
val trustRoot = trustStore.getX509Certificate(X509Utilities.CORDA_ROOT_CA)
|
||||
val clientCa = caKeyStore.certificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA)
|
||||
val caCertificates = arrayOf(info.legalIdentitiesAndCerts[0].certificate, clientCa.certificate.cert)
|
||||
val caCertificates = arrayOf(identityCert, clientCa.certificate.cert)
|
||||
return PersistentIdentityService(trustRoot, *caCertificates)
|
||||
}
|
||||
|
||||
@ -735,24 +761,17 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
override val keyManagementService: KeyManagementService,
|
||||
override val schemaService: SchemaService,
|
||||
override val validatedTransactions: WritableTransactionStorage,
|
||||
private val stateLoader: StateLoader,
|
||||
override val monitoringService: MonitoringService,
|
||||
override val cordappProvider: CordappProviderInternal,
|
||||
override val database: CordaPersistence,
|
||||
override val myInfo: NodeInfo
|
||||
) : SingletonSerializeAsToken(), ServiceHubInternal, StateLoader by stateLoader {
|
||||
override val myInfo: NodeInfo,
|
||||
override val networkMapCache: NetworkMapCacheInternal
|
||||
) : SingletonSerializeAsToken(), ServiceHubInternal, StateLoader by validatedTransactions {
|
||||
override val rpcFlows = ArrayList<Class<out FlowLogic<*>>>()
|
||||
override val stateMachineRecordedTransactionMapping = DBTransactionMappingStorage()
|
||||
override val auditService = DummyAuditService()
|
||||
override val transactionVerifierService by lazy { makeTransactionVerifierService() }
|
||||
override val networkMapCache by lazy {
|
||||
NetworkMapCacheImpl(
|
||||
PersistentNetworkMapCache(
|
||||
database,
|
||||
networkParameters.notaries),
|
||||
identityService)
|
||||
}
|
||||
override val vaultService by lazy { makeVaultService(keyManagementService, stateLoader, database.hibernateConfig) }
|
||||
override val vaultService by lazy { makeVaultService(keyManagementService, validatedTransactions, database.hibernateConfig) }
|
||||
override val contractUpgradeService by lazy { ContractUpgradeServiceImpl() }
|
||||
override val attachments: AttachmentStorage get() = this@AbstractNode.attachments
|
||||
override val networkService: MessagingService get() = network
|
||||
|
@ -34,68 +34,79 @@ open class NodeStartup(val args: Array<String>) {
|
||||
val LOGS_CAN_BE_FOUND_IN_STRING = "Logs can be found in"
|
||||
}
|
||||
|
||||
open fun run() {
|
||||
val startTime = System.currentTimeMillis()
|
||||
assertCanNormalizeEmptyPath()
|
||||
val (argsParser, cmdlineOptions) = parseArguments()
|
||||
|
||||
// We do the single node check before we initialise logging so that in case of a double-node start it
|
||||
// doesn't mess with the running node's logs.
|
||||
enforceSingleNodeIsRunning(cmdlineOptions.baseDirectory)
|
||||
|
||||
initLogging(cmdlineOptions)
|
||||
|
||||
val versionInfo = getVersionInfo()
|
||||
|
||||
if (cmdlineOptions.isVersion) {
|
||||
println("${versionInfo.vendor} ${versionInfo.releaseVersion}")
|
||||
println("Revision ${versionInfo.revision}")
|
||||
println("Platform Version ${versionInfo.platformVersion}")
|
||||
exitProcess(0)
|
||||
}
|
||||
|
||||
// Maybe render command line help.
|
||||
if (cmdlineOptions.help) {
|
||||
argsParser.printHelp(System.out)
|
||||
exitProcess(0)
|
||||
}
|
||||
|
||||
drawBanner(versionInfo)
|
||||
Node.printBasicNodeInfo(LOGS_CAN_BE_FOUND_IN_STRING, System.getProperty("log-path"))
|
||||
val conf0 = loadConfigFile(cmdlineOptions)
|
||||
|
||||
val conf = if (cmdlineOptions.bootstrapRaftCluster) {
|
||||
if (conf0 is NodeConfigurationImpl) {
|
||||
println("Bootstrapping raft cluster (starting up as seed node).")
|
||||
// Ignore the configured clusterAddresses to make the node bootstrap a cluster instead of joining.
|
||||
conf0.copy(notary = conf0.notary?.copy(raft = conf0.notary?.raft?.copy(clusterAddresses = emptyList())))
|
||||
} else {
|
||||
println("bootstrap-raft-notaries flag not recognized, exiting...")
|
||||
exitProcess(1)
|
||||
}
|
||||
} else {
|
||||
conf0
|
||||
}
|
||||
|
||||
banJavaSerialisation(conf)
|
||||
preNetworkRegistration(conf)
|
||||
maybeRegisterWithNetworkAndExit(cmdlineOptions, conf)
|
||||
logStartupInfo(versionInfo, cmdlineOptions, conf)
|
||||
|
||||
/**
|
||||
* @return true if the node startup was successful. This value is intended to be the exit code of the process.
|
||||
*/
|
||||
open fun run(): Boolean {
|
||||
try {
|
||||
cmdlineOptions.baseDirectory.createDirectories()
|
||||
startNode(conf, versionInfo, startTime, cmdlineOptions)
|
||||
} catch (e: Exception) {
|
||||
if (e.message?.startsWith("Unknown named curve:") == true) {
|
||||
logger.error("Exception during node startup - ${e.message}. " +
|
||||
"This is a known OpenJDK issue on some Linux distributions, please use OpenJDK from zulu.org or Oracle JDK.")
|
||||
} else
|
||||
logger.error("Exception during node startup", e)
|
||||
exitProcess(1)
|
||||
}
|
||||
val startTime = System.currentTimeMillis()
|
||||
assertCanNormalizeEmptyPath()
|
||||
val (argsParser, cmdlineOptions) = parseArguments()
|
||||
|
||||
logger.info("Node exiting successfully")
|
||||
exitProcess(0)
|
||||
// We do the single node check before we initialise logging so that in case of a double-node start it
|
||||
// doesn't mess with the running node's logs.
|
||||
enforceSingleNodeIsRunning(cmdlineOptions.baseDirectory)
|
||||
|
||||
initLogging(cmdlineOptions)
|
||||
|
||||
val versionInfo = getVersionInfo()
|
||||
|
||||
if (cmdlineOptions.isVersion) {
|
||||
println("${versionInfo.vendor} ${versionInfo.releaseVersion}")
|
||||
println("Revision ${versionInfo.revision}")
|
||||
println("Platform Version ${versionInfo.platformVersion}")
|
||||
return true
|
||||
}
|
||||
|
||||
// Maybe render command line help.
|
||||
if (cmdlineOptions.help) {
|
||||
argsParser.printHelp(System.out)
|
||||
return true
|
||||
}
|
||||
|
||||
drawBanner(versionInfo)
|
||||
Node.printBasicNodeInfo(LOGS_CAN_BE_FOUND_IN_STRING, System.getProperty("log-path"))
|
||||
val conf0 = loadConfigFile(cmdlineOptions)
|
||||
|
||||
val conf = if (cmdlineOptions.bootstrapRaftCluster) {
|
||||
if (conf0 is NodeConfigurationImpl) {
|
||||
println("Bootstrapping raft cluster (starting up as seed node).")
|
||||
// Ignore the configured clusterAddresses to make the node bootstrap a cluster instead of joining.
|
||||
conf0.copy(notary = conf0.notary?.copy(raft = conf0.notary?.raft?.copy(clusterAddresses = emptyList())))
|
||||
} else {
|
||||
println("bootstrap-raft-notaries flag not recognized, exiting...")
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
conf0
|
||||
}
|
||||
|
||||
banJavaSerialisation(conf)
|
||||
preNetworkRegistration(conf)
|
||||
if (shouldRegisterWithNetwork(cmdlineOptions, conf)) {
|
||||
registerWithNetwork(cmdlineOptions, conf)
|
||||
return true
|
||||
}
|
||||
logStartupInfo(versionInfo, cmdlineOptions, conf)
|
||||
|
||||
try {
|
||||
cmdlineOptions.baseDirectory.createDirectories()
|
||||
startNode(conf, versionInfo, startTime, cmdlineOptions)
|
||||
} catch (e: Exception) {
|
||||
if (e.message?.startsWith("Unknown named curve:") == true) {
|
||||
logger.error("Exception during node startup - ${e.message}. " +
|
||||
"This is a known OpenJDK issue on some Linux distributions, please use OpenJDK from zulu.org or Oracle JDK.")
|
||||
} else {
|
||||
logger.error("Exception during node startup", e)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
logger.info("Node exiting successfully")
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
open protected fun preNetworkRegistration(conf: NodeConfiguration) = Unit
|
||||
@ -155,9 +166,13 @@ open class NodeStartup(val args: Array<String>) {
|
||||
logger.info("Starting as node on ${conf.p2pAddress}")
|
||||
}
|
||||
|
||||
open protected fun maybeRegisterWithNetworkAndExit(cmdlineOptions: CmdLineOptions, conf: NodeConfiguration) {
|
||||
private fun shouldRegisterWithNetwork(cmdlineOptions: CmdLineOptions, conf: NodeConfiguration): Boolean {
|
||||
val compatibilityZoneURL = conf.compatibilityZoneURL
|
||||
if (!cmdlineOptions.isRegistration || compatibilityZoneURL == null) return
|
||||
return !(!cmdlineOptions.isRegistration || compatibilityZoneURL == null)
|
||||
}
|
||||
|
||||
open protected fun registerWithNetwork(cmdlineOptions: CmdLineOptions, conf: NodeConfiguration) {
|
||||
val compatibilityZoneURL = conf.compatibilityZoneURL!!
|
||||
println()
|
||||
println("******************************************************************")
|
||||
println("* *")
|
||||
@ -165,15 +180,14 @@ open class NodeStartup(val args: Array<String>) {
|
||||
println("* *")
|
||||
println("******************************************************************")
|
||||
NetworkRegistrationHelper(conf, HTTPNetworkRegistrationService(compatibilityZoneURL)).buildKeystore()
|
||||
exitProcess(0)
|
||||
}
|
||||
|
||||
open protected fun loadConfigFile(cmdlineOptions: CmdLineOptions): NodeConfiguration {
|
||||
try {
|
||||
return cmdlineOptions.loadConfig()
|
||||
} catch (e: ConfigException) {
|
||||
println("Unable to load the configuration file: ${e.rootCause.message}")
|
||||
exitProcess(2)
|
||||
} catch (configException: ConfigException) {
|
||||
println("Unable to load the configuration file: ${configException.rootCause.message}")
|
||||
throw configException
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,11 @@
|
||||
package net.corda.node.internal
|
||||
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.internal.VisibleForTesting
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.StateLoader
|
||||
import net.corda.core.node.services.NotaryService
|
||||
import net.corda.core.node.services.TransactionStorage
|
||||
import net.corda.node.services.api.CheckpointStorage
|
||||
import net.corda.node.services.api.StartedNodeServices
|
||||
import net.corda.node.services.messaging.MessagingService
|
||||
@ -44,17 +41,3 @@ interface StartedNode<out N : AbstractNode> {
|
||||
return internals.internalRegisterFlowFactory(smm, initiatingFlowClass, flowFactory, initiatedFlowClass, track)
|
||||
}
|
||||
}
|
||||
|
||||
class StateLoaderImpl(private val validatedTransactions: TransactionStorage) : StateLoader {
|
||||
@Throws(TransactionResolutionException::class)
|
||||
override fun loadState(stateRef: StateRef): TransactionState<*> {
|
||||
val stx = validatedTransactions.getTransaction(stateRef.txhash) ?: throw TransactionResolutionException(stateRef.txhash)
|
||||
return stx.resolveBaseTransaction(this).outputs[stateRef.index]
|
||||
}
|
||||
|
||||
@Throws(TransactionResolutionException::class)
|
||||
// TODO: future implementation to retrieve contract states from a Vault BLOB store
|
||||
override fun loadStates(stateRefs: Set<StateRef>): Set<StateAndRef<ContractState>> {
|
||||
return (stateRefs.map { StateAndRef(loadState(it), it) }).toSet()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
package net.corda.node.services.api
|
||||
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.IdentityService
|
||||
|
||||
interface IdentityServiceInternal : IdentityService {
|
||||
/** This method exists so it can be mocked with doNothing, rather than having to make up a possibly invalid return value. */
|
||||
fun justVerifyAndRegisterIdentity(identity: PartyAndCertificate) {
|
||||
verifyAndRegisterIdentity(identity)
|
||||
}
|
||||
}
|
@ -50,7 +50,7 @@ fun NodeConfiguration.configureWithDevSSLCertificate() = configureDevKeyAndTrust
|
||||
fun SSLConfiguration.configureDevKeyAndTrustStores(myLegalName: CordaX500Name) {
|
||||
certificatesDirectory.createDirectories()
|
||||
if (!trustStoreFile.exists()) {
|
||||
javaClass.classLoader.getResourceAsStream("certificates/cordatruststore.jks").copyTo(trustStoreFile)
|
||||
loadKeyStore(javaClass.classLoader.getResourceAsStream("certificates/cordatruststore.jks"), "trustpass").save(trustStoreFile, trustStorePassword)
|
||||
}
|
||||
if (!sslKeystore.exists() || !nodeKeystore.exists()) {
|
||||
val caKeyStore = loadKeyStore(javaClass.classLoader.getResourceAsStream("certificates/cordadevcakeys.jks"), "cordacadevpass")
|
||||
|
@ -5,11 +5,11 @@ import net.corda.core.crypto.toStringShort
|
||||
import net.corda.core.identity.*
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.internal.toX509CertHolder
|
||||
import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.node.services.UnknownAnonymousPartyException
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.core.utilities.trace
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import org.bouncycastle.cert.X509CertificateHolder
|
||||
import java.security.InvalidAlgorithmParameterException
|
||||
@ -24,14 +24,8 @@ import javax.annotation.concurrent.ThreadSafe
|
||||
* @param identities initial set of identities for the service, typically only used for unit tests.
|
||||
*/
|
||||
@ThreadSafe
|
||||
class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptySet(),
|
||||
confidentialIdentities: Iterable<PartyAndCertificate> = emptySet(),
|
||||
override val trustRoot: X509Certificate,
|
||||
vararg caCertificates: X509Certificate) : SingletonSerializeAsToken(), IdentityService {
|
||||
constructor(wellKnownIdentities: Iterable<PartyAndCertificate> = emptySet(),
|
||||
confidentialIdentities: Iterable<PartyAndCertificate> = emptySet(),
|
||||
trustRoot: X509CertificateHolder) : this(wellKnownIdentities, confidentialIdentities, trustRoot.cert)
|
||||
|
||||
class InMemoryIdentityService(identities: Iterable<PartyAndCertificate>,
|
||||
trustRoot: X509CertificateHolder) : SingletonSerializeAsToken(), IdentityServiceInternal {
|
||||
companion object {
|
||||
private val log = contextLogger()
|
||||
}
|
||||
@ -40,32 +34,28 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptyS
|
||||
* Certificate store for certificate authority and intermediary certificates.
|
||||
*/
|
||||
override val caCertStore: CertStore
|
||||
override val trustAnchor: TrustAnchor = TrustAnchor(trustRoot, null)
|
||||
override val trustRoot = trustRoot.cert
|
||||
override val trustAnchor: TrustAnchor = TrustAnchor(this.trustRoot, null)
|
||||
private val keyToParties = ConcurrentHashMap<PublicKey, PartyAndCertificate>()
|
||||
private val principalToParties = ConcurrentHashMap<CordaX500Name, PartyAndCertificate>()
|
||||
|
||||
init {
|
||||
val caCertificatesWithRoot: Set<X509Certificate> = caCertificates.toSet() + trustRoot
|
||||
caCertStore = CertStore.getInstance("Collection", CollectionCertStoreParameters(caCertificatesWithRoot))
|
||||
caCertStore = CertStore.getInstance("Collection", CollectionCertStoreParameters(setOf(this.trustRoot)))
|
||||
keyToParties.putAll(identities.associateBy { it.owningKey })
|
||||
principalToParties.putAll(identities.associateBy { it.name })
|
||||
confidentialIdentities.forEach { identity ->
|
||||
principalToParties.computeIfAbsent(identity.name) { identity }
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check the certificate validation logic
|
||||
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
||||
override fun verifyAndRegisterIdentity(identity: PartyAndCertificate): PartyAndCertificate? {
|
||||
// Validate the chain first, before we do anything clever with it
|
||||
try {
|
||||
identity.verify(trustAnchor)
|
||||
} catch (e: CertPathValidatorException) {
|
||||
log.error("Certificate validation failed for ${identity.name} against trusted root ${trustAnchor.trustedCert.subjectX500Principal}.")
|
||||
log.error("Certificate path :")
|
||||
log.warn("Certificate validation failed for ${identity.name} against trusted root ${trustAnchor.trustedCert.subjectX500Principal}.")
|
||||
log.warn("Certificate path :")
|
||||
identity.certPath.certificates.reversed().forEachIndexed { index, certificate ->
|
||||
val space = (0 until index).joinToString("") { " " }
|
||||
log.error("$space${certificate.toX509CertHolder().subject}")
|
||||
log.warn("$space${certificate.toX509CertHolder().subject}")
|
||||
}
|
||||
throw e
|
||||
}
|
||||
|
@ -6,12 +6,12 @@ import net.corda.core.crypto.toStringShort
|
||||
import net.corda.core.identity.*
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.internal.toX509CertHolder
|
||||
import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.node.services.UnknownAnonymousPartyException
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.utilities.MAX_HASH_HEX_SIZE
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.core.utilities.debug
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.node.utilities.AppendOnlyPersistentMap
|
||||
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
@ -27,7 +27,7 @@ import javax.persistence.Lob
|
||||
|
||||
@ThreadSafe
|
||||
class PersistentIdentityService(override val trustRoot: X509Certificate,
|
||||
vararg caCertificates: X509Certificate) : SingletonSerializeAsToken(), IdentityService {
|
||||
vararg caCertificates: X509Certificate) : SingletonSerializeAsToken(), IdentityServiceInternal {
|
||||
constructor(trustRoot: X509CertificateHolder) : this(trustRoot.cert)
|
||||
|
||||
companion object {
|
||||
@ -110,17 +110,16 @@ class PersistentIdentityService(override val trustRoot: X509Certificate,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check the certificate validation logic
|
||||
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
||||
override fun verifyAndRegisterIdentity(identity: PartyAndCertificate): PartyAndCertificate? {
|
||||
// Validate the chain first, before we do anything clever with it
|
||||
try {
|
||||
identity.verify(trustAnchor)
|
||||
} catch (e: CertPathValidatorException) {
|
||||
log.error(e.localizedMessage)
|
||||
log.error("Path = ")
|
||||
log.warn(e.localizedMessage)
|
||||
log.warn("Path = ")
|
||||
identity.certPath.certificates.reversed().forEach {
|
||||
log.error(it.toX509CertHolder().subject.toString())
|
||||
log.warn(it.toX509CertHolder().subject.toString())
|
||||
}
|
||||
throw e
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ package net.corda.node.services.keys
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.ThreadBox
|
||||
import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.node.services.KeyManagementService
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import org.bouncycastle.operator.ContentSigner
|
||||
import java.security.KeyPair
|
||||
import java.security.PrivateKey
|
||||
@ -25,7 +25,7 @@ import javax.annotation.concurrent.ThreadSafe
|
||||
* etc.
|
||||
*/
|
||||
@ThreadSafe
|
||||
class E2ETestKeyManagementService(val identityService: IdentityService,
|
||||
class E2ETestKeyManagementService(val identityService: IdentityServiceInternal,
|
||||
initialKeys: Set<KeyPair>) : SingletonSerializeAsToken(), KeyManagementService {
|
||||
private class InnerState {
|
||||
val keys = HashMap<PublicKey, PrivateKey>()
|
||||
|
@ -4,8 +4,8 @@ import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.internal.toX509CertHolder
|
||||
import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.utilities.days
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.ContentSignerBuilder
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
@ -28,18 +28,18 @@ import java.time.Duration
|
||||
* @param revocationEnabled whether to check revocation status of certificates in the certificate path.
|
||||
* @return X.509 certificate and path to the trust root.
|
||||
*/
|
||||
fun freshCertificate(identityService: IdentityService,
|
||||
fun freshCertificate(identityService: IdentityServiceInternal,
|
||||
subjectPublicKey: PublicKey,
|
||||
issuer: PartyAndCertificate,
|
||||
issuerSigner: ContentSigner,
|
||||
revocationEnabled: Boolean = false): PartyAndCertificate {
|
||||
val issuerCert = issuer.certificate.toX509CertHolder()
|
||||
val window = X509Utilities.getCertificateValidityWindow(Duration.ZERO, 3650.days, issuerCert)
|
||||
val ourCertificate = X509Utilities.createCertificate(CertificateType.IDENTITY, issuerCert.subject,
|
||||
val ourCertificate = X509Utilities.createCertificate(CertificateType.WELL_KNOWN_IDENTITY, issuerCert.subject,
|
||||
issuerSigner, issuer.name, subjectPublicKey, window)
|
||||
val ourCertPath = X509CertificateFactory().generateCertPath(listOf(ourCertificate.cert) + issuer.certPath.certificates)
|
||||
val anonymisedIdentity = PartyAndCertificate(ourCertPath)
|
||||
identityService.verifyAndRegisterIdentity(anonymisedIdentity)
|
||||
identityService.justVerifyAndRegisterIdentity(anonymisedIdentity)
|
||||
return anonymisedIdentity
|
||||
}
|
||||
|
||||
|
@ -2,10 +2,10 @@ package net.corda.node.services.keys
|
||||
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.node.services.KeyManagementService
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.utilities.MAX_HASH_HEX_SIZE
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.node.utilities.AppendOnlyPersistentMap
|
||||
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
|
||||
import org.bouncycastle.operator.ContentSigner
|
||||
@ -24,7 +24,7 @@ import javax.persistence.Lob
|
||||
*
|
||||
* This class needs database transactions to be in-flight during method calls and init.
|
||||
*/
|
||||
class PersistentKeyManagementService(val identityService: IdentityService,
|
||||
class PersistentKeyManagementService(val identityService: IdentityServiceInternal,
|
||||
initialKeys: Set<KeyPair>) : SingletonSerializeAsToken(), KeyManagementService {
|
||||
|
||||
@Entity
|
||||
|
@ -108,6 +108,7 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal,
|
||||
|
||||
// Only publish and write to disk if there are changes to the node info.
|
||||
val signedNodeInfo = signNodeInfo(newInfo)
|
||||
networkMapCache.addNode(newInfo)
|
||||
fileWatcher.saveToFile(signedNodeInfo)
|
||||
|
||||
if (networkMapClient != null) {
|
||||
|
@ -19,6 +19,7 @@ import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.node.services.api.NetworkMapCacheBaseInternal
|
||||
import net.corda.node.services.api.NetworkMapCacheInternal
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
@ -38,13 +39,22 @@ class NetworkMapCacheImpl(
|
||||
networkMapCacheBase: NetworkMapCacheBaseInternal,
|
||||
private val identityService: IdentityService
|
||||
) : NetworkMapCacheBaseInternal by networkMapCacheBase, NetworkMapCacheInternal {
|
||||
companion object {
|
||||
private val logger = loggerFor<NetworkMapCacheImpl>()
|
||||
}
|
||||
|
||||
init {
|
||||
networkMapCacheBase.allNodes.forEach { it.legalIdentitiesAndCerts.forEach { identityService.verifyAndRegisterIdentity(it) } }
|
||||
networkMapCacheBase.changed.subscribe { mapChange ->
|
||||
// TODO how should we handle network map removal
|
||||
if (mapChange is MapChange.Added) {
|
||||
mapChange.node.legalIdentitiesAndCerts.forEach {
|
||||
identityService.verifyAndRegisterIdentity(it)
|
||||
try {
|
||||
identityService.verifyAndRegisterIdentity(it)
|
||||
} catch (ignore: Exception) {
|
||||
// Log a warning to indicate node info is not added to the network map cache.
|
||||
logger.warn("Node info for :'${it.name}' is not added to the network map due to verification error.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,48 +0,0 @@
|
||||
package net.corda.node.services.persistence
|
||||
|
||||
import net.corda.core.internal.ThreadBox
|
||||
import net.corda.core.internal.bufferUntilSubscribed
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.messaging.DataFeed
|
||||
import net.corda.core.messaging.StateMachineTransactionMapping
|
||||
import net.corda.node.services.api.StateMachineRecordedTransactionMappingStorage
|
||||
import rx.subjects.PublishSubject
|
||||
import java.util.*
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
|
||||
/**
|
||||
* This is a temporary in-memory storage of a state machine id -> txhash mapping
|
||||
*
|
||||
* TODO persist this instead
|
||||
*/
|
||||
@ThreadSafe
|
||||
class InMemoryStateMachineRecordedTransactionMappingStorage : StateMachineRecordedTransactionMappingStorage {
|
||||
private class InnerState {
|
||||
val stateMachineTransactionMap = HashMap<StateMachineRunId, HashSet<SecureHash>>()
|
||||
val updates = PublishSubject.create<StateMachineTransactionMapping>()!!
|
||||
}
|
||||
|
||||
private val mutex = ThreadBox(InnerState())
|
||||
|
||||
override fun addMapping(stateMachineRunId: StateMachineRunId, transactionId: SecureHash) {
|
||||
mutex.locked {
|
||||
stateMachineTransactionMap.getOrPut(stateMachineRunId) { HashSet() }.add(transactionId)
|
||||
updates.onNext(StateMachineTransactionMapping(stateMachineRunId, transactionId))
|
||||
}
|
||||
}
|
||||
|
||||
override fun track():
|
||||
DataFeed<List<StateMachineTransactionMapping>, StateMachineTransactionMapping> {
|
||||
mutex.locked {
|
||||
return DataFeed(
|
||||
stateMachineTransactionMap.flatMap { entry ->
|
||||
entry.value.map {
|
||||
StateMachineTransactionMapping(entry.key, it)
|
||||
}
|
||||
},
|
||||
updates.bufferUntilSubscribed()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@ import java.nio.file.Path
|
||||
import java.security.KeyPair
|
||||
import java.security.KeyStore
|
||||
import java.security.cert.Certificate
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
/**
|
||||
* Helper for managing the node registration process, which checks for any existing certificates and requests them if
|
||||
@ -42,16 +41,16 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v
|
||||
private val rootCert = X509Utilities.loadCertificateFromPEMFile(config.rootCertFile)
|
||||
|
||||
/**
|
||||
* Ensure the initial keystore for a node is set up; note that this function may cause the process to exit under
|
||||
* some circumstances.
|
||||
* Ensure the initial keystore for a node is set up.
|
||||
*
|
||||
* This checks the "config.certificatesDirectory" field for certificates required to connect to a Corda network.
|
||||
* If the certificates are not found, a PKCS #10 certification request will be submitted to the
|
||||
* Corda network permissioning server via [NetworkRegistrationService]. This process will enter a polling loop until
|
||||
* the request has been approved, and then the certificate chain will be downloaded and stored in [KeyStore] reside in
|
||||
* the certificates directory.
|
||||
*
|
||||
* @throws CertificateRequestException if the certificate retrieved by doorman is invalid.
|
||||
*/
|
||||
// TODO: Stop killing the calling process from within a called function.
|
||||
fun buildKeystore() {
|
||||
config.certificatesDirectory.createDirectories()
|
||||
val caKeyStore = loadOrCreateKeyStore(config.nodeKeystore, keystorePassword)
|
||||
@ -71,12 +70,12 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v
|
||||
|
||||
val certificates = try {
|
||||
pollServerForCertificates(requestId)
|
||||
} catch (e: CertificateRequestException) {
|
||||
System.err.println(e.message)
|
||||
println("Please make sure the details in configuration file are correct and try again.")
|
||||
println("Corda node will now terminate.")
|
||||
} catch (certificateRequestException: CertificateRequestException) {
|
||||
System.err.println(certificateRequestException.message)
|
||||
System.err.println("Please make sure the details in configuration file are correct and try again.")
|
||||
System.err.println("Corda node will now terminate.")
|
||||
requestIdStore.deleteIfExists()
|
||||
exitProcess(1)
|
||||
throw certificateRequestException
|
||||
}
|
||||
|
||||
println("Certificate signing request approved, storing private key with the certificate chain.")
|
||||
|
@ -4,9 +4,9 @@ import com.google.common.collect.ImmutableSet;
|
||||
import kotlin.Pair;
|
||||
import kotlin.Triple;
|
||||
import net.corda.core.contracts.*;
|
||||
import net.corda.core.crypto.CryptoUtils;
|
||||
import net.corda.core.identity.AbstractParty;
|
||||
import net.corda.core.messaging.DataFeed;
|
||||
import net.corda.core.node.services.IdentityService;
|
||||
import net.corda.core.node.services.Vault;
|
||||
import net.corda.core.node.services.VaultQueryException;
|
||||
import net.corda.core.node.services.VaultService;
|
||||
@ -14,12 +14,11 @@ import net.corda.core.node.services.vault.*;
|
||||
import net.corda.core.node.services.vault.QueryCriteria.LinearStateQueryCriteria;
|
||||
import net.corda.core.node.services.vault.QueryCriteria.VaultCustomQueryCriteria;
|
||||
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria;
|
||||
import net.corda.core.utilities.EncodingUtils;
|
||||
import net.corda.core.utilities.OpaqueBytes;
|
||||
import net.corda.finance.contracts.DealState;
|
||||
import net.corda.finance.contracts.asset.Cash;
|
||||
import net.corda.finance.schemas.CashSchemaV1;
|
||||
import net.corda.node.services.identity.InMemoryIdentityService;
|
||||
import net.corda.node.services.api.IdentityServiceInternal;
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence;
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseTransaction;
|
||||
import net.corda.testing.SerializationEnvironmentRule;
|
||||
@ -48,6 +47,7 @@ import static net.corda.finance.contracts.asset.CashUtilities.*;
|
||||
import static net.corda.testing.CoreTestUtils.*;
|
||||
import static net.corda.testing.TestConstants.*;
|
||||
import static net.corda.testing.node.MockServices.makeTestDatabaseAndMockServices;
|
||||
import static net.corda.testing.node.MockServicesKt.makeTestIdentityService;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class VaultQueryJavaTests {
|
||||
@ -61,15 +61,13 @@ public class VaultQueryJavaTests {
|
||||
@Before
|
||||
public void setUp() throws CertificateException, InvalidAlgorithmParameterException {
|
||||
List<String> cordappPackages = Arrays.asList("net.corda.testing.contracts", "net.corda.finance.contracts.asset", CashSchemaV1.class.getPackage().getName());
|
||||
IdentityService identitySvc = new InMemoryIdentityService(
|
||||
Arrays.asList(getMEGA_CORP_IDENTITY(), getDUMMY_CASH_ISSUER_IDENTITY(), getDUMMY_NOTARY_IDENTITY()),
|
||||
Collections.emptySet(),
|
||||
getDEV_TRUST_ROOT());
|
||||
IdentityServiceInternal identitySvc = makeTestIdentityService(Arrays.asList(getMEGA_CORP_IDENTITY(), getDUMMY_CASH_ISSUER_IDENTITY(), getDUMMY_NOTARY_IDENTITY()));
|
||||
Pair<CordaPersistence, MockServices> databaseAndServices = makeTestDatabaseAndMockServices(
|
||||
Arrays.asList(getMEGA_CORP_KEY(), getDUMMY_NOTARY_KEY()),
|
||||
identitySvc,
|
||||
cordappPackages);
|
||||
issuerServices = new MockServices(cordappPackages, getDUMMY_CASH_ISSUER_NAME(), getDUMMY_CASH_ISSUER_KEY(), getBOC_KEY());
|
||||
cordappPackages,
|
||||
getMEGA_CORP().getName());
|
||||
issuerServices = new MockServices(cordappPackages, rigorousMock(IdentityServiceInternal.class), getDUMMY_CASH_ISSUER_NAME(), getDUMMY_CASH_ISSUER_KEY(), getBOC_KEY());
|
||||
database = databaseAndServices.getFirst();
|
||||
MockServices services = databaseAndServices.getSecond();
|
||||
vaultFiller = new VaultFiller(services, getDUMMY_NOTARY(), getDUMMY_NOTARY_KEY());
|
||||
@ -451,30 +449,28 @@ public class VaultQueryJavaTests {
|
||||
// DOCSTART VaultJavaQueryExample23
|
||||
Field pennies = CashSchemaV1.PersistentCashState.class.getDeclaredField("pennies");
|
||||
Field currency = CashSchemaV1.PersistentCashState.class.getDeclaredField("currency");
|
||||
Field issuerParty = CashSchemaV1.PersistentCashState.class.getDeclaredField("issuerParty");
|
||||
|
||||
QueryCriteria sumCriteria = new VaultCustomQueryCriteria(Builder.sum(pennies, Arrays.asList(issuerParty, currency), Sort.Direction.DESC));
|
||||
|
||||
Field issuerPartyHash = CashSchemaV1.PersistentCashState.class.getDeclaredField("issuerPartyHash");
|
||||
QueryCriteria sumCriteria = new VaultCustomQueryCriteria(Builder.sum(pennies, Arrays.asList(issuerPartyHash, currency), Sort.Direction.DESC));
|
||||
Vault.Page<Cash.State> results = vaultService.queryBy(Cash.State.class, sumCriteria);
|
||||
// DOCEND VaultJavaQueryExample23
|
||||
|
||||
assertThat(results.getOtherResults()).hasSize(12);
|
||||
|
||||
assertThat(results.getOtherResults().get(0)).isEqualTo(400L);
|
||||
assertThat(results.getOtherResults().get(1)).isEqualTo(EncodingUtils.toBase58String(getBOC_PUBKEY()));
|
||||
assertThat(results.getOtherResults().get(1)).isEqualTo(CryptoUtils.toStringShort(getBOC_PUBKEY()));
|
||||
assertThat(results.getOtherResults().get(2)).isEqualTo("GBP");
|
||||
assertThat(results.getOtherResults().get(3)).isEqualTo(300L);
|
||||
assertThat(results.getOtherResults().get(4)).isEqualTo(EncodingUtils.toBase58String(getDUMMY_CASH_ISSUER().getParty().getOwningKey()));
|
||||
assertThat(results.getOtherResults().get(4)).isEqualTo(CryptoUtils.toStringShort(getDUMMY_CASH_ISSUER().getParty().getOwningKey()));
|
||||
assertThat(results.getOtherResults().get(5)).isEqualTo("GBP");
|
||||
assertThat(results.getOtherResults().get(6)).isEqualTo(200L);
|
||||
assertThat(results.getOtherResults().get(7)).isEqualTo(EncodingUtils.toBase58String(getBOC_PUBKEY()));
|
||||
assertThat(results.getOtherResults().get(7)).isEqualTo(CryptoUtils.toStringShort(getBOC_PUBKEY()));
|
||||
assertThat(results.getOtherResults().get(8)).isEqualTo("USD");
|
||||
assertThat(results.getOtherResults().get(9)).isEqualTo(100L);
|
||||
assertThat(results.getOtherResults().get(10)).isEqualTo(EncodingUtils.toBase58String(getDUMMY_CASH_ISSUER().getParty().getOwningKey()));
|
||||
assertThat(results.getOtherResults().get(10)).isEqualTo(CryptoUtils.toStringShort(getDUMMY_CASH_ISSUER().getParty().getOwningKey()));
|
||||
assertThat(results.getOtherResults().get(11)).isEqualTo("USD");
|
||||
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return tx;
|
||||
});
|
||||
|
@ -11,13 +11,12 @@ import net.corda.core.internal.concurrent.openFuture
|
||||
import net.corda.core.messaging.FlowProgressHandleImpl
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||
import net.corda.node.services.identity.InMemoryIdentityService
|
||||
import net.corda.node.shell.InteractiveShell
|
||||
import net.corda.node.internal.configureDatabase
|
||||
import net.corda.testing.DEV_TRUST_ROOT
|
||||
import net.corda.testing.MEGA_CORP
|
||||
import net.corda.testing.MEGA_CORP_IDENTITY
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.makeTestIdentityService
|
||||
import net.corda.testing.rigorousMock
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
@ -49,7 +48,7 @@ class InteractiveShellTest {
|
||||
override fun call() = a
|
||||
}
|
||||
|
||||
private val ids = InMemoryIdentityService(listOf(MEGA_CORP_IDENTITY), trustRoot = DEV_TRUST_ROOT)
|
||||
private val ids = makeTestIdentityService(listOf(MEGA_CORP_IDENTITY))
|
||||
private val om = JacksonSupport.createInMemoryMapper(ids, YAMLFactory())
|
||||
|
||||
private fun check(input: String, expected: String) {
|
||||
|
@ -1,6 +1,8 @@
|
||||
package net.corda.node.messaging
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.nhaarman.mockito_kotlin.doReturn
|
||||
import com.nhaarman.mockito_kotlin.whenever
|
||||
import net.corda.core.concurrent.CordaFuture
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.*
|
||||
@ -34,6 +36,7 @@ import net.corda.finance.flows.TwoPartyTradeFlow.Buyer
|
||||
import net.corda.finance.flows.TwoPartyTradeFlow.Seller
|
||||
import net.corda.node.internal.StartedNode
|
||||
import net.corda.node.services.api.WritableTransactionStorage
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.node.services.persistence.DBTransactionStorage
|
||||
import net.corda.node.services.persistence.checkpoints
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
@ -90,13 +93,15 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
// we run in the unit test thread exclusively to speed things up, ensure deterministic results and
|
||||
// allow interruption half way through.
|
||||
mockNet = MockNetwork(threadPerNode = true, cordappPackages = cordappPackages)
|
||||
ledger(MockServices(cordappPackages)) {
|
||||
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
|
||||
ledger(MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name)) {
|
||||
val notaryNode = mockNet.defaultNotaryNode
|
||||
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
|
||||
val bobNode = mockNet.createPartyNode(BOB_NAME)
|
||||
val bankNode = mockNet.createPartyNode(BOC_NAME)
|
||||
val alice = aliceNode.info.singleIdentity()
|
||||
val bank = bankNode.info.singleIdentity()
|
||||
doReturn(null).whenever(ledgerIdentityService).partyFromKey(bank.owningKey)
|
||||
val bob = bobNode.info.singleIdentity()
|
||||
val notary = mockNet.defaultNotaryIdentity
|
||||
val cashIssuer = bank.ref(1)
|
||||
@ -140,13 +145,15 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
@Test(expected = InsufficientBalanceException::class)
|
||||
fun `trade cash for commercial paper fails using soft locking`() {
|
||||
mockNet = MockNetwork(threadPerNode = true, cordappPackages = cordappPackages)
|
||||
ledger(MockServices(cordappPackages)) {
|
||||
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
|
||||
ledger(MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name)) {
|
||||
val notaryNode = mockNet.defaultNotaryNode
|
||||
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
|
||||
val bobNode = mockNet.createPartyNode(BOB_NAME)
|
||||
val bankNode = mockNet.createPartyNode(BOC_NAME)
|
||||
val alice = aliceNode.info.singleIdentity()
|
||||
val bank = bankNode.info.singleIdentity()
|
||||
doReturn(null).whenever(ledgerIdentityService).partyFromKey(bank.owningKey)
|
||||
val bob = bobNode.info.singleIdentity()
|
||||
val issuer = bank.ref(1)
|
||||
val notary = mockNet.defaultNotaryIdentity
|
||||
@ -196,7 +203,8 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
@Test
|
||||
fun `shutdown and restore`() {
|
||||
mockNet = MockNetwork(cordappPackages = cordappPackages)
|
||||
ledger(MockServices(cordappPackages)) {
|
||||
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
|
||||
ledger(MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name)) {
|
||||
val notaryNode = mockNet.defaultNotaryNode
|
||||
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
|
||||
var bobNode = mockNet.createPartyNode(BOB_NAME)
|
||||
@ -210,6 +218,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
val notary = mockNet.defaultNotaryIdentity
|
||||
val alice = aliceNode.info.singleIdentity()
|
||||
val bank = bankNode.info.singleIdentity()
|
||||
doReturn(null).whenever(ledgerIdentityService).partyFromKey(bank.owningKey)
|
||||
val bob = bobNode.info.singleIdentity()
|
||||
val issuer = bank.ref(1, 2, 3)
|
||||
|
||||
@ -491,16 +500,18 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
@Test
|
||||
fun `dependency with error on buyer side`() {
|
||||
mockNet = MockNetwork(cordappPackages = cordappPackages)
|
||||
ledger(MockServices(cordappPackages)) {
|
||||
runWithError(true, false, "at least one cash input")
|
||||
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
|
||||
ledger(MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name)) {
|
||||
runWithError(ledgerIdentityService, true, false, "at least one cash input")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `dependency with error on seller side`() {
|
||||
mockNet = MockNetwork(cordappPackages = cordappPackages)
|
||||
ledger(MockServices(cordappPackages)) {
|
||||
runWithError(false, true, "Issuances have a time-window")
|
||||
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
|
||||
ledger(MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name)) {
|
||||
runWithError(ledgerIdentityService, false, true, "Issuances have a time-window")
|
||||
}
|
||||
}
|
||||
|
||||
@ -562,6 +573,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
data class TestTx(val notaryIdentity: Party, val price: Amount<Currency>, val anonymous: Boolean)
|
||||
|
||||
private fun LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.runWithError(
|
||||
ledgerIdentityService: IdentityServiceInternal,
|
||||
bobError: Boolean,
|
||||
aliceError: Boolean,
|
||||
expectedMessageSubstring: String
|
||||
@ -575,6 +587,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
||||
val alice = aliceNode.info.singleIdentity()
|
||||
val bob = bobNode.info.singleIdentity()
|
||||
val bank = bankNode.info.singleIdentity()
|
||||
doReturn(null).whenever(ledgerIdentityService).partyFromKey(bank.owningKey)
|
||||
val issuer = bank.ref(1, 2, 3)
|
||||
|
||||
val bobsBadCash = bobNode.database.transaction {
|
||||
|
@ -4,6 +4,7 @@ import co.paralleluniverse.fibers.Suspendable
|
||||
import com.codahale.metrics.MetricRegistry
|
||||
import com.nhaarman.mockito_kotlin.*
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.FlowLogicRef
|
||||
import net.corda.core.flows.FlowLogicRefFactory
|
||||
@ -16,12 +17,10 @@ import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.utilities.days
|
||||
import net.corda.node.internal.FlowStarterImpl
|
||||
import net.corda.node.internal.StateLoaderImpl
|
||||
import net.corda.node.internal.cordapp.CordappLoader
|
||||
import net.corda.node.internal.cordapp.CordappProviderImpl
|
||||
import net.corda.node.services.api.MonitoringService
|
||||
import net.corda.node.services.api.ServiceHubInternal
|
||||
import net.corda.node.services.identity.InMemoryIdentityService
|
||||
import net.corda.node.services.network.NetworkMapCacheImpl
|
||||
import net.corda.node.services.persistence.DBCheckpointStorage
|
||||
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl
|
||||
@ -51,6 +50,7 @@ import kotlin.test.assertTrue
|
||||
|
||||
class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
||||
companion object {
|
||||
private val DUMMY_IDENTITY_1 = getTestPartyAndCertificate(Party(CordaX500Name("Dummy", "Madrid", "ES"), generateKeyPair().public))
|
||||
private val myInfo = NodeInfo(listOf(MOCK_HOST_AND_PORT), listOf(DUMMY_IDENTITY_1), 1, serial = 1L)
|
||||
}
|
||||
|
||||
@ -91,11 +91,10 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
||||
calls = 0
|
||||
val dataSourceProps = makeTestDataSourceProperties()
|
||||
database = configureDatabase(dataSourceProps, DatabaseConfig(), rigorousMock())
|
||||
val identityService = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
|
||||
val identityService = makeTestIdentityService()
|
||||
kms = MockKeyManagementService(identityService, ALICE_KEY)
|
||||
val configuration = testNodeConfiguration(Paths.get("."), CordaX500Name("Alice", "London", "GB"))
|
||||
val validatedTransactions = MockTransactionStorage()
|
||||
val stateLoader = StateLoaderImpl(validatedTransactions)
|
||||
database.transaction {
|
||||
services = rigorousMock<Services>().also {
|
||||
doReturn(configuration).whenever(it).configuration
|
||||
@ -105,13 +104,13 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
||||
doReturn(myInfo).whenever(it).myInfo
|
||||
doReturn(kms).whenever(it).keyManagementService
|
||||
doReturn(CordappProviderImpl(CordappLoader.createWithTestPackages(listOf("net.corda.testing.contracts")), MockAttachmentStorage())).whenever(it).cordappProvider
|
||||
doReturn(NodeVaultService(testClock, kms, stateLoader, database.hibernateConfig)).whenever(it).vaultService
|
||||
doReturn(NodeVaultService(testClock, kms, validatedTransactions, database.hibernateConfig)).whenever(it).vaultService
|
||||
doReturn(this@NodeSchedulerServiceTest).whenever(it).testReference
|
||||
|
||||
}
|
||||
smmExecutor = AffinityExecutor.ServiceAffinityExecutor("test", 1)
|
||||
mockSMM = StateMachineManagerImpl(services, DBCheckpointStorage(), smmExecutor, database)
|
||||
scheduler = NodeSchedulerService(testClock, database, FlowStarterImpl(smmExecutor, mockSMM), stateLoader, schedulerGatedExecutor, serverThread = smmExecutor)
|
||||
scheduler = NodeSchedulerService(testClock, database, FlowStarterImpl(smmExecutor, mockSMM), validatedTransactions, schedulerGatedExecutor, serverThread = smmExecutor)
|
||||
mockSMM.changes.subscribe { change ->
|
||||
if (change is StateMachineManager.Change.Removed && mockSMM.allStateMachines.isEmpty()) {
|
||||
smmHasRemovedAllFlows.countDown()
|
||||
@ -294,7 +293,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
||||
database.transaction {
|
||||
apply {
|
||||
val freshKey = kms.freshKey()
|
||||
val state = TestState(FlowLogicRefFactoryImpl.createForRPC(TestFlowLogic::class.java, increment), instant, myInfo.chooseIdentity())
|
||||
val state = TestState(FlowLogicRefFactoryImpl.createForRPC(TestFlowLogic::class.java, increment), instant, DUMMY_IDENTITY_1.party)
|
||||
val builder = TransactionBuilder(null).apply {
|
||||
addOutputState(state, DummyContract.PROGRAM_ID, DUMMY_NOTARY)
|
||||
addCommand(Command(), freshKey)
|
||||
|
@ -9,7 +9,6 @@ import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.internal.toX509CertHolder
|
||||
import net.corda.core.node.services.UnknownAnonymousPartyException
|
||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
@ -23,9 +22,13 @@ import kotlin.test.assertNull
|
||||
* Tests for the in memory identity service.
|
||||
*/
|
||||
class InMemoryIdentityServiceTests {
|
||||
companion object {
|
||||
private fun createService(vararg identities: PartyAndCertificate) = InMemoryIdentityService(identities.toSet(), DEV_TRUST_ROOT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get all identities`() {
|
||||
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
|
||||
val service = createService()
|
||||
// Nothing registered, so empty set
|
||||
assertNull(service.getAllIdentities().firstOrNull())
|
||||
|
||||
@ -43,7 +46,7 @@ class InMemoryIdentityServiceTests {
|
||||
|
||||
@Test
|
||||
fun `get identity by key`() {
|
||||
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
|
||||
val service = createService()
|
||||
assertNull(service.partyFromKey(ALICE_PUBKEY))
|
||||
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
|
||||
assertEquals(ALICE, service.partyFromKey(ALICE_PUBKEY))
|
||||
@ -52,13 +55,13 @@ class InMemoryIdentityServiceTests {
|
||||
|
||||
@Test
|
||||
fun `get identity by name with no registered identities`() {
|
||||
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
|
||||
val service = createService()
|
||||
assertNull(service.wellKnownPartyFromX500Name(ALICE.name))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get identity by substring match`() {
|
||||
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
|
||||
val service = createService()
|
||||
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
|
||||
service.verifyAndRegisterIdentity(BOB_IDENTITY)
|
||||
val alicente = getTestPartyAndCertificate(CordaX500Name(organisation = "Alicente Worldwide", locality = "London", country = "GB"), generateKeyPair().public)
|
||||
@ -70,7 +73,7 @@ class InMemoryIdentityServiceTests {
|
||||
|
||||
@Test
|
||||
fun `get identity by name`() {
|
||||
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
|
||||
val service = createService()
|
||||
val identities = listOf("Org A", "Org B", "Org C")
|
||||
.map { getTestPartyAndCertificate(CordaX500Name(organisation = it, locality = "London", country = "GB"), generateKeyPair().public) }
|
||||
assertNull(service.wellKnownPartyFromX500Name(identities.first().name))
|
||||
@ -87,7 +90,7 @@ class InMemoryIdentityServiceTests {
|
||||
val rootKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val rootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name, rootKey)
|
||||
val txKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
|
||||
val service = createService()
|
||||
// TODO: Generate certificate with an EdDSA key rather than ECDSA
|
||||
val identity = Party(rootCert.cert)
|
||||
val txIdentity = AnonymousParty(txKey.public)
|
||||
@ -104,11 +107,11 @@ class InMemoryIdentityServiceTests {
|
||||
*/
|
||||
@Test
|
||||
fun `get anonymous identity by key`() {
|
||||
val (alice, aliceTxIdentity) = createParty(ALICE.name, DEV_CA)
|
||||
val (_, bobTxIdentity) = createParty(ALICE.name, DEV_CA)
|
||||
val (alice, aliceTxIdentity) = createConfidentialIdentity(ALICE.name)
|
||||
val (_, bobTxIdentity) = createConfidentialIdentity(ALICE.name)
|
||||
|
||||
// Now we have identities, construct the service and let it know about both
|
||||
val service = InMemoryIdentityService(setOf(alice), emptySet(), DEV_TRUST_ROOT)
|
||||
val service = createService(alice)
|
||||
service.verifyAndRegisterIdentity(aliceTxIdentity)
|
||||
|
||||
var actual = service.certificateFromKey(aliceTxIdentity.party.owningKey)
|
||||
@ -127,12 +130,11 @@ class InMemoryIdentityServiceTests {
|
||||
@Test
|
||||
fun `assert ownership`() {
|
||||
withTestSerialization {
|
||||
val (alice, anonymousAlice) = createParty(ALICE.name, DEV_CA)
|
||||
val (bob, anonymousBob) = createParty(BOB.name, DEV_CA)
|
||||
val (alice, anonymousAlice) = createConfidentialIdentity(ALICE.name)
|
||||
val (bob, anonymousBob) = createConfidentialIdentity(BOB.name)
|
||||
|
||||
// Now we have identities, construct the service and let it know about both
|
||||
val service = InMemoryIdentityService(setOf(alice, bob), emptySet(), DEV_TRUST_ROOT)
|
||||
|
||||
val service = createService(alice, bob)
|
||||
service.verifyAndRegisterIdentity(anonymousAlice)
|
||||
service.verifyAndRegisterIdentity(anonymousBob)
|
||||
|
||||
@ -154,11 +156,11 @@ class InMemoryIdentityServiceTests {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createParty(x500Name: CordaX500Name, ca: CertificateAndKeyPair): Pair<PartyAndCertificate, PartyAndCertificate> {
|
||||
private fun createConfidentialIdentity(x500Name: CordaX500Name): Pair<PartyAndCertificate, PartyAndCertificate> {
|
||||
val issuerKeyPair = generateKeyPair()
|
||||
val issuer = getTestPartyAndCertificate(x500Name, issuerKeyPair.public, ca)
|
||||
val issuer = getTestPartyAndCertificate(x500Name, issuerKeyPair.public)
|
||||
val txKey = Crypto.generateKeyPair()
|
||||
val txCert = X509Utilities.createCertificate(CertificateType.IDENTITY, issuer.certificate.toX509CertHolder(), issuerKeyPair, x500Name, txKey.public)
|
||||
val txCert = X509Utilities.createCertificate(CertificateType.CONFIDENTIAL_IDENTITY, issuer.certificate.toX509CertHolder(), issuerKeyPair, x500Name, txKey.public)
|
||||
val txCertPath = X509CertificateFactory().generateCertPath(listOf(txCert.cert) + issuer.certPath.certificates)
|
||||
return Pair(issuer, PartyAndCertificate(txCertPath))
|
||||
}
|
||||
@ -168,7 +170,7 @@ class InMemoryIdentityServiceTests {
|
||||
*/
|
||||
@Test
|
||||
fun `deanonymising a well known identity should return the identity`() {
|
||||
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
|
||||
val service = createService()
|
||||
val expected = ALICE
|
||||
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
|
||||
val actual = service.wellKnownPartyFromAnonymous(expected)
|
||||
@ -180,7 +182,7 @@ class InMemoryIdentityServiceTests {
|
||||
*/
|
||||
@Test
|
||||
fun `deanonymising a false well known identity should return null`() {
|
||||
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
|
||||
val service = createService()
|
||||
val notAlice = Party(ALICE.name, generateKeyPair().public)
|
||||
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
|
||||
val actual = service.wellKnownPartyFromAnonymous(notAlice)
|
||||
|
@ -10,13 +10,15 @@ import net.corda.core.internal.cert
|
||||
import net.corda.core.internal.toX509CertHolder
|
||||
import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.node.services.UnknownAnonymousPartyException
|
||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||
import net.corda.node.internal.configureDatabase
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
||||
import net.corda.testing.node.makeTestIdentityService
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@ -29,15 +31,12 @@ import kotlin.test.assertNull
|
||||
*/
|
||||
class PersistentIdentityServiceTests {
|
||||
private lateinit var database: CordaPersistence
|
||||
private lateinit var services: MockServices
|
||||
private lateinit var identityService: IdentityService
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
val databaseAndServices = MockServices.makeTestDatabaseAndMockServices(keys = emptyList(), identityService = PersistentIdentityService(DEV_TRUST_ROOT))
|
||||
database = databaseAndServices.first
|
||||
services = databaseAndServices.second
|
||||
identityService = services.identityService
|
||||
identityService = PersistentIdentityService(DEV_TRUST_ROOT)
|
||||
database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(), identityService)
|
||||
}
|
||||
|
||||
@After
|
||||
@ -149,8 +148,8 @@ class PersistentIdentityServiceTests {
|
||||
*/
|
||||
@Test
|
||||
fun `get anonymous identity by key`() {
|
||||
val (alice, aliceTxIdentity) = createParty(ALICE.name, DEV_CA)
|
||||
val (_, bobTxIdentity) = createParty(ALICE.name, DEV_CA)
|
||||
val (alice, aliceTxIdentity) = createConfidentialIdentity(ALICE.name)
|
||||
val (_, bobTxIdentity) = createConfidentialIdentity(ALICE.name)
|
||||
|
||||
// Now we have identities, construct the service and let it know about both
|
||||
database.transaction {
|
||||
@ -182,8 +181,8 @@ class PersistentIdentityServiceTests {
|
||||
@Test
|
||||
fun `assert ownership`() {
|
||||
withTestSerialization {
|
||||
val (alice, anonymousAlice) = createParty(ALICE.name, DEV_CA)
|
||||
val (bob, anonymousBob) = createParty(BOB.name, DEV_CA)
|
||||
val (alice, anonymousAlice) = createConfidentialIdentity(ALICE.name)
|
||||
val (bob, anonymousBob) = createConfidentialIdentity(BOB.name)
|
||||
|
||||
database.transaction {
|
||||
// Now we have identities, construct the service and let it know about both
|
||||
@ -219,8 +218,8 @@ class PersistentIdentityServiceTests {
|
||||
|
||||
@Test
|
||||
fun `Test Persistence`() {
|
||||
val (alice, anonymousAlice) = createParty(ALICE.name, DEV_CA)
|
||||
val (bob, anonymousBob) = createParty(BOB.name, DEV_CA)
|
||||
val (alice, anonymousAlice) = createConfidentialIdentity(ALICE.name)
|
||||
val (bob, anonymousBob) = createConfidentialIdentity(BOB.name)
|
||||
|
||||
database.transaction {
|
||||
// Register well known identities
|
||||
@ -252,11 +251,11 @@ class PersistentIdentityServiceTests {
|
||||
assertEquals(anonymousBob, bobReload!!)
|
||||
}
|
||||
|
||||
private fun createParty(x500Name: CordaX500Name, ca: CertificateAndKeyPair): Pair<PartyAndCertificate, PartyAndCertificate> {
|
||||
private fun createConfidentialIdentity(x500Name: CordaX500Name): Pair<PartyAndCertificate, PartyAndCertificate> {
|
||||
val issuerKeyPair = generateKeyPair()
|
||||
val issuer = getTestPartyAndCertificate(x500Name, issuerKeyPair.public, ca)
|
||||
val issuer = getTestPartyAndCertificate(x500Name, issuerKeyPair.public)
|
||||
val txKey = Crypto.generateKeyPair()
|
||||
val txCert = X509Utilities.createCertificate(CertificateType.IDENTITY, issuer.certificate.toX509CertHolder(), issuerKeyPair, x500Name, txKey.public)
|
||||
val txCert = X509Utilities.createCertificate(CertificateType.CONFIDENTIAL_IDENTITY, issuer.certificate.toX509CertHolder(), issuerKeyPair, x500Name, txKey.public)
|
||||
val txCertPath = X509CertificateFactory().generateCertPath(listOf(txCert.cert) + issuer.certPath.certificates)
|
||||
return Pair(issuer, PartyAndCertificate(txCertPath))
|
||||
}
|
||||
@ -266,7 +265,7 @@ class PersistentIdentityServiceTests {
|
||||
*/
|
||||
@Test
|
||||
fun `deanonymising a well known identity should return the identity`() {
|
||||
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
|
||||
val service = makeTestIdentityService()
|
||||
val expected = ALICE
|
||||
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
|
||||
val actual = service.wellKnownPartyFromAnonymous(expected)
|
||||
@ -278,7 +277,7 @@ class PersistentIdentityServiceTests {
|
||||
*/
|
||||
@Test
|
||||
fun `deanonymising a false well known identity should return null`() {
|
||||
val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
|
||||
val service = makeTestIdentityService()
|
||||
val notAlice = Party(ALICE.name, generateKeyPair().public)
|
||||
service.verifyAndRegisterIdentity(ALICE_IDENTITY)
|
||||
val actual = service.wellKnownPartyFromAnonymous(notAlice)
|
||||
|
@ -3,7 +3,6 @@ package net.corda.node.services.network
|
||||
import net.corda.core.node.services.NetworkMapCache
|
||||
import net.corda.testing.ALICE_NAME
|
||||
import net.corda.testing.BOB_NAME
|
||||
import net.corda.testing.DUMMY_NOTARY
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockNodeParameters
|
||||
import net.corda.testing.singleIdentity
|
||||
|
@ -26,7 +26,7 @@ object TestNodeInfoFactory {
|
||||
|
||||
fun createNodeInfo(organisation: String): SignedData<NodeInfo> {
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisation, locality = "London", country = "GB"), keyPair.public)
|
||||
val clientCert = X509Utilities.createCertificate(CertificateType.NODE_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisation, locality = "London", country = "GB"), keyPair.public)
|
||||
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.$organisation.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
return sign(keyPair, nodeInfo)
|
||||
|
@ -5,20 +5,14 @@ import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.SignatureMetadata
|
||||
import net.corda.core.crypto.TransactionSignature
|
||||
import net.corda.core.node.StatesToRecord
|
||||
import net.corda.core.toFuture
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.node.services.api.VaultServiceInternal
|
||||
import net.corda.node.services.schema.HibernateObserver
|
||||
import net.corda.node.services.schema.NodeSchemaService
|
||||
import net.corda.node.services.transactions.PersistentUniquenessProvider
|
||||
import net.corda.node.services.vault.NodeVaultService
|
||||
import net.corda.node.internal.configureDatabase
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.After
|
||||
@ -35,32 +29,11 @@ class DBTransactionStorageTests {
|
||||
|
||||
private lateinit var database: CordaPersistence
|
||||
private lateinit var transactionStorage: DBTransactionStorage
|
||||
private lateinit var services: MockServices
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
||||
val dataSourceProps = makeTestDataSourceProperties()
|
||||
val schemaService = NodeSchemaService()
|
||||
database = configureDatabase(dataSourceProps, DatabaseConfig(), rigorousMock(), schemaService)
|
||||
database.transaction {
|
||||
services = object : MockServices(BOB_KEY) {
|
||||
override val vaultService: VaultServiceInternal
|
||||
get() {
|
||||
val vaultService = NodeVaultService(clock, keyManagementService, stateLoader, database.hibernateConfig)
|
||||
hibernatePersister = HibernateObserver.install(vaultService.rawUpdates, database.hibernateConfig, schemaService)
|
||||
return vaultService
|
||||
}
|
||||
|
||||
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
||||
for (stx in txs) {
|
||||
validatedTransactions.addTransaction(stx)
|
||||
}
|
||||
// Refactored to use notifyAll() as we have no other unit test for that method with multiple transactions.
|
||||
vaultService.notifyAll(StatesToRecord.ONLY_RELEVANT, txs.map { it.tx })
|
||||
}
|
||||
}
|
||||
}
|
||||
database = configureDatabase(dataSourceProps, DatabaseConfig(), rigorousMock())
|
||||
newTransactionStorage()
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
package net.corda.node.services.persistence
|
||||
|
||||
import com.nhaarman.mockito_kotlin.any
|
||||
import com.nhaarman.mockito_kotlin.doReturn
|
||||
import com.nhaarman.mockito_kotlin.whenever
|
||||
import com.nhaarman.mockito_kotlin.*
|
||||
import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.StateRef
|
||||
@ -35,6 +33,7 @@ import net.corda.node.services.schema.HibernateObserver
|
||||
import net.corda.node.services.schema.NodeSchemaService
|
||||
import net.corda.node.services.vault.VaultSchemaV1
|
||||
import net.corda.node.internal.configureDatabase
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||
import net.corda.nodeapi.internal.persistence.HibernateConfiguration
|
||||
@ -85,9 +84,9 @@ class HibernateConfigurationTest {
|
||||
@Before
|
||||
fun setUp() {
|
||||
val cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts.asset")
|
||||
bankServices = MockServices(cordappPackages, BOC.name, BOC_KEY)
|
||||
issuerServices = MockServices(cordappPackages, DUMMY_CASH_ISSUER_NAME, DUMMY_CASH_ISSUER_KEY)
|
||||
notaryServices = MockServices(cordappPackages, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
||||
bankServices = MockServices(cordappPackages, rigorousMock(), BOC.name, BOC_KEY)
|
||||
issuerServices = MockServices(cordappPackages, rigorousMock(), DUMMY_CASH_ISSUER_NAME, DUMMY_CASH_ISSUER_KEY)
|
||||
notaryServices = MockServices(cordappPackages, rigorousMock(), DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
||||
notary = notaryServices.myInfo.singleIdentity()
|
||||
val dataSourceProps = makeTestDataSourceProperties()
|
||||
val identityService = rigorousMock<IdentityService>().also { mock ->
|
||||
@ -102,7 +101,9 @@ class HibernateConfigurationTest {
|
||||
database.transaction {
|
||||
hibernateConfig = database.hibernateConfig
|
||||
// `consumeCash` expects we can self-notarise transactions
|
||||
services = object : MockServices(cordappPackages, BOB_NAME, generateKeyPair(), DUMMY_NOTARY_KEY) {
|
||||
services = object : MockServices(cordappPackages, rigorousMock<IdentityServiceInternal>().also {
|
||||
doNothing().whenever(it).justVerifyAndRegisterIdentity(argThat { name == BOB_NAME })
|
||||
}, BOB_NAME, generateKeyPair(), DUMMY_NOTARY_KEY) {
|
||||
override val vaultService = makeVaultService(database.hibernateConfig, schemaService)
|
||||
override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable<SignedTransaction>) {
|
||||
for (stx in txs) {
|
||||
|
@ -1,6 +1,9 @@
|
||||
package net.corda.node.services.vault
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.nhaarman.mockito_kotlin.argThat
|
||||
import com.nhaarman.mockito_kotlin.doNothing
|
||||
import com.nhaarman.mockito_kotlin.whenever
|
||||
import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.Issued
|
||||
import net.corda.core.contracts.StateAndRef
|
||||
@ -34,10 +37,12 @@ import net.corda.finance.contracts.asset.DUMMY_CASH_ISSUER_NAME
|
||||
import net.corda.finance.contracts.getCashBalance
|
||||
import net.corda.finance.schemas.CashSchemaV1
|
||||
import net.corda.finance.utils.sumCash
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.contracts.VaultFiller
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.makeTestIdentityService
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
import org.junit.After
|
||||
@ -72,15 +77,18 @@ class NodeVaultServiceTest {
|
||||
@Before
|
||||
fun setUp() {
|
||||
LogHelper.setLevel(NodeVaultService::class)
|
||||
val databaseAndServices = MockServices.makeTestDatabaseAndMockServices(cordappPackages = cordappPackages)
|
||||
val databaseAndServices = MockServices.makeTestDatabaseAndMockServices(
|
||||
listOf(MEGA_CORP_KEY),
|
||||
makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)),
|
||||
cordappPackages,
|
||||
MEGA_CORP.name)
|
||||
database = databaseAndServices.first
|
||||
services = databaseAndServices.second
|
||||
vaultFiller = VaultFiller(services, DUMMY_NOTARY, DUMMY_NOTARY_KEY)
|
||||
// This is safe because MockServices only ever have a single identity
|
||||
identity = services.myInfo.singleIdentityAndCert()
|
||||
issuerServices = MockServices(cordappPackages, DUMMY_CASH_ISSUER_NAME, DUMMY_CASH_ISSUER_KEY)
|
||||
bocServices = MockServices(cordappPackages, BOC_NAME, BOC_KEY)
|
||||
|
||||
issuerServices = MockServices(cordappPackages, rigorousMock(), DUMMY_CASH_ISSUER_NAME, DUMMY_CASH_ISSUER_KEY)
|
||||
bocServices = MockServices(cordappPackages, rigorousMock(), BOC_NAME, BOC_KEY)
|
||||
services.identityService.verifyAndRegisterIdentity(DUMMY_CASH_ISSUER_IDENTITY)
|
||||
services.identityService.verifyAndRegisterIdentity(BOC_IDENTITY)
|
||||
}
|
||||
@ -120,7 +128,7 @@ class NodeVaultServiceTest {
|
||||
assertThat(w1).hasSize(3)
|
||||
|
||||
val originalVault = vaultService
|
||||
val services2 = object : MockServices() {
|
||||
val services2 = object : MockServices(rigorousMock(), MEGA_CORP.name) {
|
||||
override val vaultService: NodeVaultService get() = originalVault
|
||||
override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable<SignedTransaction>) {
|
||||
for (stx in txs) {
|
||||
@ -463,7 +471,7 @@ class NodeVaultServiceTest {
|
||||
|
||||
@Test
|
||||
fun addNoteToTransaction() {
|
||||
val megaCorpServices = MockServices(cordappPackages, MEGA_CORP.name, MEGA_CORP_KEY)
|
||||
val megaCorpServices = MockServices(cordappPackages, rigorousMock(), MEGA_CORP.name, MEGA_CORP_KEY)
|
||||
database.transaction {
|
||||
val freshKey = identity.owningKey
|
||||
|
||||
@ -523,6 +531,7 @@ class NodeVaultServiceTest {
|
||||
|
||||
val identity = services.myInfo.singleIdentityAndCert()
|
||||
val anonymousIdentity = services.keyManagementService.freshKeyAndCert(identity, false)
|
||||
// We use a random key pair to pay to here, as we don't actually use the cash once sent
|
||||
val thirdPartyIdentity = AnonymousParty(generateKeyPair().public)
|
||||
val amount = Amount(1000, Issued(BOC.ref(1), GBP))
|
||||
|
||||
@ -542,8 +551,7 @@ class NodeVaultServiceTest {
|
||||
|
||||
database.transaction {
|
||||
val moveBuilder = TransactionBuilder(notary).apply {
|
||||
val changeIdentity = services.keyManagementService.freshKeyAndCert(identity, false)
|
||||
Cash.generateSpend(services, this, Amount(1000, GBP), changeIdentity, thirdPartyIdentity)
|
||||
Cash.generateSpend(services, this, Amount(1000, GBP), identity, thirdPartyIdentity)
|
||||
}
|
||||
val moveTx = moveBuilder.toWireTransaction(services)
|
||||
vaultService.notify(StatesToRecord.ONLY_RELEVANT, moveTx)
|
||||
@ -570,7 +578,9 @@ class NodeVaultServiceTest {
|
||||
val identity = services.myInfo.singleIdentityAndCert()
|
||||
assertEquals(services.identityService.partyFromKey(identity.owningKey), identity.party)
|
||||
val anonymousIdentity = services.keyManagementService.freshKeyAndCert(identity, false)
|
||||
val thirdPartyServices = MockServices()
|
||||
val thirdPartyServices = MockServices(rigorousMock<IdentityServiceInternal>().also {
|
||||
doNothing().whenever(it).justVerifyAndRegisterIdentity(argThat { name == MEGA_CORP.name })
|
||||
}, MEGA_CORP.name)
|
||||
val thirdPartyIdentity = thirdPartyServices.keyManagementService.freshKeyAndCert(thirdPartyServices.myInfo.singleIdentityAndCert(), false)
|
||||
val amount = Amount(1000, Issued(BOC.ref(1), GBP))
|
||||
|
||||
@ -600,7 +610,7 @@ class NodeVaultServiceTest {
|
||||
// Move cash
|
||||
val moveTxBuilder = database.transaction {
|
||||
TransactionBuilder(newNotary).apply {
|
||||
Cash.generateSpend(services, this, Amount(amount.quantity, GBP), anonymousIdentity, thirdPartyIdentity.party.anonymise())
|
||||
Cash.generateSpend(services, this, Amount(amount.quantity, GBP), identity, thirdPartyIdentity.party.anonymise())
|
||||
}
|
||||
}
|
||||
val moveTx = moveTxBuilder.toWireTransaction(services)
|
||||
|
@ -35,6 +35,7 @@ import net.corda.testing.*
|
||||
import net.corda.testing.contracts.*
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices
|
||||
import net.corda.testing.node.makeTestIdentityService
|
||||
import net.corda.testing.schemas.DummyLinearStateSchemaV1
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
@ -79,13 +80,16 @@ class VaultQueryTests {
|
||||
@Before
|
||||
fun setUp() {
|
||||
// register additional identities
|
||||
val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(MEGA_CORP_KEY, DUMMY_NOTARY_KEY),
|
||||
cordappPackages = cordappPackages)
|
||||
val databaseAndServices = makeTestDatabaseAndMockServices(
|
||||
listOf(MEGA_CORP_KEY, DUMMY_NOTARY_KEY),
|
||||
makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)),
|
||||
cordappPackages,
|
||||
MEGA_CORP.name)
|
||||
database = databaseAndServices.first
|
||||
services = databaseAndServices.second
|
||||
vaultFiller = VaultFiller(services, DUMMY_NOTARY, DUMMY_NOTARY_KEY)
|
||||
vaultFillerCashNotary = VaultFiller(services, DUMMY_NOTARY, DUMMY_NOTARY_KEY, CASH_NOTARY)
|
||||
notaryServices = MockServices(cordappPackages, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY, DUMMY_CASH_ISSUER_KEY, BOC_KEY, MEGA_CORP_KEY)
|
||||
notaryServices = MockServices(cordappPackages, rigorousMock(), DUMMY_NOTARY.name, DUMMY_NOTARY_KEY, DUMMY_CASH_ISSUER_KEY, BOC_KEY, MEGA_CORP_KEY)
|
||||
identitySvc = services.identityService
|
||||
// Register all of the identities we're going to use
|
||||
(notaryServices.myInfo.legalIdentitiesAndCerts + BOC_IDENTITY + CASH_NOTARY_IDENTITY + MINI_CORP_IDENTITY + MEGA_CORP_IDENTITY).forEach { identity ->
|
||||
@ -1320,15 +1324,15 @@ class VaultQueryTests {
|
||||
fun `unconsumed fungible assets for selected issuer parties`() {
|
||||
// GBP issuer
|
||||
val gbpCashIssuerName = CordaX500Name(organisation = "British Pounds Cash Issuer", locality = "London", country = "GB")
|
||||
val gbpCashIssuerServices = MockServices(cordappPackages, gbpCashIssuerName, generateKeyPair())
|
||||
val gbpCashIssuerServices = MockServices(cordappPackages, rigorousMock(), gbpCashIssuerName, generateKeyPair())
|
||||
val gbpCashIssuer = gbpCashIssuerServices.myInfo.singleIdentityAndCert()
|
||||
// USD issuer
|
||||
val usdCashIssuerName = CordaX500Name(organisation = "US Dollars Cash Issuer", locality = "New York", country = "US")
|
||||
val usdCashIssuerServices = MockServices(cordappPackages, usdCashIssuerName, generateKeyPair())
|
||||
val usdCashIssuerServices = MockServices(cordappPackages, rigorousMock(), usdCashIssuerName, generateKeyPair())
|
||||
val usdCashIssuer = usdCashIssuerServices.myInfo.singleIdentityAndCert()
|
||||
// CHF issuer
|
||||
val chfCashIssuerName = CordaX500Name(organisation = "Swiss Francs Cash Issuer", locality = "Zurich", country = "CH")
|
||||
val chfCashIssuerServices = MockServices(cordappPackages, chfCashIssuerName, generateKeyPair())
|
||||
val chfCashIssuerServices = MockServices(cordappPackages, rigorousMock(), chfCashIssuerName, generateKeyPair())
|
||||
val chfCashIssuer = chfCashIssuerServices.myInfo.singleIdentityAndCert()
|
||||
listOf(gbpCashIssuer, usdCashIssuer, chfCashIssuer).forEach { identity ->
|
||||
services.identityService.verifyAndRegisterIdentity(identity)
|
||||
|
@ -29,6 +29,7 @@ import net.corda.testing.*
|
||||
import net.corda.testing.contracts.*
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices
|
||||
import net.corda.testing.node.makeTestIdentityService
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.junit.After
|
||||
@ -60,12 +61,16 @@ class VaultWithCashTest {
|
||||
@Before
|
||||
fun setUp() {
|
||||
LogHelper.setLevel(VaultWithCashTest::class)
|
||||
val databaseAndServices = makeTestDatabaseAndMockServices(cordappPackages = cordappPackages, keys = listOf(generateKeyPair(), DUMMY_NOTARY_KEY))
|
||||
val databaseAndServices = makeTestDatabaseAndMockServices(
|
||||
listOf(generateKeyPair(), DUMMY_NOTARY_KEY),
|
||||
makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)),
|
||||
cordappPackages,
|
||||
MEGA_CORP.name)
|
||||
database = databaseAndServices.first
|
||||
services = databaseAndServices.second
|
||||
vaultFiller = VaultFiller(services, DUMMY_NOTARY, DUMMY_NOTARY_KEY)
|
||||
issuerServices = MockServices(cordappPackages, DUMMY_CASH_ISSUER_NAME, DUMMY_CASH_ISSUER_KEY, MEGA_CORP_KEY)
|
||||
notaryServices = MockServices(cordappPackages, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
||||
issuerServices = MockServices(cordappPackages, rigorousMock(), DUMMY_CASH_ISSUER_NAME, DUMMY_CASH_ISSUER_KEY, MEGA_CORP_KEY)
|
||||
notaryServices = MockServices(cordappPackages, rigorousMock(), DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
||||
notary = notaryServices.myInfo.legalIdentitiesAndCerts.single().party
|
||||
}
|
||||
|
||||
@ -96,7 +101,7 @@ class VaultWithCashTest {
|
||||
|
||||
@Test
|
||||
fun `issue and spend total correctly and irrelevant ignored`() {
|
||||
val megaCorpServices = MockServices(cordappPackages, MEGA_CORP.name, MEGA_CORP_KEY)
|
||||
val megaCorpServices = MockServices(cordappPackages, rigorousMock(), MEGA_CORP.name, MEGA_CORP_KEY)
|
||||
val freshKey = services.keyManagementService.freshKey()
|
||||
|
||||
val usefulTX =
|
||||
|
@ -242,7 +242,7 @@ class TLSAuthenticationTests {
|
||||
// Client 1 keys, certs and SSLKeyStore.
|
||||
val client1CAKeyPair = Crypto.generateKeyPair(client1CAScheme)
|
||||
val client1CACert = X509Utilities.createCertificate(
|
||||
CertificateType.CLIENT_CA,
|
||||
CertificateType.NODE_CA,
|
||||
intermediateCACert,
|
||||
intermediateCAKeyPair,
|
||||
CLIENT_1_X500,
|
||||
@ -269,7 +269,7 @@ class TLSAuthenticationTests {
|
||||
// Client 2 keys, certs and SSLKeyStore.
|
||||
val client2CAKeyPair = Crypto.generateKeyPair(client2CAScheme)
|
||||
val client2CACert = X509Utilities.createCertificate(
|
||||
CertificateType.CLIENT_CA,
|
||||
CertificateType.NODE_CA,
|
||||
intermediateCACert,
|
||||
intermediateCAKeyPair,
|
||||
CLIENT_2_X500,
|
||||
|
Reference in New Issue
Block a user