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:
Shams Asari
2017-12-08 16:03:16 +00:00
160 changed files with 2044 additions and 1285 deletions

View File

@ -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)
}
}
}
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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()
}
}

View File

@ -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)
}
}

View File

@ -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")

View File

@ -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
}

View File

@ -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
}

View File

@ -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>()

View File

@ -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
}

View File

@ -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

View File

@ -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) {

View File

@ -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.")
}
}
}
}

View File

@ -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()
)
}
}
}

View File

@ -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.")

View File

@ -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;
});

View File

@ -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) {

View File

@ -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 {

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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()
}

View File

@ -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) {

View File

@ -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)

View File

@ -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)

View File

@ -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 =

View File

@ -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,