diff --git a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt
index 3bb2c963c1..fe650218da 100644
--- a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt
+++ b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt
@@ -1,6 +1,8 @@
 package com.r3corda.node.internal
 
 import com.codahale.metrics.MetricRegistry
+import com.google.common.util.concurrent.Futures
+import com.google.common.util.concurrent.JdkFutureAdapters
 import com.google.common.util.concurrent.ListenableFuture
 import com.google.common.util.concurrent.SettableFuture
 import com.r3corda.core.RunOnCallerThread
@@ -47,6 +49,7 @@ import java.security.KeyPair
 import java.time.Clock
 import java.time.Instant
 import java.util.*
+import java.util.concurrent.CompletableFuture
 
 /**
  * A base node implementation that can be customised either for production (with real implementations that do real
@@ -109,9 +112,9 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
     var isPreviousCheckpointsPresent = false
         private set
 
-    /** Completes once the node has successfully registered with the network map service. Null until [start] returns. */
-    @Volatile var networkMapRegistrationFuture: ListenableFuture<Unit>? = null
-        private set
+    /** Completes once the node has successfully registered with the network map service */
+    val networkMapRegistrationSettableFuture: SettableFuture<Unit> = SettableFuture.create()
+    val networkMapRegistrationFuture: ListenableFuture<Unit> = networkMapRegistrationSettableFuture
 
     /** Set to true once [start] has been successfully called. */
     @Volatile var started = false
@@ -145,7 +148,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
         CashBalanceAsMetricsObserver(services)
 
         startMessagingService()
-        networkMapRegistrationFuture = registerWithNetworkMap()
+        networkMapRegistrationSettableFuture.setFuture(registerWithNetworkMap())
         isPreviousCheckpointsPresent = checkpointStorage.checkpoints.any()
         smm.start()
         started = true
diff --git a/node/src/main/kotlin/com/r3corda/node/internal/testing/Simulation.kt b/node/src/main/kotlin/com/r3corda/node/internal/testing/Simulation.kt
index f02ca57494..ee94d6eaf7 100644
--- a/node/src/main/kotlin/com/r3corda/node/internal/testing/Simulation.kt
+++ b/node/src/main/kotlin/com/r3corda/node/internal/testing/Simulation.kt
@@ -1,5 +1,6 @@
 package com.r3corda.node.internal.testing
 
+import com.google.common.base.Function
 import com.google.common.util.concurrent.Futures
 import com.google.common.util.concurrent.ListenableFuture
 import com.r3corda.core.node.CityDatabase
@@ -213,6 +214,8 @@ abstract class Simulation(val runAsync: Boolean,
         }
     }
 
+    val networkInitialisationFinished: ListenableFuture<Unit> = Futures.transform(Futures.allAsList(network.nodes.map { it.networkMapRegistrationFuture }), Function { })
+
     fun start(): ListenableFuture<Unit> {
         network.startNodes()
         // Wait for all the nodes to have finished registering with the network map service.