Merged in simulation-bug-fixes (pull request )

Simulation bug fixes
This commit is contained in:
Mike Hearn 2016-05-17 18:10:17 +02:00
commit 8211a7937b
12 changed files with 452 additions and 167 deletions

@ -4,14 +4,13 @@ import api.APIServer
import api.APIServerImpl
import com.codahale.metrics.MetricRegistry
import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.MoreExecutors
import com.google.common.util.concurrent.SettableFuture
import core.RunOnCallerThread
import core.crypto.Party
import core.messaging.MessagingService
import core.messaging.StateMachineManager
import core.messaging.runOnNextMessage
import core.node.services.*
import core.node.subsystems.*
import core.node.storage.CheckpointStorage
import core.node.storage.PerFileCheckpointStorage
import core.node.subsystems.*
@ -27,7 +26,6 @@ import java.nio.file.Files
import java.nio.file.Path
import java.security.KeyPair
import java.time.Clock
import java.time.Duration
import java.time.Instant
import java.util.*
@ -35,18 +33,16 @@ import java.util.*
* A base node implementation that can be customised either for production (with real implementations that do real
* I/O), or a mock implementation suitable for unit test environments.
*/
// TODO: Where this node is the initial network map service, currently no initialNetworkMapAddress is provided.
// TODO: Where this node is the initial network map service, currently no networkMapService is provided.
// In theory the NodeInfo for the node should be passed in, instead, however currently this is constructed by the
// AbstractNode. It should be possible to generate the NodeInfo outside of AbstractNode, so it can be passed in.
abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, val initialNetworkMapAddress: NodeInfo?,
abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, val networkMapService: NodeInfo?,
val advertisedServices: Set<ServiceType>, val platformClock: Clock) {
companion object {
val PRIVATE_KEY_FILE_NAME = "identity-private-key"
val PUBLIC_IDENTITY_FILE_NAME = "identity-public"
}
val networkMapServiceCallTimeout: Duration = Duration.ofSeconds(1)
// TODO: Persist this, as well as whether the node is registered.
/**
* Sequence number of changes sent to the network map service, when registering/de-registering this node
@ -79,7 +75,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
NodeInfo(net.myAddress, storage.myLegalIdentity, advertisedServices, findMyLocation())
}
protected open fun findMyLocation(): PhysicalLocation? = CityDatabase[configuration.nearestCity]
open fun findMyLocation(): PhysicalLocation? = CityDatabase[configuration.nearestCity]
lateinit var storage: StorageService
lateinit var smm: StateMachineManager
@ -91,7 +87,16 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
lateinit var net: MessagingService
lateinit var api: APIServer
/** Completes once the node has successfully registered with the network map service. Null until [start] returns. */
@Volatile var networkMapRegistrationFuture: ListenableFuture<Unit>? = null
private set
/** Set to true once [start] has been successfully called. */
@Volatile var started = false
private set
open fun start(): AbstractNode {
require(!started) { "Node has already been started" }
log.info("Node starting up ...")
storage = initialiseStorageService(dir)
@ -113,29 +118,37 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
DataVendingService(net, storage)
startMessagingService()
require(initialNetworkMapAddress == null || NetworkMapService.Type in initialNetworkMapAddress.advertisedServices)
{ "Initial network map address must indicate a node that provides a network map service" }
configureNetworkMapCache()
networkMapRegistrationFuture = registerWithNetworkMap()
started = true
return this
}
/**
* Register this node with the network map cache, and load network map from a remote service (and register for
* updates) if one has been supplied.
*/
private fun configureNetworkMapCache() {
private fun registerWithNetworkMap(): ListenableFuture<Unit> {
require(networkMapService == null || NetworkMapService.Type in networkMapService.advertisedServices) {
"Initial network map address must indicate a node that provides a network map service"
}
services.networkMapCache.addNode(info)
if (initialNetworkMapAddress != null) {
// TODO: Return a future so the caller knows these operations may not have completed yet, and can monitor
// if needed
updateRegistration(initialNetworkMapAddress, AddOrRemove.ADD)
services.networkMapCache.addMapService(net, initialNetworkMapAddress, true, null)
}
if (inNodeNetworkMapService != null) {
// Register for updates
services.networkMapCache.addMapService(net, info, true, null)
if (networkMapService != null && networkMapService != info) {
// Only register if we are pointed at a network map service and it's not us.
// TODO: Return a future so the caller knows these operations may not have completed yet, and can monitor if needed
updateRegistration(networkMapService, AddOrRemove.ADD)
return services.networkMapCache.addMapService(net, networkMapService, true, null)
}
// In the unit test environment, we may run without any network map service sometimes.
if (inNodeNetworkMapService == null)
return noNetworkMapConfigured()
// Register for updates, even if we're the one running the network map.
return services.networkMapCache.addMapService(net, info, true, null)
}
/** This is overriden by the mock node implementation to enable operation without any network map service */
protected open fun noNetworkMapConfigured(): ListenableFuture<Unit> {
// TODO: There should be a consistent approach to configuration error exceptions.
throw IllegalStateException("Configuration error: this node isn't being asked to act as the network map, nor " +
"has any other map node been configured.")
}
private fun updateRegistration(serviceInfo: NodeInfo, type: AddOrRemove): ListenableFuture<NetworkMapService.RegistrationResponse> {
@ -148,7 +161,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
val future = SettableFuture.create<NetworkMapService.RegistrationResponse>()
val topic = NetworkMapService.REGISTER_PROTOCOL_TOPIC + "." + sessionID
net.runOnNextMessage(topic, MoreExecutors.directExecutor()) { message ->
net.runOnNextMessage(topic, RunOnCallerThread) { message ->
future.set(message.data.deserialize())
}
net.send(message, serviceInfo.address)
@ -178,8 +191,8 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
protected open fun makeIdentityService(): IdentityService {
val service = InMemoryIdentityService()
if (initialNetworkMapAddress != null)
service.registerIdentity(initialNetworkMapAddress.identity)
if (networkMapService != null)
service.registerIdentity(networkMapService.identity)
service.registerIdentity(storage.myLegalIdentity)
services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.identity) }

@ -18,13 +18,13 @@ import core.serialization.deserialize
import core.serialization.serialize
import core.utilities.AddOrRemove
import org.slf4j.LoggerFactory
import protocols.*
import protocols.AbstractRequestMessage
import java.security.PrivateKey
import java.time.Period
import java.time.Instant
import java.util.ArrayList
import java.util.concurrent.atomic.AtomicInteger
import java.time.Period
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger
import javax.annotation.concurrent.ThreadSafe

@ -1,6 +1,7 @@
package core.testing
import com.fasterxml.jackson.module.kotlin.readValue
import com.google.common.util.concurrent.FutureCallback
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.SettableFuture
@ -12,6 +13,7 @@ import core.crypto.SecureHash
import core.node.subsystems.linearHeadsOfType
import core.utilities.JsonSupport
import protocols.TwoPartyDealProtocol
import java.security.KeyPair
import java.time.LocalDate
import java.util.*
@ -26,28 +28,49 @@ class IRSSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwork
currentDay = LocalDate.of(2016, 3, 10) // Should be 12th but the actual first fixing date gets rolled backwards.
}
private var nodeAKey: KeyPair? = null
private var nodeBKey: KeyPair? = null
private val executeOnNextIteration = Collections.synchronizedList(LinkedList<() -> Unit>())
override fun start() {
override fun startMainSimulation(): ListenableFuture<Unit> {
val future = SettableFuture.create<Unit>()
nodeAKey = banks[0].keyManagement.freshKey()
nodeBKey = banks[1].keyManagement.freshKey()
startIRSDealBetween(0, 1).success {
// Next iteration is a pause.
executeOnNextIteration.add {}
executeOnNextIteration.add {
// Keep fixing until there's no more left to do.
doNextFixing(0, 1)?.addListener(object : Runnable {
override fun run() {
val initialFixFuture = doNextFixing(0, 1)
Futures.addCallback(initialFixFuture, object : FutureCallback<Unit> {
override fun onFailure(t: Throwable) {
future.setException(t) // Propagate the error.
}
override fun onSuccess(result: Unit?) {
// Pause for an iteration.
executeOnNextIteration.add {}
executeOnNextIteration.add {
doNextFixing(0, 1)?.addListener(this, RunOnCallerThread)
val f = doNextFixing(0, 1)
if (f != null) {
Futures.addCallback(f, this, RunOnCallerThread)
} else {
// All done!
future.set(Unit)
}
}
}
}, RunOnCallerThread)
}
}
return future
}
private fun doNextFixing(i: Int, j: Int): ListenableFuture<*>? {
private fun doNextFixing(i: Int, j: Int): ListenableFuture<Unit>? {
println("Doing a fixing between $i and $j")
val node1: SimulatedNode = banks[i]
val node2: SimulatedNode = banks[j]
@ -65,10 +88,8 @@ class IRSSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwork
if (nextFixingDate > currentDay)
currentDay = nextFixingDate
val sideA = TwoPartyDealProtocol.Floater(node2.net.myAddress, sessionID, notary.info,
theDealRef, node1.services.keyManagementService.freshKey(), sessionID)
val sideB = TwoPartyDealProtocol.Fixer(node1.net.myAddress, notary.info.identity,
theDealRef, sessionID)
val sideA = TwoPartyDealProtocol.Floater(node2.net.myAddress, sessionID, notary.info, theDealRef, nodeAKey!!, sessionID)
val sideB = TwoPartyDealProtocol.Fixer(node1.net.myAddress, notary.info.identity, theDealRef, sessionID)
linkConsensus(listOf(node1, node2, regulators[0]), sideB)
linkProtocolProgress(node1, sideA)
@ -77,12 +98,14 @@ class IRSSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwork
// We have to start the protocols in separate iterations, as adding to the SMM effectively 'iterates' that node
// in the simulation, so if we don't do this then the two sides seem to act simultaneously.
val retFuture = SettableFuture.create<Any>()
val retFuture = SettableFuture.create<Unit>()
val futA = node1.smm.add("floater", sideA)
executeOnNextIteration += {
val futB = node2.smm.add("fixer", sideB)
Futures.allAsList(futA, futB).then {
Futures.allAsList(futA, futB) success {
retFuture.set(null)
} failure { throwable ->
retFuture.setException(throwable)
}
}
return retFuture
@ -102,17 +125,10 @@ class IRSSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwork
irs.fixedLeg.fixedRatePayer = node1.info.identity
irs.floatingLeg.floatingRatePayer = node2.info.identity
if (irs.fixedLeg.effectiveDate < irs.floatingLeg.effectiveDate)
currentDay = irs.fixedLeg.effectiveDate
else
currentDay = irs.floatingLeg.effectiveDate
val sessionID = random63BitValue()
val instigator = TwoPartyDealProtocol.Instigator(node2.net.myAddress, notary.info,
irs, node1.services.keyManagementService.freshKey(), sessionID)
val acceptor = TwoPartyDealProtocol.Acceptor(node1.net.myAddress, notary.info.identity,
irs, sessionID)
val instigator = TwoPartyDealProtocol.Instigator(node2.net.myAddress, notary.info, irs, nodeAKey!!, sessionID)
val acceptor = TwoPartyDealProtocol.Acceptor(node1.net.myAddress, notary.info.identity, irs, sessionID)
// TODO: Eliminate the need for linkProtocolProgress
linkConsensus(listOf(node1, node2, regulators[0]), acceptor)
@ -126,9 +142,9 @@ class IRSSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwork
}
}
override fun iterate() {
override fun iterate(): InMemoryMessagingNetwork.MessageTransfer? {
if (executeOnNextIteration.isNotEmpty())
executeOnNextIteration.removeAt(0)()
super.iterate()
return super.iterate()
}
}

@ -7,6 +7,8 @@ import core.ThreadBox
import core.crypto.sha256
import core.messaging.*
import core.utilities.loggerFor
import core.utilities.trace
import org.slf4j.LoggerFactory
import rx.Observable
import rx.subjects.PublishSubject
import java.time.Duration
@ -27,13 +29,23 @@ import kotlin.concurrent.thread
*/
@ThreadSafe
class InMemoryMessagingNetwork {
companion object {
val MESSAGES_LOG_NAME = "messages"
private val log = LoggerFactory.getLogger(MESSAGES_LOG_NAME)
}
private var counter = 0 // -1 means stopped.
private val handleEndpointMap = HashMap<Handle, InMemoryMessaging>()
data class MessageTransfer(val sender: InMemoryMessaging, val message: Message, val recipients: MessageRecipients) {
override fun toString() = "${message.topic} from '${sender.myAddress}' to '$recipients'"
}
// All messages are kept here until the messages are pumped off the queue by a caller to the node class.
// Queues are created on-demand when a message is sent to an address: the receiving node doesn't have to have
// been created yet. If the node identified by the given handle has gone away/been shut down then messages
// stack up here waiting for it to come back. The intent of this is to simulate a reliable messaging network.
private val messageQueues = HashMap<Handle, LinkedBlockingQueue<Message>>()
private val messageQueues = HashMap<Handle, LinkedBlockingQueue<MessageTransfer>>()
val endpoints: List<InMemoryMessaging> @Synchronized get() = handleEndpointMap.values.toList()
@ -55,14 +67,20 @@ class InMemoryMessagingNetwork {
return Pair(id, builder)
}
/** Creates a node at the given address: useful if you want to recreate a node to simulate a restart */
fun createNodeWithID(manuallyPumped: Boolean, id: Int): MessagingServiceBuilder<InMemoryMessaging> {
return Builder(manuallyPumped, Handle(id))
/**
* Creates a node at the given address: useful if you want to recreate a node to simulate a restart.
*
* @param manuallyPumped see [createNode]
* @param id the numeric ID to use, e.g. set to whatever ID the node used last time.
* @param description text string that identifies this node for message logging (if is enabled) or null to autogenerate
*/
fun createNodeWithID(manuallyPumped: Boolean, id: Int, description: String? = null): MessagingServiceBuilder<InMemoryMessaging> {
return Builder(manuallyPumped, Handle(id, description ?: "In memory node $id"))
}
private val _allMessages = PublishSubject.create<Triple<SingleMessageRecipient, Message, MessageRecipients>>()
private val _allMessages = PublishSubject.create<MessageTransfer>()
/** A stream of (sender, message, recipients) triples */
val allMessages: Observable<Triple<SingleMessageRecipient, Message, MessageRecipients>> = _allMessages
val allMessages: Observable<MessageTransfer> = _allMessages
interface LatencyCalculator {
fun between(sender: SingleMessageRecipient, receiver: SingleMessageRecipient): Duration
@ -74,27 +92,29 @@ class InMemoryMessagingNetwork {
@Synchronized
private fun msgSend(from: InMemoryMessaging, message: Message, recipients: MessageRecipients) {
val transfer = MessageTransfer(from, message, recipients)
log.trace { transfer.toString() }
val calc = latencyCalculator
if (calc != null && recipients is SingleMessageRecipient) {
// Inject some artificial latency.
timer.schedule(calc.between(from.myAddress, recipients).toMillis()) {
msgSendInternal(message, recipients)
msgSendInternal(transfer)
}
} else {
msgSendInternal(message, recipients)
msgSendInternal(transfer)
}
_allMessages.onNext(Triple(from.myAddress, message, recipients))
_allMessages.onNext(MessageTransfer(from, message, recipients))
}
private fun msgSendInternal(message: Message, recipients: MessageRecipients) {
when (recipients) {
is Handle -> getQueueForHandle(recipients).add(message)
private fun msgSendInternal(transfer: MessageTransfer) {
when (transfer.recipients) {
is Handle -> getQueueForHandle(transfer.recipients).add(transfer)
is AllPossibleRecipients -> {
// This means all possible recipients _that the network knows about at the time_, not literally everyone
// who joins into the indefinite future.
for (handle in handleEndpointMap.keys)
getQueueForHandle(handle).add(message)
getQueueForHandle(handle).add(transfer)
}
else -> throw IllegalArgumentException("Unknown type of recipient handle")
}
@ -133,8 +153,8 @@ class InMemoryMessagingNetwork {
}
}
class Handle(val id: Int) : SingleMessageRecipient {
override fun toString() = "In memory node $id"
class Handle(val id: Int, val description: String) : SingleMessageRecipient {
override fun toString() = description
override fun equals(other: Any?) = other is Handle && other.id == id
override fun hashCode() = id.hashCode()
}
@ -156,7 +176,7 @@ class InMemoryMessagingNetwork {
protected inner class InnerState {
val handlers: MutableList<Handler> = ArrayList()
val pendingRedelivery = LinkedList<Message>()
val pendingRedelivery = LinkedList<MessageTransfer>()
}
protected val state = ThreadBox(InnerState())
@ -183,7 +203,7 @@ class InMemoryMessagingNetwork {
Pair(handler, items)
}
for (it in items)
msgSend(this, it, handle)
msgSend(this, it.message, handle)
return handler
}
@ -223,19 +243,21 @@ class InMemoryMessagingNetwork {
* Delivers a single message from the internal queue. If there are no messages waiting to be delivered and block
* is true, waits until one has been provided on a different thread via send. If block is false, the return
* result indicates whether a message was delivered or not.
*
* @return the message that was processed, if any in this round.
*/
fun pump(block: Boolean): Boolean {
fun pump(block: Boolean): MessageTransfer? {
check(manuallyPumped)
check(running)
return pumpInternal(block)
}
private fun pumpInternal(block: Boolean): Boolean {
private fun pumpInternal(block: Boolean): MessageTransfer? {
val q = getQueueForHandle(handle)
val message = (if (block) q.take() else q.poll()) ?: return false
val transfer = (if (block) q.take() else q.poll()) ?: return null
val deliverTo = state.locked {
val h = handlers.filter { if (it.topic.isBlank()) true else message.topic == it.topic }
val h = handlers.filter { if (it.topic.isBlank()) true else transfer.message.topic == it.topic }
if (h.isEmpty()) {
// Got no handlers for this message yet. Keep the message around and attempt redelivery after a new
@ -243,8 +265,8 @@ class InMemoryMessagingNetwork {
// reliable, as a sender may attempt to send a message to a receiver that hasn't finished setting
// up a handler for yet. Most unit tests don't run threaded, but we want to test true parallelism at
// least sometimes.
pendingRedelivery.add(message)
return false
pendingRedelivery.add(transfer)
return null
}
h
@ -254,14 +276,14 @@ class InMemoryMessagingNetwork {
// Now deliver via the requested executor, or on this thread if no executor was provided at registration time.
(handler.executor ?: MoreExecutors.directExecutor()).execute {
try {
handler.callback(message, handler)
handler.callback(transfer.message, handler)
} catch(e: Exception) {
loggerFor<InMemoryMessagingNetwork>().error("Caught exception in handler for $this/${handler.topic}", e)
}
}
}
return true
return transfer
}
}
}

@ -1,6 +1,7 @@
package core.testing
import com.google.common.jimfs.Jimfs
import com.google.common.util.concurrent.Futures
import core.crypto.Party
import core.messaging.MessagingService
import core.messaging.SingleMessageRecipient
@ -27,6 +28,10 @@ import java.util.*
* Mock network nodes require manual pumping by default: they will not run asynchronous. This means that
* for message exchanges to take place (and associated handlers to run), you must call the [runNetwork]
* method.
*
* You can get a printout of every message sent by using code like:
*
* BriefLogFormatter.initVerbose("+messaging")
*/
class MockNetwork(private val threadPerNode: Boolean = false,
private val defaultFactory: Factory = MockNetwork.DefaultFactory) {
@ -71,7 +76,7 @@ class MockNetwork(private val threadPerNode: Boolean = false,
override fun makeMessagingService(): MessagingService {
require(id >= 0) { "Node ID must be zero or positive, was passed: " + id }
return mockNet.messagingNetwork.createNodeWithID(!mockNet.threadPerNode, id).start().get()
return mockNet.messagingNetwork.createNodeWithID(!mockNet.threadPerNode, id, configuration.myLegalName).start().get()
}
override fun makeIdentityService() = MockIdentityService(mockNet.identities)
@ -82,6 +87,9 @@ class MockNetwork(private val threadPerNode: Boolean = false,
override fun generateKeyPair(): KeyPair? = keyPair ?: super.generateKeyPair()
// It's OK to not have a network map service in the mock network.
override fun noNetworkMapConfigured() = Futures.immediateFuture(Unit)
// There is no need to slow down the unit tests by initialising CityDatabase
override fun findMyLocation(): PhysicalLocation? = null
@ -91,12 +99,13 @@ class MockNetwork(private val threadPerNode: Boolean = false,
return this
}
val place: PhysicalLocation get() = info.physicalLocation!!
// This does not indirect through the NodeInfo object so it can be called before the node is started.
val place: PhysicalLocation get() = findMyLocation()!!
}
/** Returns a started node, optionally created by the passed factory method */
/** Returns a node, optionally created by the passed factory method. */
fun createNode(networkMapAddress: NodeInfo? = null, forcedID: Int = -1, nodeFactory: Factory = defaultFactory,
legalName: String? = null, keyPair: KeyPair? = null, vararg advertisedServices: ServiceType): MockNode {
start: Boolean = true, legalName: String? = null, keyPair: KeyPair? = null, vararg advertisedServices: ServiceType): MockNode {
val newNode = forcedID == -1
val id = if (newNode) counter++ else forcedID
@ -108,7 +117,8 @@ class MockNetwork(private val threadPerNode: Boolean = false,
override val exportJMXto: String = ""
override val nearestCity: String = "Atlantis"
}
val node = nodeFactory.create(path, config, this, networkMapAddress, advertisedServices.toSet(), id, keyPair).start()
val node = nodeFactory.create(path, config, this, networkMapAddress, advertisedServices.toSet(), id, keyPair)
if (start) node.start()
_nodes.add(node)
return node
}
@ -121,8 +131,9 @@ class MockNetwork(private val threadPerNode: Boolean = false,
*/
fun runNetwork(rounds: Int = -1) {
fun pumpAll() = messagingNetwork.endpoints.map { it.pump(false) }
if (rounds == -1)
while (pumpAll().any { it }) {
while (pumpAll().any { it != null }) {
}
else
repeat(rounds) { pumpAll() }
@ -135,13 +146,23 @@ class MockNetwork(private val threadPerNode: Boolean = false,
fun createTwoNodes(nodeFactory: Factory = defaultFactory, notaryKeyPair: KeyPair? = null): Pair<MockNode, MockNode> {
require(nodes.isEmpty())
return Pair(
createNode(null, -1, nodeFactory, null, notaryKeyPair, NetworkMapService.Type, NotaryService.Type),
createNode(nodes[0].info, -1, nodeFactory, null)
createNode(null, -1, nodeFactory, true, null, notaryKeyPair, NetworkMapService.Type, NotaryService.Type),
createNode(nodes[0].info, -1, nodeFactory, true, null)
)
}
fun createNotaryNode(legalName: String? = null, keyPair: KeyPair? = null) = createNode(null, -1, defaultFactory, legalName, keyPair, NetworkMapService.Type, NotaryService.Type)
fun createPartyNode(networkMapAddr: NodeInfo, legalName: String? = null, keyPair: KeyPair? = null) = createNode(networkMapAddr, -1, defaultFactory, legalName, keyPair)
fun createNotaryNode(legalName: String? = null, keyPair: KeyPair? = null) = createNode(null, -1, defaultFactory, true, legalName, keyPair, NetworkMapService.Type, NotaryService.Type)
fun createPartyNode(networkMapAddr: NodeInfo, legalName: String? = null, keyPair: KeyPair? = null) = createNode(networkMapAddr, -1, defaultFactory, true, legalName, keyPair)
fun addressToNode(address: SingleMessageRecipient): MockNode = nodes.single { it.net.myAddress == address }
fun startNodes() {
require(nodes.isNotEmpty())
nodes.forEach { if (!it.started) it.start() }
}
fun stopNodes() {
require(nodes.isNotEmpty())
nodes.forEach { if (it.started) it.stop() }
}
}

@ -1,5 +1,6 @@
package core.testing
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
import core.node.CityDatabase
import core.node.NodeConfiguration
@ -58,7 +59,7 @@ abstract class Simulation(val runAsync: Boolean,
}
fun createAll(): List<SimulatedNode> = bankLocations.
map { network.createNode(networkMap.info, nodeFactory = this) as SimulatedNode }
map { network.createNode(networkMap.info, start = false, nodeFactory = this) as SimulatedNode }
}
val bankFactory = BankFactory()
@ -68,9 +69,9 @@ abstract class Simulation(val runAsync: Boolean,
networkMapAddr: NodeInfo?, advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
require(advertisedServices.contains(NetworkMapService.Type))
val cfg = object : NodeConfiguration {
override val myLegalName: String = "Network Map Service Provider"
override val myLegalName: String = "Network coordination center"
override val exportJMXto: String = ""
override val nearestCity: String = "Madrid"
override val nearestCity: String = "Amsterdam"
}
return object : SimulatedNode(dir, cfg, network, networkMapAddr, advertisedServices, id, keyPair) {}
@ -127,24 +128,19 @@ abstract class Simulation(val runAsync: Boolean,
}
}
val network = MockNetwork(false)
val regulators: List<SimulatedNode> = listOf(network.createNode(null, nodeFactory = RegulatorFactory) as SimulatedNode)
val network = MockNetwork(runAsync)
// This one must come first.
val networkMap: SimulatedNode
= network.createNode(null, nodeFactory = NetworkMapNodeFactory, advertisedServices = NetworkMapService.Type) as SimulatedNode
val notary: SimulatedNode
= network.createNode(null, nodeFactory = NotaryNodeFactory, advertisedServices = NotaryService.Type) as SimulatedNode
= network.createNode(networkMap.info, nodeFactory = NotaryNodeFactory, advertisedServices = NotaryService.Type) as SimulatedNode
val regulators: List<SimulatedNode> = listOf(network.createNode(networkMap.info, start = false, nodeFactory = RegulatorFactory) as SimulatedNode)
val ratesOracle: SimulatedNode
= network.createNode(null, nodeFactory = RatesOracleFactory, advertisedServices = NodeInterestRates.Type) as SimulatedNode
val serviceProviders: List<SimulatedNode> = listOf(notary, ratesOracle)
val banks: List<SimulatedNode> = bankFactory.createAll()
= network.createNode(networkMap.info, start = false, nodeFactory = RatesOracleFactory, advertisedServices = NodeInterestRates.Type) as SimulatedNode
init {
// Now wire up the network maps for each node.
for (node in regulators + serviceProviders + banks) {
node.services.networkMapCache.addNode(node.info)
}
}
// All nodes must be in one of these two lists for the purposes of the visualiser tool.
val serviceProviders: List<SimulatedNode> = listOf(notary, ratesOracle, networkMap)
val banks: List<SimulatedNode> = bankFactory.createAll()
private val _allProtocolSteps = PublishSubject.create<Pair<SimulatedNode, ProgressTracker.Change>>()
private val _doneSteps = PublishSubject.create<Collection<SimulatedNode>>()
@ -179,18 +175,22 @@ abstract class Simulation(val runAsync: Boolean,
* will carry on from where this one stopped. In an environment where you want to take actions between anything
* interesting happening, or control the precise speed at which things operate (beyond the latency injector), this
* is a useful way to do things.
*
* @return the message that was processed, or null if no node accepted a message in this round.
*/
open fun iterate() {
open fun iterate(): InMemoryMessagingNetwork.MessageTransfer? {
// Keep going until one of the nodes has something to do, or we have checked every node.
val endpoints = network.messagingNetwork.endpoints
var countDown = endpoints.size
while (countDown > 0) {
val handledMessage = endpoints[pumpCursor].pump(false)
if (handledMessage) break
if (handledMessage != null)
return handledMessage
// If this node had nothing to do, advance the cursor with wraparound and try again.
pumpCursor = (pumpCursor + 1) % endpoints.size
countDown--
}
return null
}
protected fun linkProtocolProgress(node: SimulatedNode, protocol: ProtocolLogic<*>) {
@ -212,11 +212,23 @@ abstract class Simulation(val runAsync: Boolean,
}
}
open fun start() {
fun start(): ListenableFuture<Unit> {
network.startNodes()
// Wait for all the nodes to have finished registering with the network map service.
val startup: ListenableFuture<List<Unit>> = Futures.allAsList(network.nodes.map { it.networkMapRegistrationFuture })
return Futures.transformAsync(startup) { l: List<Unit>? -> startMainSimulation() }
}
/**
* Sub-classes should override this to trigger whatever they want to simulate. This method will be invoked once the
* network bringup has been simulated.
*/
protected open fun startMainSimulation(): ListenableFuture<Unit> {
return Futures.immediateFuture(Unit)
}
fun stop() {
network.nodes.forEach { it.stop() }
network.stopNodes()
}
/**

@ -3,11 +3,12 @@ package core.testing
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
import contracts.CommercialPaper
import core.*
import core.contracts.DOLLARS
import core.contracts.SignedTransaction
import core.days
import core.node.subsystems.NodeWalletService
import core.utilities.BriefLogFormatter
import core.random63BitValue
import core.seconds
import protocols.TwoPartyTradeProtocol
import java.time.Instant
@ -16,9 +17,9 @@ import java.time.Instant
* then B and C trade with each other, then C and A etc).
*/
class TradeSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwork.LatencyCalculator?) : Simulation(runAsync, latencyInjector) {
override fun start() {
BriefLogFormatter.loggingOn("bank", "core.contract.TransactionGroup", "recordingmap")
override fun startMainSimulation(): ListenableFuture<Unit> {
startTradingCircle { i, j -> tradeBetween(i, j) }
return Futures.immediateFailedFuture(UnsupportedOperationException("This future never completes"))
}
private fun tradeBetween(buyerBankIndex: Int, sellerBankIndex: Int): ListenableFuture<MutableList<SignedTransaction>> {

@ -1,51 +1,228 @@
# Some pretend noddy rate fixes, for the interest rate oracles.
3M USD 2016-03-16 1M = 0.678
3M USD 2016-03-16 2M = 0.655
ICE LIBOR 2016-03-16 1M = 0.678
ICE LIBOR 2016-03-16 2M = 0.655
EURIBOR 2016-03-15 1M = 0.123
EURIBOR 2016-03-15 2M = 0.111
3M USD 2016-03-08 3M = 0.0063515
3M USD 2016-06-08 3M = 0.0063520
3M USD 2016-09-08 3M = 0.0063521
3M USD 2016-12-08 3M = 0.0063515
3M USD 2017-03-08 3M = 0.0063525
3M USD 2017-06-08 3M = 0.0063530
3M USD 2017-09-07 3M = 0.0063531
3M USD 2017-12-07 3M = 0.0063532
3M USD 2018-03-08 3M = 0.0063533
3M USD 2018-06-07 3M = 0.0063534
3M USD 2018-09-06 3M = 0.0063535
3M USD 2018-12-06 3M = 0.0063536
3M USD 2019-03-07 3M = 0.0063537
3M USD 2019-06-06 3M = 0.0063538
3M USD 2019-09-06 3M = 0.0063539
3M USD 2019-12-06 3M = 0.0063540
3M USD 2020-03-06 3M = 0.0063541
3M USD 2020-06-08 3M = 0.0063542
3M USD 2020-09-08 3M = 0.0063543
3M USD 2020-12-08 3M = 0.0063544
3M USD 2021-03-08 3M = 0.0063545
3M USD 2021-06-08 3M = 0.0063546
3M USD 2021-09-08 3M = 0.0063547
3M USD 2021-12-08 3M = 0.0063548
3M USD 2022-03-08 3M = 0.0063549
3M USD 2022-06-08 3M = 0.0063550
3M USD 2022-09-08 3M = 0.0063551
3M USD 2022-12-08 3M = 0.0063553
3M USD 2023-03-08 3M = 0.0063554
3M USD 2023-06-08 3M = 0.0063555
3M USD 2023-09-07 3M = 0.0063556
3M USD 2023-12-07 3M = 0.0063557
3M USD 2024-03-07 3M = 0.0063558
3M USD 2024-06-06 3M = 0.0063559
3M USD 2024-09-06 3M = 0.0063560
3M USD 2024-12-06 3M = 0.0063561
3M USD 2025-03-06 3M = 0.0063562
3M USD 2025-06-06 3M = 0.0063563
3M USD 2025-09-08 3M = 0.0063564
3M USD 2025-12-08 3M = 0.0063565
3M USD 2026-03-06 3M = 0.0063566
3M USD 2026-06-08 3M = 0.0063567
3M USD 2026-09-08 3M = 0.0063568
3M USD 2026-12-08 3M = 0.0063569
# Previous fixings
ICE LIBOR 2016-03-07 3M = 0.0063516
ICE LIBOR 2016-03-07 3M = 0.0063516
ICE LIBOR 2016-03-08 3M = 0.0063517
ICE LIBOR 2016-03-09 3M = 0.0063518
ICE LIBOR 2016-03-10 3M = 0.0063519
ICE LIBOR 2016-06-06 3M = 0.0063520
ICE LIBOR 2016-06-07 3M = 0.0063521
ICE LIBOR 2016-06-08 3M = 0.0063522
ICE LIBOR 2016-06-09 3M = 0.0063523
ICE LIBOR 2016-06-10 3M = 0.0063524
ICE LIBOR 2016-09-06 3M = 0.0063525
ICE LIBOR 2016-09-07 3M = 0.0063526
ICE LIBOR 2016-09-08 3M = 0.0063527
ICE LIBOR 2016-09-09 3M = 0.0063528
ICE LIBOR 2016-09-10 3M = 0.0063529
ICE LIBOR 2016-12-06 3M = 0.0063530
ICE LIBOR 2016-12-07 3M = 0.0063531
ICE LIBOR 2016-12-08 3M = 0.0063532
ICE LIBOR 2016-12-09 3M = 0.0063533
ICE LIBOR 2016-12-10 3M = 0.0063534
ICE LIBOR 2017-03-06 3M = 0.0063535
ICE LIBOR 2017-03-07 3M = 0.0063536
ICE LIBOR 2017-03-08 3M = 0.0063537
ICE LIBOR 2017-03-09 3M = 0.0063538
ICE LIBOR 2017-03-10 3M = 0.0063539
ICE LIBOR 2017-06-06 3M = 0.0063540
ICE LIBOR 2017-06-07 3M = 0.0063541
ICE LIBOR 2017-06-08 3M = 0.0063542
ICE LIBOR 2017-06-09 3M = 0.0063543
ICE LIBOR 2017-06-10 3M = 0.0063544
ICE LIBOR 2017-09-06 3M = 0.0063545
ICE LIBOR 2017-09-07 3M = 0.0063546
ICE LIBOR 2017-09-08 3M = 0.0063547
ICE LIBOR 2017-09-09 3M = 0.0063548
ICE LIBOR 2017-09-10 3M = 0.0063549
ICE LIBOR 2017-12-06 3M = 0.0063550
ICE LIBOR 2017-12-07 3M = 0.0063551
ICE LIBOR 2017-12-08 3M = 0.0063552
ICE LIBOR 2017-12-09 3M = 0.0063553
ICE LIBOR 2017-12-10 3M = 0.0063554
ICE LIBOR 2018-03-06 3M = 0.0063555
ICE LIBOR 2018-03-07 3M = 0.0063556
ICE LIBOR 2018-03-08 3M = 0.0063557
ICE LIBOR 2018-03-09 3M = 0.0063558
ICE LIBOR 2018-03-10 3M = 0.0063559
ICE LIBOR 2018-06-06 3M = 0.0063560
ICE LIBOR 2018-06-07 3M = 0.0063561
ICE LIBOR 2018-06-08 3M = 0.0063562
ICE LIBOR 2018-06-09 3M = 0.0063563
ICE LIBOR 2018-06-10 3M = 0.0063564
ICE LIBOR 2018-09-06 3M = 0.0063565
ICE LIBOR 2018-09-07 3M = 0.0063566
ICE LIBOR 2018-09-08 3M = 0.0063567
ICE LIBOR 2018-09-09 3M = 0.0063568
ICE LIBOR 2018-09-10 3M = 0.0063569
ICE LIBOR 2018-12-06 3M = 0.0063570
ICE LIBOR 2018-12-07 3M = 0.0063571
ICE LIBOR 2018-12-08 3M = 0.0063572
ICE LIBOR 2018-12-09 3M = 0.0063573
ICE LIBOR 2018-12-10 3M = 0.0063574
ICE LIBOR 2019-03-06 3M = 0.0063575
ICE LIBOR 2019-03-07 3M = 0.0063576
ICE LIBOR 2019-03-08 3M = 0.0063577
ICE LIBOR 2019-03-09 3M = 0.0063578
ICE LIBOR 2019-03-10 3M = 0.0063579
ICE LIBOR 2019-06-06 3M = 0.0063580
ICE LIBOR 2019-06-07 3M = 0.0063581
ICE LIBOR 2019-06-08 3M = 0.0063582
ICE LIBOR 2019-06-09 3M = 0.0063583
ICE LIBOR 2019-06-10 3M = 0.0063584
ICE LIBOR 2019-09-06 3M = 0.0063585
ICE LIBOR 2019-09-07 3M = 0.0063586
ICE LIBOR 2019-09-08 3M = 0.0063587
ICE LIBOR 2019-09-09 3M = 0.0063588
ICE LIBOR 2019-09-10 3M = 0.0063589
ICE LIBOR 2019-12-06 3M = 0.0063590
ICE LIBOR 2019-12-07 3M = 0.0063591
ICE LIBOR 2019-12-08 3M = 0.0063592
ICE LIBOR 2019-12-09 3M = 0.0063593
ICE LIBOR 2019-12-10 3M = 0.0063594
ICE LIBOR 2020-03-06 3M = 0.0063595
ICE LIBOR 2020-03-07 3M = 0.0063596
ICE LIBOR 2020-03-08 3M = 0.0063597
ICE LIBOR 2020-03-09 3M = 0.0063598
ICE LIBOR 2020-03-10 3M = 0.0063599
ICE LIBOR 2020-06-06 3M = 0.0063600
ICE LIBOR 2020-06-07 3M = 0.0063601
ICE LIBOR 2020-06-08 3M = 0.0063602
ICE LIBOR 2020-06-09 3M = 0.0063603
ICE LIBOR 2020-06-10 3M = 0.0063604
ICE LIBOR 2020-09-06 3M = 0.0063605
ICE LIBOR 2020-09-07 3M = 0.0063606
ICE LIBOR 2020-09-08 3M = 0.0063607
ICE LIBOR 2020-09-09 3M = 0.0063608
ICE LIBOR 2020-09-10 3M = 0.0063609
ICE LIBOR 2020-12-06 3M = 0.0063610
ICE LIBOR 2020-12-07 3M = 0.0063611
ICE LIBOR 2020-12-08 3M = 0.0063612
ICE LIBOR 2020-12-09 3M = 0.0063613
ICE LIBOR 2020-12-10 3M = 0.0063614
ICE LIBOR 2021-03-06 3M = 0.0063615
ICE LIBOR 2021-03-07 3M = 0.0063616
ICE LIBOR 2021-03-08 3M = 0.0063617
ICE LIBOR 2021-03-09 3M = 0.0063618
ICE LIBOR 2021-03-10 3M = 0.0063619
ICE LIBOR 2021-06-06 3M = 0.0063620
ICE LIBOR 2021-06-07 3M = 0.0063621
ICE LIBOR 2021-06-08 3M = 0.0063622
ICE LIBOR 2021-06-09 3M = 0.0063623
ICE LIBOR 2021-06-10 3M = 0.0063624
ICE LIBOR 2021-09-06 3M = 0.0063625
ICE LIBOR 2021-09-07 3M = 0.0063626
ICE LIBOR 2021-09-08 3M = 0.0063627
ICE LIBOR 2021-09-09 3M = 0.0063628
ICE LIBOR 2021-09-10 3M = 0.0063629
ICE LIBOR 2021-12-06 3M = 0.0063630
ICE LIBOR 2021-12-07 3M = 0.0063631
ICE LIBOR 2021-12-08 3M = 0.0063632
ICE LIBOR 2021-12-09 3M = 0.0063633
ICE LIBOR 2021-12-10 3M = 0.0063634
ICE LIBOR 2022-03-06 3M = 0.0063635
ICE LIBOR 2022-03-07 3M = 0.0063636
ICE LIBOR 2022-03-08 3M = 0.0063637
ICE LIBOR 2022-03-09 3M = 0.0063638
ICE LIBOR 2022-03-10 3M = 0.0063639
ICE LIBOR 2022-06-06 3M = 0.0063640
ICE LIBOR 2022-06-07 3M = 0.0063641
ICE LIBOR 2022-06-08 3M = 0.0063642
ICE LIBOR 2022-06-09 3M = 0.0063643
ICE LIBOR 2022-06-10 3M = 0.0063644
ICE LIBOR 2022-09-06 3M = 0.0063645
ICE LIBOR 2022-09-07 3M = 0.0063646
ICE LIBOR 2022-09-08 3M = 0.0063647
ICE LIBOR 2022-09-09 3M = 0.0063648
ICE LIBOR 2022-09-10 3M = 0.0063649
ICE LIBOR 2022-12-06 3M = 0.0063650
ICE LIBOR 2022-12-07 3M = 0.0063651
ICE LIBOR 2022-12-08 3M = 0.0063652
ICE LIBOR 2022-12-09 3M = 0.0063653
ICE LIBOR 2022-12-10 3M = 0.0063654
ICE LIBOR 2023-03-06 3M = 0.0063655
ICE LIBOR 2023-03-07 3M = 0.0063656
ICE LIBOR 2023-03-08 3M = 0.0063657
ICE LIBOR 2023-03-09 3M = 0.0063658
ICE LIBOR 2023-03-10 3M = 0.0063659
ICE LIBOR 2023-06-06 3M = 0.0063660
ICE LIBOR 2023-06-07 3M = 0.0063661
ICE LIBOR 2023-06-08 3M = 0.0063662
ICE LIBOR 2023-06-09 3M = 0.0063663
ICE LIBOR 2023-06-10 3M = 0.0063664
ICE LIBOR 2023-09-06 3M = 0.0063665
ICE LIBOR 2023-09-07 3M = 0.0063666
ICE LIBOR 2023-09-08 3M = 0.0063667
ICE LIBOR 2023-09-09 3M = 0.0063668
ICE LIBOR 2023-09-10 3M = 0.0063669
ICE LIBOR 2023-12-06 3M = 0.0063670
ICE LIBOR 2023-12-07 3M = 0.0063671
ICE LIBOR 2023-12-08 3M = 0.0063672
ICE LIBOR 2023-12-09 3M = 0.0063673
ICE LIBOR 2023-12-10 3M = 0.0063674
ICE LIBOR 2024-03-06 3M = 0.0063675
ICE LIBOR 2024-03-07 3M = 0.0063676
ICE LIBOR 2024-03-08 3M = 0.0063677
ICE LIBOR 2024-03-09 3M = 0.0063678
ICE LIBOR 2024-03-10 3M = 0.0063679
ICE LIBOR 2024-06-06 3M = 0.0063680
ICE LIBOR 2024-06-07 3M = 0.0063681
ICE LIBOR 2024-06-08 3M = 0.0063682
ICE LIBOR 2024-06-09 3M = 0.0063683
ICE LIBOR 2024-06-10 3M = 0.0063684
ICE LIBOR 2024-09-06 3M = 0.0063685
ICE LIBOR 2024-09-07 3M = 0.0063686
ICE LIBOR 2024-09-08 3M = 0.0063687
ICE LIBOR 2024-09-09 3M = 0.0063688
ICE LIBOR 2024-09-10 3M = 0.0063689
ICE LIBOR 2024-12-06 3M = 0.0063690
ICE LIBOR 2024-12-07 3M = 0.0063691
ICE LIBOR 2024-12-08 3M = 0.0063692
ICE LIBOR 2024-12-09 3M = 0.0063693
ICE LIBOR 2024-12-10 3M = 0.0063694
ICE LIBOR 2025-03-06 3M = 0.0063695
ICE LIBOR 2025-03-07 3M = 0.0063696
ICE LIBOR 2025-03-08 3M = 0.0063697
ICE LIBOR 2025-03-09 3M = 0.0063698
ICE LIBOR 2025-03-10 3M = 0.0063699
ICE LIBOR 2025-06-06 3M = 0.0063700
ICE LIBOR 2025-06-07 3M = 0.0063701
ICE LIBOR 2025-06-08 3M = 0.0063702
ICE LIBOR 2025-06-09 3M = 0.0063703
ICE LIBOR 2025-06-10 3M = 0.0063704
ICE LIBOR 2025-09-06 3M = 0.0063705
ICE LIBOR 2025-09-07 3M = 0.0063706
ICE LIBOR 2025-09-08 3M = 0.0063707
ICE LIBOR 2025-09-09 3M = 0.0063708
ICE LIBOR 2025-09-10 3M = 0.0063709
ICE LIBOR 2025-12-06 3M = 0.0063710
ICE LIBOR 2025-12-07 3M = 0.0063711
ICE LIBOR 2025-12-08 3M = 0.0063712
ICE LIBOR 2025-12-09 3M = 0.0063713
ICE LIBOR 2025-12-10 3M = 0.0063714
ICE LIBOR 2026-03-06 3M = 0.0063715
ICE LIBOR 2026-03-07 3M = 0.0063716
ICE LIBOR 2026-03-08 3M = 0.0063717
ICE LIBOR 2026-03-09 3M = 0.0063718
ICE LIBOR 2026-03-10 3M = 0.0063719
ICE LIBOR 2026-06-06 3M = 0.0063720
ICE LIBOR 2026-06-07 3M = 0.0063721
ICE LIBOR 2026-06-08 3M = 0.0063722
ICE LIBOR 2026-06-09 3M = 0.0063723
ICE LIBOR 2026-06-10 3M = 0.0063724
ICE LIBOR 2026-09-06 3M = 0.0063725
ICE LIBOR 2026-09-07 3M = 0.0063726
ICE LIBOR 2026-09-08 3M = 0.0063727
ICE LIBOR 2026-09-09 3M = 0.0063728
ICE LIBOR 2026-09-10 3M = 0.0063729
ICE LIBOR 2026-12-06 3M = 0.0063730
ICE LIBOR 2026-12-07 3M = 0.0063731
ICE LIBOR 2026-12-08 3M = 0.0063732
ICE LIBOR 2026-12-09 3M = 0.0063733
ICE LIBOR 2026-12-10 3M = 0.0063734

@ -6,9 +6,9 @@
"currency": "USD"
},
"paymentFrequency": "SemiAnnual",
"effectiveDate": "2016-03-16",
"effectiveDate": "2016-03-11",
"effectiveDateAdjustment": null,
"terminationDate": "2026-03-16",
"terminationDate": "2026-03-11",
"terminationDateAdjustment": null,
"fixedRate": {
"ratioUnit": {
@ -31,9 +31,9 @@
"currency": "USD"
},
"paymentFrequency": "Quarterly",
"effectiveDate": "2016-03-12",
"effectiveDate": "2016-03-11",
"effectiveDateAdjustment": null,
"terminationDate": "2026-03-12",
"terminationDate": "2026-03-11",
"terminationDateAdjustment": null,
"dayCountBasisDay": "D30",
"dayCountBasisYear": "Y360",
@ -49,7 +49,7 @@
"resetRule": "InAdvance",
"fixingsPerPayment": "Quarterly",
"fixingCalendar": [ "NewYork" ],
"index": "3M USD",
"index": "ICE LIBOR",
"indexSource": "Rates Service Provider",
"indexTenor": {
"name": "3M"
@ -100,5 +100,5 @@
"tradeID": "tradeXXX",
"hashLegalDocs": "put hash here"
},
"programRef": "1E6BBA305D445341F0026E51B6C7F3ACB834AFC6C2510C0EF7BC0477235EFECF"
"notary": "Notary Service"
}

@ -100,7 +100,7 @@ class AttachmentTests {
}
}
}
}, null, null, NetworkMapService.Type, NotaryService.Type)
}, true, null, null, NetworkMapService.Type, NotaryService.Type)
val n1 = network.createNode(n0.info)
// Insert an attachment into node zero's store directly.

@ -36,6 +36,7 @@ import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
/**
@ -171,7 +172,7 @@ class TwoPartyTradeProtocolTests {
// Alice doesn't know that and carries on: she wants to know about the cash transactions he's trying to use.
// She will wait around until Bob comes back.
assertTrue(pumpAlice())
assertNotNull(pumpAlice())
// ... bring the node back up ... the act of constructing the SMM will re-register the message handlers
// that Bob was waiting on before the reboot occurred.
@ -180,7 +181,7 @@ class TwoPartyTradeProtocolTests {
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
return MockNetwork.MockNode(dir, config, network, networkMapAddr, advertisedServices, bobAddr.id, BOB_KEY)
}
}, BOB.name, BOB_KEY)
}, true, BOB.name, BOB_KEY)
// TODO: remove once validated transactions are persisted to disk
bobNode.storage.validatedTransactions.putAll(recordedTransactions)
@ -213,7 +214,7 @@ class TwoPartyTradeProtocolTests {
}
}
}
}, name, keyPair)
}, true, name, keyPair)
}
@Test

@ -0,0 +1,22 @@
package core.testing
import com.google.common.base.Throwables
import core.utilities.BriefLogFormatter
import org.junit.Ignore
import org.junit.Test
class IRSSimulationTest {
// TODO: These tests should be a lot more complete.
@Test @Ignore fun `runs to completion`() {
BriefLogFormatter.initVerbose("messaging")
val sim = IRSSimulation(false, null)
val future = sim.start()
while (!future.isDone) sim.iterate()
try {
future.get()
} catch(e: Throwable) {
throw Throwables.getRootCause(e)
}
}
}