diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 2ab20fde69..3f3b539ad8 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -218,6 +218,8 @@
+
+
@@ -232,6 +234,8 @@
+
+
@@ -328,4 +332,4 @@
-
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index d92c4ea889..9f4a085b55 100644
--- a/build.gradle
+++ b/build.gradle
@@ -403,7 +403,9 @@ bintrayConfig {
'corda-notary-healthcheck-contract',
'corda-notary-healthcheck-cordapp',
'corda-notary-healthcheck-client',
- 'corda-tools-cliutils'
+ 'corda-tools-cliutils',
+ 'corda-notary-raft',
+ 'corda-notary-bft-smart'
]
license {
name = 'Apache-2.0'
diff --git a/core/src/main/kotlin/net/corda/core/cordapp/Cordapp.kt b/core/src/main/kotlin/net/corda/core/cordapp/Cordapp.kt
index ddf369b668..9ca4e04e36 100644
--- a/core/src/main/kotlin/net/corda/core/cordapp/Cordapp.kt
+++ b/core/src/main/kotlin/net/corda/core/cordapp/Cordapp.kt
@@ -4,6 +4,7 @@ import net.corda.core.DeleteForDJVM
import net.corda.core.DoNotImplement
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
+import net.corda.core.internal.notary.NotaryService
import net.corda.core.schemas.MappedSchema
import net.corda.core.serialization.SerializationCustomSerializer
import net.corda.core.serialization.SerializationWhitelist
@@ -48,4 +49,5 @@ interface Cordapp {
val jarPath: URL
val cordappClasses: List
val jarHash: SecureHash.SHA256
+ val notaryService: Class?
}
diff --git a/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappImpl.kt b/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappImpl.kt
index 2e1761afa8..8ab16a5190 100644
--- a/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappImpl.kt
+++ b/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappImpl.kt
@@ -4,6 +4,7 @@ import net.corda.core.DeleteForDJVM
import net.corda.core.cordapp.Cordapp
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
+import net.corda.core.internal.notary.NotaryService
import net.corda.core.internal.toPath
import net.corda.core.schemas.MappedSchema
import net.corda.core.serialization.SerializationCustomSerializer
@@ -25,7 +26,10 @@ data class CordappImpl(
override val allFlows: List>>,
override val jarPath: URL,
val info: Info,
- override val jarHash: SecureHash.SHA256) : Cordapp {
+ override val jarHash: SecureHash.SHA256,
+ override val notaryService: Class? = null,
+ /** Indicates whether the CorDapp is loaded from external sources, or generated on node startup (virtual). */
+ val isLoaded: Boolean = true) : Cordapp {
override val name: String = jarName(jarPath)
companion object {
@@ -37,7 +41,10 @@ data class CordappImpl(
*
* TODO: Also add [SchedulableFlow] as a Cordapp class
*/
- override val cordappClasses: List = (rpcFlows + initiatedFlows + services + serializationWhitelists.map { javaClass }).map { it.name } + contractClassNames
+ override val cordappClasses: List = run {
+ val classList = rpcFlows + initiatedFlows + services + serializationWhitelists.map { javaClass } + notaryService
+ classList.mapNotNull { it?.name } + contractClassNames
+ }
// TODO Why a seperate Info class and not just have the fields directly in CordappImpl?
data class Info(val shortName: String, val vendor: String, val version: String, val minimumPlatformVersion: Int, val targetPlatformVersion: Int) {
@@ -48,4 +55,4 @@ data class CordappImpl(
fun hasUnknownFields(): Boolean = arrayOf(shortName, vendor, version).any { it == UNKNOWN_VALUE }
}
-}
+}
\ No newline at end of file
diff --git a/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt b/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt
index eaabb2d987..e2a2e22b71 100644
--- a/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt
+++ b/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt
@@ -128,7 +128,7 @@ class AttachmentTests : WithMockNet {
// Makes a node that doesn't do sanity checking at load time.
private fun makeBadNode(name: CordaX500Name) = mockNet.createNode(
InternalMockNodeParameters(legalName = makeUnique(name)),
- nodeFactory = { args, _ ->
+ nodeFactory = { args ->
object : InternalMockNetwork.MockNode(args) {
override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = false }
}
diff --git a/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt b/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt
index 43c35ca0dd..3ba769ce88 100644
--- a/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt
+++ b/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt
@@ -161,7 +161,7 @@ class AttachmentSerializationTest {
}
private fun rebootClientAndGetAttachmentContent(checkAttachmentsOnLoad: Boolean = true): String {
- client = mockNet.restartNode(client) { args, _ ->
+ client = mockNet.restartNode(client) { args ->
object : InternalMockNetwork.MockNode(args) {
override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = checkAttachmentsOnLoad }
}
diff --git a/experimental/notary-bft-smart/build.gradle b/experimental/notary-bft-smart/build.gradle
new file mode 100644
index 0000000000..b4ff48b444
--- /dev/null
+++ b/experimental/notary-bft-smart/build.gradle
@@ -0,0 +1,35 @@
+apply plugin: 'kotlin'
+apply plugin: 'kotlin-jpa'
+apply plugin: 'idea'
+apply plugin: 'net.corda.plugins.cordapp'
+apply plugin: 'net.corda.plugins.publish-utils'
+
+configurations {
+ integrationTestCompile.extendsFrom testCompile
+ integrationTestRuntime.extendsFrom testRuntime
+}
+
+dependencies {
+ cordaCompile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+
+ // Corda integration dependencies
+ cordaCompile project(':node')
+
+ // BFT-SMaRt
+ compile 'commons-codec:commons-codec:1.10'
+ compile 'com.github.bft-smart:library:master-v1.1-beta-g6215ec8-87'
+
+ testCompile "junit:junit:$junit_version"
+ testCompile project(':node-driver')
+}
+
+idea {
+ module {
+ downloadJavadoc = true // defaults to false
+ downloadSources = true
+ }
+}
+
+publish {
+ name 'corda-notary-bft-smart'
+}
diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt b/experimental/notary-bft-smart/src/main/kotlin/net/corda/notary/bftsmart/BFTSMaRt.kt
similarity index 97%
rename from node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt
rename to experimental/notary-bft-smart/src/main/kotlin/net/corda/notary/bftsmart/BFTSMaRt.kt
index 885746ecb6..a825b3c1a5 100644
--- a/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt
+++ b/experimental/notary-bft-smart/src/main/kotlin/net/corda/notary/bftsmart/BFTSMaRt.kt
@@ -1,4 +1,4 @@
-package net.corda.node.services.transactions
+package net.corda.notary.bftsmart
import bftsmart.communication.ServerCommunicationSystem
import bftsmart.communication.client.netty.NettyClientServerCommunicationSystemClientSide
@@ -34,10 +34,11 @@ import net.corda.core.serialization.serialize
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.debug
import net.corda.node.services.api.ServiceHubInternal
-import net.corda.node.services.transactions.BFTSMaRt.Client
-import net.corda.node.services.transactions.BFTSMaRt.Replica
+import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.node.utilities.AppendOnlyPersistentMap
import net.corda.nodeapi.internal.persistence.currentDBSession
+import net.corda.notary.bftsmart.BFTSMaRt.Client
+import net.corda.notary.bftsmart.BFTSMaRt.Replica
import java.nio.file.Path
import java.security.PublicKey
import java.util.*
@@ -78,7 +79,7 @@ object BFTSMaRt {
fun waitUntilAllReplicasHaveInitialized()
}
- class Client(config: BFTSMaRtConfig, private val clientId: Int, private val cluster: Cluster, private val notaryService: BFTNonValidatingNotaryService) : SingletonSerializeAsToken() {
+ class Client(config: BFTSMaRtConfig, private val clientId: Int, private val cluster: Cluster, private val notaryService: BftSmartNotaryService) : SingletonSerializeAsToken() {
companion object {
private val log = contextLogger()
}
@@ -178,7 +179,7 @@ object BFTSMaRt {
abstract class Replica(config: BFTSMaRtConfig,
replicaId: Int,
createMap: () -> AppendOnlyPersistentMap,
+ BftSmartNotaryService.CommittedState, PersistentStateRef>,
protected val services: ServiceHubInternal,
protected val notaryIdentityKey: PublicKey) : DefaultRecoverable() {
companion object {
diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRtConfig.kt b/experimental/notary-bft-smart/src/main/kotlin/net/corda/notary/bftsmart/BFTSMaRtConfig.kt
similarity index 97%
rename from node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRtConfig.kt
rename to experimental/notary-bft-smart/src/main/kotlin/net/corda/notary/bftsmart/BFTSMaRtConfig.kt
index e642dc858f..489f190d6f 100644
--- a/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRtConfig.kt
+++ b/experimental/notary-bft-smart/src/main/kotlin/net/corda/notary/bftsmart/BFTSMaRtConfig.kt
@@ -1,10 +1,11 @@
-package net.corda.node.services.transactions
+package net.corda.notary.bftsmart
import net.corda.core.internal.div
import net.corda.core.internal.writer
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.debug
+import net.corda.node.services.transactions.PathManager
import java.io.PrintWriter
import java.net.InetAddress
import java.net.Socket
diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt b/experimental/notary-bft-smart/src/main/kotlin/net/corda/notary/bftsmart/BftSmartNotaryService.kt
similarity index 87%
rename from node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt
rename to experimental/notary-bft-smart/src/main/kotlin/net/corda/notary/bftsmart/BftSmartNotaryService.kt
index 156640c443..57560699cb 100644
--- a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt
+++ b/experimental/notary-bft-smart/src/main/kotlin/net/corda/notary/bftsmart/BftSmartNotaryService.kt
@@ -1,4 +1,4 @@
-package net.corda.node.services.transactions
+package net.corda.notary.bftsmart
import co.paralleluniverse.fibers.Suspendable
import com.google.common.util.concurrent.SettableFuture
@@ -10,6 +10,7 @@ import net.corda.core.identity.Party
import net.corda.core.internal.notary.NotaryInternalException
import net.corda.core.internal.notary.NotaryService
import net.corda.core.internal.notary.verifySignature
+import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentStateRef
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
@@ -21,6 +22,7 @@ import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.config.BFTSMaRtConfiguration
+import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.node.utilities.AppendOnlyPersistentMap
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
import java.security.PublicKey
@@ -33,16 +35,30 @@ import kotlin.concurrent.thread
*
* A transaction is notarised when the consensus is reached by the cluster on its uniqueness, and time-window validity.
*/
-class BFTNonValidatingNotaryService(
+class BftSmartNotaryService(
override val services: ServiceHubInternal,
- override val notaryIdentityKey: PublicKey,
- private val bftSMaRtConfig: BFTSMaRtConfiguration,
- cluster: BFTSMaRt.Cluster
+ override val notaryIdentityKey: PublicKey
) : NotaryService() {
companion object {
private val log = contextLogger()
}
+ private val notaryConfig = services.configuration.notary
+ ?: throw IllegalArgumentException("Failed to register ${this::class.java}: notary configuration not present")
+
+ private val bftSMaRtConfig = notaryConfig.bftSMaRt
+ ?: throw IllegalArgumentException("Failed to register ${this::class.java}: raft configuration not present")
+
+ private val cluster: BFTSMaRt.Cluster = makeBFTCluster(notaryIdentityKey, bftSMaRtConfig)
+
+ protected open fun makeBFTCluster(notaryKey: PublicKey, bftSMaRtConfig: BFTSMaRtConfiguration): BFTSMaRt.Cluster {
+ return object : BFTSMaRt.Cluster {
+ override fun waitUntilAllReplicasHaveInitialized() {
+ log.warn("A BFT replica may still be initializing, in which case the upcoming consensus change may cause it to spin.")
+ }
+ }
+ }
+
private val client: BFTSMaRt.Client
private val replicaHolder = SettableFuture.create()
@@ -71,7 +87,7 @@ class BFTNonValidatingNotaryService(
override fun createServiceFlow(otherPartySession: FlowSession): FlowLogic = ServiceFlow(otherPartySession, this)
- private class ServiceFlow(val otherSideSession: FlowSession, val service: BFTNonValidatingNotaryService) : FlowLogic() {
+ private class ServiceFlow(val otherSideSession: FlowSession, val service: BftSmartNotaryService) : FlowLogic() {
@Suspendable
override fun call(): Void? {
val payload = otherSideSession.receive().unwrap { it }
diff --git a/experimental/notary-bft-smart/src/main/kotlin/net/corda/notary/bftsmart/Schema.kt b/experimental/notary-bft-smart/src/main/kotlin/net/corda/notary/bftsmart/Schema.kt
new file mode 100644
index 0000000000..360c1af5df
--- /dev/null
+++ b/experimental/notary-bft-smart/src/main/kotlin/net/corda/notary/bftsmart/Schema.kt
@@ -0,0 +1,20 @@
+package net.corda.notary.bftsmart
+
+import net.corda.core.schemas.MappedSchema
+import net.corda.node.services.transactions.PersistentUniquenessProvider
+import net.corda.notary.bftsmart.BftSmartNotaryService
+
+object BftSmartNotarySchema
+
+object BftSmartNotarySchemaV1 : MappedSchema(
+ schemaFamily = BftSmartNotarySchema.javaClass,
+ version = 1,
+ mappedTypes = listOf(
+ PersistentUniquenessProvider.BaseComittedState::class.java,
+ PersistentUniquenessProvider.Request::class.java,
+ BftSmartNotaryService.CommittedState::class.java
+ )
+) {
+ override val migrationResource: String?
+ get() = "notary-bft-smart.changelog-master"
+}
\ No newline at end of file
diff --git a/experimental/notary-bft-smart/src/main/resources/migration/notary-bft-smart.changelog-init.xml b/experimental/notary-bft-smart/src/main/resources/migration/notary-bft-smart.changelog-init.xml
new file mode 100644
index 0000000000..1b8dbf7464
--- /dev/null
+++ b/experimental/notary-bft-smart/src/main/resources/migration/notary-bft-smart.changelog-init.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/experimental/notary-bft-smart/src/main/resources/migration/notary-bft-smart.changelog-master.xml b/experimental/notary-bft-smart/src/main/resources/migration/notary-bft-smart.changelog-master.xml
new file mode 100644
index 0000000000..fdf0632cf8
--- /dev/null
+++ b/experimental/notary-bft-smart/src/main/resources/migration/notary-bft-smart.changelog-master.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/experimental/notary-bft-smart/src/main/resources/migration/notary-bft-smart.changelog-pkey.xml b/experimental/notary-bft-smart/src/main/resources/migration/notary-bft-smart.changelog-pkey.xml
new file mode 100644
index 0000000000..59a5b1fb50
--- /dev/null
+++ b/experimental/notary-bft-smart/src/main/resources/migration/notary-bft-smart.changelog-pkey.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/experimental/notary-bft-smart/src/main/resources/migration/notary-bft-smart.changelog-v1.xml b/experimental/notary-bft-smart/src/main/resources/migration/notary-bft-smart.changelog-v1.xml
new file mode 100644
index 0000000000..57b9adbf93
--- /dev/null
+++ b/experimental/notary-bft-smart/src/main/resources/migration/notary-bft-smart.changelog-v1.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/node/src/main/resources/net/corda/node/services/transactions/system.config.printf b/experimental/notary-bft-smart/src/main/resources/net/corda/notary/bftsmart/system.config.printf
similarity index 100%
rename from node/src/main/resources/net/corda/node/services/transactions/system.config.printf
rename to experimental/notary-bft-smart/src/main/resources/net/corda/notary/bftsmart/system.config.printf
diff --git a/node/src/integration-test/kotlin/net/corda/node/services/BFTNotaryServiceTests.kt b/experimental/notary-bft-smart/src/test/kotlin/net/corda/notary/bftsmart/BFTNotaryServiceTests.kt
similarity index 96%
rename from node/src/integration-test/kotlin/net/corda/node/services/BFTNotaryServiceTests.kt
rename to experimental/notary-bft-smart/src/test/kotlin/net/corda/notary/bftsmart/BFTNotaryServiceTests.kt
index f6fa0fe452..2fc3806206 100644
--- a/node/src/integration-test/kotlin/net/corda/node/services/BFTNotaryServiceTests.kt
+++ b/experimental/notary-bft-smart/src/test/kotlin/net/corda/notary/bftsmart/BFTNotaryServiceTests.kt
@@ -1,4 +1,4 @@
-package net.corda.node.services
+package net.corda.notary.bftsmart
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.whenever
@@ -23,8 +23,6 @@ import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds
import net.corda.node.services.config.BFTSMaRtConfiguration
import net.corda.node.services.config.NotaryConfig
-import net.corda.node.services.transactions.minClusterSize
-import net.corda.node.services.transactions.minCorrectReplicas
import net.corda.nodeapi.internal.DevIdentityGenerator
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.testing.common.internal.testNetworkParameters
@@ -94,7 +92,11 @@ class BFTNotaryServiceTests {
val nodes = replicaIds.map { replicaId ->
mockNet.createUnstartedNode(InternalMockNodeParameters(configOverrides = {
- val notary = NotaryConfig(validating = false, bftSMaRt = BFTSMaRtConfiguration(replicaId, clusterAddresses, exposeRaces = exposeRaces))
+ val notary = NotaryConfig(
+ validating = false,
+ bftSMaRt = BFTSMaRtConfiguration(replicaId, clusterAddresses, exposeRaces = exposeRaces),
+ className = "net.corda.notary.bftsmart.BftSmartNotaryService"
+ )
doReturn(notary).whenever(it).notary
}))
} + mockNet.createUnstartedNode()
diff --git a/node/src/test/kotlin/net/corda/node/services/transactions/BFTSMaRtConfigTests.kt b/experimental/notary-bft-smart/src/test/kotlin/net/corda/notary/bftsmart/BFTSMaRtConfigTests.kt
similarity index 92%
rename from node/src/test/kotlin/net/corda/node/services/transactions/BFTSMaRtConfigTests.kt
rename to experimental/notary-bft-smart/src/test/kotlin/net/corda/notary/bftsmart/BFTSMaRtConfigTests.kt
index 1837953266..cdf5364b83 100644
--- a/node/src/test/kotlin/net/corda/node/services/transactions/BFTSMaRtConfigTests.kt
+++ b/experimental/notary-bft-smart/src/test/kotlin/net/corda/notary/bftsmart/BFTSMaRtConfigTests.kt
@@ -1,7 +1,7 @@
-package net.corda.node.services.transactions
+package net.corda.notary.bftsmart
import net.corda.core.utilities.NetworkHostAndPort
-import net.corda.node.services.transactions.BFTSMaRtConfig.Companion.portIsClaimedFormat
+import net.corda.notary.bftsmart.BFTSMaRtConfig.Companion.portIsClaimedFormat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Test
import kotlin.test.assertEquals
diff --git a/experimental/notary-raft/build.gradle b/experimental/notary-raft/build.gradle
new file mode 100644
index 0000000000..b07659ef2f
--- /dev/null
+++ b/experimental/notary-raft/build.gradle
@@ -0,0 +1,35 @@
+apply plugin: 'kotlin'
+apply plugin: 'idea'
+apply plugin: 'net.corda.plugins.cordapp'
+apply plugin: 'net.corda.plugins.publish-utils'
+
+configurations {
+ integrationTestCompile.extendsFrom testCompile
+ integrationTestRuntime.extendsFrom testRuntime
+}
+
+dependencies {
+ cordaCompile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+
+ // Corda integration dependencies
+ cordaCompile project(':node')
+
+ // Java Atomix: RAFT library
+ compile 'io.atomix.copycat:copycat-client:1.2.8'
+ compile 'io.atomix.copycat:copycat-server:1.2.8'
+ compile 'io.atomix.catalyst:catalyst-netty:1.2.1'
+
+ testCompile "junit:junit:$junit_version"
+ testCompile project(':node-driver')
+}
+
+idea {
+ module {
+ downloadJavadoc = true // defaults to false
+ downloadSources = true
+ }
+}
+
+publish {
+ name 'corda-notary-raft'
+}
diff --git a/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/RaftNotaryService.kt b/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/RaftNotaryService.kt
new file mode 100644
index 0000000000..3913551802
--- /dev/null
+++ b/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/RaftNotaryService.kt
@@ -0,0 +1,46 @@
+package net.corda.notary.raft
+
+import net.corda.core.flows.FlowSession
+import net.corda.core.internal.notary.NotaryServiceFlow
+import net.corda.core.internal.notary.TrustedAuthorityNotaryService
+import net.corda.node.services.api.ServiceHubInternal
+import net.corda.node.services.transactions.NonValidatingNotaryFlow
+import net.corda.node.services.transactions.ValidatingNotaryFlow
+import java.security.PublicKey
+
+/** A highly available notary service using the Raft algorithm to achieve consensus. */
+class RaftNotaryService(
+ override val services: ServiceHubInternal,
+ override val notaryIdentityKey: PublicKey
+) : TrustedAuthorityNotaryService() {
+ private val notaryConfig = services.configuration.notary
+ ?: throw IllegalArgumentException("Failed to register ${this::class.java}: notary configuration not present")
+
+ override val uniquenessProvider = with(services) {
+ val raftConfig = notaryConfig.raft
+ ?: throw IllegalArgumentException("Failed to register ${this::class.java}: raft configuration not present")
+ RaftUniquenessProvider(
+ configuration.baseDirectory,
+ configuration.p2pSslOptions,
+ database,
+ clock,
+ monitoringService.metrics,
+ services.cacheFactory,
+ raftConfig
+ )
+ }
+
+ override fun createServiceFlow(otherPartySession: FlowSession): NotaryServiceFlow {
+ return if (notaryConfig.validating) {
+ ValidatingNotaryFlow(otherPartySession, this)
+ } else NonValidatingNotaryFlow(otherPartySession, this)
+ }
+
+ override fun start() {
+ uniquenessProvider.start()
+ }
+
+ override fun stop() {
+ uniquenessProvider.stop()
+ }
+}
diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/RaftTransactionCommitLog.kt b/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/RaftTransactionCommitLog.kt
similarity index 96%
rename from node/src/main/kotlin/net/corda/node/services/transactions/RaftTransactionCommitLog.kt
rename to experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/RaftTransactionCommitLog.kt
index c35ae146ab..a6fcd0b8a3 100644
--- a/node/src/main/kotlin/net/corda/node/services/transactions/RaftTransactionCommitLog.kt
+++ b/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/RaftTransactionCommitLog.kt
@@ -1,4 +1,4 @@
-package net.corda.node.services.transactions
+package net.corda.notary.raft
import io.atomix.catalyst.buffer.BufferInput
import io.atomix.catalyst.buffer.BufferOutput
@@ -27,6 +27,7 @@ import net.corda.core.serialization.internal.checkpointSerialize
import net.corda.core.utilities.ByteSequence
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.debug
+import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.node.utilities.AppendOnlyPersistentMap
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.currentDBSession
@@ -111,7 +112,7 @@ class RaftTransactionCommitLog(
}
}
- private fun logRequest(commitCommand: RaftTransactionCommitLog.Commands.CommitTransaction) {
+ private fun logRequest(commitCommand: Commands.CommitTransaction) {
val request = PersistentUniquenessProvider.Request(
consumingTxHash = commitCommand.txId.toString(),
partyName = commitCommand.requestingParty,
@@ -192,8 +193,8 @@ class RaftTransactionCommitLog(
registerAbstract(SecureHash::class.java, CordaKryoSerializer::class.java)
registerAbstract(TimeWindow::class.java, CordaKryoSerializer::class.java)
registerAbstract(NotaryError::class.java, CordaKryoSerializer::class.java)
- register(RaftTransactionCommitLog.Commands.CommitTransaction::class.java, CordaKryoSerializer::class.java)
- register(RaftTransactionCommitLog.Commands.Get::class.java, CordaKryoSerializer::class.java)
+ register(Commands.CommitTransaction::class.java, CordaKryoSerializer::class.java)
+ register(Commands.Get::class.java, CordaKryoSerializer::class.java)
register(StateRef::class.java, CordaKryoSerializer::class.java)
register(LinkedHashMap::class.java, CordaKryoSerializer::class.java)
}
diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt b/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/RaftUniquenessProvider.kt
similarity index 98%
rename from node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt
rename to experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/RaftUniquenessProvider.kt
index 2192343fa1..c7670d0c18 100644
--- a/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt
+++ b/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/RaftUniquenessProvider.kt
@@ -1,4 +1,4 @@
-package net.corda.node.services.transactions
+package net.corda.notary.raft
import com.codahale.metrics.Gauge
import com.codahale.metrics.MetricRegistry
@@ -26,12 +26,12 @@ import net.corda.core.serialization.serialize
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.debug
import net.corda.node.services.config.RaftConfig
-import net.corda.node.services.transactions.RaftTransactionCommitLog.Commands.CommitTransaction
import net.corda.node.utilities.AppendOnlyPersistentMap
import net.corda.node.utilities.NamedCacheFactory
import net.corda.nodeapi.internal.config.MutualSslConfiguration
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
+import net.corda.notary.raft.RaftTransactionCommitLog.Commands.CommitTransaction
import java.nio.file.Path
import java.time.Clock
import java.util.concurrent.CompletableFuture
diff --git a/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/Schema.kt b/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/Schema.kt
new file mode 100644
index 0000000000..3a93164875
--- /dev/null
+++ b/experimental/notary-raft/src/main/kotlin/net/corda/notary/raft/Schema.kt
@@ -0,0 +1,19 @@
+package net.corda.notary.raft
+
+import net.corda.core.schemas.MappedSchema
+import net.corda.node.services.transactions.PersistentUniquenessProvider
+
+object RaftNotarySchema
+
+object RaftNotarySchemaV1 : MappedSchema(
+ schemaFamily = RaftNotarySchema.javaClass,
+ version = 1,
+ mappedTypes = listOf(
+ PersistentUniquenessProvider.BaseComittedState::class.java,
+ PersistentUniquenessProvider.Request::class.java,
+ RaftUniquenessProvider.CommittedState::class.java
+ )
+) {
+ override val migrationResource: String?
+ get() = "notary-raft.changelog-master"
+}
\ No newline at end of file
diff --git a/experimental/notary-raft/src/main/resources/migration/notary-raft.changelog-init.xml b/experimental/notary-raft/src/main/resources/migration/notary-raft.changelog-init.xml
new file mode 100644
index 0000000000..5fe85ce568
--- /dev/null
+++ b/experimental/notary-raft/src/main/resources/migration/notary-raft.changelog-init.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/experimental/notary-raft/src/main/resources/migration/notary-raft.changelog-master.xml b/experimental/notary-raft/src/main/resources/migration/notary-raft.changelog-master.xml
new file mode 100644
index 0000000000..555344167e
--- /dev/null
+++ b/experimental/notary-raft/src/main/resources/migration/notary-raft.changelog-master.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
diff --git a/experimental/notary-raft/src/main/resources/migration/notary-raft.changelog-pkey.xml b/experimental/notary-raft/src/main/resources/migration/notary-raft.changelog-pkey.xml
new file mode 100644
index 0000000000..24cf747d58
--- /dev/null
+++ b/experimental/notary-raft/src/main/resources/migration/notary-raft.changelog-pkey.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/experimental/notary-raft/src/main/resources/migration/notary-raft.changelog-v1.xml b/experimental/notary-raft/src/main/resources/migration/notary-raft.changelog-v1.xml
new file mode 100644
index 0000000000..f95c8e7923
--- /dev/null
+++ b/experimental/notary-raft/src/main/resources/migration/notary-raft.changelog-v1.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/node/src/integration-test/kotlin/net/corda/node/services/RaftNotaryServiceTests.kt b/experimental/notary-raft/src/test/kotlin/net/corda/notary/raft/RaftNotaryServiceTests.kt
similarity index 99%
rename from node/src/integration-test/kotlin/net/corda/node/services/RaftNotaryServiceTests.kt
rename to experimental/notary-raft/src/test/kotlin/net/corda/notary/raft/RaftNotaryServiceTests.kt
index 4b215aabce..05858e5805 100644
--- a/node/src/integration-test/kotlin/net/corda/node/services/RaftNotaryServiceTests.kt
+++ b/experimental/notary-raft/src/test/kotlin/net/corda/notary/raft/RaftNotaryServiceTests.kt
@@ -1,4 +1,4 @@
-package net.corda.node.services
+package net.corda.notary.raft
import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.StateRef
diff --git a/node/src/integration-test/kotlin/net/corda/node/services/transactions/RaftTransactionCommitLogTests.kt b/experimental/notary-raft/src/test/kotlin/net/corda/notary/raft/RaftTransactionCommitLogTests.kt
similarity index 98%
rename from node/src/integration-test/kotlin/net/corda/node/services/transactions/RaftTransactionCommitLogTests.kt
rename to experimental/notary-raft/src/test/kotlin/net/corda/notary/raft/RaftTransactionCommitLogTests.kt
index 6668f8c373..cfd7df9cdc 100644
--- a/node/src/integration-test/kotlin/net/corda/node/services/transactions/RaftTransactionCommitLogTests.kt
+++ b/experimental/notary-raft/src/test/kotlin/net/corda/notary/raft/RaftTransactionCommitLogTests.kt
@@ -1,4 +1,4 @@
-package net.corda.node.services.transactions
+package net.corda.notary.raft
import com.typesafe.config.ConfigFactory
import io.atomix.catalyst.transport.Address
@@ -17,7 +17,7 @@ import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.configureDatabase
import net.corda.node.services.schema.NodeSchemaService
-import net.corda.node.utilities.TestingNamedCacheFactory
+import net.corda.testing.internal.TestingNamedCacheFactory
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.core.ALICE_NAME
@@ -156,7 +156,7 @@ class RaftTransactionCommitLogTests {
val storage = Storage.builder().withStorageLevel(StorageLevel.MEMORY).build()
val address = Address(myAddress.host, myAddress.port)
// Enterprise - OS difference: below configureDatabase parameters differs with OS intentionally to be able run test in remote database
- val database = configureDatabase(makeInternalTestDataSourceProperties( configSupplier = { ConfigFactory.empty() }), DatabaseConfig(runMigration = true), { null }, { null }, NodeSchemaService(includeNotarySchemas = true))
+ val database = configureDatabase(makeInternalTestDataSourceProperties( configSupplier = { ConfigFactory.empty() }), DatabaseConfig(runMigration = true), { null }, { null }, NodeSchemaService(extraSchemas = setOf(RaftNotarySchemaV1)))
databases.add(database)
val stateMachineFactory = { RaftTransactionCommitLog(database, Clock.systemUTC(), { RaftUniquenessProvider.createMap(TestingNamedCacheFactory()) }) }
diff --git a/node/build.gradle b/node/build.gradle
index 40876c3373..d69f58623f 100644
--- a/node/build.gradle
+++ b/node/build.gradle
@@ -155,18 +155,9 @@ dependencies {
// We only need this dependency to compile our Caplet against.
compileOnly "co.paralleluniverse:capsule:$capsule_version"
- // Java Atomix: RAFT library
- compile 'io.atomix.copycat:copycat-client:1.2.8'
- compile 'io.atomix.copycat:copycat-server:1.2.8'
- compile 'io.atomix.catalyst:catalyst-netty:1.2.1'
-
// OkHTTP: Simple HTTP library.
compile "com.squareup.okhttp3:okhttp:$okhttp_version"
- // BFT-SMaRt
- compile 'commons-codec:commons-codec:1.10'
- compile 'com.github.bft-smart:library:master-v1.1-beta-g6215ec8-87'
-
// Apache Shiro: authentication, authorization and session management.
compile "org.apache.shiro:shiro-core:${shiro_version}"
diff --git a/node/src/integration-test/kotlin/net/corda/node/services/distributed/DistributedServiceTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/distributed/DistributedServiceTests.kt
index 014e1ce453..ec3b92f392 100644
--- a/node/src/integration-test/kotlin/net/corda/node/services/distributed/DistributedServiceTests.kt
+++ b/node/src/integration-test/kotlin/net/corda/node/services/distributed/DistributedServiceTests.kt
@@ -52,7 +52,7 @@ class DistributedServiceTests : IntegrationTest() {
invokeRpc(CordaRPCOps::stateMachinesFeed))
)
driver(DriverParameters(
- extraCordappPackagesToScan = listOf("net.corda.finance.contracts", "net.corda.finance.schemas"),
+ extraCordappPackagesToScan = listOf("net.corda.finance.contracts", "net.corda.finance.schemas", "net.corda.notary.raft"),
notarySpecs = listOf(
NotarySpec(
DUMMY_NOTARY_NAME,
diff --git a/node/src/integration-test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTest.kt
index d652517a2e..2a63d16066 100644
--- a/node/src/integration-test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTest.kt
+++ b/node/src/integration-test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTest.kt
@@ -16,7 +16,6 @@ import net.corda.node.services.config.configureWithDevSSLCertificate
import net.corda.node.services.network.PersistentNetworkMapCache
import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
-import net.corda.node.utilities.TestingNamedCacheFactory
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.core.ALICE_NAME
@@ -30,6 +29,8 @@ import net.corda.testing.node.internal.MOCK_VERSION_INFO
import net.corda.testing.node.internal.makeInternalTestDataSourceProperties
import org.apache.activemq.artemis.api.core.Message.HDR_VALIDATED_USER
import org.apache.activemq.artemis.api.core.SimpleString
+import net.corda.testing.internal.TestingNamedCacheFactory
+import org.apache.activemq.artemis.api.core.ActiveMQConnectionTimedOutException
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.After
diff --git a/node/src/integration-test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt
index a4768c1e28..7a061840aa 100644
--- a/node/src/integration-test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt
+++ b/node/src/integration-test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt
@@ -5,7 +5,6 @@ import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.internal.configureDatabase
import net.corda.node.internal.schemas.NodeInfoSchemaV1
import net.corda.node.services.identity.InMemoryIdentityService
-import net.corda.node.utilities.TestingNamedCacheFactory
import net.corda.nodeapi.internal.DEV_ROOT_CA
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
@@ -14,6 +13,7 @@ import net.corda.testing.internal.IntegrationTest
import net.corda.testing.internal.IntegrationTestSchemas
import net.corda.testing.internal.toDatabaseSchemaName
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
+import net.corda.testing.internal.TestingNamedCacheFactory
import net.corda.testing.node.internal.makeTestDatabaseProperties
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatIllegalArgumentException
diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMessagingTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMessagingTest.kt
index 8e560bc538..b2d0a0f290 100644
--- a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMessagingTest.kt
+++ b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMessagingTest.kt
@@ -48,8 +48,9 @@ class P2PMessagingTest : IntegrationTest() {
private fun startDriverWithDistributedService(dsl: DriverDSL.(List) -> Unit) {
driver(DriverParameters(
- startNodesInProcess = true,
- notarySpecs = listOf(NotarySpec(DISTRIBUTED_SERVICE_NAME, cluster = ClusterSpec.Raft(clusterSize = 2)))
+ startNodesInProcess = true,
+ extraCordappPackagesToScan = listOf("net.corda.notary.raft"),
+ notarySpecs = listOf(NotarySpec(DISTRIBUTED_SERVICE_NAME, cluster = ClusterSpec.Raft(clusterSize = 2)))
)) {
dsl(defaultNotaryHandle.nodeHandles.getOrThrow().map { (it as InProcess) })
}
diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt
index 32e1c25bb4..0f53ff55e4 100644
--- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt
+++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt
@@ -118,7 +118,6 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
val platformClock: CordaClock,
cacheFactoryPrototype: NamedCacheFactory,
protected val versionInfo: VersionInfo,
- protected val cordappLoader: CordappLoader,
protected val serverThread: AffinityExecutor.ServiceAffinityExecutor,
protected val busyNodeLatch: ReusableLatch = ReusableLatch()) : SingletonSerializeAsToken() {
@@ -144,7 +143,8 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
}
}
- val schemaService = NodeSchemaService(cordappLoader.cordappSchemas, configuration.notary != null).tokenize()
+ protected val cordappLoader: CordappLoader = makeCordappLoader(configuration, versionInfo)
+ val schemaService = NodeSchemaService(cordappLoader.cordappSchemas).tokenize()
val identityService = PersistentIdentityService(cacheFactory).tokenize()
val database: CordaPersistence = createCordaPersistence(
configuration.database,
@@ -515,6 +515,24 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
)
}
+ private fun makeCordappLoader(configuration: NodeConfiguration, versionInfo: VersionInfo): CordappLoader {
+ val generatedCordapps = mutableListOf(VirtualCordapp.generateCoreCordapp(versionInfo))
+ if (isRunningSimpleNotaryService(configuration)) {
+ // For backwards compatibility purposes the single node notary implementation is built-in: a virtual
+ // CorDapp will be generated.
+ generatedCordapps += VirtualCordapp.generateSimpleNotaryCordapp(versionInfo)
+ }
+ return JarScanningCordappLoader.fromDirectories(
+ configuration.cordappDirectories,
+ versionInfo,
+ extraCordapps = generatedCordapps
+ )
+ }
+
+ private fun isRunningSimpleNotaryService(configuration: NodeConfiguration): Boolean {
+ return configuration.notary != null && configuration.notary?.className == SimpleNotaryService::class.java.name
+ }
+
private class ServiceInstantiationException(cause: Throwable?) : CordaException("Service Instantiation Error", cause)
private fun installCordaServices(myNotaryIdentity: PartyAndCertificate?) {
@@ -810,17 +828,32 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
}
private fun makeNotaryService(myNotaryIdentity: PartyAndCertificate?): NotaryService? {
- return configuration.notary?.let {
- makeCoreNotaryService(it, myNotaryIdentity).also {
- it.tokenize()
- runOnStop += it::stop
- installCoreFlow(NotaryFlow.Client::class, it::createServiceFlow)
- log.info("Running core notary: ${it.javaClass.name}")
- it.start()
+ return configuration.notary?.let { notaryConfig ->
+ val serviceClass = getNotaryServiceClass(notaryConfig.className)
+ log.info("Starting notary service: $serviceClass")
+
+ val notaryKey = myNotaryIdentity?.owningKey
+ ?: throw IllegalArgumentException("Unable to start notary service $serviceClass: notary identity not found")
+ val constructor = serviceClass.getDeclaredConstructor(ServiceHubInternal::class.java, PublicKey::class.java).apply { isAccessible = true }
+ val service = constructor.newInstance(services, notaryKey) as NotaryService
+
+ service.run {
+ tokenize()
+ runOnStop += ::stop
+ installCoreFlow(NotaryFlow.Client::class, ::createServiceFlow)
+ start()
}
+ return service
}
}
+ private fun getNotaryServiceClass(className: String): Class {
+ val loadedImplementations = cordappLoader.cordapps.mapNotNull { it.notaryService }
+ log.debug("Notary service implementations found: ${loadedImplementations.joinToString(", ")}")
+ return loadedImplementations.firstOrNull { it.name == className }
+ ?: throw IllegalArgumentException("The notary service implementation specified in the configuration: $className is not found. Available implementations: ${loadedImplementations.joinToString(", ")}}")
+ }
+
protected open fun makeKeyManagementService(identityService: PersistentIdentityService): KeyManagementServiceInternal {
// Place the long term identity key in the KMS. Eventually, this is likely going to be separated again because
// the KMS is meant for derived temporary keys used in transactions, and we're not supposed to sign things with
@@ -828,35 +861,6 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
return PersistentKeyManagementService(cacheFactory, identityService, database)
}
- private fun makeCoreNotaryService(notaryConfig: NotaryConfig, myNotaryIdentity: PartyAndCertificate?): NotaryService {
- val notaryKey = myNotaryIdentity?.owningKey
- ?: throw IllegalArgumentException("No notary identity initialized when creating a notary service")
- return notaryConfig.run {
- when {
- raft != null -> {
- val uniquenessProvider = RaftUniquenessProvider(configuration.baseDirectory, configuration.p2pSslOptions, database, platformClock, monitoringService.metrics, cacheFactory, raft)
- (if (validating) ::RaftValidatingNotaryService else ::RaftNonValidatingNotaryService)(services, notaryKey, uniquenessProvider)
- }
- bftSMaRt != null -> {
- if (validating) throw IllegalArgumentException("Validating BFTSMaRt notary not supported")
- BFTNonValidatingNotaryService(services, notaryKey, bftSMaRt, makeBFTCluster(notaryKey, bftSMaRt))
- }
- mysql != null -> {
- (if (validating) ::MySQLValidatingNotaryService else ::MySQLNonValidatingNotaryService)(services, notaryKey, mysql, configuration.devMode)
- }
- else -> (if (validating) ::ValidatingNotaryService else ::SimpleNotaryService)(services, notaryKey)
- }
- }
- }
-
- protected open fun makeBFTCluster(notaryKey: PublicKey, bftSMaRtConfig: BFTSMaRtConfiguration): BFTSMaRt.Cluster {
- return object : BFTSMaRt.Cluster {
- override fun waitUntilAllReplicasHaveInitialized() {
- log.warn("A BFT replica may still be initializing, in which case the upcoming consensus change may cause it to spin.")
- }
- }
- }
-
open fun stop() {
// TODO: We need a good way of handling "nice to have" shutdown events, especially those that deal with the
// network, including unsubscribing from updates from remote services. Possibly some sort of parameter to stop()
diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt
index df8807330f..1723aec99e 100644
--- a/node/src/main/kotlin/net/corda/node/internal/Node.kt
+++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt
@@ -28,10 +28,8 @@ import net.corda.core.utilities.contextLogger
import net.corda.node.CordaClock
import net.corda.node.SimpleClock
import net.corda.node.VersionInfo
-import net.corda.node.cordapp.CordappLoader
import net.corda.node.internal.artemis.ArtemisBroker
import net.corda.node.internal.artemis.BrokerAddresses
-import net.corda.node.internal.cordapp.JarScanningCordappLoader
import net.corda.node.internal.security.RPCSecurityManager
import net.corda.node.internal.security.RPCSecurityManagerImpl
import net.corda.node.internal.security.RPCSecurityManagerWithAdditionalUser
@@ -88,14 +86,12 @@ class NodeWithInfo(val node: Node, val info: NodeInfo) {
open class Node(configuration: NodeConfiguration,
versionInfo: VersionInfo,
private val initialiseSerialization: Boolean = true,
- cordappLoader: CordappLoader = makeCordappLoader(configuration, versionInfo),
cacheFactoryPrototype: NamedCacheFactory = DefaultNamedCacheFactory()
) : AbstractNode(
configuration,
createClock(configuration),
cacheFactoryPrototype,
versionInfo,
- cordappLoader,
// Under normal (non-test execution) it will always be "1"
AffinityExecutor.ServiceAffinityExecutor("Node thread-${sameVmNodeCounter.incrementAndGet()}", 1)
) {
@@ -133,10 +129,6 @@ open class Node(configuration: NodeConfiguration,
private val sameVmNodeCounter = AtomicInteger()
- private fun makeCordappLoader(configuration: NodeConfiguration, versionInfo: VersionInfo): CordappLoader {
- return JarScanningCordappLoader.fromDirectories(configuration.cordappDirectories, versionInfo)
- }
-
// TODO: make this configurable.
const val MAX_RPC_MESSAGE_SIZE = 10485760
diff --git a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt
index ea6745247e..caf89a6f69 100644
--- a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt
+++ b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt
@@ -22,7 +22,6 @@ import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.NodeConfigurationImpl
import net.corda.node.services.config.shouldStartLocalShell
import net.corda.node.services.config.shouldStartSSHDaemon
-import net.corda.node.services.transactions.bftSMaRtSerialFilter
import net.corda.node.utilities.createKeyPairAndSelfSignedTLSCertificate
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
import net.corda.node.utilities.registration.NodeRegistrationException
@@ -259,7 +258,8 @@ open class NodeStartup : CordaCliWrapper("corda", "Runs a Corda Node") {
}
val nodeInfo = node.start()
- logLoadedCorDapps(node.services.cordappProvider.cordapps)
+ val loadedCodapps = node.services.cordappProvider.cordapps.filter { it.isLoaded }
+ logLoadedCorDapps(loadedCodapps)
node.nodeReadyFuture.thenMatch({
// Elapsed time in seconds. We used 10 / 100.0 and not directly / 1000.0 to only keep two decimal digits.
@@ -426,6 +426,16 @@ open class NodeStartup : CordaCliWrapper("corda", "Runs a Corda Node") {
SerialFilter.install(filter)
}
+ /** This filter is required for BFT-Smart to work as it only supports Java serialization. */
+ // TODO: move this filter out of the node, allow Cordapps to specify filters.
+ private fun bftSMaRtSerialFilter(clazz: Class<*>): Boolean = clazz.name.let {
+ it.startsWith("bftsmart.")
+ || it.startsWith("java.security.")
+ || it.startsWith("java.util.")
+ || it.startsWith("java.lang.")
+ || it.startsWith("java.net.")
+ }
+
protected open fun getVersionInfo(): VersionInfo {
return VersionInfo(
PLATFORM_VERSION,
diff --git a/node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt b/node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt
index 96d1e4f435..e47badd63e 100644
--- a/node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt
+++ b/node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt
@@ -9,6 +9,8 @@ import net.corda.core.flows.*
import net.corda.core.internal.*
import net.corda.core.internal.cordapp.CordappImpl
import net.corda.core.internal.cordapp.CordappInfoResolver
+import net.corda.core.internal.notary.NotaryService
+import net.corda.core.internal.notary.TrustedAuthorityNotaryService
import net.corda.core.node.services.CordaService
import net.corda.core.schemas.MappedSchema
import net.corda.core.serialization.SerializationCustomSerializer
@@ -36,9 +38,12 @@ import kotlin.streams.toList
* @property cordappJarPaths The classpath of cordapp JARs
*/
class JarScanningCordappLoader private constructor(private val cordappJarPaths: List,
- private val versionInfo: VersionInfo = VersionInfo.UNKNOWN) : CordappLoaderTemplate() {
+ private val versionInfo: VersionInfo = VersionInfo.UNKNOWN,
+ extraCordapps: List) : CordappLoaderTemplate() {
- override val cordapps: List by lazy { loadCordapps() + coreCordapp }
+ override val cordapps: List by lazy {
+ loadCordapps() + extraCordapps
+ }
override val appClassLoader: ClassLoader = URLClassLoader(cordappJarPaths.stream().map { it.url }.toTypedArray(), javaClass.classLoader)
@@ -58,9 +63,10 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
*
* @param corDappDirectories Directories used to scan for CorDapp JARs.
*/
- fun fromDirectories(corDappDirectories: Iterable, versionInfo: VersionInfo = VersionInfo.UNKNOWN): JarScanningCordappLoader {
+ fun fromDirectories(corDappDirectories: Iterable, versionInfo: VersionInfo = VersionInfo.UNKNOWN, extraCordapps: List = emptyList()): JarScanningCordappLoader {
logger.info("Looking for CorDapps in ${corDappDirectories.distinct().joinToString(", ", "[", "]")}")
- return JarScanningCordappLoader(corDappDirectories.distinct().flatMap(this::jarUrlsInDirectory).map { it.restricted() }, versionInfo)
+ val paths = corDappDirectories.distinct().flatMap(this::jarUrlsInDirectory).map { it.restricted() }
+ return JarScanningCordappLoader(paths, versionInfo, extraCordapps)
}
/**
@@ -68,11 +74,12 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
*
* @param scanJars Uses the JAR URLs provided for classpath scanning and Cordapp detection.
*/
- fun fromJarUrls(scanJars: List, versionInfo: VersionInfo = VersionInfo.UNKNOWN): JarScanningCordappLoader {
- return JarScanningCordappLoader(scanJars.map { it.restricted() }, versionInfo)
+ fun fromJarUrls(scanJars: List, versionInfo: VersionInfo = VersionInfo.UNKNOWN, extraCordapps: List = emptyList()): JarScanningCordappLoader {
+ val paths = scanJars.map { it.restricted() }
+ return JarScanningCordappLoader(paths, versionInfo, extraCordapps)
}
- private fun URL.restricted(rootPackageName: String? = null) = RestrictedURL(this, rootPackageName)
+ private fun URL.restricted(rootPackageName: String? = null) = RestrictedURL(this, rootPackageName)
private fun jarUrlsInDirectory(directory: Path): List {
@@ -85,32 +92,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
}
}
}
-
- /** A list of the core RPC flows present in Corda */
- private val coreRPCFlows = listOf(
- ContractUpgradeFlow.Initiate::class.java,
- ContractUpgradeFlow.Authorise::class.java,
- ContractUpgradeFlow.Deauthorise::class.java)
}
-
- /** A Cordapp representing the core package which is not scanned automatically. */
- @VisibleForTesting
- internal val coreCordapp = CordappImpl(
- contractClassNames = listOf(),
- initiatedFlows = listOf(),
- rpcFlows = coreRPCFlows,
- serviceFlows = listOf(),
- schedulableFlows = listOf(),
- services = listOf(),
- serializationWhitelists = listOf(),
- serializationCustomSerializers = listOf(),
- customSchemas = setOf(),
- info = CordappImpl.Info("corda-core", versionInfo.vendor, versionInfo.releaseVersion, 1, versionInfo.platformVersion),
- allFlows = listOf(),
- jarPath = ContractUpgradeFlow.javaClass.location, // Core JAR location
- jarHash = SecureHash.allOnesHash
- )
-
private fun loadCordapps(): List {
val cordapps = cordappJarPaths
.map { scanCordapp(it).toCordapp(it) }
@@ -126,7 +108,6 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
cordapps.forEach { CordappInfoResolver.register(it.cordappClasses, it.info) }
return cordapps
}
-
private fun RestrictedScanResult.toCordapp(url: RestrictedURL): CordappImpl {
val info = url.url.openStream().let(::JarInputStream).use { it.manifest?.toCordappInfo(CordappImpl.jarName(url.url)) ?: CordappImpl.Info.UNKNOWN }
return CordappImpl(
@@ -142,10 +123,21 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
findAllFlows(this),
url.url,
info,
- getJarHash(url.url)
+ getJarHash(url.url),
+ findNotaryService(this)
)
}
+ private fun findNotaryService(scanResult: RestrictedScanResult): Class? {
+ // Note: we search for implementations of both NotaryService and TrustedAuthorityNotaryService as
+ // the scanner won't find subclasses deeper down the hierarchy if any intermediate class is not
+ // present in the CorDapp.
+ val result = scanResult.getClassesWithSuperclass(NotaryService::class) +
+ scanResult.getClassesWithSuperclass(TrustedAuthorityNotaryService::class)
+ logger.info("Found notary service CorDapp implementations: " + result.joinToString(", "))
+ return result.firstOrNull()
+ }
+
private fun getJarHash(url: URL): SecureHash.SHA256 = url.openStream().readFully().sha256()
private fun findServices(scanResult: RestrictedScanResult): List> {
@@ -202,7 +194,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
}
private fun findCustomSchemas(scanResult: RestrictedScanResult): Set {
- return scanResult.getClassesWithSuperclass(MappedSchema::class).toSet()
+ return scanResult.getClassesWithSuperclass(MappedSchema::class).instances().toSet()
}
private val cachedScanResult = LRUMap(1000)
@@ -243,18 +235,21 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
val qualifiedNamePrefix: String get() = rootPackageName?.let { "$it." } ?: ""
}
+ private fun List>.instances(): List {
+ return map { it.kotlin.objectOrNewInstance() }
+ }
+
private inner class RestrictedScanResult(private val scanResult: ScanResult, private val qualifiedNamePrefix: String) {
fun getNamesOfClassesImplementing(type: KClass<*>): List {
return scanResult.getNamesOfClassesImplementing(type.java)
.filter { it.startsWith(qualifiedNamePrefix) }
}
- fun getClassesWithSuperclass(type: KClass): List {
+ fun getClassesWithSuperclass(type: KClass): List> {
return scanResult.getNamesOfSubclassesOf(type.java)
.filter { it.startsWith(qualifiedNamePrefix) }
.mapNotNull { loadClass(it, type) }
.filterNot { Modifier.isAbstract(it.modifiers) }
- .map { it.kotlin.objectOrNewInstance() }
}
fun getClassesImplementing(type: KClass): List {
diff --git a/node/src/main/kotlin/net/corda/node/internal/cordapp/VirtualCordapps.kt b/node/src/main/kotlin/net/corda/node/internal/cordapp/VirtualCordapps.kt
new file mode 100644
index 0000000000..8fa3d24222
--- /dev/null
+++ b/node/src/main/kotlin/net/corda/node/internal/cordapp/VirtualCordapps.kt
@@ -0,0 +1,60 @@
+package net.corda.node.internal.cordapp
+
+import net.corda.core.crypto.SecureHash
+import net.corda.core.flows.ContractUpgradeFlow
+import net.corda.core.internal.cordapp.CordappImpl
+import net.corda.core.internal.location
+import net.corda.node.VersionInfo
+import net.corda.node.services.transactions.NodeNotarySchemaV1
+import net.corda.node.services.transactions.SimpleNotaryService
+
+internal object VirtualCordapp {
+ /** A list of the core RPC flows present in Corda */
+ private val coreRpcFlows = listOf(
+ ContractUpgradeFlow.Initiate::class.java,
+ ContractUpgradeFlow.Authorise::class.java,
+ ContractUpgradeFlow.Deauthorise::class.java
+ )
+
+ /** A Cordapp representing the core package which is not scanned automatically. */
+ fun generateCoreCordapp(versionInfo: VersionInfo): CordappImpl {
+ return CordappImpl(
+ contractClassNames = listOf(),
+ initiatedFlows = listOf(),
+ rpcFlows = coreRpcFlows,
+ serviceFlows = listOf(),
+ schedulableFlows = listOf(),
+ services = listOf(),
+ serializationWhitelists = listOf(),
+ serializationCustomSerializers = listOf(),
+ customSchemas = setOf(),
+ info = CordappImpl.Info("corda-core", versionInfo.vendor, versionInfo.releaseVersion, 1, versionInfo.platformVersion),
+ allFlows = listOf(),
+ jarPath = ContractUpgradeFlow.javaClass.location, // Core JAR location
+ jarHash = SecureHash.allOnesHash,
+ notaryService = null,
+ isLoaded = false
+ )
+ }
+
+ /** A Cordapp for the built-in notary service implementation. */
+ fun generateSimpleNotaryCordapp(versionInfo: VersionInfo): CordappImpl {
+ return CordappImpl(
+ contractClassNames = listOf(),
+ initiatedFlows = listOf(),
+ rpcFlows = listOf(),
+ serviceFlows = listOf(),
+ schedulableFlows = listOf(),
+ services = listOf(),
+ serializationWhitelists = listOf(),
+ serializationCustomSerializers = listOf(),
+ customSchemas = setOf(NodeNotarySchemaV1),
+ info = CordappImpl.Info("corda-notary", versionInfo.vendor, versionInfo.releaseVersion, 1, versionInfo.platformVersion),
+ allFlows = listOf(),
+ jarPath = SimpleNotaryService::class.java.location,
+ jarHash = SecureHash.allOnesHash,
+ notaryService = SimpleNotaryService::class.java,
+ isLoaded = false
+ )
+ }
+}
\ No newline at end of file
diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt
index 3fe0ee2875..a7d557911e 100644
--- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt
+++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt
@@ -137,7 +137,8 @@ data class NotaryConfig(val validating: Boolean,
val bftSMaRt: BFTSMaRtConfiguration? = null,
val custom: Boolean = false,
val mysql: MySQLConfiguration? = null,
- val serviceLegalName: CordaX500Name? = null
+ val serviceLegalName: CordaX500Name? = null,
+ val className: String = "net.corda.node.services.transactions.SimpleNotaryService"
) {
init {
require(raft == null || bftSMaRt == null || !custom || mysql == null) {
diff --git a/node/src/main/kotlin/net/corda/node/services/schema/NodeSchemaService.kt b/node/src/main/kotlin/net/corda/node/services/schema/NodeSchemaService.kt
index 0855cd80a5..2367ac5fa6 100644
--- a/node/src/main/kotlin/net/corda/node/services/schema/NodeSchemaService.kt
+++ b/node/src/main/kotlin/net/corda/node/services/schema/NodeSchemaService.kt
@@ -14,12 +14,10 @@ import net.corda.node.services.identity.PersistentIdentityService
import net.corda.node.services.keys.PersistentKeyManagementService
import net.corda.node.services.messaging.P2PMessageDeduplicator
import net.corda.node.services.persistence.DBCheckpointStorage
+import net.corda.node.services.persistence.RunOnceService
import net.corda.node.services.persistence.DBTransactionStorage
import net.corda.node.services.persistence.NodeAttachmentService
-import net.corda.node.services.persistence.RunOnceService
-import net.corda.node.services.transactions.BFTNonValidatingNotaryService
import net.corda.node.services.transactions.PersistentUniquenessProvider
-import net.corda.node.services.transactions.RaftUniquenessProvider
import net.corda.node.services.upgrade.ContractUpgradeServiceImpl
import net.corda.node.services.vault.VaultSchemaV1
@@ -30,7 +28,7 @@ import net.corda.node.services.vault.VaultSchemaV1
* TODO: support plugins for schema version upgrading or custom mapping not supported by original [QueryableState].
* TODO: create whitelisted tables when a CorDapp is first installed
*/
-class NodeSchemaService(private val extraSchemas: Set = emptySet(), includeNotarySchemas: Boolean = false) : SchemaService, SingletonSerializeAsToken() {
+class NodeSchemaService(private val extraSchemas: Set = emptySet()) : SchemaService, SingletonSerializeAsToken() {
// Core Entities used by a Node
object NodeCore
@@ -49,26 +47,12 @@ class NodeSchemaService(private val extraSchemas: Set = emptySet()
override val migrationResource = "node-core.changelog-master"
}
- // Entities used by a Notary
- object NodeNotary
-
- object NodeNotaryV1 : MappedSchema(schemaFamily = NodeNotary.javaClass, version = 1,
- mappedTypes = listOf(PersistentUniquenessProvider.BaseComittedState::class.java,
- PersistentUniquenessProvider.Request::class.java,
- PersistentUniquenessProvider.CommittedState::class.java,
- RaftUniquenessProvider.CommittedState::class.java,
- BFTNonValidatingNotaryService.CommittedState::class.java
- )) {
- override val migrationResource = "node-notary.changelog-master"
- }
-
// Required schemas are those used by internal Corda services
private val requiredSchemas: Map =
mapOf(Pair(CommonSchemaV1, SchemaOptions()),
- Pair(VaultSchemaV1, SchemaOptions()),
- Pair(NodeInfoSchemaV1, SchemaOptions()),
- Pair(NodeCoreV1, SchemaOptions())) +
- if (includeNotarySchemas) mapOf(Pair(NodeNotaryV1, SchemaOptions())) else emptyMap()
+ Pair(VaultSchemaV1, SchemaOptions()),
+ Pair(NodeInfoSchemaV1, SchemaOptions()),
+ Pair(NodeCoreV1, SchemaOptions()))
fun internalSchemas() = requiredSchemas.keys + extraSchemas.filter { schema -> // when mapped schemas from the finance module are present, they are considered as internal ones
schema::class.qualifiedName == "net.corda.finance.schemas.CashSchemaV1" || schema::class.qualifiedName == "net.corda.finance.schemas.CommercialPaperSchemaV1" }
diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt
deleted file mode 100644
index 158d86b3c7..0000000000
--- a/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package net.corda.node.services.transactions
-
-import net.corda.core.flows.FlowSession
-import net.corda.core.internal.notary.NotaryServiceFlow
-import net.corda.core.internal.notary.TrustedAuthorityNotaryService
-import net.corda.core.node.ServiceHub
-import java.security.PublicKey
-
-/** A non-validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */
-class RaftNonValidatingNotaryService(
- override val services: ServiceHub,
- override val notaryIdentityKey: PublicKey,
- override val uniquenessProvider: RaftUniquenessProvider
-) : TrustedAuthorityNotaryService() {
- override fun createServiceFlow(otherPartySession: FlowSession): NotaryServiceFlow {
- return NonValidatingNotaryFlow(otherPartySession, this)
- }
-
- override fun start() {
- uniquenessProvider.start()
- }
-
- override fun stop() {
- uniquenessProvider.stop()
- }
-}
\ No newline at end of file
diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt
deleted file mode 100644
index f0cb8c1f8e..0000000000
--- a/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package net.corda.node.services.transactions
-
-import net.corda.core.flows.FlowSession
-import net.corda.core.internal.notary.NotaryServiceFlow
-import net.corda.core.internal.notary.TrustedAuthorityNotaryService
-import net.corda.core.node.ServiceHub
-import java.security.PublicKey
-
-/** A validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */
-class RaftValidatingNotaryService(
- override val services: ServiceHub,
- override val notaryIdentityKey: PublicKey,
- override val uniquenessProvider: RaftUniquenessProvider
-) : TrustedAuthorityNotaryService() {
- override fun createServiceFlow(otherPartySession: FlowSession): NotaryServiceFlow {
- return ValidatingNotaryFlow(otherPartySession, this)
- }
-
- override fun start() {
- uniquenessProvider.start()
- }
-
- override fun stop() {
- uniquenessProvider.stop()
- }
-}
diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt
index 51909ea5b1..d382b2feae 100644
--- a/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt
+++ b/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt
@@ -3,15 +3,38 @@ package net.corda.node.services.transactions
import net.corda.core.flows.FlowSession
import net.corda.core.internal.notary.NotaryServiceFlow
import net.corda.core.internal.notary.TrustedAuthorityNotaryService
+import net.corda.core.schemas.MappedSchema
import net.corda.node.services.api.ServiceHubInternal
import java.security.PublicKey
-/** A simple Notary service that does not perform transaction validation */
+/** An embedded notary service that uses the node's database to store committed states. */
class SimpleNotaryService(override val services: ServiceHubInternal, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
+ private val notaryConfig = services.configuration.notary
+ ?: throw IllegalArgumentException("Failed to register ${this::class.java}: notary configuration not present")
+
override val uniquenessProvider = PersistentUniquenessProvider(services.clock, services.database, services.cacheFactory)
- override fun createServiceFlow(otherPartySession: FlowSession): NotaryServiceFlow = NonValidatingNotaryFlow(otherPartySession, this)
+ override fun createServiceFlow(otherPartySession: FlowSession): NotaryServiceFlow {
+ return if (notaryConfig.validating) {
+ log.info("Starting in validating mode")
+ ValidatingNotaryFlow(otherPartySession, this)
+ } else {
+ log.info("Starting in non-validating mode")
+ NonValidatingNotaryFlow(otherPartySession, this)
+ }
+ }
override fun start() {}
override fun stop() {}
}
+
+// Entities used by a Notary
+object NodeNotarySchema
+
+object NodeNotarySchemaV1 : MappedSchema(schemaFamily = NodeNotarySchema.javaClass, version = 1,
+ mappedTypes = listOf(PersistentUniquenessProvider.BaseComittedState::class.java,
+ PersistentUniquenessProvider.Request::class.java,
+ PersistentUniquenessProvider.CommittedState::class.java
+ )) {
+ override val migrationResource = "node-notary.changelog-master"
+}
\ No newline at end of file
diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt
index 6e39a3ea1e..e69de29bb2 100644
--- a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt
+++ b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt
@@ -1,17 +0,0 @@
-package net.corda.node.services.transactions
-
-import net.corda.core.flows.FlowSession
-import net.corda.core.internal.notary.NotaryServiceFlow
-import net.corda.core.internal.notary.TrustedAuthorityNotaryService
-import net.corda.node.services.api.ServiceHubInternal
-import java.security.PublicKey
-
-/** A Notary service that validates the transaction chain of the submitted transaction before committing it */
-class ValidatingNotaryService(override val services: ServiceHubInternal, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
- override val uniquenessProvider = PersistentUniquenessProvider(services.clock, services.database, services.cacheFactory)
-
- override fun createServiceFlow(otherPartySession: FlowSession): NotaryServiceFlow = ValidatingNotaryFlow(otherPartySession, this)
-
- override fun start() {}
- override fun stop() {}
-}
diff --git a/node/src/main/resources/migration/node-notary.changelog-init.xml b/node/src/main/resources/migration/node-notary.changelog-init.xml
index fed5c691b8..8d0f1bcb6f 100644
--- a/node/src/main/resources/migration/node-notary.changelog-init.xml
+++ b/node/src/main/resources/migration/node-notary.changelog-init.xml
@@ -27,18 +27,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
@@ -58,18 +46,11 @@
-
-
-
+
-
-
-
diff --git a/node/src/main/resources/migration/node-notary.changelog-pkey.xml b/node/src/main/resources/migration/node-notary.changelog-pkey.xml
index 64a99cc978..c4d7c59376 100644
--- a/node/src/main/resources/migration/node-notary.changelog-pkey.xml
+++ b/node/src/main/resources/migration/node-notary.changelog-pkey.xml
@@ -13,9 +13,4 @@
-
-
-
-
\ No newline at end of file
diff --git a/node/src/main/resources/migration/node-notary.changelog-v1.xml b/node/src/main/resources/migration/node-notary.changelog-v1.xml
index 0856d543b4..3002133bad 100644
--- a/node/src/main/resources/migration/node-notary.changelog-v1.xml
+++ b/node/src/main/resources/migration/node-notary.changelog-v1.xml
@@ -7,10 +7,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/node/src/test/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoaderTest.kt b/node/src/test/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoaderTest.kt
index 927852e1e8..4dd255f414 100644
--- a/node/src/test/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoaderTest.kt
+++ b/node/src/test/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoaderTest.kt
@@ -47,7 +47,7 @@ class JarScanningCordappLoaderTest {
fun `classes that aren't in cordapps aren't loaded`() {
// Basedir will not be a corda node directory so the dummy flow shouldn't be recognised as a part of a cordapp
val loader = JarScanningCordappLoader.fromDirectories(listOf(Paths.get(".")))
- assertThat(loader.cordapps).containsOnly(loader.coreCordapp)
+ assertThat(loader.cordapps).isEmpty()
}
@Test
@@ -55,9 +55,9 @@ class JarScanningCordappLoaderTest {
val isolatedJAR = JarScanningCordappLoaderTest::class.java.getResource("isolated.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR))
- assertThat(loader.cordapps).hasSize(2)
+ assertThat(loader.cordapps).hasSize(1)
- val actualCordapp = loader.cordapps.single { it != loader.coreCordapp }
+ val actualCordapp = loader.cordapps.single()
assertThat(actualCordapp.contractClassNames).isEqualTo(listOf(isolatedContractId))
assertThat(actualCordapp.initiatedFlows.single().name).isEqualTo("net.corda.finance.contracts.isolated.IsolatedDummyFlow\$Acceptor")
assertThat(actualCordapp.rpcFlows).isEmpty()
@@ -73,8 +73,8 @@ class JarScanningCordappLoaderTest {
val loader = cordappLoaderForPackages(listOf(testScanPackage))
val actual = loader.cordapps.toTypedArray()
- // One core cordapp, one cordapp from this source tree. In gradle it will also pick up the node jar.
- assertThat(actual.size == 2 || actual.size == 3).isTrue()
+ // One cordapp from this source tree. In gradle it will also pick up the node jar.
+ assertThat(actual.size == 0 || actual.size == 1).isTrue()
val actualCordapp = actual.single { !it.initiatedFlows.isEmpty() }
assertThat(actualCordapp.initiatedFlows).first().hasSameClassAs(DummyFlow::class.java)
@@ -111,7 +111,7 @@ class JarScanningCordappLoaderTest {
fun `cordapp classloader sets target and min version to 1 if not specified`() {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/no-min-or-target-version.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN)
- loader.cordapps.filter { it.info.shortName != "corda-core" }.forEach {
+ loader.cordapps.forEach {
assertThat(it.info.targetPlatformVersion).isEqualTo(1)
assertThat(it.info.minimumPlatformVersion).isEqualTo(1)
}
@@ -123,8 +123,7 @@ class JarScanningCordappLoaderTest {
// make sure classloader extracts correct values
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN)
- // exclude the core cordapp
- val cordapp = loader.cordapps.single { it.cordappClasses.contains("net.corda.core.internal.cordapp.CordappImpl") }
+ val cordapp = loader.cordapps.first()
assertThat(cordapp.info.targetPlatformVersion).isEqualTo(3)
assertThat(cordapp.info.minimumPlatformVersion).isEqualTo(2)
}
@@ -144,24 +143,21 @@ class JarScanningCordappLoaderTest {
fun `cordapp classloader does not load apps when their min platform version is greater than the node platform version`() {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-no-target.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1))
- // exclude the core cordapp
- assertThat(loader.cordapps).hasSize(1)
+ assertThat(loader.cordapps).hasSize(0)
}
@Test
fun `cordapp classloader does load apps when their min platform version is less than the platform version`() {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1000))
- // exclude the core cordapp
- assertThat(loader.cordapps).hasSize(2)
+ assertThat(loader.cordapps).hasSize(1)
}
@Test
fun `cordapp classloader does load apps when their min platform version is equal to the platform version`() {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 2))
- // exclude the core cordapp
- assertThat(loader.cordapps).hasSize(2)
+ assertThat(loader.cordapps).hasSize(1)
}
private fun cordappLoaderForPackages(packages: Iterable): CordappLoader {
diff --git a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt
index 8303cacefd..30e4a518ba 100644
--- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt
+++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt
@@ -313,20 +313,11 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
// of gets and puts.
private fun makeNodeWithTracking(name: CordaX500Name): TestStartedNode {
// Create a node in the mock network ...
- return mockNet.createNode(InternalMockNodeParameters(legalName = name), nodeFactory = { args, cordappLoader ->
- if (cordappLoader != null) {
- object : InternalMockNetwork.MockNode(args, cordappLoader) {
- // That constructs a recording tx storage
- override fun makeTransactionStorage(transactionCacheSizeBytes: Long): WritableTransactionStorage {
- return RecordingTransactionStorage(database, super.makeTransactionStorage(transactionCacheSizeBytes))
- }
- }
- } else {
- object : InternalMockNetwork.MockNode(args) {
- // That constructs a recording tx storage
- override fun makeTransactionStorage(transactionCacheSizeBytes: Long): WritableTransactionStorage {
- return RecordingTransactionStorage(database, super.makeTransactionStorage(transactionCacheSizeBytes))
- }
+ return mockNet.createNode(InternalMockNodeParameters(legalName = name), nodeFactory = { args ->
+ object : InternalMockNetwork.MockNode(args) {
+ // That constructs a recording tx storage
+ override fun makeTransactionStorage(transactionCacheSizeBytes: Long): WritableTransactionStorage {
+ return RecordingTransactionStorage(database, super.makeTransactionStorage(transactionCacheSizeBytes))
}
}
})
@@ -611,7 +602,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
fillUpForBuyer(bobError, issuer, bob, notary).second
}
val alicesFakePaper = aliceNode.database.transaction {
- fillUpForSeller(aliceError, issuer, alice,1200.DOLLARS `issued by` issuer, null, notary).second
+ fillUpForSeller(aliceError, issuer, alice, 1200.DOLLARS `issued by` issuer, null, notary).second
}
insertFakeTransactions(bobsBadCash, bobNode, bob, notaryNode, bankNode)
diff --git a/node/src/test/kotlin/net/corda/node/services/TimedFlowTests.kt b/node/src/test/kotlin/net/corda/node/services/TimedFlowTests.kt
index 605338f8c3..88ffd0711e 100644
--- a/node/src/test/kotlin/net/corda/node/services/TimedFlowTests.kt
+++ b/node/src/test/kotlin/net/corda/node/services/TimedFlowTests.kt
@@ -22,6 +22,7 @@ import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.seconds
+import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.config.FlowTimeoutConfiguration
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.NotaryConfig
@@ -60,12 +61,13 @@ class TimedFlowTestRule(val clusterSize: Int) : ExternalResource() {
replicaIds.map { mockNet.baseDirectory(mockNet.nextNodeId + it) },
CordaX500Name("Custom Notary", "Zurich", "CH"))
- val networkParameters = NetworkParametersCopier(testNetworkParameters(listOf(NotaryInfo(notaryIdentity, true))))
- val notaryConfig = mock {
- whenever(it.custom).thenReturn(true)
- whenever(it.isClusterConfig).thenReturn(true)
- whenever(it.validating).thenReturn(true)
- }
+ val networkParameters = NetworkParametersCopier(testNetworkParameters(listOf(NotaryInfo(notaryIdentity, true))))
+ val notaryConfig = mock {
+ whenever(it.custom).thenReturn(true)
+ whenever(it.isClusterConfig).thenReturn(true)
+ whenever(it.validating).thenReturn(true)
+ whenever(it.className).thenReturn(TestNotaryService::class.java.name)
+ }
val notaryNodes = (0 until clusterSize).map {
mockNet.createUnstartedNode(InternalMockNodeParameters(configOverrides = {
@@ -191,8 +193,7 @@ class TimedFlowTests {
}.bufferUntilSubscribed().toBlocking().toFuture()
}
- @CordaService
- private class TestNotaryService(override val services: AppServiceHub, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
+ private class TestNotaryService(override val services: ServiceHubInternal, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
override val uniquenessProvider = mock()
override fun createServiceFlow(otherPartySession: FlowSession): FlowLogic = TestNotaryFlow(otherPartySession, this)
override fun start() {}
diff --git a/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt
index 9fe578de44..37cffad6b9 100644
--- a/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt
+++ b/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt
@@ -8,7 +8,7 @@ import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.UnknownAnonymousPartyException
import net.corda.node.internal.configureDatabase
-import net.corda.node.utilities.TestingNamedCacheFactory
+import net.corda.testing.internal.TestingNamedCacheFactory
import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.x509Certificates
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt
index 5ed16e74a8..b52d8f39a8 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt
@@ -5,7 +5,7 @@ import net.corda.core.utilities.loggerFor
import net.corda.node.internal.configureDatabase
import net.corda.node.services.schema.NodeSchemaService
import net.corda.node.utilities.AppendOnlyPersistentMap
-import net.corda.node.utilities.TestingNamedCacheFactory
+import net.corda.testing.internal.TestingNamedCacheFactory
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import org.junit.After
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt
index d0fc54e934..1b9d96c792 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt
@@ -9,7 +9,7 @@ import net.corda.core.toFuture
import net.corda.core.transactions.SignedTransaction
import net.corda.node.internal.configureDatabase
import net.corda.node.services.transactions.PersistentUniquenessProvider
-import net.corda.node.utilities.TestingNamedCacheFactory
+import net.corda.testing.internal.TestingNamedCacheFactory
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.core.*
@@ -154,7 +154,8 @@ class DBTransactionStorageTests {
}
private fun newTransactionStorage(cacheSizeBytesOverride: Long? = null) {
- transactionStorage = DBTransactionStorage(database, TestingNamedCacheFactory(cacheSizeBytesOverride ?: 1024))
+ transactionStorage = DBTransactionStorage(database, TestingNamedCacheFactory(cacheSizeBytesOverride
+ ?: 1024))
}
private fun assertTransactionIsRetrievable(transaction: SignedTransaction) {
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/HibernateColumnConverterTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/HibernateColumnConverterTests.kt
index 0c5213eb63..4ce3b354e5 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/HibernateColumnConverterTests.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/HibernateColumnConverterTests.kt
@@ -9,7 +9,7 @@ import net.corda.finance.contracts.asset.Cash
import net.corda.finance.flows.CashIssueFlow
import net.corda.node.services.identity.PersistentIdentityService
import net.corda.node.services.keys.E2ETestKeyManagementService
-import net.corda.node.utilities.TestingNamedCacheFactory
+import net.corda.testing.internal.TestingNamedCacheFactory
import net.corda.testing.core.BOC_NAME
import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.MockNetwork
diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt
index 52b42ba913..6583677215 100644
--- a/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt
@@ -15,7 +15,7 @@ import net.corda.core.node.services.vault.Sort
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.configureDatabase
import net.corda.node.services.transactions.PersistentUniquenessProvider
-import net.corda.node.utilities.TestingNamedCacheFactory
+import net.corda.testing.internal.TestingNamedCacheFactory
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.internal.LogHelper
diff --git a/node/src/test/kotlin/net/corda/node/services/schema/NodeSchemaServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/schema/NodeSchemaServiceTest.kt
index 2f620c79cf..b9ffd74f30 100644
--- a/node/src/test/kotlin/net/corda/node/services/schema/NodeSchemaServiceTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/schema/NodeSchemaServiceTest.kt
@@ -10,20 +10,18 @@ import net.corda.core.schemas.PersistentState
import net.corda.core.utilities.getOrThrow
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.schema.NodeSchemaService.NodeCoreV1
-import net.corda.node.services.schema.NodeSchemaService.NodeNotaryV1
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.driver
import net.corda.testing.driver.internal.InProcessImpl
import net.corda.testing.internal.vault.DummyLinearStateSchemaV1
-import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.InternalMockNetwork
+import net.corda.testing.node.internal.cordappsForPackages
import org.hibernate.annotations.Cascade
import org.hibernate.annotations.CascadeType
import org.junit.Ignore
import org.junit.Test
import javax.persistence.*
import kotlin.test.assertEquals
-import kotlin.test.assertFalse
import kotlin.test.assertTrue
class NodeSchemaServiceTest {
@@ -47,7 +45,6 @@ class NodeSchemaServiceTest {
// check against NodeCore schemas
assertTrue(schemaService.schemaOptions.containsKey(NodeCoreV1))
- assertFalse(schemaService.schemaOptions.containsKey(NodeNotaryV1))
mockNet.stopNodes()
}
@@ -57,9 +54,8 @@ class NodeSchemaServiceTest {
val mockNotaryNode = mockNet.notaryNodes.first()
val schemaService = mockNotaryNode.services.schemaService
- // check against NodeCore + NodeNotary Schemas
+ // check against NodeCore Schema
assertTrue(schemaService.schemaOptions.containsKey(NodeCoreV1))
- assertTrue(schemaService.schemaOptions.containsKey(NodeNotaryV1))
mockNet.stopNodes()
}
@@ -97,7 +93,6 @@ class NodeSchemaServiceTest {
val mappedSchemas = result.returnValue.getOrThrow()
// check against NodeCore schemas
assertTrue(mappedSchemas.contains(NodeCoreV1.name))
- assertFalse(mappedSchemas.contains(NodeNotaryV1.name)) // still gets loaded due TODO restriction
}
}
@@ -107,9 +102,8 @@ class NodeSchemaServiceTest {
driver(DriverParameters(startNodesInProcess = true)) {
val notary = defaultNotaryNode.getOrThrow()
val mappedSchemas = notary.rpc.startFlow(::MappedSchemasFlow).returnValue.getOrThrow()
- // check against NodeCore + NodeNotary Schemas
+ // check against NodeCore Schema
assertTrue(mappedSchemas.contains(NodeCoreV1.name))
- assertTrue(mappedSchemas.contains(NodeNotaryV1.name))
}
}
diff --git a/node/src/test/kotlin/net/corda/node/services/transactions/MaxTransactionSizeTests.kt b/node/src/test/kotlin/net/corda/node/services/transactions/MaxTransactionSizeTests.kt
index 14ff42b13e..28db2d7d13 100644
--- a/node/src/test/kotlin/net/corda/node/services/transactions/MaxTransactionSizeTests.kt
+++ b/node/src/test/kotlin/net/corda/node/services/transactions/MaxTransactionSizeTests.kt
@@ -37,7 +37,7 @@ class MaxTransactionSizeTests {
@Before
fun setup() {
- mockNet = MockNetwork(listOf("net.corda.testing.contracts", "net.corda.node.services.transactions"), networkParameters = testNetworkParameters(maxTransactionSize = 3_000_000))
+ mockNet = MockNetwork(listOf("net.corda.testing.contracts"), networkParameters = testNetworkParameters(maxTransactionSize = 3_000_000))
aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME))
bobNode = mockNet.createNode(MockNodeParameters(legalName = BOB_NAME))
notaryNode = mockNet.defaultNotaryNode
diff --git a/node/src/test/kotlin/net/corda/node/services/transactions/PersistentUniquenessProviderTests.kt b/node/src/test/kotlin/net/corda/node/services/transactions/PersistentUniquenessProviderTests.kt
index aaca7927d5..463a4120d9 100644
--- a/node/src/test/kotlin/net/corda/node/services/transactions/PersistentUniquenessProviderTests.kt
+++ b/node/src/test/kotlin/net/corda/node/services/transactions/PersistentUniquenessProviderTests.kt
@@ -10,7 +10,7 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.notary.NotaryInternalException
import net.corda.node.internal.configureDatabase
import net.corda.node.services.schema.NodeSchemaService
-import net.corda.node.utilities.TestingNamedCacheFactory
+import net.corda.testing.internal.TestingNamedCacheFactory
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.core.SerializationEnvironmentRule
@@ -39,7 +39,7 @@ class PersistentUniquenessProviderTests {
@Before
fun setUp() {
LogHelper.setLevel(PersistentUniquenessProvider::class)
- database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true), { null }, { null }, NodeSchemaService(includeNotarySchemas = true))
+ database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true), { null }, { null }, NodeSchemaService(extraSchemas = setOf(NodeNotarySchemaV1)))
}
@After
diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultSoftLockManagerTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultSoftLockManagerTest.kt
index 93e60859fe..073800fd0b 100644
--- a/node/src/test/kotlin/net/corda/node/services/vault/VaultSoftLockManagerTest.kt
+++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultSoftLockManagerTest.kt
@@ -82,7 +82,7 @@ class VaultSoftLockManagerTest {
private val mockVault = rigorousMock().also {
doNothing().whenever(it).softLockRelease(any(), anyOrNull())
}
- private val mockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages(ContractImpl::class.packageName), defaultFactory = { args, _ ->
+ private val mockNet = InternalMockNetwork(cordappsForAllNodes = cordappsForPackages(ContractImpl::class.packageName), defaultFactory = { args ->
object : InternalMockNetwork.MockNode(args) {
override fun makeVaultService(keyManagementService: KeyManagementService, services: ServicesForResolution, database: CordaPersistence): VaultServiceInternal {
val node = this
diff --git a/samples/notary-demo/build.gradle b/samples/notary-demo/build.gradle
index 586d67109b..7f52642b53 100644
--- a/samples/notary-demo/build.gradle
+++ b/samples/notary-demo/build.gradle
@@ -4,10 +4,8 @@ apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'idea'
apply plugin: 'net.corda.plugins.quasar-utils'
-apply plugin: 'net.corda.plugins.publish-utils'
apply plugin: 'net.corda.plugins.cordapp'
apply plugin: 'net.corda.plugins.cordformation'
-apply plugin: 'maven-publish'
configurations {
integrationTestCompile.extendsFrom testCompile
@@ -16,7 +14,6 @@ configurations {
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
- testCompile "junit:junit:$junit_version"
// Corda integration dependencies
cordaCompile project(path: ":node:capsule", configuration: 'runtimeArtifacts')
@@ -24,26 +21,11 @@ dependencies {
cordaCompile project(':core')
cordaCompile project(':client:jfx')
cordaCompile project(':client:rpc')
- cordaCompile project(':node-driver')
-}
+ cordaCompile project(':test-utils')
-idea {
- module {
- downloadJavadoc = true // defaults to false
- downloadSources = true
- }
-}
-
-publishing {
- publications {
- jarAndSources(MavenPublication) {
- from components.java
- artifactId 'notarydemo'
-
- artifact sourceJar
- artifact javadocJar
- }
- }
+ // Notary implementations
+ cordapp project(':experimental:notary-raft')
+ cordapp project(':experimental:notary-bft-smart')
}
task deployNodes(dependsOn: ['deployNodesSingle', 'deployNodesRaft', 'deployNodesBFT', 'deployNodesCustom'])
@@ -99,9 +81,11 @@ task deployNodesCustom(type: Cordform, dependsOn: 'jar') {
}
task deployNodesRaft(type: Cordform, dependsOn: 'jar') {
+ def className = "net.corda.notary.raft.RaftNotaryService"
directory file("$buildDir/nodes/nodesRaft")
nodeDefaults {
extraConfig = [h2Settings: [address: "localhost:0"]]
+ cordapp project(':experimental:notary-raft')
}
node {
name "O=Alice Corp,L=Madrid,C=ES"
@@ -124,7 +108,8 @@ task deployNodesRaft(type: Cordform, dependsOn: 'jar') {
serviceLegalName: "O=Raft,L=Zurich,C=CH",
raft: [
nodeAddress: "localhost:10008"
- ]
+ ],
+ className: className
]
}
node {
@@ -140,7 +125,8 @@ task deployNodesRaft(type: Cordform, dependsOn: 'jar') {
raft: [
nodeAddress: "localhost:10012",
clusterAddresses: ["localhost:10008"]
- ]
+ ],
+ className: className
]
}
node {
@@ -156,16 +142,19 @@ task deployNodesRaft(type: Cordform, dependsOn: 'jar') {
raft: [
nodeAddress: "localhost:10016",
clusterAddresses: ["localhost:10008"]
- ]
+ ],
+ className: className
]
}
}
task deployNodesBFT(type: Cordform, dependsOn: 'jar') {
def clusterAddresses = ["localhost:11000", "localhost:11010", "localhost:11020", "localhost:11030"]
+ def className = "net.corda.notary.bftsmart.BftSmartNotaryService"
directory file("$buildDir/nodes/nodesBFT")
nodeDefaults {
extraConfig = [h2Settings: [address: "localhost:0"]]
+ cordapp project(':experimental:notary-bft-smart')
}
node {
name "O=Alice Corp,L=Madrid,C=ES"
@@ -189,7 +178,8 @@ task deployNodesBFT(type: Cordform, dependsOn: 'jar') {
bftSMaRt: [
replicaId: 0,
clusterAddresses: clusterAddresses
- ]
+ ],
+ className: className
]
}
node {
@@ -203,9 +193,10 @@ task deployNodesBFT(type: Cordform, dependsOn: 'jar') {
validating: false,
serviceLegalName: "O=BFT,L=Zurich,C=CH",
bftSMaRt: [
- replicaId: 0,
+ replicaId: 1,
clusterAddresses: clusterAddresses
- ]
+ ],
+ className: className
]
}
node {
@@ -219,9 +210,10 @@ task deployNodesBFT(type: Cordform, dependsOn: 'jar') {
validating: false,
serviceLegalName: "O=BFT,L=Zurich,C=CH",
bftSMaRt: [
- replicaId: 0,
+ replicaId: 2,
clusterAddresses: clusterAddresses
- ]
+ ],
+ className: className
]
}
node {
@@ -235,9 +227,10 @@ task deployNodesBFT(type: Cordform, dependsOn: 'jar') {
validating: false,
serviceLegalName: "O=BFT,L=Zurich,C=CH",
bftSMaRt: [
- replicaId: 0,
+ replicaId: 3,
clusterAddresses: clusterAddresses
- ]
+ ],
+ className: className
]
}
}
diff --git a/settings.gradle b/settings.gradle
index f9e560574a..a6f0f4b173 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -30,6 +30,8 @@ include 'experimental:flow-worker'
include 'experimental:ha-testing'
include 'experimental:corda-utils'
include 'experimental:rpc-worker'
+include 'experimental:notary-raft'
+include 'experimental:notary-bft-smart'
include 'jdk8u-deterministic'
include 'test-common'
include 'test-cli'
diff --git a/testing/node-driver/build.gradle b/testing/node-driver/build.gradle
index 102249761e..cdcb25d649 100644
--- a/testing/node-driver/build.gradle
+++ b/testing/node-driver/build.gradle
@@ -25,6 +25,8 @@ sourceSets {
}
dependencies {
+ // Bundling in the Raft notary service for tests involving distributed notaries
+ compile project(':experimental:notary-raft')
compile project(':test-utils')
// Integration test helpers
diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt
index 347adcbe39..82efa3749f 100644
--- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt
+++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt
@@ -497,6 +497,7 @@ class DriverDSLImpl(
val config = NotaryConfig(
validating = spec.validating,
serviceLegalName = spec.name,
+ className = "net.corda.notary.raft.RaftNotaryService",
raft = RaftConfig(nodeAddress = nodeAddress, clusterAddresses = clusterAddresses))
return config.toConfigMap()
}
diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt
index 73e7a0ed0b..88b22b7f70 100644
--- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt
+++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt
@@ -28,14 +28,15 @@ import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.hours
import net.corda.core.utilities.seconds
import net.corda.node.VersionInfo
-import net.corda.node.cordapp.CordappLoader
import net.corda.node.internal.AbstractNode
import net.corda.node.internal.InitiatedFlowFactory
-import net.corda.node.internal.cordapp.JarScanningCordappLoader
import net.corda.node.services.api.FlowStarter
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.api.StartedNodeServices
-import net.corda.node.services.config.*
+import net.corda.node.services.config.FlowTimeoutConfiguration
+import net.corda.node.services.config.NodeConfiguration
+import net.corda.node.services.config.NotaryConfig
+import net.corda.node.services.config.VerifierType
import net.corda.node.services.identity.PersistentIdentityService
import net.corda.node.services.keys.E2ETestKeyManagementService
import net.corda.node.services.keys.KeyManagementServiceInternal
@@ -43,9 +44,6 @@ import net.corda.node.services.messaging.Message
import net.corda.node.services.messaging.MessagingService
import net.corda.node.services.persistence.NodeAttachmentService
import net.corda.node.services.statemachine.StateMachineManager
-import net.corda.node.services.transactions.BFTNonValidatingNotaryService
-import net.corda.node.services.transactions.BFTSMaRt
-import net.corda.node.services.transactions.InMemoryTransactionVerifierService
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
import net.corda.node.utilities.DefaultNamedCacheFactory
import net.corda.nodeapi.internal.DevIdentityGenerator
@@ -69,7 +67,6 @@ import java.math.BigInteger
import java.nio.file.Path
import java.nio.file.Paths
import java.security.KeyPair
-import java.security.PublicKey
import java.time.Clock
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
@@ -149,7 +146,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
val notarySpecs: List = defaultParameters.notarySpecs,
val testDirectory: Path = Paths.get("build", getTimestampAsDirectoryName()),
val networkParameters: NetworkParameters = testNetworkParameters(),
- val defaultFactory: (MockNodeArgs, CordappLoader?) -> MockNode = { args, cordappLoader -> cordappLoader?.let { MockNode(args, it) } ?: MockNode(args) },
+ val defaultFactory: (MockNodeArgs) -> MockNode = { args -> MockNode(args) },
val cordappsForAllNodes: Set = emptySet(),
val autoVisibleNodes: Boolean = true) : AutoCloseable {
init {
@@ -276,12 +273,11 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
}
}
- open class MockNode(args: MockNodeArgs, cordappLoader: CordappLoader = JarScanningCordappLoader.fromDirectories(args.config.cordappDirectories, args.version)) : AbstractNode(
+ open class MockNode(args: MockNodeArgs) : AbstractNode(
args.config,
TestClock(Clock.systemUTC()),
DefaultNamedCacheFactory(),
args.version,
- cordappLoader,
args.network.getServerThread(args.id),
args.network.busyLatch
) {
@@ -424,27 +420,13 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
var acceptableLiveFiberCountOnStop: Int = 0
override fun acceptableLiveFiberCountOnStop(): Int = acceptableLiveFiberCountOnStop
-
- override fun makeBFTCluster(notaryKey: PublicKey, bftSMaRtConfig: BFTSMaRtConfiguration): BFTSMaRt.Cluster {
- return object : BFTSMaRt.Cluster {
- override fun waitUntilAllReplicasHaveInitialized() {
- val clusterNodes = mockNet.nodes.map { it.started!! }.filter { notaryKey in it.info.legalIdentities.map { it.owningKey } }
- if (clusterNodes.size != bftSMaRtConfig.clusterAddresses.size) {
- throw IllegalStateException("Unable to enumerate all nodes in BFT cluster.")
- }
- clusterNodes.forEach {
- (it.notaryService as BFTNonValidatingNotaryService).waitUntilReplicaHasInitialized()
- }
- }
- }
- }
}
fun createUnstartedNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters()): MockNode {
return createUnstartedNode(parameters, defaultFactory)
}
- fun createUnstartedNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), nodeFactory: (MockNodeArgs, CordappLoader?) -> MockNode): MockNode {
+ fun createUnstartedNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), nodeFactory: (MockNodeArgs) -> MockNode): MockNode {
return createNodeImpl(parameters, nodeFactory, false)
}
@@ -453,11 +435,11 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
}
/** Like the other [createNode] but takes a [nodeFactory] and propagates its [MockNode] subtype. */
- fun createNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), nodeFactory: (MockNodeArgs, CordappLoader?) -> MockNode): TestStartedNode {
+ fun createNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), nodeFactory: (MockNodeArgs) -> MockNode): TestStartedNode {
return uncheckedCast(createNodeImpl(parameters, nodeFactory, true).started)!!
}
- private fun createNodeImpl(parameters: InternalMockNodeParameters, nodeFactory: (MockNodeArgs, CordappLoader?) -> MockNode, start: Boolean): MockNode {
+ private fun createNodeImpl(parameters: InternalMockNodeParameters, nodeFactory: (MockNodeArgs) -> MockNode, start: Boolean): MockNode {
val id = parameters.forcedID ?: nextNodeId++
val baseDirectory = baseDirectory(id)
val certificatesDirectory = baseDirectory / "certificates"
@@ -475,7 +457,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
val cordappDirectories = sharedCorDappsDirectories + TestCordappDirectories.cached(cordapps)
doReturn(cordappDirectories).whenever(config).cordappDirectories
- val node = nodeFactory(MockNodeArgs(config, this, id, parameters.entropyRoot, parameters.version), JarScanningCordappLoader.fromDirectories(cordappDirectories, parameters.version))
+ val node = nodeFactory(MockNodeArgs(config, this, id, parameters.entropyRoot, parameters.version))
_nodes += node
if (start) {
node.start()
@@ -483,7 +465,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
return node
}
- fun restartNode(node: TestStartedNode, nodeFactory: (MockNodeArgs, CordappLoader?) -> MockNode): TestStartedNode {
+ fun restartNode(node: TestStartedNode, nodeFactory: (MockNodeArgs) -> MockNode): TestStartedNode {
node.internals.disableDBCloseOnStop()
node.dispose()
return createNode(
diff --git a/node/src/test/kotlin/net/corda/node/utilities/TestingNamedCacheFactory.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/TestingNamedCacheFactory.kt
similarity index 95%
rename from node/src/test/kotlin/net/corda/node/utilities/TestingNamedCacheFactory.kt
rename to testing/test-utils/src/main/kotlin/net/corda/testing/internal/TestingNamedCacheFactory.kt
index 4582246e09..7908d5dd27 100644
--- a/node/src/test/kotlin/net/corda/node/utilities/TestingNamedCacheFactory.kt
+++ b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/TestingNamedCacheFactory.kt
@@ -1,4 +1,4 @@
-package net.corda.node.utilities
+package net.corda.testing.internal
import com.codahale.metrics.MetricRegistry
import com.github.benmanes.caffeine.cache.Cache
@@ -9,6 +9,7 @@ import net.corda.core.internal.buildNamed
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.node.services.config.MB
import net.corda.node.services.config.NodeConfiguration
+import net.corda.node.utilities.NamedCacheFactory
class TestingNamedCacheFactory private constructor(private val sizeOverride: Long, private val metricRegistry: MetricRegistry?, private val nodeConfiguration: NodeConfiguration?) : NamedCacheFactory, SingletonSerializeAsToken() {
constructor(sizeOverride: Long = 1024) : this(sizeOverride, null, null)