mirror of
https://github.com/corda/corda.git
synced 2024-12-23 23:02:29 +00:00
The integration tests for demos now spawn a new JVM instead of using threads. Demos no longer need or contain any in memory node logic.
This commit is contained in:
parent
22dd36950c
commit
03e2852880
@ -1,8 +1,5 @@
|
||||
package com.r3corda.core.testing
|
||||
|
||||
import com.r3corda.demos.DemoConfig
|
||||
import com.r3corda.demos.runIRSDemo
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.test.assertEquals
|
||||
import org.junit.Test
|
||||
import java.nio.file.Path
|
||||
@ -12,51 +9,53 @@ class IRSDemoTest {
|
||||
@Test fun `runs IRS demo`() {
|
||||
val dirA = Paths.get("./nodeA")
|
||||
val dirB = Paths.get("./nodeB")
|
||||
var procA: Process? = null
|
||||
var procB: Process? = null
|
||||
try {
|
||||
setupNode(dirA, "NodeA")
|
||||
setupNode(dirB, "NodeB")
|
||||
val threadA = startNode(dirA, "NodeA")
|
||||
val threadB = startNode(dirB, "NodeB")
|
||||
procA = startNode(dirA, "NodeA")
|
||||
procB = startNode(dirB, "NodeB")
|
||||
runTrade()
|
||||
runDateChange()
|
||||
stopNode(threadA)
|
||||
stopNode(threadB)
|
||||
} finally {
|
||||
stopNode(procA)
|
||||
stopNode(procB)
|
||||
cleanup(dirA)
|
||||
cleanup(dirB)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupNode(dir: Path, nodeType: String) {
|
||||
runIRSDemo(arrayOf("--role", "Setup" + nodeType, "--dir", dir.toString()))
|
||||
val args = listOf("--role", "Setup" + nodeType, "--dir", dir.toString())
|
||||
val proc = spawn("com.r3corda.demos.IRSDemoKt", args)
|
||||
proc.waitFor();
|
||||
assertEquals(proc.exitValue(), 0)
|
||||
}
|
||||
|
||||
private fun startNode(dir: Path, nodeType: String): Thread {
|
||||
val config = DemoConfig(true)
|
||||
val nodeThread = thread(true, false, null, nodeType, -1, {
|
||||
try {
|
||||
runIRSDemo(arrayOf("--role", nodeType, "--dir", dir.toString()), config)
|
||||
} finally {
|
||||
// Will only reach here during error or after node is stopped, so ensure lock is unlocked.
|
||||
config.nodeReady.countDown()
|
||||
}
|
||||
})
|
||||
config.nodeReady.await()
|
||||
return nodeThread
|
||||
private fun startNode(dir: Path, nodeType: String): Process {
|
||||
val args = listOf("--role", nodeType, "--dir", dir.toString())
|
||||
val proc = spawn("com.r3corda.demos.IRSDemoKt", args)
|
||||
Thread.sleep(15000)
|
||||
return proc
|
||||
}
|
||||
|
||||
private fun runTrade() {
|
||||
assertEquals(runIRSDemo(arrayOf("--role", "Trade", "trade1")), 0)
|
||||
val args = listOf("--role", "Trade", "trade1")
|
||||
val proc = spawn("com.r3corda.demos.IRSDemoKt", args)
|
||||
proc.waitFor();
|
||||
assertEquals(proc.exitValue(), 0)
|
||||
}
|
||||
|
||||
private fun runDateChange() {
|
||||
assertEquals(runIRSDemo(arrayOf("--role", "Date", "2017-01-02")), 0)
|
||||
val args = listOf("--role", "Date", "2017-01-02")
|
||||
val proc = spawn("com.r3corda.demos.IRSDemoKt", args)
|
||||
proc.waitFor();
|
||||
assertEquals(proc.exitValue(), 0)
|
||||
}
|
||||
|
||||
private fun stopNode(nodeThread: Thread) {
|
||||
// The demo is designed to exit on interrupt
|
||||
nodeThread.interrupt()
|
||||
private fun stopNode(nodeProc: Process?) {
|
||||
nodeProc?.destroy()
|
||||
}
|
||||
|
||||
private fun cleanup(dir: Path) {
|
||||
|
@ -0,0 +1,15 @@
|
||||
package com.r3corda.core.testing
|
||||
|
||||
import java.nio.file.Paths
|
||||
|
||||
fun spawn(className: String, args: List<String>): Process {
|
||||
val separator = System.getProperty("file.separator")
|
||||
val classpath = System.getProperty("java.class.path")
|
||||
val path = System.getProperty("java.home") + separator + "bin" + separator + "java"
|
||||
val javaArgs = listOf(path, "-javaagent:lib/quasar.jar", "-cp", classpath, className)
|
||||
val builder = ProcessBuilder(javaArgs + args)
|
||||
builder.redirectError(Paths.get("error.$className.log").toFile())
|
||||
builder.inheritIO()
|
||||
val process = builder.start();
|
||||
return process
|
||||
}
|
@ -1,39 +1,34 @@
|
||||
package com.r3corda.core.testing
|
||||
|
||||
import com.r3corda.demos.DemoConfig
|
||||
import com.r3corda.demos.runTraderDemo
|
||||
import org.junit.Test
|
||||
import java.nio.file.Paths
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class TraderDemoTest {
|
||||
@Test fun `runs trader demo`() {
|
||||
var nodeProc: Process? = null
|
||||
try {
|
||||
runBuyer()
|
||||
nodeProc = runBuyer()
|
||||
runSeller()
|
||||
} finally {
|
||||
nodeProc?.destroy()
|
||||
cleanup()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun runBuyer() {
|
||||
val config = DemoConfig(true)
|
||||
thread(true, false, null, "Buyer", -1, {
|
||||
try {
|
||||
runTraderDemo(arrayOf("--role", "BUYER"), config)
|
||||
} finally {
|
||||
// Will only reach here during error or after node is stopped, so ensure lock is unlocked.
|
||||
config.nodeReady.countDown()
|
||||
}
|
||||
})
|
||||
config.nodeReady.await()
|
||||
private fun runBuyer(): Process {
|
||||
val args = listOf("--role", "BUYER")
|
||||
val proc = spawn("com.r3corda.demos.TraderDemoKt", args)
|
||||
Thread.sleep(15000)
|
||||
return proc
|
||||
}
|
||||
|
||||
private fun runSeller() {
|
||||
val config = DemoConfig(true)
|
||||
assertEquals(runTraderDemo(arrayOf("--role", "SELLER"), config), 0)
|
||||
val args = listOf("--role", "SELLER")
|
||||
val proc = spawn("com.r3corda.demos.TraderDemoKt", args)
|
||||
proc.waitFor();
|
||||
assertEquals(proc.exitValue(), 0)
|
||||
}
|
||||
|
||||
private fun cleanup() {
|
||||
|
@ -1,33 +0,0 @@
|
||||
package com.r3corda.demos
|
||||
|
||||
import com.google.common.net.HostAndPort
|
||||
import com.r3corda.core.messaging.MessagingService
|
||||
import com.r3corda.core.node.NodeInfo
|
||||
import com.r3corda.core.node.services.ServiceType
|
||||
import com.r3corda.node.internal.Node
|
||||
import com.r3corda.node.serialization.NodeClock
|
||||
import com.r3corda.node.services.config.NodeConfiguration
|
||||
import com.r3corda.node.services.network.InMemoryMessagingNetwork
|
||||
import java.nio.file.Path
|
||||
import java.time.Clock
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
val messageNetwork = InMemoryMessagingNetwork()
|
||||
|
||||
class DemoNode(messagingService: MessagingService, dir: Path, p2pAddr: HostAndPort, config: NodeConfiguration,
|
||||
networkMapAddress: NodeInfo?, advertisedServices: Set<ServiceType>,
|
||||
clock: Clock = NodeClock(), clientAPIs: List<Class<*>> = listOf())
|
||||
: Node(dir, p2pAddr, config, networkMapAddress, advertisedServices, clock, clientAPIs) {
|
||||
|
||||
val messagingService = messagingService
|
||||
override fun makeMessagingService(): MessagingService {
|
||||
return messagingService
|
||||
}
|
||||
|
||||
override fun startMessagingService() = Unit
|
||||
}
|
||||
|
||||
class DemoConfig(useInMemoryMessaging: Boolean = false) {
|
||||
val inMemory = useInMemoryMessaging
|
||||
val nodeReady = CountDownLatch(1)
|
||||
}
|
@ -89,7 +89,7 @@ fun main(args: Array<String>) {
|
||||
exitProcess(runIRSDemo(args))
|
||||
}
|
||||
|
||||
fun runIRSDemo(args: Array<String>, demoNodeConfig: DemoConfig = DemoConfig()): Int {
|
||||
fun runIRSDemo(args: Array<String>): Int {
|
||||
val parser = OptionParser()
|
||||
val demoArgs = setupArgs(parser)
|
||||
val options = try {
|
||||
@ -107,8 +107,8 @@ fun runIRSDemo(args: Array<String>, demoNodeConfig: DemoConfig = DemoConfig()):
|
||||
return when (role) {
|
||||
IRSDemoRole.SetupNodeA -> setup(configureNodeParams(IRSDemoRole.NodeA, demoArgs, options))
|
||||
IRSDemoRole.SetupNodeB -> setup(configureNodeParams(IRSDemoRole.NodeB, demoArgs, options))
|
||||
IRSDemoRole.NodeA -> runNode(role, demoArgs, options, demoNodeConfig)
|
||||
IRSDemoRole.NodeB -> runNode(role, demoArgs, options, demoNodeConfig)
|
||||
IRSDemoRole.NodeA -> runNode(role, demoArgs, options)
|
||||
IRSDemoRole.NodeB -> runNode(role, demoArgs, options)
|
||||
IRSDemoRole.Trade -> runTrade(demoArgs, options)
|
||||
IRSDemoRole.Date -> runDateChange(demoArgs, options)
|
||||
}
|
||||
@ -156,7 +156,7 @@ private fun runDateChange(demoArgs: DemoArgs, options: OptionSet): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
private fun runNode(role: IRSDemoRole, demoArgs: DemoArgs, options: OptionSet, demoNodeConfig: DemoConfig): Int {
|
||||
private fun runNode(role: IRSDemoRole, demoArgs: DemoArgs, options: OptionSet): Int {
|
||||
// If these directory and identity file arguments aren't specified then we can assume a default setup and
|
||||
// create everything that is needed without needing to run setup.
|
||||
if(!options.has(demoArgs.dirArg) && !options.has(demoArgs.fakeTradeWithIdentityFile)) {
|
||||
@ -165,7 +165,7 @@ private fun runNode(role: IRSDemoRole, demoArgs: DemoArgs, options: OptionSet, d
|
||||
}
|
||||
|
||||
try {
|
||||
runNode(configureNodeParams(role, demoArgs, options), demoNodeConfig)
|
||||
runNode(configureNodeParams(role, demoArgs, options))
|
||||
} catch (e: NotSetupException) {
|
||||
println(e.message)
|
||||
return 1
|
||||
@ -252,13 +252,13 @@ private fun configureNodeParams(role: IRSDemoRole, args: DemoArgs, options: Opti
|
||||
return nodeParams
|
||||
}
|
||||
|
||||
private fun runNode(nodeParams: NodeParams, demoNodeConfig: DemoConfig) : Unit {
|
||||
val networkMap = createRecipient(nodeParams.mapAddress, demoNodeConfig.inMemory)
|
||||
private fun runNode(nodeParams: NodeParams) : Unit {
|
||||
val networkMap = createRecipient(nodeParams.mapAddress)
|
||||
val destinations = nodeParams.tradeWithAddrs.map({
|
||||
createRecipient(it, demoNodeConfig.inMemory)
|
||||
createRecipient(it)
|
||||
})
|
||||
|
||||
val node = startNode(nodeParams, networkMap, destinations, demoNodeConfig.inMemory)
|
||||
val node = startNode(nodeParams, networkMap, destinations)
|
||||
// Register handlers for the demo
|
||||
AutoOfferProtocol.Handler.register(node)
|
||||
UpdateBusinessDayProtocol.Handler.register(node)
|
||||
@ -268,7 +268,6 @@ private fun runNode(nodeParams: NodeParams, demoNodeConfig: DemoConfig) : Unit {
|
||||
runUploadRates("http://localhost:31341")
|
||||
}
|
||||
|
||||
demoNodeConfig.nodeReady.countDown()
|
||||
try {
|
||||
while (true) Thread.sleep(Long.MAX_VALUE)
|
||||
} catch(e: InterruptedException) {
|
||||
@ -276,18 +275,12 @@ private fun runNode(nodeParams: NodeParams, demoNodeConfig: DemoConfig) : Unit {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createRecipient(addr: String, inMemory: Boolean) : SingleMessageRecipient {
|
||||
private fun createRecipient(addr: String) : SingleMessageRecipient {
|
||||
val hostAndPort = HostAndPort.fromString(addr).withDefaultPort(Node.DEFAULT_PORT)
|
||||
return if(inMemory) {
|
||||
// Assumption here is that all nodes run in memory and thus cannot share a port number.
|
||||
val id = hostAndPort.port
|
||||
InMemoryMessagingNetwork.Handle(id, "Node " + id)
|
||||
} else {
|
||||
ArtemisMessagingService.makeRecipient(hostAndPort)
|
||||
}
|
||||
return ArtemisMessagingService.makeRecipient(hostAndPort)
|
||||
}
|
||||
|
||||
private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, recipients: List<SingleMessageRecipient>, inMemory: Boolean) : Node {
|
||||
private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, recipients: List<SingleMessageRecipient>) : Node {
|
||||
val config = getNodeConfig(params)
|
||||
val advertisedServices: Set<ServiceType>
|
||||
val myNetAddr = HostAndPort.fromString(params.address).withDefaultPort(Node.DEFAULT_PORT)
|
||||
@ -300,17 +293,9 @@ private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, r
|
||||
nodeInfo(networkMap, params.identityFile, setOf(NetworkMapService.Type, SimpleNotaryService.Type))
|
||||
}
|
||||
|
||||
val node = if(inMemory) {
|
||||
// Port is ID for in memory since we assume in memory is all on the same machine, thus ports are unique.
|
||||
val messageService = messageNetwork.createNodeWithID(false, myNetAddr.port).start().get()
|
||||
logElapsedTime("Node startup") { DemoNode(messageService, params.dir, myNetAddr, config, networkMapId,
|
||||
advertisedServices, DemoClock(),
|
||||
listOf(InterestRateSwapAPI::class.java)).start() }
|
||||
} else {
|
||||
logElapsedTime("Node startup") { Node(params.dir, myNetAddr, config, networkMapId,
|
||||
advertisedServices, DemoClock(),
|
||||
listOf(InterestRateSwapAPI::class.java)).start() }
|
||||
}
|
||||
val node = logElapsedTime("Node startup") { Node(params.dir, myNetAddr, config, networkMapId,
|
||||
advertisedServices, DemoClock(),
|
||||
listOf(InterestRateSwapAPI::class.java)).start() }
|
||||
|
||||
// TODO: This should all be replaced by the identity service being updated
|
||||
// as the network map changes.
|
||||
|
@ -24,7 +24,6 @@ import com.r3corda.core.utilities.ProgressTracker
|
||||
import com.r3corda.node.internal.Node
|
||||
import com.r3corda.node.services.config.NodeConfigurationFromConfig
|
||||
import com.r3corda.node.services.messaging.ArtemisMessagingService
|
||||
import com.r3corda.node.services.network.InMemoryMessagingNetwork
|
||||
import com.r3corda.node.services.network.NetworkMapService
|
||||
import com.r3corda.node.services.persistence.NodeAttachmentService
|
||||
import com.r3corda.node.services.transactions.SimpleNotaryService
|
||||
@ -63,10 +62,6 @@ enum class Role {
|
||||
BUYER,
|
||||
SELLER
|
||||
}
|
||||
|
||||
private class Destination constructor(addr: Any, inMemory: Boolean): Serializable {
|
||||
val inMemory = inMemory
|
||||
val addr = addr
|
||||
}
|
||||
|
||||
// And this is the directory under the current working directory where each node will create its own server directory,
|
||||
@ -77,7 +72,7 @@ fun main(args: Array<String>) {
|
||||
exitProcess(runTraderDemo(args))
|
||||
}
|
||||
|
||||
fun runTraderDemo(args: Array<String>, demoNodeConfig: DemoConfig = DemoConfig()): Int {
|
||||
fun runTraderDemo(args: Array<String>): Int {
|
||||
val cashIssuerKey = generateKeyPair()
|
||||
val cashIssuer = Party("Trusted cash issuer", cashIssuerKey.public)
|
||||
val amount = 1000.DOLLARS `issued by` cashIssuer.ref(1)
|
||||
@ -110,19 +105,6 @@ fun runTraderDemo(args: Array<String>, demoNodeConfig: DemoConfig = DemoConfig()
|
||||
}
|
||||
)
|
||||
|
||||
val peerId: Int;
|
||||
val id: Int
|
||||
when (role) {
|
||||
Role.BUYER -> {
|
||||
peerId = 1
|
||||
id = 0
|
||||
}
|
||||
Role.SELLER -> {
|
||||
peerId = 0
|
||||
id = 1
|
||||
}
|
||||
}
|
||||
|
||||
// Suppress the Artemis MQ noise, and activate the demo logging.
|
||||
//
|
||||
// The first two strings correspond to the first argument to StateMachineManager.add() but the way we handle logging
|
||||
@ -161,28 +143,9 @@ fun runTraderDemo(args: Array<String>, demoNodeConfig: DemoConfig = DemoConfig()
|
||||
advertisedServices = emptySet()
|
||||
cashIssuer = party
|
||||
NodeInfo(ArtemisMessagingService.makeRecipient(theirNetAddr), party, setOf(NetworkMapService.Type))
|
||||
|
||||
if(demoNodeConfig.inMemory) {
|
||||
val handle = InMemoryMessagingNetwork.Handle(peerId, "Other Node")
|
||||
NodeInfo(handle, party, setOf(NetworkMapService.Type))
|
||||
} else {
|
||||
NodeInfo(ArtemisMessagingService.makeRecipient(theirNetAddr), party, setOf(NetworkMapService.Type))
|
||||
}
|
||||
}
|
||||
val messageService = messageNetwork.createNodeWithID(false, id).start().get()
|
||||
// And now construct then start the node object. It takes a little while.
|
||||
val node = logElapsedTime("Node startup") {
|
||||
if(demoNodeConfig.inMemory) {
|
||||
DemoNode(messageService, directory, myNetAddr, config, networkMapId, advertisedServices).setup().start()
|
||||
} else {
|
||||
Node(directory, myNetAddr, config, networkMapId, advertisedServices).setup().start()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Replace with a separate trusted cash issuer
|
||||
if (cashIssuer == null) {
|
||||
cashIssuer = node.services.storageService.myLegalIdentity
|
||||
}
|
||||
val node = logElapsedTime("Node startup") { Node(directory, myNetAddr, config, networkMapId, advertisedServices).setup().start() }
|
||||
|
||||
// What happens next depends on the role. The buyer sits around waiting for a trade to start. The seller role
|
||||
// will contact the buyer and actually make something happen.
|
||||
@ -190,24 +153,14 @@ fun runTraderDemo(args: Array<String>, demoNodeConfig: DemoConfig = DemoConfig()
|
||||
if (role == Role.BUYER) {
|
||||
runBuyer(node, amount)
|
||||
} else {
|
||||
val dest: Destination
|
||||
val recipient: SingleMessageRecipient
|
||||
|
||||
if(demoNodeConfig.inMemory) {
|
||||
recipient = InMemoryMessagingNetwork.Handle(peerId, "Other Node")
|
||||
dest = Destination(InMemoryMessagingNetwork.Handle(id, role.toString()), true)
|
||||
} else {
|
||||
recipient = ArtemisMessagingService.makeRecipient(theirNetAddr)
|
||||
dest = Destination(myNetAddr, false)
|
||||
}
|
||||
|
||||
runSeller(dest, node, recipient, amount))
|
||||
val recipient = ArtemisMessagingService.makeRecipient(theirNetAddr)
|
||||
runSeller(myNetAddr, node, recipient, amount)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
private fun runSeller(myAddr: Destination, node: Node, recipient: SingleMessageRecipient) {
|
||||
private fun runSeller(myAddr: HostAndPort, node: Node, recipient: SingleMessageRecipient) {
|
||||
// The seller will sell some commercial paper to the buyer, who will pay with (self issued) cash.
|
||||
//
|
||||
// The CP sale transaction comes with a prospectus PDF, which will tag along for the ride in an
|
||||
@ -283,12 +236,8 @@ private class TraderDemoProtocolBuyer(private val attachmentsPath: Path,
|
||||
// As the seller initiates the two-party trade protocol, here, we will be the buyer.
|
||||
try {
|
||||
progressTracker.currentStep = WAITING_FOR_SELLER_TO_CONNECT
|
||||
val origin: Destination = receive<Destination>(DEMO_TOPIC, 0).validate { it }
|
||||
val recipient: SingleMessageRecipient = if(origin.inMemory) {
|
||||
origin.addr as InMemoryMessagingNetwork.Handle
|
||||
} else {
|
||||
ArtemisMessagingService.makeRecipient(origin.addr as HostAndPort)
|
||||
}
|
||||
val origin = receive<HostAndPort>(DEMO_TOPIC, 0).validate { it.withDefaultPort(Node.DEFAULT_PORT) }
|
||||
val recipient = ArtemisMessagingService.makeRecipient(origin as HostAndPort)
|
||||
|
||||
// The session ID disambiguates the test trade.
|
||||
val sessionID = random63BitValue()
|
||||
@ -296,7 +245,7 @@ private class TraderDemoProtocolBuyer(private val attachmentsPath: Path,
|
||||
send(DEMO_TOPIC, recipient, 0, sessionID)
|
||||
|
||||
val notary = serviceHub.networkMapCache.notaryNodes[0]
|
||||
val buyer = TwoPartyTradeProtocol.Buyer(recipient, notary.identity, amount,
|
||||
val buyer = TwoPartyTradeProtocol.Buyer(recipient, notary.identity, 1000.DOLLARS,
|
||||
CommercialPaper.State::class.java, sessionID)
|
||||
|
||||
// This invokes the trading protocol and out pops our finished transaction.
|
||||
@ -339,7 +288,7 @@ ${Emoji.renderIfSupported(cpIssuance)}""")
|
||||
}
|
||||
}
|
||||
|
||||
private class TraderDemoProtocolSeller(val myAddr: Destination,
|
||||
private class TraderDemoProtocolSeller(val myAddr: HostAndPort,
|
||||
val otherSide: SingleMessageRecipient,
|
||||
val amount: Amount<Issued<Currency>>,
|
||||
override val progressTracker: ProgressTracker = TraderDemoProtocolSeller.tracker()) : ProtocolLogic<Unit>() {
|
||||
@ -350,21 +299,21 @@ private class TraderDemoProtocolSeller(val myAddr: Destination,
|
||||
|
||||
object SELF_ISSUING : ProgressTracker.Step("Got session ID back, issuing and timestamping some commercial paper")
|
||||
|
||||
object TRADING : ProgressTracker.Step("Starting the trade protocol") {
|
||||
override fun childProgressTracker(): ProgressTracker = TwoPartyTradeProtocol.Seller.tracker()
|
||||
}
|
||||
object TRADING : ProgressTracker.Step("Starting the trade protocol")
|
||||
|
||||
// We vend a progress tracker that already knows there's going to be a TwoPartyTradingProtocol involved at some
|
||||
// point: by setting up the tracker in advance, the user can see what's coming in more detail, instead of being
|
||||
// surprised when it appears as a new set of tasks below the current one.
|
||||
fun tracker() = ProgressTracker(ANNOUNCING, SELF_ISSUING, TRADING)
|
||||
fun tracker() = ProgressTracker(ANNOUNCING, SELF_ISSUING, TRADING).apply {
|
||||
childrenFor[TRADING] = TwoPartyTradeProtocol.Seller.tracker()
|
||||
}
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
progressTracker.currentStep = ANNOUNCING
|
||||
|
||||
val sessionID = sendAndReceive<Long>(DEMO_TOPIC, otherSide, 0, 0, myAddress).validate { it }
|
||||
val sessionID = sendAndReceive<Long>(DEMO_TOPIC, otherSide, 0, 0, myAddr).validate { it }
|
||||
|
||||
progressTracker.currentStep = SELF_ISSUING
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user