diff --git a/node/src/main/kotlin/com/r3corda/node/driver/Driver.kt b/node/src/main/kotlin/com/r3corda/node/driver/Driver.kt index f44bb7f4e2..7bbcc43239 100644 --- a/node/src/main/kotlin/com/r3corda/node/driver/Driver.kt +++ b/node/src/main/kotlin/com/r3corda/node/driver/Driver.kt @@ -59,7 +59,7 @@ interface DriverDSLExposedInterface { * @param advertisedServices The set of services to be advertised by the node. Defaults to empty set. * @return The [NodeInfo] of the started up node retrieved from the network map service. */ - fun startNode(providedName: String? = null, advertisedServices: Set = setOf()): Future + fun startNode(providedName: String? = null, advertisedServices: Set = setOf()): Future fun waitForAllNodesToFinish() } @@ -69,7 +69,7 @@ interface DriverDSLInternalInterface : DriverDSLExposedInterface { fun shutdown() } -data class DriverNodeInfo(val nodeInfo: NodeInfo, val messagingAddress: HostAndPort, val apiAddress: HostAndPort) +data class NodeInfoAndConfig(val nodeInfo: NodeInfo, val config: Config) sealed class PortAllocation { abstract fun nextPort(): Int @@ -116,7 +116,7 @@ fun driver( baseDirectory: String = "build/${getTimestampAsDirectoryName()}", portAllocation: PortAllocation = PortAllocation.Incremental(10000), debugPortAllocation: PortAllocation = PortAllocation.Incremental(5005), - clockClass: Class<*> = NodeClock::class.java, + useTestClock: Boolean = false, isDebug: Boolean = false, dsl: DriverDSLExposedInterface.() -> A ) = genericDriver( @@ -124,7 +124,7 @@ fun driver( portAllocation = portAllocation, debugPortAllocation = debugPortAllocation, baseDirectory = baseDirectory, - clockClass = clockClass, + useTestClock = useTestClock, isDebug = isDebug ), coerce = { it }, @@ -208,7 +208,7 @@ open class DriverDSL( val portAllocation: PortAllocation, val debugPortAllocation: PortAllocation, val baseDirectory: String, - val clockClass: Class<*>, + val useTestClock: Boolean, val isDebug: Boolean ) : DriverDSLInternalInterface { private val networkMapName = "NetworkMapService" @@ -289,7 +289,7 @@ open class DriverDSL( } } - override fun startNode(providedName: String?, advertisedServices: Set): Future { + override fun startNode(providedName: String?, advertisedServices: Set): Future { val messagingAddress = portAllocation.nextHostAndPort() val apiAddress = portAllocation.nextHostAndPort() val debugPort = if (isDebug) debugPortAllocation.nextPort() else null @@ -307,13 +307,13 @@ open class DriverDSL( "webAddress" to apiAddress.toString(), "extraAdvertisedServiceIds" to advertisedServices.joinToString(","), "networkMapAddress" to networkMapAddress.toString(), - "clockClass" to clockClass.name + "useTestClock" to useTestClock ) ) - return Executors.newSingleThreadExecutor().submit(Callable { + return Executors.newSingleThreadExecutor().submit(Callable { registerProcess(DriverDSL.startNode(config, quasarJarPath, debugPort)) - DriverNodeInfo(queryNodeInfo(apiAddress)!!, messagingAddress, apiAddress) + NodeInfoAndConfig(queryNodeInfo(apiAddress)!!, config) }) } @@ -326,7 +326,6 @@ open class DriverDSL( val debugPort = if (isDebug) debugPortAllocation.nextPort() else null val nodeDirectory = "$baseDirectory/$networkMapName" - val config = ConfigHelper.loadConfig( baseDirectoryPath = Paths.get(nodeDirectory), allowMissingConfig = true, @@ -336,7 +335,7 @@ open class DriverDSL( "artemisAddress" to networkMapAddress.toString(), "webAddress" to apiAddress.toString(), "extraAdvertisedServiceIds" to "", - "clockClass" to clockClass.name + "useTestClock" to useTestClock ) ) diff --git a/node/src/main/kotlin/com/r3corda/node/services/config/NodeConfiguration.kt b/node/src/main/kotlin/com/r3corda/node/services/config/NodeConfiguration.kt index f9459db2f4..9af717c60f 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/config/NodeConfiguration.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/config/NodeConfiguration.kt @@ -8,6 +8,7 @@ import com.r3corda.node.internal.Node import com.r3corda.node.serialization.NodeClock import com.r3corda.node.services.messaging.NodeMessagingClient import com.r3corda.node.services.network.NetworkMapService +import com.r3corda.node.utilities.TestClock import com.typesafe.config.Config import java.nio.file.Path import java.time.Clock @@ -48,7 +49,7 @@ class FullNodeConfiguration(config: Config) : NodeConfiguration { val webAddress: HostAndPort by config val messagingServerAddress: HostAndPort? by config.getOrElse { null } val extraAdvertisedServiceIds: String by config - val clockClass: String? by config.getOrElse { null } + val useTestClock: Boolean by config.getOrElse { false } fun createNode(): Node { val advertisedServices = mutableSetOf() @@ -59,11 +60,7 @@ class FullNodeConfiguration(config: Config) : NodeConfiguration { } if (networkMapAddress == null) advertisedServices.add(ServiceInfo(NetworkMapService.type)) val networkMapMessageAddress: SingleMessageRecipient? = if (networkMapAddress == null) null else NodeMessagingClient.makeNetworkMapAddress(networkMapAddress!!) - return if (clockClass != null) { - Node(this, networkMapMessageAddress, advertisedServices, Class.forName(clockClass).newInstance() as Clock) - } else { - Node(this, networkMapMessageAddress, advertisedServices) - } + return Node(this, networkMapMessageAddress, advertisedServices, if(useTestClock == true) TestClock() else NodeClock()) } } diff --git a/node/src/main/kotlin/com/r3corda/node/utilities/TestClock.kt b/node/src/main/kotlin/com/r3corda/node/utilities/TestClock.kt new file mode 100644 index 0000000000..9ed7dccc2a --- /dev/null +++ b/node/src/main/kotlin/com/r3corda/node/utilities/TestClock.kt @@ -0,0 +1,43 @@ +package com.r3corda.node.utilities + +import com.r3corda.core.serialization.SerializeAsToken +import com.r3corda.core.serialization.SerializeAsTokenContext +import com.r3corda.core.serialization.SingletonSerializationToken +import java.time.* +import javax.annotation.concurrent.ThreadSafe + +/** + * A [Clock] that can have the date advanced for use in demos. + */ +@ThreadSafe +class TestClock(private var delegateClock: Clock = Clock.systemUTC()) : MutableClock(), SerializeAsToken { + + private val token = SingletonSerializationToken(this) + + override fun toToken(context: SerializeAsTokenContext) = SingletonSerializationToken.registerWithContext(token, this, context) + + @Synchronized fun updateDate(date: LocalDate): Boolean { + val currentDate = LocalDate.now(this) + if (currentDate.isBefore(date)) { + // It's ok to increment + delegateClock = Clock.offset(delegateClock, Duration.between(currentDate.atStartOfDay(), date.atStartOfDay())) + notifyMutationObservers() + return true + } + return false + } + + @Synchronized override fun instant(): Instant { + return delegateClock.instant() + } + + // Do not use this. Instead seek to use ZonedDateTime methods. + override fun withZone(zone: ZoneId): Clock { + throw UnsupportedOperationException("Tokenized clock does not support withZone()") + } + + @Synchronized override fun getZone(): ZoneId { + return delegateClock.zone + } + +} \ No newline at end of file diff --git a/node/src/main/resources/reference.conf b/node/src/main/resources/reference.conf index cb914d4cae..18e8ee805d 100644 --- a/node/src/main/resources/reference.conf +++ b/node/src/main/resources/reference.conf @@ -13,4 +13,5 @@ dataSourceProperties = { devMode = true certificateSigningService = "https://cordaci-netperm.corda.r3cev.com" useHTTPS = false -h2port = 0 \ No newline at end of file +h2port = 0 +useTestClock = false \ No newline at end of file