mirror of
https://github.com/corda/corda.git
synced 2025-04-11 13:21:26 +00:00
commit
8211a7937b
node/src
main
kotlin/core
node
testing
resources/core/testing
test/kotlin/core/messaging
src/test/kotlin/core/testing
@ -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
|
||||
|
22
src/test/kotlin/core/testing/IRSSimulationTest.kt
Normal file
22
src/test/kotlin/core/testing/IRSSimulationTest.kt
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user