mirror of
https://github.com/corda/corda.git
synced 2024-12-20 05:28:21 +00:00
Remove ListenableFuture from core/main (#1030)
This commit is contained in:
parent
d9eb9fe64f
commit
3a3ead2dfe
@ -11,7 +11,6 @@ import net.corda.core.crypto.isFulfilledBy
|
|||||||
import net.corda.core.crypto.keys
|
import net.corda.core.crypto.keys
|
||||||
import net.corda.core.flows.FlowInitiator
|
import net.corda.core.flows.FlowInitiator
|
||||||
import net.corda.core.flows.StateMachineRunId
|
import net.corda.core.flows.StateMachineRunId
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.StateMachineTransactionMapping
|
import net.corda.core.messaging.StateMachineTransactionMapping
|
||||||
import net.corda.core.messaging.StateMachineUpdate
|
import net.corda.core.messaging.StateMachineUpdate
|
||||||
@ -22,6 +21,7 @@ import net.corda.core.node.services.ServiceInfo
|
|||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.flows.CashExitFlow
|
import net.corda.flows.CashExitFlow
|
||||||
import net.corda.flows.CashIssueFlow
|
import net.corda.flows.CashIssueFlow
|
||||||
import net.corda.flows.CashPaymentFlow
|
import net.corda.flows.CashPaymentFlow
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.corda.client.rpc;
|
package net.corda.client.rpc;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import net.corda.core.concurrent.CordaFuture;
|
||||||
import net.corda.client.rpc.internal.RPCClient;
|
import net.corda.client.rpc.internal.RPCClient;
|
||||||
import net.corda.core.contracts.Amount;
|
import net.corda.core.contracts.Amount;
|
||||||
import net.corda.core.messaging.CordaRPCOps;
|
import net.corda.core.messaging.CordaRPCOps;
|
||||||
@ -46,7 +46,7 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() throws ExecutionException, InterruptedException {
|
public void setUp() throws ExecutionException, InterruptedException {
|
||||||
Set<ServiceInfo> services = new HashSet<>(Collections.singletonList(new ServiceInfo(ValidatingNotaryService.Companion.getType(), null)));
|
Set<ServiceInfo> services = new HashSet<>(Collections.singletonList(new ServiceInfo(ValidatingNotaryService.Companion.getType(), null)));
|
||||||
ListenableFuture<Node> nodeFuture = startNode(getALICE().getName(), 1, services, Arrays.asList(rpcUser), Collections.emptyMap());
|
CordaFuture<Node> nodeFuture = startNode(getALICE().getName(), 1, services, Arrays.asList(rpcUser), Collections.emptyMap());
|
||||||
node = nodeFuture.get();
|
node = nodeFuture.get();
|
||||||
client = new CordaRPCClient(node.getConfiguration().getRpcAddress(), null, getDefault(), false);
|
client = new CordaRPCClient(node.getConfiguration().getRpcAddress(), null, getDefault(), false);
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,10 @@ import net.corda.core.contracts.DOLLARS
|
|||||||
import net.corda.core.contracts.USD
|
import net.corda.core.contracts.USD
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.flows.FlowInitiator
|
import net.corda.core.flows.FlowInitiator
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.messaging.*
|
import net.corda.core.messaging.*
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.flows.CashException
|
import net.corda.flows.CashException
|
||||||
import net.corda.flows.CashIssueFlow
|
import net.corda.flows.CashIssueFlow
|
||||||
import net.corda.flows.CashPaymentFlow
|
import net.corda.flows.CashPaymentFlow
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
package net.corda.client.rpc
|
package net.corda.client.rpc
|
||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
|
||||||
import net.corda.client.rpc.internal.RPCClient
|
import net.corda.client.rpc.internal.RPCClient
|
||||||
import net.corda.client.rpc.internal.RPCClientConfiguration
|
import net.corda.client.rpc.internal.RPCClientConfiguration
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.future
|
import net.corda.core.internal.concurrent.fork
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.internal.concurrent.transpose
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.utilities.millis
|
|
||||||
import net.corda.core.utilities.seconds
|
|
||||||
import net.corda.core.serialization.SerializationDefaults
|
import net.corda.core.serialization.SerializationDefaults
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.*
|
||||||
import net.corda.core.utilities.Try
|
|
||||||
import net.corda.node.services.messaging.RPCServerConfiguration
|
import net.corda.node.services.messaging.RPCServerConfiguration
|
||||||
import net.corda.nodeapi.RPCApi
|
import net.corda.nodeapi.RPCApi
|
||||||
import net.corda.testing.*
|
import net.corda.testing.*
|
||||||
@ -24,10 +20,7 @@ import rx.Observable
|
|||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
import rx.subjects.UnicastSubject
|
import rx.subjects.UnicastSubject
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue
|
import java.util.concurrent.*
|
||||||
import java.util.concurrent.Executors
|
|
||||||
import java.util.concurrent.ScheduledExecutorService
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
class RPCStabilityTests {
|
class RPCStabilityTests {
|
||||||
@ -233,9 +226,7 @@ class RPCStabilityTests {
|
|||||||
assertEquals("pong", client.ping())
|
assertEquals("pong", client.ping())
|
||||||
serverFollower.shutdown()
|
serverFollower.shutdown()
|
||||||
startRpcServer<ReconnectOps>(ops = ops, customPort = serverPort).getOrThrow()
|
startRpcServer<ReconnectOps>(ops = ops, customPort = serverPort).getOrThrow()
|
||||||
val pingFuture = future {
|
val pingFuture = ForkJoinPool.commonPool().fork(client::ping)
|
||||||
client.ping()
|
|
||||||
}
|
|
||||||
assertEquals("pong", pingFuture.getOrThrow(10.seconds))
|
assertEquals("pong", pingFuture.getOrThrow(10.seconds))
|
||||||
clientFollower.shutdown() // Driver would do this after the new server, causing hang.
|
clientFollower.shutdown() // Driver would do this after the new server, causing hang.
|
||||||
}
|
}
|
||||||
@ -269,9 +260,9 @@ class RPCStabilityTests {
|
|||||||
).get()
|
).get()
|
||||||
|
|
||||||
val numberOfClients = 4
|
val numberOfClients = 4
|
||||||
val clients = Futures.allAsList((1 .. numberOfClients).map {
|
val clients = (1 .. numberOfClients).map {
|
||||||
startRandomRpcClient<TrackSubscriberOps>(server.broker.hostAndPort!!)
|
startRandomRpcClient<TrackSubscriberOps>(server.broker.hostAndPort!!)
|
||||||
}).get()
|
}.transpose().get()
|
||||||
|
|
||||||
// Poll until all clients connect
|
// Poll until all clients connect
|
||||||
pollUntilClientNumber(server, numberOfClients)
|
pollUntilClientNumber(server, numberOfClients)
|
||||||
|
@ -12,7 +12,6 @@ import com.google.common.util.concurrent.SettableFuture
|
|||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
||||||
import net.corda.core.internal.ThreadBox
|
import net.corda.core.internal.ThreadBox
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.internal.LazyPool
|
import net.corda.core.internal.LazyPool
|
||||||
import net.corda.core.internal.LazyStickyPool
|
import net.corda.core.internal.LazyStickyPool
|
||||||
import net.corda.core.internal.LifeCycle
|
import net.corda.core.internal.LifeCycle
|
||||||
@ -112,7 +111,7 @@ class RPCClientProxyHandler(
|
|||||||
private val serializationContextWithObservableContext = RpcClientObservableSerializer.createContext(serializationContext, observableContext)
|
private val serializationContextWithObservableContext = RpcClientObservableSerializer.createContext(serializationContext, observableContext)
|
||||||
|
|
||||||
private fun createRpcObservableMap(): RpcObservableMap {
|
private fun createRpcObservableMap(): RpcObservableMap {
|
||||||
val onObservableRemove = RemovalListener<RPCApi.ObservableId, UnicastSubject<Notification<Any>>> {
|
val onObservableRemove = RemovalListener<RPCApi.ObservableId, UnicastSubject<Notification<*>>> {
|
||||||
val rpcCallSite = callSiteMap?.remove(it.key.toLong)
|
val rpcCallSite = callSiteMap?.remove(it.key.toLong)
|
||||||
if (it.cause == RemovalCause.COLLECTED) {
|
if (it.cause == RemovalCause.COLLECTED) {
|
||||||
log.warn(listOf(
|
log.warn(listOf(
|
||||||
@ -337,7 +336,7 @@ class RPCClientProxyHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private typealias RpcObservableMap = Cache<RPCApi.ObservableId, UnicastSubject<Notification<Any>>>
|
private typealias RpcObservableMap = Cache<RPCApi.ObservableId, UnicastSubject<Notification<*>>>
|
||||||
private typealias RpcReplyMap = ConcurrentHashMap<RPCApi.RpcRequestId, SettableFuture<Any?>>
|
private typealias RpcReplyMap = ConcurrentHashMap<RPCApi.RpcRequestId, SettableFuture<Any?>>
|
||||||
private typealias CallSiteMap = ConcurrentHashMap<Long, Throwable?>
|
private typealias CallSiteMap = ConcurrentHashMap<Long, Throwable?>
|
||||||
|
|
||||||
@ -356,18 +355,17 @@ data class ObservableContext(
|
|||||||
/**
|
/**
|
||||||
* A [Serializer] to deserialise Observables once the corresponding Kryo instance has been provided with an [ObservableContext].
|
* A [Serializer] to deserialise Observables once the corresponding Kryo instance has been provided with an [ObservableContext].
|
||||||
*/
|
*/
|
||||||
object RpcClientObservableSerializer : Serializer<Observable<Any>>() {
|
object RpcClientObservableSerializer : Serializer<Observable<*>>() {
|
||||||
private object RpcObservableContextKey
|
private object RpcObservableContextKey
|
||||||
|
|
||||||
fun createContext(serializationContext: SerializationContext, observableContext: ObservableContext): SerializationContext {
|
fun createContext(serializationContext: SerializationContext, observableContext: ObservableContext): SerializationContext {
|
||||||
return serializationContext.withProperty(RpcObservableContextKey, observableContext)
|
return serializationContext.withProperty(RpcObservableContextKey, observableContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun read(kryo: Kryo, input: Input, type: Class<Observable<Any>>): Observable<Any> {
|
override fun read(kryo: Kryo, input: Input, type: Class<Observable<*>>): Observable<Any> {
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
val observableContext = kryo.context[RpcObservableContextKey] as ObservableContext
|
val observableContext = kryo.context[RpcObservableContextKey] as ObservableContext
|
||||||
val observableId = RPCApi.ObservableId(input.readLong(true))
|
val observableId = RPCApi.ObservableId(input.readLong(true))
|
||||||
val observable = UnicastSubject.create<Notification<Any>>()
|
val observable = UnicastSubject.create<Notification<*>>()
|
||||||
require(observableContext.observableMap.getIfPresent(observableId) == null) {
|
require(observableContext.observableMap.getIfPresent(observableId) == null) {
|
||||||
"Multiple Observables arrived with the same ID $observableId"
|
"Multiple Observables arrived with the same ID $observableId"
|
||||||
}
|
}
|
||||||
@ -384,7 +382,7 @@ object RpcClientObservableSerializer : Serializer<Observable<Any>>() {
|
|||||||
}.dematerialize()
|
}.dematerialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(kryo: Kryo, output: Output, observable: Observable<Any>) {
|
override fun write(kryo: Kryo, output: Output, observable: Observable<*>) {
|
||||||
throw UnsupportedOperationException("Cannot serialise Observables on the client side")
|
throw UnsupportedOperationException("Cannot serialise Observables on the client side")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,13 +9,13 @@ import net.corda.contracts.getCashBalance
|
|||||||
import net.corda.contracts.getCashBalances
|
import net.corda.contracts.getCashBalances
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.internal.InputStreamAndHash
|
import net.corda.core.internal.InputStreamAndHash
|
||||||
import net.corda.core.messaging.*
|
import net.corda.core.messaging.*
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.node.services.vault.*
|
import net.corda.core.node.services.vault.*
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.flows.CashIssueFlow
|
import net.corda.flows.CashIssueFlow
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.corda.client.rpc
|
package net.corda.client.rpc
|
||||||
|
|
||||||
import net.corda.client.rpc.internal.RPCClientConfiguration
|
import net.corda.client.rpc.internal.RPCClientConfiguration
|
||||||
import net.corda.core.flatMap
|
import net.corda.core.internal.concurrent.flatMap
|
||||||
import net.corda.core.map
|
import net.corda.core.internal.concurrent.map
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.node.services.messaging.RPCServerConfiguration
|
import net.corda.node.services.messaging.RPCServerConfiguration
|
||||||
import net.corda.nodeapi.User
|
import net.corda.nodeapi.User
|
||||||
@ -44,13 +44,13 @@ open class AbstractRPCTest {
|
|||||||
startInVmRpcClient<I>(rpcUser.username, rpcUser.password, clientConfiguration).map {
|
startInVmRpcClient<I>(rpcUser.username, rpcUser.password, clientConfiguration).map {
|
||||||
TestProxy(it, { startInVmArtemisSession(rpcUser.username, rpcUser.password) })
|
TestProxy(it, { startInVmArtemisSession(rpcUser.username, rpcUser.password) })
|
||||||
}
|
}
|
||||||
}.get()
|
}
|
||||||
RPCTestMode.Netty ->
|
RPCTestMode.Netty ->
|
||||||
startRpcServer(ops = ops, rpcUser = rpcUser, configuration = serverConfiguration).flatMap { server ->
|
startRpcServer(ops = ops, rpcUser = rpcUser, configuration = serverConfiguration).flatMap { server ->
|
||||||
startRpcClient<I>(server.broker.hostAndPort!!, rpcUser.username, rpcUser.password, clientConfiguration).map {
|
startRpcClient<I>(server.broker.hostAndPort!!, rpcUser.username, rpcUser.password, clientConfiguration).map {
|
||||||
TestProxy(it, { startArtemisSession(server.broker.hostAndPort!!, rpcUser.username, rpcUser.password) })
|
TestProxy(it, { startArtemisSession(server.broker.hostAndPort!!, rpcUser.username, rpcUser.password) })
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}.get()
|
}.get()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package net.corda.client.rpc
|
package net.corda.client.rpc
|
||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.internal.concurrent.doneFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.internal.concurrent.thenMatch
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.thenMatch
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.node.services.messaging.getRpcContext
|
import net.corda.node.services.messaging.getRpcContext
|
||||||
import net.corda.nodeapi.RPCSinceVersion
|
import net.corda.nodeapi.RPCSinceVersion
|
||||||
import net.corda.testing.RPCDriverExposedDSLInterface
|
import net.corda.testing.RPCDriverExposedDSLInterface
|
||||||
@ -43,9 +43,9 @@ class ClientRPCInfrastructureTests : AbstractRPCTest() {
|
|||||||
|
|
||||||
fun makeComplicatedObservable(): Observable<Pair<String, Observable<String>>>
|
fun makeComplicatedObservable(): Observable<Pair<String, Observable<String>>>
|
||||||
|
|
||||||
fun makeListenableFuture(): ListenableFuture<Int>
|
fun makeListenableFuture(): CordaFuture<Int>
|
||||||
|
|
||||||
fun makeComplicatedListenableFuture(): ListenableFuture<Pair<String, ListenableFuture<String>>>
|
fun makeComplicatedListenableFuture(): CordaFuture<Pair<String, CordaFuture<String>>>
|
||||||
|
|
||||||
@RPCSinceVersion(2)
|
@RPCSinceVersion(2)
|
||||||
fun addedLater()
|
fun addedLater()
|
||||||
@ -54,7 +54,7 @@ class ClientRPCInfrastructureTests : AbstractRPCTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var complicatedObservable: Observable<Pair<String, Observable<String>>>
|
private lateinit var complicatedObservable: Observable<Pair<String, Observable<String>>>
|
||||||
private lateinit var complicatedListenableFuturee: ListenableFuture<Pair<String, ListenableFuture<String>>>
|
private lateinit var complicatedListenableFuturee: CordaFuture<Pair<String, CordaFuture<String>>>
|
||||||
|
|
||||||
inner class TestOpsImpl : TestOps {
|
inner class TestOpsImpl : TestOps {
|
||||||
override val protocolVersion = 1
|
override val protocolVersion = 1
|
||||||
@ -62,9 +62,9 @@ class ClientRPCInfrastructureTests : AbstractRPCTest() {
|
|||||||
override fun void() {}
|
override fun void() {}
|
||||||
override fun someCalculation(str: String, num: Int) = "$str $num"
|
override fun someCalculation(str: String, num: Int) = "$str $num"
|
||||||
override fun makeObservable(): Observable<Int> = Observable.just(1, 2, 3, 4)
|
override fun makeObservable(): Observable<Int> = Observable.just(1, 2, 3, 4)
|
||||||
override fun makeListenableFuture(): ListenableFuture<Int> = Futures.immediateFuture(1)
|
override fun makeListenableFuture() = doneFuture(1)
|
||||||
override fun makeComplicatedObservable() = complicatedObservable
|
override fun makeComplicatedObservable() = complicatedObservable
|
||||||
override fun makeComplicatedListenableFuture(): ListenableFuture<Pair<String, ListenableFuture<String>>> = complicatedListenableFuturee
|
override fun makeComplicatedListenableFuture() = complicatedListenableFuturee
|
||||||
override fun addedLater(): Unit = throw IllegalStateException()
|
override fun addedLater(): Unit = throw IllegalStateException()
|
||||||
override fun captureUser(): String = getRpcContext().currentUser.username
|
override fun captureUser(): String = getRpcContext().currentUser.username
|
||||||
}
|
}
|
||||||
@ -152,10 +152,10 @@ class ClientRPCInfrastructureTests : AbstractRPCTest() {
|
|||||||
fun `complex ListenableFuture`() {
|
fun `complex ListenableFuture`() {
|
||||||
rpcDriver {
|
rpcDriver {
|
||||||
val proxy = testProxy()
|
val proxy = testProxy()
|
||||||
val serverQuote = SettableFuture.create<Pair<String, ListenableFuture<String>>>()
|
val serverQuote = openFuture<Pair<String, CordaFuture<String>>>()
|
||||||
complicatedListenableFuturee = serverQuote
|
complicatedListenableFuturee = serverQuote
|
||||||
|
|
||||||
val twainQuote = "Mark Twain" to Futures.immediateFuture("I have never let my schooling interfere with my education.")
|
val twainQuote = "Mark Twain" to doneFuture("I have never let my schooling interfere with my education.")
|
||||||
|
|
||||||
val clientQuotes = LinkedBlockingQueue<String>()
|
val clientQuotes = LinkedBlockingQueue<String>()
|
||||||
val clientFuture = proxy.makeComplicatedListenableFuture()
|
val clientFuture = proxy.makeComplicatedListenableFuture()
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package net.corda.client.rpc
|
package net.corda.client.rpc
|
||||||
|
|
||||||
import net.corda.client.rpc.internal.RPCClientConfiguration
|
import net.corda.client.rpc.internal.RPCClientConfiguration
|
||||||
import net.corda.core.future
|
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.utilities.millis
|
import net.corda.core.utilities.millis
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
|
import net.corda.core.internal.concurrent.fork
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.node.services.messaging.RPCServerConfiguration
|
import net.corda.node.services.messaging.RPCServerConfiguration
|
||||||
import net.corda.testing.RPCDriverExposedDSLInterface
|
import net.corda.testing.RPCDriverExposedDSLInterface
|
||||||
@ -17,6 +17,7 @@ import rx.subjects.UnicastSubject
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.ForkJoinPool
|
||||||
|
|
||||||
@RunWith(Parameterized::class)
|
@RunWith(Parameterized::class)
|
||||||
class RPCConcurrencyTests : AbstractRPCTest() {
|
class RPCConcurrencyTests : AbstractRPCTest() {
|
||||||
@ -68,7 +69,7 @@ class RPCConcurrencyTests : AbstractRPCTest() {
|
|||||||
Observable.empty<ObservableRose<Int>>()
|
Observable.empty<ObservableRose<Int>>()
|
||||||
} else {
|
} else {
|
||||||
val publish = UnicastSubject.create<ObservableRose<Int>>()
|
val publish = UnicastSubject.create<ObservableRose<Int>>()
|
||||||
future {
|
ForkJoinPool.commonPool().fork {
|
||||||
(1..branchingFactor).toList().parallelStream().forEach {
|
(1..branchingFactor).toList().parallelStream().forEach {
|
||||||
publish.onNext(getParallelObservableTree(depth - 1, branchingFactor))
|
publish.onNext(getParallelObservableTree(depth - 1, branchingFactor))
|
||||||
}
|
}
|
||||||
@ -105,7 +106,7 @@ class RPCConcurrencyTests : AbstractRPCTest() {
|
|||||||
val done = CountDownLatch(numberOfBlockedCalls)
|
val done = CountDownLatch(numberOfBlockedCalls)
|
||||||
// Start a couple of blocking RPC calls
|
// Start a couple of blocking RPC calls
|
||||||
(1..numberOfBlockedCalls).forEach {
|
(1..numberOfBlockedCalls).forEach {
|
||||||
future {
|
ForkJoinPool.commonPool().fork {
|
||||||
proxy.ops.waitLatch(id)
|
proxy.ops.waitLatch(id)
|
||||||
done.countDown()
|
done.countDown()
|
||||||
}
|
}
|
||||||
|
@ -2,55 +2,15 @@
|
|||||||
|
|
||||||
package net.corda.core
|
package net.corda.core
|
||||||
|
|
||||||
import com.google.common.util.concurrent.*
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import org.slf4j.Logger
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
|
import net.corda.core.internal.concurrent.thenMatch
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Observer
|
import rx.Observer
|
||||||
import java.time.Duration
|
|
||||||
import java.util.concurrent.CompletableFuture
|
|
||||||
import java.util.concurrent.ExecutionException
|
|
||||||
import java.util.concurrent.Future
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
// TODO Delete this file once the Future stuff is out of here
|
// TODO Delete this file once the Future stuff is out of here
|
||||||
|
|
||||||
/** Same as [Future.get] but with a more descriptive name, and doesn't throw [ExecutionException], instead throwing its cause */
|
fun <A> CordaFuture<out A>.toObservable(): Observable<A> {
|
||||||
fun <T> Future<T>.getOrThrow(timeout: Duration? = null): T {
|
|
||||||
return try {
|
|
||||||
if (timeout == null) get() else get(timeout.toNanos(), TimeUnit.NANOSECONDS)
|
|
||||||
} catch (e: ExecutionException) {
|
|
||||||
throw e.cause!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <V> future(block: () -> V): Future<V> = CompletableFuture.supplyAsync(block)
|
|
||||||
|
|
||||||
fun <F : ListenableFuture<*>, V> F.then(block: (F) -> V) = addListener(Runnable { block(this) }, MoreExecutors.directExecutor())
|
|
||||||
|
|
||||||
fun <U, V> Future<U>.match(success: (U) -> V, failure: (Throwable) -> V): V {
|
|
||||||
return success(try {
|
|
||||||
getOrThrow()
|
|
||||||
} catch (t: Throwable) {
|
|
||||||
return failure(t)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <U, V, W> ListenableFuture<U>.thenMatch(success: (U) -> V, failure: (Throwable) -> W) = then { it.match(success, failure) }
|
|
||||||
fun ListenableFuture<*>.andForget(log: Logger) = then { it.match({}, { log.error("Background task failed:", it) }) }
|
|
||||||
@Suppress("UNCHECKED_CAST") // We need the awkward cast because otherwise F cannot be nullable, even though it's safe.
|
|
||||||
infix fun <F, T> ListenableFuture<F>.map(mapper: (F) -> T): ListenableFuture<T> = Futures.transform(this, { (mapper as (F?) -> T)(it) })
|
|
||||||
infix fun <F, T> ListenableFuture<F>.flatMap(mapper: (F) -> ListenableFuture<T>): ListenableFuture<T> = Futures.transformAsync(this) { mapper(it!!) }
|
|
||||||
|
|
||||||
/** Executes the given block and sets the future to either the result, or any exception that was thrown. */
|
|
||||||
inline fun <T> SettableFuture<T>.catch(block: () -> T) {
|
|
||||||
try {
|
|
||||||
set(block())
|
|
||||||
} catch (t: Throwable) {
|
|
||||||
setException(t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <A> ListenableFuture<out A>.toObservable(): Observable<A> {
|
|
||||||
return Observable.create { subscriber ->
|
return Observable.create { subscriber ->
|
||||||
thenMatch({
|
thenMatch({
|
||||||
subscriber.onNext(it)
|
subscriber.onNext(it)
|
||||||
@ -62,26 +22,25 @@ fun <A> ListenableFuture<out A>.toObservable(): Observable<A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [ListenableFuture] bound to the *first* item emitted by this Observable. The future will complete with a
|
* Returns a [CordaFuture] bound to the *first* item emitted by this Observable. The future will complete with a
|
||||||
* NoSuchElementException if no items are emitted or any other error thrown by the Observable. If it's cancelled then
|
* NoSuchElementException if no items are emitted or any other error thrown by the Observable. If it's cancelled then
|
||||||
* it will unsubscribe from the observable.
|
* it will unsubscribe from the observable.
|
||||||
*/
|
*/
|
||||||
fun <T> Observable<T>.toFuture(): ListenableFuture<T> = ObservableToFuture(this)
|
fun <T> Observable<T>.toFuture(): CordaFuture<T> = openFuture<T>().also {
|
||||||
|
val subscription = first().subscribe(object : Observer<T> {
|
||||||
private class ObservableToFuture<T>(observable: Observable<T>) : AbstractFuture<T>(), Observer<T> {
|
|
||||||
private val subscription = observable.first().subscribe(this)
|
|
||||||
override fun onNext(value: T) {
|
override fun onNext(value: T) {
|
||||||
set(value)
|
it.set(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
override fun onError(e: Throwable) {
|
||||||
setException(e)
|
it.setException(e)
|
||||||
}
|
|
||||||
|
|
||||||
override fun cancel(mayInterruptIfRunning: Boolean): Boolean {
|
|
||||||
subscription.unsubscribe()
|
|
||||||
return super.cancel(mayInterruptIfRunning)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCompleted() {}
|
override fun onCompleted() {}
|
||||||
|
})
|
||||||
|
it.then {
|
||||||
|
if (it.isCancelled) {
|
||||||
|
subscription.unsubscribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,44 @@
|
|||||||
package net.corda.core.concurrent
|
package net.corda.core.concurrent
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.catch
|
|
||||||
import net.corda.core.internal.VisibleForTesting
|
import net.corda.core.internal.VisibleForTesting
|
||||||
import net.corda.core.match
|
|
||||||
import net.corda.core.then
|
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.util.concurrent.Future
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
|
/** Invoke [getOrThrow] and pass the value/throwable to success/failure respectively. */
|
||||||
|
fun <V, W> Future<V>.match(success: (V) -> W, failure: (Throwable) -> W): W {
|
||||||
|
val value = try {
|
||||||
|
getOrThrow()
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
return failure(t)
|
||||||
|
}
|
||||||
|
return success(value)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* As soon as a given future becomes done, the handler is invoked with that future as its argument.
|
* As soon as a given future becomes done, the handler is invoked with that future as its argument.
|
||||||
* The result of the handler is copied into the result future, and the handler isn't invoked again.
|
* The result of the handler is copied into the result future, and the handler isn't invoked again.
|
||||||
* If a given future errors after the result future is done, the error is automatically logged.
|
* If a given future errors after the result future is done, the error is automatically logged.
|
||||||
*/
|
*/
|
||||||
fun <S, T> firstOf(vararg futures: ListenableFuture<out S>, handler: (ListenableFuture<out S>) -> T) = firstOf(futures, defaultLog, handler)
|
fun <V, W> firstOf(vararg futures: CordaFuture<out V>, handler: (CordaFuture<out V>) -> W) = firstOf(futures, defaultLog, handler)
|
||||||
|
|
||||||
private val defaultLog = LoggerFactory.getLogger("net.corda.core.concurrent")
|
private val defaultLog = LoggerFactory.getLogger("net.corda.core.concurrent")
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
internal val shortCircuitedTaskFailedMessage = "Short-circuited task failed:"
|
internal val shortCircuitedTaskFailedMessage = "Short-circuited task failed:"
|
||||||
|
|
||||||
internal fun <S, T> firstOf(futures: Array<out ListenableFuture<out S>>, log: Logger, handler: (ListenableFuture<out S>) -> T): ListenableFuture<T> {
|
internal fun <V, W> firstOf(futures: Array<out CordaFuture<out V>>, log: Logger, handler: (CordaFuture<out V>) -> W): CordaFuture<W> {
|
||||||
val resultFuture = SettableFuture.create<T>()
|
val resultFuture = openFuture<W>()
|
||||||
val winnerChosen = AtomicBoolean()
|
val winnerChosen = AtomicBoolean()
|
||||||
futures.forEach {
|
futures.forEach {
|
||||||
it.then {
|
it.then {
|
||||||
if (winnerChosen.compareAndSet(false, true)) {
|
if (winnerChosen.compareAndSet(false, true)) {
|
||||||
resultFuture.catch { handler(it) }
|
resultFuture.capture { handler(it) }
|
||||||
} else if (!it.isCancelled) {
|
} else if (it.isCancelled) {
|
||||||
|
// Do nothing.
|
||||||
|
} else {
|
||||||
it.match({}, { log.error(shortCircuitedTaskFailedMessage, it) })
|
it.match({}, { log.error(shortCircuitedTaskFailedMessage, it) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package net.corda.core.concurrent
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import java.util.concurrent.Future
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as [Future] with additional methods to provide some of the features of [java.util.concurrent.CompletableFuture] while minimising the API surface area.
|
||||||
|
* In Kotlin, to avoid compile errors, whenever CordaFuture is used in a parameter or extension method receiver type, its type parameter should be specified with out variance.
|
||||||
|
*/
|
||||||
|
interface CordaFuture<V> : Future<V> {
|
||||||
|
/**
|
||||||
|
* Run the given callback when this future is done, on the completion thread.
|
||||||
|
* If the completion thread is problematic for you e.g. deadlock, you can submit to an executor manually.
|
||||||
|
* If callback fails, its throwable is logged.
|
||||||
|
*/
|
||||||
|
fun <W> then(callback: (CordaFuture<V>) -> W): Unit
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a new [CompletableFuture] with the same outcome as this Future.
|
||||||
|
*/
|
||||||
|
fun toCompletableFuture(): CompletableFuture<V>
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.core.internal
|
package net.corda.core.internal
|
||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.flows.FlowInitiator
|
import net.corda.core.flows.FlowInitiator
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
@ -37,6 +37,6 @@ interface FlowStateMachine<R> {
|
|||||||
val serviceHub: ServiceHub
|
val serviceHub: ServiceHub
|
||||||
val logger: Logger
|
val logger: Logger
|
||||||
val id: StateMachineRunId
|
val id: StateMachineRunId
|
||||||
val resultFuture: ListenableFuture<R>
|
val resultFuture: CordaFuture<R>
|
||||||
val flowInitiator: FlowInitiator
|
val flowInitiator: FlowInitiator
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,146 @@
|
|||||||
|
package net.corda.core.internal.concurrent
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting
|
||||||
|
import net.corda.core.concurrent.CordaFuture
|
||||||
|
import net.corda.core.concurrent.match
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import net.corda.core.utilities.loggerFor
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import java.time.Duration
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
import java.util.concurrent.Future
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
/** @return a fresh [OpenFuture]. */
|
||||||
|
fun <V> openFuture(): OpenFuture<V> = CordaFutureImpl()
|
||||||
|
|
||||||
|
/** @return a done future with the given value as its outcome. */
|
||||||
|
fun <V> doneFuture(value: V): CordaFuture<V> = CordaFutureImpl<V>().apply { set(value) }
|
||||||
|
|
||||||
|
/** @return a future that will have the same outcome as the given block, when this executor has finished running it. */
|
||||||
|
fun <V> Executor.fork(block: () -> V): CordaFuture<V> = CordaFutureImpl<V>().also { execute { it.capture(block) } }
|
||||||
|
|
||||||
|
/** When this future is done, do [match]. */
|
||||||
|
fun <V, W, X> CordaFuture<out V>.thenMatch(success: (V) -> W, failure: (Throwable) -> X) = then { match(success, failure) }
|
||||||
|
|
||||||
|
/** When this future is done and the outcome is failure, log the throwable. */
|
||||||
|
fun CordaFuture<*>.andForget(log: Logger) = thenMatch({}, { log.error("Background task failed:", it) })
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a future that will have an outcome of applying the given transform to this future's value.
|
||||||
|
* But if this future fails, the transform is not invoked and the returned future becomes done with the same throwable.
|
||||||
|
*/
|
||||||
|
fun <V, W> CordaFuture<out V>.map(transform: (V) -> W): CordaFuture<W> = CordaFutureImpl<W>().also { result ->
|
||||||
|
thenMatch({
|
||||||
|
result.capture { transform(it) }
|
||||||
|
}, {
|
||||||
|
result.setException(it)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a future that will have the same outcome as the future returned by the given transform.
|
||||||
|
* But if this future or the transform fails, the returned future's outcome is the same throwable.
|
||||||
|
* In the case where this future fails, the transform is not invoked.
|
||||||
|
*/
|
||||||
|
fun <V, W> CordaFuture<out V>.flatMap(transform: (V) -> CordaFuture<out W>): CordaFuture<W> = CordaFutureImpl<W>().also { result ->
|
||||||
|
thenMatch(success@ {
|
||||||
|
result.captureLater(try {
|
||||||
|
transform(it)
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
result.setException(t)
|
||||||
|
return@success
|
||||||
|
})
|
||||||
|
}, {
|
||||||
|
result.setException(it)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If all of the given futures succeed, the returned future's outcome is a list of all their values.
|
||||||
|
* The values are in the same order as the futures in the collection, not the order of completion.
|
||||||
|
* If at least one given future fails, the returned future's outcome is the first throwable that was thrown.
|
||||||
|
* Any subsequent throwables are added to the first one as suppressed throwables, in the order they are thrown.
|
||||||
|
* If no futures were given, the returned future has an immediate outcome of empty list.
|
||||||
|
* Otherwise the returned future does not have an outcome until all given futures have an outcome.
|
||||||
|
* Unlike Guava's Futures.allAsList, this method never hides failures/hangs subsequent to the first failure.
|
||||||
|
*/
|
||||||
|
fun <V> Collection<CordaFuture<out V>>.transpose(): CordaFuture<List<V>> {
|
||||||
|
if (isEmpty()) return doneFuture(emptyList())
|
||||||
|
val transpose = CordaFutureImpl<List<V>>()
|
||||||
|
val stateLock = Any()
|
||||||
|
var failure: Throwable? = null
|
||||||
|
var remaining = size
|
||||||
|
forEach {
|
||||||
|
it.then { doneFuture ->
|
||||||
|
synchronized(stateLock) {
|
||||||
|
doneFuture.match({}, { throwable ->
|
||||||
|
if (failure == null) failure = throwable else failure!!.addSuppressed(throwable)
|
||||||
|
})
|
||||||
|
if (--remaining == 0) {
|
||||||
|
if (failure == null) transpose.set(map { it.getOrThrow() }) else transpose.setException(failure!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return transpose
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The contravariant members of [OpenFuture]. */
|
||||||
|
interface ValueOrException<in V> {
|
||||||
|
/** @return whether this future actually changed. */
|
||||||
|
fun set(value: V): Boolean
|
||||||
|
|
||||||
|
/** @return whether this future actually changed. */
|
||||||
|
fun setException(t: Throwable): Boolean
|
||||||
|
|
||||||
|
/** When the given future has an outcome, make this future have the same outcome. */
|
||||||
|
fun captureLater(f: CordaFuture<out V>) = f.then { capture { f.getOrThrow() } }
|
||||||
|
|
||||||
|
/** Run the given block (in the foreground) and set this future to its outcome. */
|
||||||
|
fun capture(block: () -> V): Boolean {
|
||||||
|
return set(try {
|
||||||
|
block()
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
return setException(t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A [CordaFuture] with additional methods to complete it with a value, exception or the outcome of another future. */
|
||||||
|
interface OpenFuture<V> : ValueOrException<V>, CordaFuture<V>
|
||||||
|
|
||||||
|
/** Unless you really want this particular implementation, use [openFuture] to make one. */
|
||||||
|
@VisibleForTesting
|
||||||
|
internal class CordaFutureImpl<V>(private val impl: CompletableFuture<V> = CompletableFuture()) : Future<V> by impl, OpenFuture<V> {
|
||||||
|
companion object {
|
||||||
|
private val defaultLog = loggerFor<CordaFutureImpl<*>>()
|
||||||
|
internal val listenerFailedMessage = "Future listener failed:"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun set(value: V) = impl.complete(value)
|
||||||
|
override fun setException(t: Throwable) = impl.completeExceptionally(t)
|
||||||
|
override fun <W> then(callback: (CordaFuture<V>) -> W) = thenImpl(defaultLog, callback)
|
||||||
|
/** For testing only. */
|
||||||
|
internal fun <W> thenImpl(log: Logger, callback: (CordaFuture<V>) -> W) {
|
||||||
|
impl.whenComplete { _, _ ->
|
||||||
|
try {
|
||||||
|
callback(this)
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
log.error(listenerFailedMessage, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't simply return impl so that the caller can't interfere with it.
|
||||||
|
override fun toCompletableFuture() = CompletableFuture<V>().also { completable ->
|
||||||
|
thenMatch({
|
||||||
|
completable.complete(it)
|
||||||
|
}, {
|
||||||
|
completable.completeExceptionally(it)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun <V> Future<V>.get(timeout: Duration? = null): V = if (timeout == null) get() else get(timeout.toNanos(), TimeUnit.NANOSECONDS)
|
@ -1,6 +1,6 @@
|
|||||||
package net.corda.core.messaging
|
package net.corda.core.messaging
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.contracts.ContractState
|
import net.corda.core.contracts.ContractState
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.contracts.UpgradedContract
|
import net.corda.core.contracts.UpgradedContract
|
||||||
@ -233,11 +233,11 @@ interface CordaRPCOps : RPCOps {
|
|||||||
fun currentNodeTime(): Instant
|
fun currentNodeTime(): Instant
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [ListenableFuture] which completes when the node has registered wih the network map service. It can also
|
* Returns a [CordaFuture] which completes when the node has registered wih the network map service. It can also
|
||||||
* complete with an exception if it is unable to.
|
* complete with an exception if it is unable to.
|
||||||
*/
|
*/
|
||||||
@RPCReturnsObservables
|
@RPCReturnsObservables
|
||||||
fun waitUntilRegisteredWithNetworkMap(): ListenableFuture<Unit>
|
fun waitUntilRegisteredWithNetworkMap(): CordaFuture<Void?>
|
||||||
|
|
||||||
// TODO These need rethinking. Instead of these direct calls we should have a way of replicating a subset of
|
// TODO These need rethinking. Instead of these direct calls we should have a way of replicating a subset of
|
||||||
// the node's state locally and query that directly.
|
// the node's state locally and query that directly.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.corda.core.messaging
|
package net.corda.core.messaging
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.flows.StateMachineRunId
|
import net.corda.core.flows.StateMachineRunId
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
@ -9,11 +9,11 @@ import rx.Observable
|
|||||||
* [FlowHandle] is a serialisable handle for the started flow, parameterised by the type of the flow's return value.
|
* [FlowHandle] is a serialisable handle for the started flow, parameterised by the type of the flow's return value.
|
||||||
*
|
*
|
||||||
* @property id The started state machine's ID.
|
* @property id The started state machine's ID.
|
||||||
* @property returnValue A [ListenableFuture] of the flow's return value.
|
* @property returnValue A [CordaFuture] of the flow's return value.
|
||||||
*/
|
*/
|
||||||
interface FlowHandle<A> : AutoCloseable {
|
interface FlowHandle<A> : AutoCloseable {
|
||||||
val id: StateMachineRunId
|
val id: StateMachineRunId
|
||||||
val returnValue: ListenableFuture<A>
|
val returnValue: CordaFuture<A>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use this function for flows whose returnValue is not going to be used, so as to free up server resources.
|
* Use this function for flows whose returnValue is not going to be used, so as to free up server resources.
|
||||||
@ -41,7 +41,7 @@ interface FlowProgressHandle<A> : FlowHandle<A> {
|
|||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
data class FlowHandleImpl<A>(
|
data class FlowHandleImpl<A>(
|
||||||
override val id: StateMachineRunId,
|
override val id: StateMachineRunId,
|
||||||
override val returnValue: ListenableFuture<A>) : FlowHandle<A> {
|
override val returnValue: CordaFuture<A>) : FlowHandle<A> {
|
||||||
|
|
||||||
// Remember to add @Throws to FlowHandle.close() if this throws an exception.
|
// Remember to add @Throws to FlowHandle.close() if this throws an exception.
|
||||||
override fun close() {
|
override fun close() {
|
||||||
@ -52,7 +52,7 @@ data class FlowHandleImpl<A>(
|
|||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
data class FlowProgressHandleImpl<A>(
|
data class FlowProgressHandleImpl<A>(
|
||||||
override val id: StateMachineRunId,
|
override val id: StateMachineRunId,
|
||||||
override val returnValue: ListenableFuture<A>,
|
override val returnValue: CordaFuture<A>,
|
||||||
override val progress: Observable<String>) : FlowProgressHandle<A> {
|
override val progress: Observable<String>) : FlowProgressHandle<A> {
|
||||||
|
|
||||||
// Remember to add @Throws to FlowProgressHandle.close() if this throws an exception.
|
// Remember to add @Throws to FlowProgressHandle.close() if this throws an exception.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.corda.core.node.services
|
package net.corda.core.node.services
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.contracts.Contract
|
import net.corda.core.contracts.Contract
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
@ -44,7 +44,7 @@ interface NetworkMapCache {
|
|||||||
/** Tracks changes to the network map cache */
|
/** Tracks changes to the network map cache */
|
||||||
val changed: Observable<MapChange>
|
val changed: Observable<MapChange>
|
||||||
/** Future to track completion of the NetworkMapService registration. */
|
/** Future to track completion of the NetworkMapService registration. */
|
||||||
val mapServiceRegistered: ListenableFuture<Unit>
|
val mapServiceRegistered: CordaFuture<Void?>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Atomically get the current party nodes and a stream of updates. Note that the Observable buffers updates until the
|
* Atomically get the current party nodes and a stream of updates. Note that the Observable buffers updates until the
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.corda.core.node.services
|
package net.corda.core.node.services
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.transactions.LedgerTransaction
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -11,5 +11,5 @@ interface TransactionVerifierService {
|
|||||||
* @param transaction The transaction to be verified.
|
* @param transaction The transaction to be verified.
|
||||||
* @return A future that completes successfully if the transaction verified, or sets an exception the verifier threw.
|
* @return A future that completes successfully if the transaction verified, or sets an exception the verifier threw.
|
||||||
*/
|
*/
|
||||||
fun verify(transaction: LedgerTransaction): ListenableFuture<*>
|
fun verify(transaction: LedgerTransaction): CordaFuture<*>
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.core.node.services
|
package net.corda.core.node.services
|
||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.flows.FlowException
|
import net.corda.core.flows.FlowException
|
||||||
@ -190,9 +190,9 @@ interface VaultService {
|
|||||||
fun notify(tx: CoreTransaction) = notifyAll(listOf(tx))
|
fun notify(tx: CoreTransaction) = notifyAll(listOf(tx))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a [Future] for when a [StateRef] is consumed, which can be very useful in building tests.
|
* Provide a [CordaFuture] for when a [StateRef] is consumed, which can be very useful in building tests.
|
||||||
*/
|
*/
|
||||||
fun whenConsumed(ref: StateRef): ListenableFuture<Vault.Update<ContractState>> {
|
fun whenConsumed(ref: StateRef): CordaFuture<Vault.Update<ContractState>> {
|
||||||
return updates.filter { it.consumed.any { it.ref == ref } }.toFuture()
|
return updates.filter { it.consumed.any { it.ref == ref } }.toFuture()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,13 +3,13 @@ package net.corda.core.transactions
|
|||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.DigitalSignature
|
import net.corda.core.crypto.DigitalSignature
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.core.serialization.SerializedBytes
|
import net.corda.core.serialization.SerializedBytes
|
||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.security.SignatureException
|
import java.security.SignatureException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package net.corda.core.utilities
|
package net.corda.core.utilities
|
||||||
|
|
||||||
|
import net.corda.core.internal.concurrent.get
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
import java.util.concurrent.ExecutionException
|
||||||
|
import java.util.concurrent.Future
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -93,3 +96,10 @@ class TransientProperty<out T>(private val initialiser: () -> T) {
|
|||||||
|
|
||||||
/** @see NonEmptySet.copyOf */
|
/** @see NonEmptySet.copyOf */
|
||||||
fun <T> Collection<T>.toNonEmptySet(): NonEmptySet<T> = NonEmptySet.copyOf(this)
|
fun <T> Collection<T>.toNonEmptySet(): NonEmptySet<T> = NonEmptySet.copyOf(this)
|
||||||
|
|
||||||
|
/** Same as [Future.get] except that the [ExecutionException] is unwrapped. */
|
||||||
|
fun <V> Future<V>.getOrThrow(timeout: Duration? = null): V = try {
|
||||||
|
get(timeout)
|
||||||
|
} catch (e: ExecutionException) {
|
||||||
|
throw e.cause!!
|
||||||
|
}
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
package net.corda.core.concurrent;
|
||||||
|
|
||||||
|
import net.corda.core.internal.concurrent.OpenFuture;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.EOFException;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import static net.corda.core.internal.concurrent.CordaFutureImplKt.doneFuture;
|
||||||
|
import static net.corda.core.internal.concurrent.CordaFutureImplKt.openFuture;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class CordaFutureInJavaTest {
|
||||||
|
@Test
|
||||||
|
public void methodsAreNotTooAwkwardToUse() throws InterruptedException, ExecutionException {
|
||||||
|
{
|
||||||
|
CordaFuture<Number> f = openFuture();
|
||||||
|
f.cancel(false);
|
||||||
|
assertTrue(f.isCancelled());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
CordaFuture<Number> f = openFuture();
|
||||||
|
assertThatThrownBy(() -> f.get(1, TimeUnit.MILLISECONDS)).isInstanceOf(TimeoutException.class);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
CordaFuture<Number> f = doneFuture(100);
|
||||||
|
assertEquals(100, f.get());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Future<Integer> f = doneFuture(100);
|
||||||
|
assertEquals(Integer.valueOf(100), f.get());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
OpenFuture<Number> f = openFuture();
|
||||||
|
OpenFuture<Number> g = openFuture();
|
||||||
|
f.then(done -> {
|
||||||
|
try {
|
||||||
|
return g.set(done.get());
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
f.set(100);
|
||||||
|
assertEquals(100, g.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toCompletableFutureWorks() throws InterruptedException, ExecutionException {
|
||||||
|
{
|
||||||
|
OpenFuture<Number> f = openFuture();
|
||||||
|
CompletableFuture<Number> g = f.toCompletableFuture();
|
||||||
|
f.set(100);
|
||||||
|
assertEquals(100, g.get());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
OpenFuture<Number> f = openFuture();
|
||||||
|
CompletableFuture<Number> g = f.toCompletableFuture();
|
||||||
|
EOFException e = new EOFException();
|
||||||
|
f.setException(e);
|
||||||
|
assertThatThrownBy(g::get).hasCause(e);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
OpenFuture<Number> f = openFuture();
|
||||||
|
CompletableFuture<Number> g = f.toCompletableFuture();
|
||||||
|
f.cancel(false);
|
||||||
|
assertTrue(g.isCancelled());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toCompletableFutureDoesNotHaveThePowerToAffectTheUnderlyingFuture() {
|
||||||
|
{
|
||||||
|
OpenFuture<Number> f = openFuture();
|
||||||
|
CompletableFuture<Number> g = f.toCompletableFuture();
|
||||||
|
g.complete(100);
|
||||||
|
assertFalse(f.isDone());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
OpenFuture<Number> f = openFuture();
|
||||||
|
CompletableFuture<Number> g = f.toCompletableFuture();
|
||||||
|
g.completeExceptionally(new EOFException());
|
||||||
|
assertFalse(f.isDone());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
OpenFuture<Number> f = openFuture();
|
||||||
|
CompletableFuture<Number> g = f.toCompletableFuture();
|
||||||
|
g.cancel(false);
|
||||||
|
// For now let's do the most conservative thing i.e. nothing:
|
||||||
|
assertFalse(f.isDone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,11 @@
|
|||||||
package net.corda.core
|
package net.corda.core
|
||||||
|
|
||||||
import com.google.common.util.concurrent.MoreExecutors
|
import net.corda.core.utilities.getOrThrow
|
||||||
import com.nhaarman.mockito_kotlin.mock
|
|
||||||
import com.nhaarman.mockito_kotlin.same
|
|
||||||
import com.nhaarman.mockito_kotlin.verify
|
|
||||||
import org.assertj.core.api.Assertions.*
|
import org.assertj.core.api.Assertions.*
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.ArgumentMatchers.anyString
|
|
||||||
import org.slf4j.Logger
|
|
||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.CancellationException
|
import java.util.concurrent.CancellationException
|
||||||
import java.util.concurrent.Executors
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
class UtilsTest {
|
class UtilsTest {
|
||||||
@Test
|
@Test
|
||||||
@ -65,17 +58,4 @@ class UtilsTest {
|
|||||||
future.get()
|
future.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `andForget works`() {
|
|
||||||
val log = mock<Logger>()
|
|
||||||
val throwable = Exception("Boom")
|
|
||||||
val executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor())
|
|
||||||
executor.submit { throw throwable }.andForget(log)
|
|
||||||
executor.shutdown()
|
|
||||||
while (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
verify(log).error(anyString(), same(throwable))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
package net.corda.core.concurrent
|
package net.corda.core.concurrent
|
||||||
|
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
|
||||||
import com.nhaarman.mockito_kotlin.*
|
import com.nhaarman.mockito_kotlin.*
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import java.io.EOFException
|
import java.io.EOFException
|
||||||
import java.util.concurrent.CancellationException
|
import java.util.concurrent.CancellationException
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class ConcurrencyUtilsTest {
|
class ConcurrencyUtilsTest {
|
||||||
private val f1 = SettableFuture.create<Int>()
|
private val f1 = openFuture<Int>()
|
||||||
private val f2 = SettableFuture.create<Double>()
|
private val f2 = openFuture<Double>()
|
||||||
private var invocations = 0
|
private var invocations = 0
|
||||||
private val log: Logger = mock<Logger>()
|
private val log = mock<Logger>()
|
||||||
@Test
|
@Test
|
||||||
fun `firstOf short circuit`() {
|
fun `firstOf short circuit`() {
|
||||||
// Order not significant in this case:
|
// Order not significant in this case:
|
||||||
@ -31,6 +32,7 @@ class ConcurrencyUtilsTest {
|
|||||||
f2.setException(throwable)
|
f2.setException(throwable)
|
||||||
assertEquals(1, invocations) // Least astonishing to skip handler side-effects.
|
assertEquals(1, invocations) // Least astonishing to skip handler side-effects.
|
||||||
verify(log).error(eq(shortCircuitedTaskFailedMessage), same(throwable))
|
verify(log).error(eq(shortCircuitedTaskFailedMessage), same(throwable))
|
||||||
|
verifyNoMoreInteractions(log)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -48,20 +50,24 @@ class ConcurrencyUtilsTest {
|
|||||||
assertTrue(f2.isCancelled)
|
assertTrue(f2.isCancelled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that if you set CancellationException on CompletableFuture it will report isCancelled.
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun `firstOf re-entrant handler attempt not due to cancel`() {
|
fun `firstOf re-entrant handler attempt not due to cancel`() {
|
||||||
val futures = arrayOf(f1, f2)
|
val futures = arrayOf(f1, f2)
|
||||||
val fakeCancel = CancellationException()
|
val nonCancel = IllegalStateException()
|
||||||
val g = firstOf(futures, log) {
|
val g = firstOf(futures, log) {
|
||||||
++invocations
|
++invocations
|
||||||
futures.forEach { it.setException(fakeCancel) } // One handler attempt here.
|
futures.forEach { it.setException(nonCancel) } // One handler attempt here.
|
||||||
it.getOrThrow()
|
it.getOrThrow()
|
||||||
}
|
}
|
||||||
f1.set(100)
|
f1.set(100)
|
||||||
assertEquals(100, g.getOrThrow())
|
assertEquals(100, g.getOrThrow())
|
||||||
assertEquals(1, invocations) // Handler didn't run as g was already done.
|
assertEquals(1, invocations) // Handler didn't run as g was already done.
|
||||||
verify(log).error(eq(shortCircuitedTaskFailedMessage), same(fakeCancel))
|
verify(log).error(eq(shortCircuitedTaskFailedMessage), same(nonCancel))
|
||||||
assertThatThrownBy { f2.getOrThrow() }.isSameAs(fakeCancel)
|
verifyNoMoreInteractions(log)
|
||||||
|
assertThatThrownBy { f2.getOrThrow() }.isSameAs(nonCancel)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -75,4 +81,37 @@ class ConcurrencyUtilsTest {
|
|||||||
assertEquals(1, invocations)
|
assertEquals(1, invocations)
|
||||||
verifyNoMoreInteractions(log)
|
verifyNoMoreInteractions(log)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `match does not pass failure of success block into the failure block`() {
|
||||||
|
val f = CompletableFuture.completedFuture(100)
|
||||||
|
val successes = mutableListOf<Any?>()
|
||||||
|
val failures = mutableListOf<Any?>()
|
||||||
|
val x = Throwable()
|
||||||
|
assertThatThrownBy {
|
||||||
|
f.match({
|
||||||
|
successes.add(it)
|
||||||
|
throw x
|
||||||
|
}, failures::add)
|
||||||
|
}.isSameAs(x)
|
||||||
|
assertEquals(listOf<Any?>(100), successes)
|
||||||
|
assertEquals(emptyList<Any?>(), failures)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `match does not pass ExecutionException to failure block`() {
|
||||||
|
val e = Throwable()
|
||||||
|
val f = CompletableFuture<Void>().apply { completeExceptionally(e) }
|
||||||
|
val successes = mutableListOf<Any?>()
|
||||||
|
val failures = mutableListOf<Any?>()
|
||||||
|
val x = Throwable()
|
||||||
|
assertThatThrownBy {
|
||||||
|
f.match(successes::add, {
|
||||||
|
failures.add(it)
|
||||||
|
throw x
|
||||||
|
})
|
||||||
|
}.isSameAs(x)
|
||||||
|
assertEquals(emptyList<Any?>(), successes)
|
||||||
|
assertEquals(listOf<Any?>(e), failures)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,12 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import net.corda.core.contracts.Attachment
|
import net.corda.core.contracts.Attachment
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
|
import net.corda.core.node.services.ServiceInfo
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FetchAttachmentsFlow
|
import net.corda.core.internal.FetchAttachmentsFlow
|
||||||
import net.corda.core.internal.FetchDataFlow
|
import net.corda.core.internal.FetchDataFlow
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
|
||||||
import net.corda.core.node.services.ServiceInfo
|
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.node.services.database.RequeryConfiguration
|
import net.corda.node.services.database.RequeryConfiguration
|
||||||
import net.corda.node.services.network.NetworkMapService
|
import net.corda.node.services.network.NetworkMapService
|
||||||
|
@ -3,13 +3,13 @@ package net.corda.core.flows
|
|||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.core.contracts.Command
|
import net.corda.core.contracts.Command
|
||||||
import net.corda.core.contracts.requireThat
|
import net.corda.core.contracts.requireThat
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.testing.contracts.DummyContract
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.utilities.unwrap
|
import net.corda.core.utilities.unwrap
|
||||||
import net.corda.testing.MINI_CORP_KEY
|
import net.corda.testing.MINI_CORP_KEY
|
||||||
import net.corda.testing.contracts.DummyContract
|
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
|
@ -4,7 +4,6 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
@ -14,6 +13,7 @@ import net.corda.core.utilities.OpaqueBytes
|
|||||||
import net.corda.core.transactions.LedgerTransaction
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.internal.Emoji
|
import net.corda.core.internal.Emoji
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.flows.CashIssueFlow
|
import net.corda.flows.CashIssueFlow
|
||||||
import net.corda.node.internal.CordaRPCOpsImpl
|
import net.corda.node.internal.CordaRPCOpsImpl
|
||||||
import net.corda.node.services.startFlowPermission
|
import net.corda.node.services.startFlowPermission
|
||||||
|
@ -4,9 +4,9 @@ import net.corda.contracts.asset.Cash
|
|||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.GBP
|
import net.corda.core.contracts.GBP
|
||||||
import net.corda.core.contracts.Issued
|
import net.corda.core.contracts.Issued
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
|
@ -4,9 +4,9 @@ import net.corda.contracts.asset.Cash
|
|||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.GBP
|
import net.corda.core.contracts.GBP
|
||||||
import net.corda.core.contracts.Issued
|
import net.corda.core.contracts.Issued
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package net.corda.core.flows
|
package net.corda.core.flows
|
||||||
|
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.AnonymousPartyAndPath
|
import net.corda.core.identity.AnonymousPartyAndPath
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.ALICE
|
import net.corda.testing.ALICE
|
||||||
import net.corda.testing.BOB
|
import net.corda.testing.BOB
|
||||||
import net.corda.testing.DUMMY_NOTARY
|
import net.corda.testing.DUMMY_NOTARY
|
||||||
|
@ -6,9 +6,9 @@ import net.corda.core.flows.FlowLogic
|
|||||||
import net.corda.core.flows.InitiatedBy
|
import net.corda.core.flows.InitiatedBy
|
||||||
import net.corda.core.flows.InitiatingFlow
|
import net.corda.core.flows.InitiatingFlow
|
||||||
import net.corda.core.flows.TestDataVendingFlow
|
import net.corda.core.flows.TestDataVendingFlow
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.sequence
|
import net.corda.core.utilities.sequence
|
||||||
import net.corda.testing.DUMMY_NOTARY_KEY
|
import net.corda.testing.DUMMY_NOTARY_KEY
|
||||||
import net.corda.testing.MEGA_CORP
|
import net.corda.testing.MEGA_CORP
|
||||||
|
@ -0,0 +1,163 @@
|
|||||||
|
package net.corda.core.internal.concurrent
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.*
|
||||||
|
import net.corda.core.concurrent.CordaFuture
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import org.assertj.core.api.Assertions
|
||||||
|
import org.junit.Test
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class CordaFutureTest {
|
||||||
|
@Test
|
||||||
|
fun `fork works`() {
|
||||||
|
val e = Executors.newSingleThreadExecutor()
|
||||||
|
try {
|
||||||
|
assertEquals(100, e.fork { 100 }.getOrThrow())
|
||||||
|
val x = Exception()
|
||||||
|
val f = e.fork { throw x }
|
||||||
|
Assertions.assertThatThrownBy { f.getOrThrow() }.isSameAs(x)
|
||||||
|
} finally {
|
||||||
|
e.shutdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `if a listener fails its throwable is logged`() {
|
||||||
|
val f = CordaFutureImpl<Int>()
|
||||||
|
val x = Exception()
|
||||||
|
val log = mock<Logger>()
|
||||||
|
val flag = AtomicBoolean()
|
||||||
|
f.thenImpl(log) { throw x }
|
||||||
|
f.thenImpl(log) { flag.set(true) } // Must not be affected by failure of previous listener.
|
||||||
|
f.set(100)
|
||||||
|
verify(log).error(eq(CordaFutureImpl.listenerFailedMessage), same(x))
|
||||||
|
verifyNoMoreInteractions(log)
|
||||||
|
assertTrue(flag.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `map works`() {
|
||||||
|
run {
|
||||||
|
val f = CordaFutureImpl<Int>()
|
||||||
|
val g = f.map { it * 2 }
|
||||||
|
f.set(100)
|
||||||
|
assertEquals(200, g.getOrThrow())
|
||||||
|
}
|
||||||
|
run {
|
||||||
|
val f = CordaFutureImpl<Int>()
|
||||||
|
val x = Exception()
|
||||||
|
val g = f.map { throw x }
|
||||||
|
f.set(100)
|
||||||
|
Assertions.assertThatThrownBy { g.getOrThrow() }.isSameAs(x)
|
||||||
|
}
|
||||||
|
run {
|
||||||
|
val block = mock<(Any?) -> Any?>()
|
||||||
|
val f = CordaFutureImpl<Int>()
|
||||||
|
val g = f.map(block)
|
||||||
|
val x = Exception()
|
||||||
|
f.setException(x)
|
||||||
|
Assertions.assertThatThrownBy { g.getOrThrow() }.isSameAs(x)
|
||||||
|
verifyNoMoreInteractions(block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `flatMap works`() {
|
||||||
|
run {
|
||||||
|
val f = CordaFutureImpl<Int>()
|
||||||
|
val g = f.flatMap { CordaFutureImpl<Int>().apply { set(it * 2) } }
|
||||||
|
f.set(100)
|
||||||
|
assertEquals(200, g.getOrThrow())
|
||||||
|
}
|
||||||
|
run {
|
||||||
|
val f = CordaFutureImpl<Int>()
|
||||||
|
val x = Exception()
|
||||||
|
val g = f.flatMap { CordaFutureImpl<Void>().apply { setException(x) } }
|
||||||
|
f.set(100)
|
||||||
|
Assertions.assertThatThrownBy { g.getOrThrow() }.isSameAs(x)
|
||||||
|
}
|
||||||
|
run {
|
||||||
|
val f = CordaFutureImpl<Int>()
|
||||||
|
val x = Exception()
|
||||||
|
val g: CordaFuture<Void> = f.flatMap { throw x }
|
||||||
|
f.set(100)
|
||||||
|
Assertions.assertThatThrownBy { g.getOrThrow() }.isSameAs(x)
|
||||||
|
}
|
||||||
|
run {
|
||||||
|
val block = mock<(Any?) -> CordaFuture<*>>()
|
||||||
|
val f = CordaFutureImpl<Int>()
|
||||||
|
val g = f.flatMap(block)
|
||||||
|
val x = Exception()
|
||||||
|
f.setException(x)
|
||||||
|
Assertions.assertThatThrownBy { g.getOrThrow() }.isSameAs(x)
|
||||||
|
verifyNoMoreInteractions(block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `andForget works`() {
|
||||||
|
val log = mock<Logger>()
|
||||||
|
val throwable = Exception("Boom")
|
||||||
|
val executor = Executors.newSingleThreadExecutor()
|
||||||
|
executor.fork { throw throwable }.andForget(log)
|
||||||
|
executor.shutdown()
|
||||||
|
while (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
verify(log).error(any(), same(throwable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TransposeTest {
|
||||||
|
private val a = openFuture<Int>()
|
||||||
|
private val b = openFuture<Int>()
|
||||||
|
private val c = openFuture<Int>()
|
||||||
|
private val f = listOf(a, b, c).transpose()
|
||||||
|
@Test
|
||||||
|
fun `transpose empty collection`() {
|
||||||
|
assertEquals(emptyList(), emptyList<CordaFuture<*>>().transpose().getOrThrow())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `transpose values are in the same order as the collection of futures`() {
|
||||||
|
b.set(2)
|
||||||
|
c.set(3)
|
||||||
|
assertFalse(f.isDone)
|
||||||
|
a.set(1)
|
||||||
|
assertEquals(listOf(1, 2, 3), f.getOrThrow())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `transpose throwables are reported in the order they were thrown`() {
|
||||||
|
val ax = Exception()
|
||||||
|
val bx = Exception()
|
||||||
|
val cx = Exception()
|
||||||
|
b.setException(bx)
|
||||||
|
c.setException(cx)
|
||||||
|
assertFalse(f.isDone)
|
||||||
|
a.setException(ax)
|
||||||
|
Assertions.assertThatThrownBy { f.getOrThrow() }.isSameAs(bx)
|
||||||
|
assertEquals(listOf(cx, ax), bx.suppressed.asList())
|
||||||
|
assertEquals(emptyList(), ax.suppressed.asList())
|
||||||
|
assertEquals(emptyList(), cx.suppressed.asList())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `transpose mixture of outcomes`() {
|
||||||
|
val bx = Exception()
|
||||||
|
val cx = Exception()
|
||||||
|
b.setException(bx)
|
||||||
|
c.setException(cx)
|
||||||
|
assertFalse(f.isDone)
|
||||||
|
a.set(100) // Discarded.
|
||||||
|
Assertions.assertThatThrownBy { f.getOrThrow() }.isSameAs(bx)
|
||||||
|
assertEquals(listOf(cx), bx.suppressed.asList())
|
||||||
|
assertEquals(emptyList(), cx.suppressed.asList())
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,6 @@ import net.corda.core.contracts.Attachment
|
|||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.InitiatingFlow
|
import net.corda.core.flows.InitiatingFlow
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FetchAttachmentsFlow
|
import net.corda.core.internal.FetchAttachmentsFlow
|
||||||
import net.corda.core.internal.FetchDataFlow
|
import net.corda.core.internal.FetchDataFlow
|
||||||
@ -13,13 +12,13 @@ import net.corda.core.messaging.RPCOps
|
|||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.utilities.unwrap
|
import net.corda.core.utilities.unwrap
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.node.internal.InitiatedFlowFactory
|
import net.corda.node.internal.InitiatedFlowFactory
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.node.services.network.NetworkMapService
|
import net.corda.node.services.network.NetworkMapService
|
||||||
import net.corda.node.services.persistence.NodeAttachmentService
|
import net.corda.node.services.persistence.NodeAttachmentService
|
||||||
import net.corda.node.services.persistence.schemas.requery.AttachmentEntity
|
import net.corda.node.services.persistence.schemas.requery.AttachmentEntity
|
||||||
import net.corda.node.services.statemachine.SessionInit
|
import net.corda.node.services.statemachine.SessionInit
|
||||||
import net.corda.core.flows.DataVendingFlow
|
|
||||||
import net.corda.core.flows.TestDataVendingFlow
|
import net.corda.core.flows.TestDataVendingFlow
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
|
@ -1,25 +1,22 @@
|
|||||||
package net.corda.docs
|
package net.corda.docs
|
||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
|
||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.contracts.ContractState
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.internal.concurrent.transpose
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.messaging.vaultTrackBy
|
import net.corda.core.messaging.vaultTrackBy
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.node.services.vault.QueryCriteria
|
import net.corda.core.node.services.vault.QueryCriteria
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
import net.corda.testing.ALICE
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.BOB
|
|
||||||
import net.corda.testing.DUMMY_NOTARY
|
|
||||||
import net.corda.flows.CashIssueFlow
|
import net.corda.flows.CashIssueFlow
|
||||||
import net.corda.flows.CashPaymentFlow
|
import net.corda.flows.CashPaymentFlow
|
||||||
import net.corda.node.services.startFlowPermission
|
import net.corda.node.services.startFlowPermission
|
||||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||||
import net.corda.nodeapi.User
|
import net.corda.nodeapi.User
|
||||||
|
import net.corda.testing.*
|
||||||
import net.corda.testing.driver.driver
|
import net.corda.testing.driver.driver
|
||||||
import net.corda.testing.expect
|
import net.corda.testing.expect
|
||||||
import net.corda.testing.expectEvents
|
import net.corda.testing.expectEvents
|
||||||
@ -41,11 +38,11 @@ class IntegrationTestingTutorial {
|
|||||||
val bobUser = User("bobUser", "testPassword2", permissions = setOf(
|
val bobUser = User("bobUser", "testPassword2", permissions = setOf(
|
||||||
startFlowPermission<CashPaymentFlow>()
|
startFlowPermission<CashPaymentFlow>()
|
||||||
))
|
))
|
||||||
val (alice, bob, notary) = Futures.allAsList(
|
val (alice, bob, notary) = listOf(
|
||||||
startNode(ALICE.name, rpcUsers = listOf(aliceUser)),
|
startNode(ALICE.name, rpcUsers = listOf(aliceUser)),
|
||||||
startNode(BOB.name, rpcUsers = listOf(bobUser)),
|
startNode(BOB.name, rpcUsers = listOf(bobUser)),
|
||||||
startNode(DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type)))
|
startNode(DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type)))
|
||||||
).getOrThrow()
|
).transpose().getOrThrow()
|
||||||
// END 1
|
// END 1
|
||||||
|
|
||||||
// START 2
|
// START 2
|
||||||
@ -66,7 +63,7 @@ class IntegrationTestingTutorial {
|
|||||||
|
|
||||||
// START 4
|
// START 4
|
||||||
val issueRef = OpaqueBytes.of(0)
|
val issueRef = OpaqueBytes.of(0)
|
||||||
val futures = Stack<ListenableFuture<*>>()
|
val futures = Stack<CordaFuture<*>>()
|
||||||
(1..10).map { i ->
|
(1..10).map { i ->
|
||||||
thread {
|
thread {
|
||||||
futures.push(aliceProxy.startFlow(::CashIssueFlow,
|
futures.push(aliceProxy.startFlow(::CashIssueFlow,
|
||||||
|
@ -2,9 +2,9 @@ package net.corda.docs
|
|||||||
|
|
||||||
import net.corda.contracts.getCashBalances
|
import net.corda.contracts.getCashBalances
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.flows.CashIssueFlow
|
import net.corda.flows.CashIssueFlow
|
||||||
import net.corda.node.services.network.NetworkMapService
|
import net.corda.node.services.network.NetworkMapService
|
||||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||||
|
@ -2,10 +2,10 @@ package net.corda.docs
|
|||||||
|
|
||||||
import net.corda.contracts.getCashBalances
|
import net.corda.contracts.getCashBalances
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.toFuture
|
import net.corda.core.toFuture
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.flows.CashIssueFlow
|
import net.corda.flows.CashIssueFlow
|
||||||
import net.corda.node.services.network.NetworkMapService
|
import net.corda.node.services.network.NetworkMapService
|
||||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||||
|
@ -3,13 +3,13 @@ package net.corda.docs
|
|||||||
import net.corda.core.contracts.LinearState
|
import net.corda.core.contracts.LinearState
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.contracts.UniqueIdentifier
|
import net.corda.core.contracts.UniqueIdentifier
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.node.services.queryBy
|
import net.corda.core.node.services.queryBy
|
||||||
import net.corda.core.node.services.vault.QueryCriteria
|
import net.corda.core.node.services.vault.QueryCriteria
|
||||||
import net.corda.core.toFuture
|
import net.corda.core.toFuture
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.DUMMY_NOTARY
|
import net.corda.testing.DUMMY_NOTARY
|
||||||
import net.corda.testing.DUMMY_NOTARY_KEY
|
import net.corda.testing.DUMMY_NOTARY_KEY
|
||||||
import net.corda.node.services.network.NetworkMapService
|
import net.corda.node.services.network.NetworkMapService
|
||||||
|
@ -3,9 +3,9 @@ package net.corda.flows
|
|||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.contracts.`issued by`
|
import net.corda.core.contracts.`issued by`
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
|
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
import net.corda.testing.node.MockNetwork.MockNode
|
import net.corda.testing.node.MockNetwork.MockNode
|
||||||
|
@ -3,9 +3,9 @@ package net.corda.flows
|
|||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.contracts.`issued by`
|
import net.corda.core.contracts.`issued by`
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
|
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
import net.corda.testing.node.MockNetwork.MockNode
|
import net.corda.testing.node.MockNetwork.MockNode
|
||||||
|
@ -3,12 +3,12 @@ package net.corda.flows
|
|||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.contracts.`issued by`
|
import net.corda.core.contracts.`issued by`
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.node.services.trackBy
|
import net.corda.core.node.services.trackBy
|
||||||
import net.corda.core.node.services.vault.QueryCriteria
|
import net.corda.core.node.services.vault.QueryCriteria
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.expect
|
import net.corda.testing.expect
|
||||||
import net.corda.testing.expectEvents
|
import net.corda.testing.expectEvents
|
||||||
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
|
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
package net.corda.flows
|
package net.corda.flows
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
|
||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
|
import net.corda.core.concurrent.CordaFuture
|
||||||
|
import net.corda.testing.contracts.calculateRandomlySizedAmounts
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.contracts.currency
|
import net.corda.core.contracts.currency
|
||||||
import net.corda.core.flows.FlowException
|
import net.corda.core.flows.FlowException
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.node.services.trackBy
|
import net.corda.core.node.services.trackBy
|
||||||
import net.corda.core.node.services.vault.QueryCriteria
|
import net.corda.core.node.services.vault.QueryCriteria
|
||||||
import net.corda.core.transactions.SignedTransaction
|
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||||
import net.corda.testing.contracts.calculateRandomlySizedAmounts
|
|
||||||
import net.corda.testing.expect
|
import net.corda.testing.expect
|
||||||
import net.corda.testing.expectEvents
|
import net.corda.testing.expectEvents
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
@ -159,7 +159,7 @@ class IssuerFlowTest(val anonymous: Boolean) {
|
|||||||
amount: Amount<Currency>,
|
amount: Amount<Currency>,
|
||||||
issueToParty: Party,
|
issueToParty: Party,
|
||||||
ref: OpaqueBytes,
|
ref: OpaqueBytes,
|
||||||
notaryParty: Party): ListenableFuture<AbstractCashFlow.Result> {
|
notaryParty: Party): CordaFuture<AbstractCashFlow.Result> {
|
||||||
val issueToPartyAndRef = issueToParty.ref(ref)
|
val issueToPartyAndRef = issueToParty.ref(ref)
|
||||||
val issueRequest = IssuanceRequester(amount, issueToParty, issueToPartyAndRef.reference, issuerNode.info.legalIdentity, notaryParty,
|
val issueRequest = IssuanceRequester(amount, issueToParty, issueToPartyAndRef.reference, issuerNode.info.legalIdentity, notaryParty,
|
||||||
anonymous)
|
anonymous)
|
||||||
|
@ -162,7 +162,7 @@ object RPCApi {
|
|||||||
|
|
||||||
data class Observation(
|
data class Observation(
|
||||||
val id: ObservableId,
|
val id: ObservableId,
|
||||||
val content: Notification<Any>
|
val content: Notification<*>
|
||||||
) : ServerToClient() {
|
) : ServerToClient() {
|
||||||
override fun writeToClientMessage(context: SerializationContext, message: ClientMessage) {
|
override fun writeToClientMessage(context: SerializationContext, message: ClientMessage) {
|
||||||
message.putIntProperty(TAG_FIELD_NAME, Tag.OBSERVATION.ordinal)
|
message.putIntProperty(TAG_FIELD_NAME, Tag.OBSERVATION.ordinal)
|
||||||
|
@ -4,7 +4,7 @@ package net.corda.nodeapi
|
|||||||
|
|
||||||
import com.esotericsoftware.kryo.Registration
|
import com.esotericsoftware.kryo.Registration
|
||||||
import com.esotericsoftware.kryo.Serializer
|
import com.esotericsoftware.kryo.Serializer
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.CordaRuntimeException
|
import net.corda.core.CordaRuntimeException
|
||||||
import net.corda.core.serialization.*
|
import net.corda.core.serialization.*
|
||||||
import net.corda.core.toFuture
|
import net.corda.core.toFuture
|
||||||
@ -45,16 +45,15 @@ class PermissionException(msg: String) : RuntimeException(msg)
|
|||||||
// The Kryo used for the RPC wire protocol. Every type in the wire protocol is listed here explicitly.
|
// The Kryo used for the RPC wire protocol. Every type in the wire protocol is listed here explicitly.
|
||||||
// This is annoying to write out, but will make it easier to formalise the wire protocol when the time comes,
|
// This is annoying to write out, but will make it easier to formalise the wire protocol when the time comes,
|
||||||
// because we can see everything we're using in one place.
|
// because we can see everything we're using in one place.
|
||||||
class RPCKryo(observableSerializer: Serializer<Observable<Any>>, whitelist: ClassWhitelist) : CordaKryo(CordaClassResolver(whitelist)) {
|
class RPCKryo(observableSerializer: Serializer<Observable<*>>, whitelist: ClassWhitelist) : CordaKryo(CordaClassResolver(whitelist)) {
|
||||||
init {
|
init {
|
||||||
DefaultKryoCustomizer.customize(this)
|
DefaultKryoCustomizer.customize(this)
|
||||||
|
|
||||||
// RPC specific classes
|
// RPC specific classes
|
||||||
register(InputStream::class.java, InputStreamSerializer)
|
register(InputStream::class.java, InputStreamSerializer)
|
||||||
register(Observable::class.java, observableSerializer)
|
register(Observable::class.java, observableSerializer)
|
||||||
@Suppress("UNCHECKED_CAST")
|
register(CordaFuture::class,
|
||||||
register(ListenableFuture::class,
|
read = { kryo, input -> observableSerializer.read(kryo, input, Observable::class.java).toFuture() },
|
||||||
read = { kryo, input -> observableSerializer.read(kryo, input, Observable::class.java as Class<Observable<Any>>).toFuture() },
|
|
||||||
write = { kryo, output, obj -> observableSerializer.write(kryo, output, obj.toObservable()) }
|
write = { kryo, output, obj -> observableSerializer.write(kryo, output, obj.toObservable()) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -66,8 +65,8 @@ class RPCKryo(observableSerializer: Serializer<Observable<Any>>, whitelist: Clas
|
|||||||
if (InputStream::class.java != type && InputStream::class.java.isAssignableFrom(type)) {
|
if (InputStream::class.java != type && InputStream::class.java.isAssignableFrom(type)) {
|
||||||
return super.getRegistration(InputStream::class.java)
|
return super.getRegistration(InputStream::class.java)
|
||||||
}
|
}
|
||||||
if (ListenableFuture::class.java != type && ListenableFuture::class.java.isAssignableFrom(type)) {
|
if (CordaFuture::class.java != type && CordaFuture::class.java.isAssignableFrom(type)) {
|
||||||
return super.getRegistration(ListenableFuture::class.java)
|
return super.getRegistration(CordaFuture::class.java)
|
||||||
}
|
}
|
||||||
type.requireExternal("RPC not allowed to deserialise internal classes")
|
type.requireExternal("RPC not allowed to deserialise internal classes")
|
||||||
return super.getRegistration(type)
|
return super.getRegistration(type)
|
||||||
|
@ -4,10 +4,10 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.StartableByRPC
|
import net.corda.core.flows.StartableByRPC
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.ServiceType
|
import net.corda.core.node.services.ServiceType
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.ALICE
|
import net.corda.testing.ALICE
|
||||||
import net.corda.node.internal.NodeStartup
|
import net.corda.node.internal.NodeStartup
|
||||||
import net.corda.node.services.startFlowPermission
|
import net.corda.node.services.startFlowPermission
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package net.corda.node
|
package net.corda.node
|
||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.google.common.util.concurrent.Futures
|
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.InitiatedBy
|
import net.corda.core.flows.InitiatedBy
|
||||||
import net.corda.core.flows.InitiatingFlow
|
import net.corda.core.flows.InitiatingFlow
|
||||||
import net.corda.core.flows.StartableByRPC
|
import net.corda.core.flows.StartableByRPC
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.internal.concurrent.transpose
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.ALICE
|
import net.corda.testing.ALICE
|
||||||
import net.corda.testing.BOB
|
import net.corda.testing.BOB
|
||||||
import net.corda.core.utilities.unwrap
|
import net.corda.core.utilities.unwrap
|
||||||
@ -24,9 +24,9 @@ class CordappScanningDriverTest {
|
|||||||
val user = User("u", "p", setOf(startFlowPermission<ReceiveFlow>()))
|
val user = User("u", "p", setOf(startFlowPermission<ReceiveFlow>()))
|
||||||
// The driver will automatically pick up the annotated flows below
|
// The driver will automatically pick up the annotated flows below
|
||||||
driver {
|
driver {
|
||||||
val (alice, bob) = Futures.allAsList(
|
val (alice, bob) = listOf(
|
||||||
startNode(ALICE.name, rpcUsers = listOf(user)),
|
startNode(ALICE.name, rpcUsers = listOf(user)),
|
||||||
startNode(BOB.name)).getOrThrow()
|
startNode(BOB.name)).transpose().getOrThrow()
|
||||||
val initiatedFlowClass = alice.rpcClientToNode()
|
val initiatedFlowClass = alice.rpcClientToNode()
|
||||||
.start(user.username, user.password)
|
.start(user.username, user.password)
|
||||||
.proxy
|
.proxy
|
||||||
|
@ -2,10 +2,10 @@ package net.corda.node
|
|||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.google.common.base.Stopwatch
|
import com.google.common.base.Stopwatch
|
||||||
import com.google.common.util.concurrent.Futures
|
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.StartableByRPC
|
import net.corda.core.flows.StartableByRPC
|
||||||
|
import net.corda.core.internal.concurrent.transpose
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.utilities.minutes
|
import net.corda.core.utilities.minutes
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
@ -113,7 +113,7 @@ class NodePerformanceTests {
|
|||||||
val doneFutures = (1..100).toList().parallelStream().map {
|
val doneFutures = (1..100).toList().parallelStream().map {
|
||||||
connection.proxy.startFlow(::CashIssueFlow, 1.DOLLARS, OpaqueBytes.of(0), a.nodeInfo.legalIdentity, a.nodeInfo.notaryIdentity).returnValue
|
connection.proxy.startFlow(::CashIssueFlow, 1.DOLLARS, OpaqueBytes.of(0), a.nodeInfo.legalIdentity, a.nodeInfo.notaryIdentity).returnValue
|
||||||
}.toList()
|
}.toList()
|
||||||
Futures.allAsList(doneFutures).get()
|
doneFutures.transpose().get()
|
||||||
println("STARTING PAYMENT")
|
println("STARTING PAYMENT")
|
||||||
startPublishingFixedRateInjector(metricRegistry, 8, 5.minutes, 100L / TimeUnit.SECONDS) {
|
startPublishingFixedRateInjector(metricRegistry, 8, 5.minutes, 100L / TimeUnit.SECONDS) {
|
||||||
connection.proxy.startFlow(::CashPaymentFlow, 1.DOLLARS, a.nodeInfo.legalIdentity).returnValue.get()
|
connection.proxy.startFlow(::CashPaymentFlow, 1.DOLLARS, a.nodeInfo.legalIdentity).returnValue.get()
|
||||||
|
@ -9,12 +9,12 @@ import net.corda.core.internal.div
|
|||||||
import net.corda.core.flows.NotaryError
|
import net.corda.core.flows.NotaryError
|
||||||
import net.corda.core.flows.NotaryException
|
import net.corda.core.flows.NotaryException
|
||||||
import net.corda.core.flows.NotaryFlow
|
import net.corda.core.flows.NotaryFlow
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.Try
|
import net.corda.core.utilities.Try
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.node.internal.AbstractNode
|
import net.corda.node.internal.AbstractNode
|
||||||
import net.corda.node.services.config.BFTSMaRtConfiguration
|
import net.corda.node.services.config.BFTSMaRtConfiguration
|
||||||
import net.corda.node.services.network.NetworkMapService
|
import net.corda.node.services.network.NetworkMapService
|
||||||
|
@ -2,7 +2,6 @@ package net.corda.node.services
|
|||||||
|
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.POUNDS
|
import net.corda.core.contracts.POUNDS
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.bufferUntilSubscribed
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
@ -10,6 +9,9 @@ import net.corda.core.messaging.StateMachineUpdate
|
|||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import net.corda.testing.ALICE
|
||||||
|
import net.corda.testing.DUMMY_NOTARY
|
||||||
import net.corda.flows.CashIssueFlow
|
import net.corda.flows.CashIssueFlow
|
||||||
import net.corda.flows.CashPaymentFlow
|
import net.corda.flows.CashPaymentFlow
|
||||||
import net.corda.node.services.transactions.RaftValidatingNotaryService
|
import net.corda.node.services.transactions.RaftValidatingNotaryService
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
package net.corda.node.services
|
package net.corda.node.services
|
||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
|
import net.corda.testing.contracts.DummyContract
|
||||||
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.testing.DUMMY_BANK_A
|
||||||
import net.corda.core.flows.NotaryError
|
import net.corda.core.flows.NotaryError
|
||||||
import net.corda.core.flows.NotaryException
|
import net.corda.core.flows.NotaryException
|
||||||
import net.corda.core.flows.NotaryFlow
|
import net.corda.core.flows.NotaryFlow
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.internal.concurrent.map
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.internal.concurrent.transpose
|
||||||
import net.corda.core.map
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.node.internal.AbstractNode
|
import net.corda.node.internal.AbstractNode
|
||||||
import net.corda.testing.DUMMY_BANK_A
|
|
||||||
import net.corda.testing.contracts.DummyContract
|
|
||||||
import net.corda.testing.node.NodeBasedTest
|
import net.corda.testing.node.NodeBasedTest
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -25,10 +25,10 @@ class RaftNotaryServiceTests : NodeBasedTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `detect double spend`() {
|
fun `detect double spend`() {
|
||||||
val (bankA) = Futures.allAsList(
|
val (bankA) = listOf(
|
||||||
startNode(DUMMY_BANK_A.name),
|
startNode(DUMMY_BANK_A.name),
|
||||||
startNotaryCluster(notaryName, 3).map { it.first() }
|
startNotaryCluster(notaryName, 3).map { it.first() }
|
||||||
).getOrThrow()
|
).transpose().getOrThrow()
|
||||||
|
|
||||||
val notaryParty = bankA.services.networkMapCache.getNotary(notaryName)!!
|
val notaryParty = bankA.services.networkMapCache.getNotary(notaryName)!!
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package net.corda.node.services.statemachine
|
package net.corda.node.services.statemachine
|
||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.google.common.util.concurrent.Futures
|
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.InitiatingFlow
|
import net.corda.core.flows.InitiatingFlow
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.internal.concurrent.transpose
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.ALICE
|
import net.corda.testing.ALICE
|
||||||
import net.corda.testing.BOB
|
import net.corda.testing.BOB
|
||||||
import net.corda.core.utilities.unwrap
|
import net.corda.core.utilities.unwrap
|
||||||
@ -16,9 +16,9 @@ import org.junit.Test
|
|||||||
class FlowVersioningTest : NodeBasedTest() {
|
class FlowVersioningTest : NodeBasedTest() {
|
||||||
@Test
|
@Test
|
||||||
fun `core flows receive platform version of initiator`() {
|
fun `core flows receive platform version of initiator`() {
|
||||||
val (alice, bob) = Futures.allAsList(
|
val (alice, bob) = listOf(
|
||||||
startNode(ALICE.name, platformVersion = 2),
|
startNode(ALICE.name, platformVersion = 2),
|
||||||
startNode(BOB.name, platformVersion = 3)).getOrThrow()
|
startNode(BOB.name, platformVersion = 3)).transpose().getOrThrow()
|
||||||
bob.installCoreFlow(ClientFlow::class, ::SendBackPlatformVersionFlow)
|
bob.installCoreFlow(ClientFlow::class, ::SendBackPlatformVersionFlow)
|
||||||
val resultFuture = alice.services.startFlow(ClientFlow(bob.info.legalIdentity)).resultFuture
|
val resultFuture = alice.services.startFlow(ClientFlow(bob.info.legalIdentity)).resultFuture
|
||||||
assertThat(resultFuture.getOrThrow()).isEqualTo(2)
|
assertThat(resultFuture.getOrThrow()).isEqualTo(2)
|
||||||
|
@ -7,11 +7,11 @@ import net.corda.core.crypto.toBase58String
|
|||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.InitiatedBy
|
import net.corda.core.flows.InitiatedBy
|
||||||
import net.corda.core.flows.InitiatingFlow
|
import net.corda.core.flows.InitiatingFlow
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.ALICE
|
import net.corda.testing.ALICE
|
||||||
import net.corda.testing.BOB
|
import net.corda.testing.BOB
|
||||||
import net.corda.core.utilities.unwrap
|
import net.corda.core.utilities.unwrap
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package net.corda.services.messaging
|
package net.corda.services.messaging
|
||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.internal.concurrent.transpose
|
||||||
import net.corda.core.internal.elapsedTime
|
import net.corda.core.internal.elapsedTime
|
||||||
import net.corda.core.internal.times
|
import net.corda.core.internal.times
|
||||||
import net.corda.core.messaging.MessageRecipients
|
import net.corda.core.messaging.MessageRecipients
|
||||||
@ -12,6 +11,7 @@ import net.corda.core.node.services.ServiceInfo
|
|||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.node.internal.Node
|
import net.corda.node.internal.Node
|
||||||
import net.corda.node.services.api.DEFAULT_SESSION_ID
|
import net.corda.node.services.api.DEFAULT_SESSION_ID
|
||||||
@ -39,7 +39,7 @@ class P2PMessagingTest : NodeBasedTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `network map will work after restart`() {
|
fun `network map will work after restart`() {
|
||||||
val identities = listOf(DUMMY_BANK_A, DUMMY_BANK_B, DUMMY_NOTARY)
|
val identities = listOf(DUMMY_BANK_A, DUMMY_BANK_B, DUMMY_NOTARY)
|
||||||
fun startNodes() = Futures.allAsList(identities.map { startNode(it.name) })
|
fun startNodes() = identities.map { startNode(it.name) }.transpose()
|
||||||
|
|
||||||
val startUpDuration = elapsedTime { startNodes().getOrThrow() }
|
val startUpDuration = elapsedTime { startNodes().getOrThrow() }
|
||||||
// Start the network map a second time - this will restore message queues from the journal.
|
// Start the network map a second time - this will restore message queues from the journal.
|
||||||
@ -75,7 +75,7 @@ class P2PMessagingTest : NodeBasedTest() {
|
|||||||
DUMMY_MAP.name,
|
DUMMY_MAP.name,
|
||||||
advertisedServices = setOf(distributedService),
|
advertisedServices = setOf(distributedService),
|
||||||
configOverrides = mapOf("notaryNodeAddress" to notaryClusterAddress.toString()))
|
configOverrides = mapOf("notaryNodeAddress" to notaryClusterAddress.toString()))
|
||||||
val (serviceNode2, alice) = Futures.allAsList(
|
val (serviceNode2, alice) = listOf(
|
||||||
startNode(
|
startNode(
|
||||||
SERVICE_2_NAME,
|
SERVICE_2_NAME,
|
||||||
advertisedServices = setOf(distributedService),
|
advertisedServices = setOf(distributedService),
|
||||||
@ -83,7 +83,7 @@ class P2PMessagingTest : NodeBasedTest() {
|
|||||||
"notaryNodeAddress" to freeLocalHostAndPort().toString(),
|
"notaryNodeAddress" to freeLocalHostAndPort().toString(),
|
||||||
"notaryClusterAddresses" to listOf(notaryClusterAddress.toString()))),
|
"notaryClusterAddresses" to listOf(notaryClusterAddress.toString()))),
|
||||||
startNode(ALICE.name)
|
startNode(ALICE.name)
|
||||||
).getOrThrow()
|
).transpose().getOrThrow()
|
||||||
|
|
||||||
assertAllNodesAreUsed(listOf(networkMapNode, serviceNode2), DISTRIBUTED_SERVICE_NAME, alice)
|
assertAllNodesAreUsed(listOf(networkMapNode, serviceNode2), DISTRIBUTED_SERVICE_NAME, alice)
|
||||||
}
|
}
|
||||||
@ -217,7 +217,7 @@ class P2PMessagingTest : NodeBasedTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Node.receiveFrom(target: MessageRecipients): ListenableFuture<Any> {
|
private fun Node.receiveFrom(target: MessageRecipients): CordaFuture<Any> {
|
||||||
val request = TestRequest(replyTo = network.myAddress)
|
val request = TestRequest(replyTo = network.myAddress)
|
||||||
return network.sendRequest<Any>(javaClass.name, request, target)
|
return network.sendRequest<Any>(javaClass.name, request, target)
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package net.corda.services.messaging
|
package net.corda.services.messaging
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.crypto.cert
|
import net.corda.core.crypto.cert
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.core.utilities.NonEmptySet
|
import net.corda.core.utilities.NonEmptySet
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.node.internal.NetworkMapInfo
|
import net.corda.node.internal.NetworkMapInfo
|
||||||
import net.corda.node.services.config.configureWithDevSSLCertificate
|
import net.corda.node.services.config.configureWithDevSSLCertificate
|
||||||
import net.corda.node.services.messaging.sendRequest
|
import net.corda.node.services.messaging.sendRequest
|
||||||
@ -65,7 +65,7 @@ class P2PSecurityTest : NodeBasedTest() {
|
|||||||
return SimpleNode(config, trustRoot = trustRoot).apply { start() }
|
return SimpleNode(config, trustRoot = trustRoot).apply { start() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun SimpleNode.registerWithNetworkMap(registrationName: X500Name): ListenableFuture<NetworkMapService.RegistrationResponse> {
|
private fun SimpleNode.registerWithNetworkMap(registrationName: X500Name): CordaFuture<NetworkMapService.RegistrationResponse> {
|
||||||
val legalIdentity = getTestPartyAndCertificate(registrationName, identity.public)
|
val legalIdentity = getTestPartyAndCertificate(registrationName, identity.public)
|
||||||
val nodeInfo = NodeInfo(listOf(MOCK_HOST_AND_PORT), legalIdentity, NonEmptySet.of(legalIdentity), 1)
|
val nodeInfo = NodeInfo(listOf(MOCK_HOST_AND_PORT), legalIdentity, NonEmptySet.of(legalIdentity), 1)
|
||||||
val registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX)
|
val registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX)
|
||||||
|
@ -3,17 +3,17 @@ package net.corda.node.internal
|
|||||||
import com.codahale.metrics.MetricRegistry
|
import com.codahale.metrics.MetricRegistry
|
||||||
import com.google.common.annotations.VisibleForTesting
|
import com.google.common.annotations.VisibleForTesting
|
||||||
import com.google.common.collect.MutableClassToInstanceMap
|
import com.google.common.collect.MutableClassToInstanceMap
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
|
||||||
import com.google.common.util.concurrent.MoreExecutors
|
import com.google.common.util.concurrent.MoreExecutors
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
|
||||||
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
||||||
import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult
|
import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult
|
||||||
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.flatMap
|
|
||||||
import net.corda.core.flows.*
|
import net.corda.core.flows.*
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.identity.PartyAndCertificate
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
|
import net.corda.core.internal.concurrent.flatMap
|
||||||
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
@ -139,9 +139,9 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
var isPreviousCheckpointsPresent = false
|
var isPreviousCheckpointsPresent = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
protected val _networkMapRegistrationFuture: SettableFuture<Unit> = SettableFuture.create()
|
protected val _networkMapRegistrationFuture = openFuture<Unit>()
|
||||||
/** Completes once the node has successfully registered with the network map service */
|
/** Completes once the node has successfully registered with the network map service */
|
||||||
val networkMapRegistrationFuture: ListenableFuture<Unit>
|
val networkMapRegistrationFuture: CordaFuture<Unit>
|
||||||
get() = _networkMapRegistrationFuture
|
get() = _networkMapRegistrationFuture
|
||||||
|
|
||||||
/** Fetch CordaPluginRegistry classes registered in META-INF/services/net.corda.core.node.CordaPluginRegistry files that exist in the classpath */
|
/** Fetch CordaPluginRegistry classes registered in META-INF/services/net.corda.core.node.CordaPluginRegistry files that exist in the classpath */
|
||||||
@ -212,7 +212,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
registerInitiatedFlow(IssuerFlow.Issuer::class.java)
|
registerInitiatedFlow(IssuerFlow.Issuer::class.java)
|
||||||
|
|
||||||
runOnStop += network::stop
|
runOnStop += network::stop
|
||||||
_networkMapRegistrationFuture.setFuture(registerWithNetworkMapIfConfigured())
|
_networkMapRegistrationFuture.captureLater(registerWithNetworkMapIfConfigured())
|
||||||
smm.start()
|
smm.start()
|
||||||
// Shut down the SMM so no Fibers are scheduled.
|
// Shut down the SMM so no Fibers are scheduled.
|
||||||
runOnStop += { smm.stop(acceptableLiveFiberCountOnStop()) }
|
runOnStop += { smm.stop(acceptableLiveFiberCountOnStop()) }
|
||||||
@ -575,7 +575,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerWithNetworkMapIfConfigured(): ListenableFuture<Unit> {
|
private fun registerWithNetworkMapIfConfigured(): CordaFuture<Unit> {
|
||||||
services.networkMapCache.addNode(info)
|
services.networkMapCache.addNode(info)
|
||||||
// In the unit test environment, we may sometimes run without any network map service
|
// In the unit test environment, we may sometimes run without any network map service
|
||||||
return if (networkMapAddress == null && inNodeNetworkMapService == null) {
|
return if (networkMapAddress == null && inNodeNetworkMapService == null) {
|
||||||
@ -590,7 +590,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
* Register this node with the network map cache, and load network map from a remote service (and register for
|
* 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.
|
* updates) if one has been supplied.
|
||||||
*/
|
*/
|
||||||
protected open fun registerWithNetworkMap(): ListenableFuture<Unit> {
|
protected open fun registerWithNetworkMap(): CordaFuture<Unit> {
|
||||||
require(networkMapAddress != null || NetworkMapService.type in advertisedServices.map { it.type }) {
|
require(networkMapAddress != null || NetworkMapService.type in advertisedServices.map { it.type }) {
|
||||||
"Initial network map address must indicate a node that provides a network map service"
|
"Initial network map address must indicate a node that provides a network map service"
|
||||||
}
|
}
|
||||||
@ -604,7 +604,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendNetworkMapRegistration(networkMapAddress: SingleMessageRecipient): ListenableFuture<RegistrationResponse> {
|
private fun sendNetworkMapRegistration(networkMapAddress: SingleMessageRecipient): CordaFuture<RegistrationResponse> {
|
||||||
// Register this node against the network
|
// Register this node against the network
|
||||||
val instant = platformClock.instant()
|
val instant = platformClock.instant()
|
||||||
val expires = instant + NetworkMapService.DEFAULT_EXPIRATION_PERIOD
|
val expires = instant + NetworkMapService.DEFAULT_EXPIRATION_PERIOD
|
||||||
@ -618,7 +618,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
protected abstract fun myAddresses(): List<NetworkHostAndPort>
|
protected abstract fun myAddresses(): List<NetworkHostAndPort>
|
||||||
|
|
||||||
/** This is overriden by the mock node implementation to enable operation without any network map service */
|
/** This is overriden by the mock node implementation to enable operation without any network map service */
|
||||||
protected open fun noNetworkMapConfigured(): ListenableFuture<Unit> {
|
protected open fun noNetworkMapConfigured(): CordaFuture<Unit> {
|
||||||
// TODO: There should be a consistent approach to configuration error exceptions.
|
// 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 " +
|
throw IllegalStateException("Configuration error: this node isn't being asked to act as the network map, nor " +
|
||||||
"has any other map node been configured.")
|
"has any other map node been configured.")
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package net.corda.node.internal
|
package net.corda.node.internal
|
||||||
|
|
||||||
import com.codahale.metrics.JmxReporter
|
import com.codahale.metrics.JmxReporter
|
||||||
import com.google.common.util.concurrent.Futures
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.internal.concurrent.doneFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import net.corda.core.internal.concurrent.flatMap
|
||||||
import net.corda.core.flatMap
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
|
import net.corda.core.internal.concurrent.thenMatch
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.serialization.SerializationDefaults
|
import net.corda.core.serialization.SerializationDefaults
|
||||||
import net.corda.core.thenMatch
|
|
||||||
import net.corda.core.utilities.*
|
import net.corda.core.utilities.*
|
||||||
import net.corda.node.VersionInfo
|
import net.corda.node.VersionInfo
|
||||||
import net.corda.node.serialization.KryoServerSerializationScheme
|
import net.corda.node.serialization.KryoServerSerializationScheme
|
||||||
@ -252,8 +252,8 @@ open class Node(override val configuration: FullNodeConfiguration,
|
|||||||
* Insert an initial step in the registration process which will throw an exception if a non-recoverable error is
|
* Insert an initial step in the registration process which will throw an exception if a non-recoverable error is
|
||||||
* encountered when trying to connect to the network map node.
|
* encountered when trying to connect to the network map node.
|
||||||
*/
|
*/
|
||||||
override fun registerWithNetworkMap(): ListenableFuture<Unit> {
|
override fun registerWithNetworkMap(): CordaFuture<Unit> {
|
||||||
val networkMapConnection = messageBroker?.networkMapConnectionFuture ?: Futures.immediateFuture(Unit)
|
val networkMapConnection = messageBroker?.networkMapConnectionFuture ?: doneFuture(Unit)
|
||||||
return networkMapConnection.flatMap { super.registerWithNetworkMap() }
|
return networkMapConnection.flatMap { super.registerWithNetworkMap() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +292,8 @@ open class Node(override val configuration: FullNodeConfiguration,
|
|||||||
super.initialiseDatabasePersistence(insideTransaction)
|
super.initialiseDatabasePersistence(insideTransaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
val startupComplete: ListenableFuture<Unit> = SettableFuture.create()
|
private val _startupComplete = openFuture<Unit>()
|
||||||
|
val startupComplete: CordaFuture<Unit> get() = _startupComplete
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
if (initialiseSerialization) {
|
if (initialiseSerialization) {
|
||||||
@ -320,7 +321,7 @@ open class Node(override val configuration: FullNodeConfiguration,
|
|||||||
build().
|
build().
|
||||||
start()
|
start()
|
||||||
|
|
||||||
(startupComplete as SettableFuture<Unit>).set(Unit)
|
_startupComplete.set(Unit)
|
||||||
}
|
}
|
||||||
}, {})
|
}, {})
|
||||||
shutdownHook = addShutdownHook {
|
shutdownHook = addShutdownHook {
|
||||||
|
@ -5,10 +5,11 @@ import com.typesafe.config.ConfigException
|
|||||||
import joptsimple.OptionException
|
import joptsimple.OptionException
|
||||||
import net.corda.core.crypto.commonName
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.crypto.orgName
|
import net.corda.core.crypto.orgName
|
||||||
|
import net.corda.core.internal.concurrent.thenMatch
|
||||||
|
import net.corda.core.internal.createDirectories
|
||||||
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.then
|
|
||||||
import net.corda.core.thenMatch
|
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.node.*
|
import net.corda.node.*
|
||||||
import net.corda.node.serialization.NodeClock
|
import net.corda.node.serialization.NodeClock
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.node.services.api
|
package net.corda.node.services.api
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting
|
import com.google.common.annotations.VisibleForTesting
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.flows.FlowInitiator
|
import net.corda.core.flows.FlowInitiator
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
@ -36,7 +36,7 @@ interface NetworkMapCacheInternal : NetworkMapCache {
|
|||||||
* @param network the network messaging service.
|
* @param network the network messaging service.
|
||||||
* @param service the network map service to fetch current state from.
|
* @param service the network map service to fetch current state from.
|
||||||
*/
|
*/
|
||||||
fun deregisterForUpdates(network: MessagingService, service: NodeInfo): ListenableFuture<Unit>
|
fun deregisterForUpdates(network: MessagingService, service: NodeInfo): CordaFuture<Unit>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a network map service; fetches a copy of the latest map from the service and subscribes to any further
|
* Add a network map service; fetches a copy of the latest map from the service and subscribes to any further
|
||||||
@ -48,7 +48,7 @@ interface NetworkMapCacheInternal : NetworkMapCache {
|
|||||||
* version is less than or equal to the given version, no update is fetched.
|
* version is less than or equal to the given version, no update is fetched.
|
||||||
*/
|
*/
|
||||||
fun addMapService(network: MessagingService, networkMapAddress: SingleMessageRecipient,
|
fun addMapService(network: MessagingService, networkMapAddress: SingleMessageRecipient,
|
||||||
subscribe: Boolean, ifChangedSinceVer: Int? = null): ListenableFuture<Unit>
|
subscribe: Boolean, ifChangedSinceVer: Int? = null): CordaFuture<Unit>
|
||||||
|
|
||||||
/** Adds a node to the local cache (generally only used for adding ourselves). */
|
/** Adds a node to the local cache (generally only used for adding ourselves). */
|
||||||
fun addNode(node: NodeInfo)
|
fun addNode(node: NodeInfo)
|
||||||
|
@ -9,7 +9,6 @@ import net.corda.core.contracts.StateRef
|
|||||||
import net.corda.core.flows.FlowInitiator
|
import net.corda.core.flows.FlowInitiator
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.core.then
|
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.core.utilities.trace
|
import net.corda.core.utilities.trace
|
||||||
import net.corda.node.services.api.SchedulerService
|
import net.corda.node.services.api.SchedulerService
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package net.corda.node.services.messaging
|
package net.corda.node.services.messaging
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
|
||||||
import io.netty.handler.ssl.SslHandler
|
import io.netty.handler.ssl.SslHandler
|
||||||
import net.corda.core.*
|
import net.corda.core.*
|
||||||
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.crypto.X509Utilities.CORDA_CLIENT_TLS
|
import net.corda.core.crypto.X509Utilities.CORDA_CLIENT_TLS
|
||||||
import net.corda.core.crypto.X509Utilities.CORDA_ROOT_CA
|
import net.corda.core.crypto.X509Utilities.CORDA_ROOT_CA
|
||||||
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
import net.corda.core.internal.ThreadBox
|
import net.corda.core.internal.ThreadBox
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.internal.noneOrSingle
|
import net.corda.core.internal.noneOrSingle
|
||||||
@ -107,12 +108,12 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
private val mutex = ThreadBox(InnerState())
|
private val mutex = ThreadBox(InnerState())
|
||||||
private lateinit var activeMQServer: ActiveMQServer
|
private lateinit var activeMQServer: ActiveMQServer
|
||||||
val serverControl: ActiveMQServerControl get() = activeMQServer.activeMQServerControl
|
val serverControl: ActiveMQServerControl get() = activeMQServer.activeMQServerControl
|
||||||
private val _networkMapConnectionFuture = config.networkMapService?.let { SettableFuture.create<Unit>() }
|
private val _networkMapConnectionFuture = config.networkMapService?.let { openFuture<Unit>() }
|
||||||
/**
|
/**
|
||||||
* A [ListenableFuture] which completes when the server successfully connects to the network map node. If a
|
* A [ListenableFuture] which completes when the server successfully connects to the network map node. If a
|
||||||
* non-recoverable error is encountered then the Future will complete with an exception.
|
* non-recoverable error is encountered then the Future will complete with an exception.
|
||||||
*/
|
*/
|
||||||
val networkMapConnectionFuture: SettableFuture<Unit>? get() = _networkMapConnectionFuture
|
val networkMapConnectionFuture: CordaFuture<Unit>? get() = _networkMapConnectionFuture
|
||||||
private var networkChangeHandle: Subscription? = null
|
private var networkChangeHandle: Subscription? = null
|
||||||
private val nodeRunsNetworkMapService = config.networkMapService == null
|
private val nodeRunsNetworkMapService = config.networkMapService == null
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.corda.node.services.messaging
|
package net.corda.node.services.messaging
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.catch
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
import net.corda.core.messaging.MessageRecipients
|
import net.corda.core.messaging.MessageRecipients
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
import net.corda.core.node.services.PartyInfo
|
import net.corda.core.node.services.PartyInfo
|
||||||
@ -147,13 +147,13 @@ inline fun MessagingService.runOnNextMessage(topicSession: TopicSession, crossin
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [ListenableFuture] of the next message payload ([Message.data]) which is received on the given topic and sessionId.
|
* Returns a [CordaFuture] of the next message payload ([Message.data]) which is received on the given topic and sessionId.
|
||||||
* The payload is deserialized to an object of type [M]. Any exceptions thrown will be captured by the future.
|
* The payload is deserialized to an object of type [M]. Any exceptions thrown will be captured by the future.
|
||||||
*/
|
*/
|
||||||
fun <M : Any> MessagingService.onNext(topic: String, sessionId: Long): ListenableFuture<M> {
|
fun <M : Any> MessagingService.onNext(topic: String, sessionId: Long): CordaFuture<M> {
|
||||||
val messageFuture = SettableFuture.create<M>()
|
val messageFuture = openFuture<M>()
|
||||||
runOnNextMessage(topic, sessionId) { message ->
|
runOnNextMessage(topic, sessionId) { message ->
|
||||||
messageFuture.catch {
|
messageFuture.capture {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
message.data.deserialize<Any>() as M
|
message.data.deserialize<Any>() as M
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package net.corda.node.services.messaging
|
package net.corda.node.services.messaging
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.andForget
|
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.internal.concurrent.andForget
|
||||||
|
import net.corda.core.internal.concurrent.thenMatch
|
||||||
import net.corda.core.internal.ThreadBox
|
import net.corda.core.internal.ThreadBox
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.MessageRecipients
|
import net.corda.core.messaging.MessageRecipients
|
||||||
@ -11,12 +11,8 @@ import net.corda.core.messaging.RPCOps
|
|||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
import net.corda.core.node.services.PartyInfo
|
import net.corda.core.node.services.PartyInfo
|
||||||
import net.corda.core.node.services.TransactionVerifierService
|
import net.corda.core.node.services.TransactionVerifierService
|
||||||
import net.corda.core.thenMatch
|
|
||||||
import net.corda.core.transactions.LedgerTransaction
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.*
|
||||||
import net.corda.core.utilities.loggerFor
|
|
||||||
import net.corda.core.utilities.sequence
|
|
||||||
import net.corda.core.utilities.trace
|
|
||||||
import net.corda.node.VersionInfo
|
import net.corda.node.VersionInfo
|
||||||
import net.corda.node.services.RPCUserService
|
import net.corda.node.services.RPCUserService
|
||||||
import net.corda.node.services.api.MonitoringService
|
import net.corda.node.services.api.MonitoringService
|
||||||
@ -77,7 +73,7 @@ class NodeMessagingClient(override val config: NodeConfiguration,
|
|||||||
val myIdentity: PublicKey?,
|
val myIdentity: PublicKey?,
|
||||||
val nodeExecutor: AffinityExecutor.ServiceAffinityExecutor,
|
val nodeExecutor: AffinityExecutor.ServiceAffinityExecutor,
|
||||||
val database: CordaPersistence,
|
val database: CordaPersistence,
|
||||||
val networkMapRegistrationFuture: ListenableFuture<Unit>,
|
val networkMapRegistrationFuture: CordaFuture<Unit>,
|
||||||
val monitoringService: MonitoringService,
|
val monitoringService: MonitoringService,
|
||||||
advertisedAddress: NetworkHostAndPort = serverAddress
|
advertisedAddress: NetworkHostAndPort = serverAddress
|
||||||
) : ArtemisMessagingComponent(), MessagingService {
|
) : ArtemisMessagingComponent(), MessagingService {
|
||||||
|
@ -406,7 +406,7 @@ class ObservableContext(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object RpcServerObservableSerializer : Serializer<Observable<Any>>() {
|
object RpcServerObservableSerializer : Serializer<Observable<*>>() {
|
||||||
private object RpcObservableContextKey
|
private object RpcObservableContextKey
|
||||||
private val log = loggerFor<RpcServerObservableSerializer>()
|
private val log = loggerFor<RpcServerObservableSerializer>()
|
||||||
|
|
||||||
@ -414,11 +414,11 @@ object RpcServerObservableSerializer : Serializer<Observable<Any>>() {
|
|||||||
return RPC_SERVER_CONTEXT.withProperty(RpcServerObservableSerializer.RpcObservableContextKey, observableContext)
|
return RPC_SERVER_CONTEXT.withProperty(RpcServerObservableSerializer.RpcObservableContextKey, observableContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun read(kryo: Kryo?, input: Input?, type: Class<Observable<Any>>?): Observable<Any> {
|
override fun read(kryo: Kryo?, input: Input?, type: Class<Observable<*>>?): Observable<Any> {
|
||||||
throw UnsupportedOperationException()
|
throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(kryo: Kryo, output: Output, observable: Observable<Any>) {
|
override fun write(kryo: Kryo, output: Output, observable: Observable<*>) {
|
||||||
val observableId = RPCApi.ObservableId(random63BitValue())
|
val observableId = RPCApi.ObservableId(random63BitValue())
|
||||||
val observableContext = kryo.context[RpcObservableContextKey] as ObservableContext
|
val observableContext = kryo.context[RpcObservableContextKey] as ObservableContext
|
||||||
output.writeLong(observableId.toLong, true)
|
output.writeLong(observableId.toLong, true)
|
||||||
@ -426,8 +426,8 @@ object RpcServerObservableSerializer : Serializer<Observable<Any>>() {
|
|||||||
// We capture [observableContext] in the subscriber. Note that all synchronisation/kryo borrowing
|
// We capture [observableContext] in the subscriber. Note that all synchronisation/kryo borrowing
|
||||||
// must be done again within the subscriber
|
// must be done again within the subscriber
|
||||||
subscription = observable.materialize().subscribe(
|
subscription = observable.materialize().subscribe(
|
||||||
object : Subscriber<Notification<Any>>() {
|
object : Subscriber<Notification<*>>() {
|
||||||
override fun onNext(observation: Notification<Any>) {
|
override fun onNext(observation: Notification<*>) {
|
||||||
if (!isUnsubscribed) {
|
if (!isUnsubscribed) {
|
||||||
observableContext.observationSendExecutor.submit {
|
observableContext.observationSendExecutor.submit {
|
||||||
observableContext.sendMessage(RPCApi.ServerToClient.Observation(observableId, observation))
|
observableContext.sendMessage(RPCApi.ServerToClient.Observation(observableId, observation))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.corda.node.services.messaging
|
package net.corda.node.services.messaging
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.messaging.MessageRecipients
|
import net.corda.core.messaging.MessageRecipients
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
@ -16,12 +16,12 @@ interface ServiceRequestMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a [ServiceRequestMessage] to [target] and returns a [ListenableFuture] of the response.
|
* Sends a [ServiceRequestMessage] to [target] and returns a [CordaFuture] of the response.
|
||||||
* @param R The type of the response.
|
* @param R The type of the response.
|
||||||
*/
|
*/
|
||||||
fun <R : Any> MessagingService.sendRequest(topic: String,
|
fun <R : Any> MessagingService.sendRequest(topic: String,
|
||||||
request: ServiceRequestMessage,
|
request: ServiceRequestMessage,
|
||||||
target: MessageRecipients): ListenableFuture<R> {
|
target: MessageRecipients): CordaFuture<R> {
|
||||||
val responseFuture = onNext<R>(topic, request.sessionID)
|
val responseFuture = onNext<R>(topic, request.sessionID)
|
||||||
send(topic, DEFAULT_SESSION_ID, request, target)
|
send(topic, DEFAULT_SESSION_ID, request, target)
|
||||||
return responseFuture
|
return responseFuture
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package net.corda.node.services.network
|
package net.corda.node.services.network
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting
|
import com.google.common.annotations.VisibleForTesting
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
|
||||||
import net.corda.core.internal.bufferUntilSubscribed
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.map
|
import net.corda.core.internal.concurrent.map
|
||||||
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
import net.corda.core.messaging.DataFeed
|
import net.corda.core.messaging.DataFeed
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
@ -55,8 +55,8 @@ open class InMemoryNetworkMapCache(private val serviceHub: ServiceHub?) : Single
|
|||||||
override val changed: Observable<MapChange> = _changed.wrapWithDatabaseTransaction()
|
override val changed: Observable<MapChange> = _changed.wrapWithDatabaseTransaction()
|
||||||
private val changePublisher: rx.Observer<MapChange> get() = _changed.bufferUntilDatabaseCommit()
|
private val changePublisher: rx.Observer<MapChange> get() = _changed.bufferUntilDatabaseCommit()
|
||||||
|
|
||||||
private val _registrationFuture = SettableFuture.create<Unit>()
|
private val _registrationFuture = openFuture<Void?>()
|
||||||
override val mapServiceRegistered: ListenableFuture<Unit> get() = _registrationFuture
|
override val mapServiceRegistered: CordaFuture<Void?> get() = _registrationFuture
|
||||||
|
|
||||||
private var registeredForPush = false
|
private var registeredForPush = false
|
||||||
protected var registeredNodes: MutableMap<PublicKey, NodeInfo> = Collections.synchronizedMap(HashMap())
|
protected var registeredNodes: MutableMap<PublicKey, NodeInfo> = Collections.synchronizedMap(HashMap())
|
||||||
@ -96,7 +96,7 @@ open class InMemoryNetworkMapCache(private val serviceHub: ServiceHub?) : Single
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun addMapService(network: MessagingService, networkMapAddress: SingleMessageRecipient, subscribe: Boolean,
|
override fun addMapService(network: MessagingService, networkMapAddress: SingleMessageRecipient, subscribe: Boolean,
|
||||||
ifChangedSinceVer: Int?): ListenableFuture<Unit> {
|
ifChangedSinceVer: Int?): CordaFuture<Unit> {
|
||||||
if (subscribe && !registeredForPush) {
|
if (subscribe && !registeredForPush) {
|
||||||
// Add handler to the network, for updates received from the remote network map service.
|
// Add handler to the network, for updates received from the remote network map service.
|
||||||
network.addMessageHandler(NetworkMapService.PUSH_TOPIC, DEFAULT_SESSION_ID) { message, _ ->
|
network.addMessageHandler(NetworkMapService.PUSH_TOPIC, DEFAULT_SESSION_ID) { message, _ ->
|
||||||
@ -122,7 +122,7 @@ open class InMemoryNetworkMapCache(private val serviceHub: ServiceHub?) : Single
|
|||||||
nodes?.forEach { processRegistration(it) }
|
nodes?.forEach { processRegistration(it) }
|
||||||
Unit
|
Unit
|
||||||
}
|
}
|
||||||
_registrationFuture.setFuture(future)
|
_registrationFuture.captureLater(future.map { null })
|
||||||
|
|
||||||
return future
|
return future
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ open class InMemoryNetworkMapCache(private val serviceHub: ServiceHub?) : Single
|
|||||||
* Unsubscribes from updates from the given map service.
|
* Unsubscribes from updates from the given map service.
|
||||||
* @param service the network map service to listen to updates from.
|
* @param service the network map service to listen to updates from.
|
||||||
*/
|
*/
|
||||||
override fun deregisterForUpdates(network: MessagingService, service: NodeInfo): ListenableFuture<Unit> {
|
override fun deregisterForUpdates(network: MessagingService, service: NodeInfo): CordaFuture<Unit> {
|
||||||
// Fetch the network map and register for updates at the same time
|
// Fetch the network map and register for updates at the same time
|
||||||
val req = NetworkMapService.SubscribeRequest(false, network.myAddress)
|
val req = NetworkMapService.SubscribeRequest(false, network.myAddress)
|
||||||
// `network.getAddressOfParty(partyInfo)` is a work-around for MockNetwork and InMemoryMessaging to get rid of SingleMessageRecipient in NodeInfo.
|
// `network.getAddressOfParty(partyInfo)` is a work-around for MockNetwork and InMemoryMessaging to get rid of SingleMessageRecipient in NodeInfo.
|
||||||
@ -157,7 +157,7 @@ open class InMemoryNetworkMapCache(private val serviceHub: ServiceHub?) : Single
|
|||||||
val future = network.sendRequest<SubscribeResponse>(NetworkMapService.SUBSCRIPTION_TOPIC, req, address).map {
|
val future = network.sendRequest<SubscribeResponse>(NetworkMapService.SUBSCRIPTION_TOPIC, req, address).map {
|
||||||
if (it.confirmed) Unit else throw NetworkCacheError.DeregistrationFailed()
|
if (it.confirmed) Unit else throw NetworkCacheError.DeregistrationFailed()
|
||||||
}
|
}
|
||||||
_registrationFuture.setFuture(future)
|
_registrationFuture.captureLater(future.map { null })
|
||||||
return future
|
return future
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,6 +181,6 @@ open class InMemoryNetworkMapCache(private val serviceHub: ServiceHub?) : Single
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
override fun runWithoutMapService() {
|
override fun runWithoutMapService() {
|
||||||
_registrationFuture.set(Unit)
|
_registrationFuture.set(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,14 @@ import co.paralleluniverse.fibers.Fiber
|
|||||||
import co.paralleluniverse.fibers.FiberScheduler
|
import co.paralleluniverse.fibers.FiberScheduler
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import co.paralleluniverse.strands.Strand
|
import co.paralleluniverse.strands.Strand
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.flows.*
|
import net.corda.core.flows.*
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FlowStateMachine
|
import net.corda.core.internal.FlowStateMachine
|
||||||
|
import net.corda.core.internal.concurrent.OpenFuture
|
||||||
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
import net.corda.core.internal.abbreviate
|
import net.corda.core.internal.abbreviate
|
||||||
import net.corda.core.internal.staticField
|
import net.corda.core.internal.staticField
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
@ -76,10 +77,10 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
|
|||||||
*/
|
*/
|
||||||
override val logger: Logger = LoggerFactory.getLogger("net.corda.flow.$id")
|
override val logger: Logger = LoggerFactory.getLogger("net.corda.flow.$id")
|
||||||
|
|
||||||
@Transient private var _resultFuture: SettableFuture<R>? = SettableFuture.create<R>()
|
@Transient private var _resultFuture: OpenFuture<R>? = openFuture()
|
||||||
/** This future will complete when the call method returns. */
|
/** This future will complete when the call method returns. */
|
||||||
override val resultFuture: ListenableFuture<R>
|
override val resultFuture: CordaFuture<R>
|
||||||
get() = _resultFuture ?: SettableFuture.create<R>().also { _resultFuture = it }
|
get() = _resultFuture ?: openFuture<R>().also { _resultFuture = it }
|
||||||
|
|
||||||
// This state IS serialised, as we need it to know what the fiber is waiting for.
|
// This state IS serialised, as we need it to know what the fiber is waiting for.
|
||||||
internal val openSessions = HashMap<Pair<FlowLogic<*>, Party>, FlowSession>()
|
internal val openSessions = HashMap<Pair<FlowLogic<*>, Party>, FlowSession>()
|
||||||
|
@ -6,8 +6,8 @@ import co.paralleluniverse.strands.Strand
|
|||||||
import com.codahale.metrics.Gauge
|
import com.codahale.metrics.Gauge
|
||||||
import com.esotericsoftware.kryo.KryoException
|
import com.esotericsoftware.kryo.KryoException
|
||||||
import com.google.common.collect.HashMultimap
|
import com.google.common.collect.HashMultimap
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
|
||||||
import com.google.common.util.concurrent.MoreExecutors
|
import com.google.common.util.concurrent.MoreExecutors
|
||||||
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.flows.FlowException
|
import net.corda.core.flows.FlowException
|
||||||
@ -22,7 +22,6 @@ import net.corda.core.messaging.DataFeed
|
|||||||
import net.corda.core.serialization.*
|
import net.corda.core.serialization.*
|
||||||
import net.corda.core.serialization.SerializationDefaults.CHECKPOINT_CONTEXT
|
import net.corda.core.serialization.SerializationDefaults.CHECKPOINT_CONTEXT
|
||||||
import net.corda.core.serialization.SerializationDefaults.SERIALIZATION_FACTORY
|
import net.corda.core.serialization.SerializationDefaults.SERIALIZATION_FACTORY
|
||||||
import net.corda.core.then
|
|
||||||
import net.corda.core.utilities.Try
|
import net.corda.core.utilities.Try
|
||||||
import net.corda.core.utilities.debug
|
import net.corda.core.utilities.debug
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
@ -144,7 +143,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal,
|
|||||||
fun findServices(predicate: (Any) -> Boolean) = tokenizableServices.filter(predicate)
|
fun findServices(predicate: (Any) -> Boolean) = tokenizableServices.filter(predicate)
|
||||||
|
|
||||||
/** Returns a list of all state machines executing the given flow logic at the top level (subflows do not count) */
|
/** Returns a list of all state machines executing the given flow logic at the top level (subflows do not count) */
|
||||||
fun <P : FlowLogic<T>, T> findStateMachines(flowClass: Class<P>): List<Pair<P, ListenableFuture<T>>> {
|
fun <P : FlowLogic<T>, T> findStateMachines(flowClass: Class<P>): List<Pair<P, CordaFuture<T>>> {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return mutex.locked {
|
return mutex.locked {
|
||||||
stateMachines.keys.mapNotNull {
|
stateMachines.keys.mapNotNull {
|
||||||
|
@ -5,7 +5,6 @@ import com.google.common.util.concurrent.SettableFuture
|
|||||||
import net.corda.core.crypto.DigitalSignature
|
import net.corda.core.crypto.DigitalSignature
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.NotaryException
|
import net.corda.core.flows.NotaryException
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.node.services.NotaryService
|
import net.corda.core.node.services.NotaryService
|
||||||
import net.corda.core.node.services.TimeWindowChecker
|
import net.corda.core.node.services.TimeWindowChecker
|
||||||
@ -13,6 +12,7 @@ import net.corda.core.serialization.deserialize
|
|||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.transactions.FilteredTransaction
|
import net.corda.core.transactions.FilteredTransaction
|
||||||
import net.corda.core.utilities.debug
|
import net.corda.core.utilities.debug
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.core.utilities.unwrap
|
import net.corda.core.utilities.unwrap
|
||||||
import net.corda.node.services.api.ServiceHubInternal
|
import net.corda.node.services.api.ServiceHubInternal
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.node.services.transactions
|
package net.corda.node.services.transactions
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
|
||||||
import com.google.common.util.concurrent.MoreExecutors
|
import com.google.common.util.concurrent.MoreExecutors
|
||||||
|
import net.corda.core.internal.concurrent.fork
|
||||||
import net.corda.core.node.services.TransactionVerifierService
|
import net.corda.core.node.services.TransactionVerifierService
|
||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.core.transactions.LedgerTransaction
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
@ -10,9 +10,5 @@ import java.util.concurrent.Executors
|
|||||||
class InMemoryTransactionVerifierService(numberOfWorkers: Int) : SingletonSerializeAsToken(), TransactionVerifierService {
|
class InMemoryTransactionVerifierService(numberOfWorkers: Int) : SingletonSerializeAsToken(), TransactionVerifierService {
|
||||||
private val workerPool = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(numberOfWorkers))
|
private val workerPool = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(numberOfWorkers))
|
||||||
|
|
||||||
override fun verify(transaction: LedgerTransaction): ListenableFuture<*> {
|
override fun verify(transaction: LedgerTransaction) = workerPool.fork(transaction::verify)
|
||||||
return workerPool.submit {
|
|
||||||
transaction.verify()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,12 @@ package net.corda.node.services.transactions
|
|||||||
|
|
||||||
import com.codahale.metrics.Gauge
|
import com.codahale.metrics.Gauge
|
||||||
import com.codahale.metrics.Timer
|
import com.codahale.metrics.Timer
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.node.services.TransactionVerifierService
|
import net.corda.core.node.services.TransactionVerifierService
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
|
import net.corda.core.internal.concurrent.OpenFuture
|
||||||
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.core.transactions.LedgerTransaction
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
@ -24,7 +25,7 @@ abstract class OutOfProcessTransactionVerifierService(
|
|||||||
|
|
||||||
private data class VerificationHandle(
|
private data class VerificationHandle(
|
||||||
val transactionId: SecureHash,
|
val transactionId: SecureHash,
|
||||||
val resultFuture: SettableFuture<Unit>,
|
val resultFuture: OpenFuture<Unit>,
|
||||||
val durationTimerContext: Timer.Context
|
val durationTimerContext: Timer.Context
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -61,9 +62,9 @@ abstract class OutOfProcessTransactionVerifierService(
|
|||||||
|
|
||||||
abstract fun sendRequest(nonce: Long, transaction: LedgerTransaction)
|
abstract fun sendRequest(nonce: Long, transaction: LedgerTransaction)
|
||||||
|
|
||||||
override fun verify(transaction: LedgerTransaction): ListenableFuture<*> {
|
override fun verify(transaction: LedgerTransaction): CordaFuture<*> {
|
||||||
log.info("Verifying ${transaction.id}")
|
log.info("Verifying ${transaction.id}")
|
||||||
val future = SettableFuture.create<Unit>()
|
val future = openFuture<Unit>()
|
||||||
val nonce = random63BitValue()
|
val nonce = random63BitValue()
|
||||||
verificationHandles[nonce] = VerificationHandle(transaction.id, future, durationTimer.time())
|
verificationHandles[nonce] = VerificationHandle(transaction.id, future, durationTimer.time())
|
||||||
sendRequest(nonce, transaction)
|
sendRequest(nonce, transaction)
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
package net.corda.node.shell
|
package net.corda.node.shell
|
||||||
|
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
|
||||||
import net.corda.core.crypto.commonName
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.flows.FlowInitiator
|
import net.corda.core.flows.FlowInitiator
|
||||||
import net.corda.core.flows.StateMachineRunId
|
import net.corda.core.flows.StateMachineRunId
|
||||||
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
import net.corda.core.messaging.StateMachineUpdate
|
import net.corda.core.messaging.StateMachineUpdate
|
||||||
import net.corda.core.messaging.StateMachineUpdate.Added
|
import net.corda.core.messaging.StateMachineUpdate.Added
|
||||||
import net.corda.core.messaging.StateMachineUpdate.Removed
|
import net.corda.core.messaging.StateMachineUpdate.Removed
|
||||||
import net.corda.core.then
|
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.utilities.Try
|
import net.corda.core.utilities.Try
|
||||||
import org.crsh.text.Color
|
import org.crsh.text.Color
|
||||||
@ -22,7 +21,7 @@ import rx.Subscriber
|
|||||||
class FlowWatchPrintingSubscriber(private val toStream: RenderPrintWriter) : Subscriber<Any>() {
|
class FlowWatchPrintingSubscriber(private val toStream: RenderPrintWriter) : Subscriber<Any>() {
|
||||||
private val indexMap = HashMap<StateMachineRunId, Int>()
|
private val indexMap = HashMap<StateMachineRunId, Int>()
|
||||||
private val table = createStateMachinesTable()
|
private val table = createStateMachinesTable()
|
||||||
val future: SettableFuture<Unit> = SettableFuture.create()
|
val future = openFuture<Unit>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// The future is public and can be completed by something else to indicate we don't wish to follow
|
// The future is public and can be completed by something else to indicate we don't wish to follow
|
||||||
|
@ -7,16 +7,19 @@ import com.fasterxml.jackson.databind.*
|
|||||||
import com.fasterxml.jackson.databind.module.SimpleModule
|
import com.fasterxml.jackson.databind.module.SimpleModule
|
||||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
|
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
|
||||||
import com.google.common.io.Closeables
|
import com.google.common.io.Closeables
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
|
||||||
import net.corda.core.*
|
|
||||||
import net.corda.core.contracts.UniqueIdentifier
|
import net.corda.core.contracts.UniqueIdentifier
|
||||||
import net.corda.core.flows.FlowInitiator
|
import net.corda.core.flows.FlowInitiator
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
|
import net.corda.core.internal.FlowStateMachine
|
||||||
|
import net.corda.core.internal.concurrent.OpenFuture
|
||||||
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
|
import net.corda.core.internal.createDirectories
|
||||||
|
import net.corda.core.internal.div
|
||||||
|
import net.corda.core.internal.write
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.StateMachineUpdate
|
import net.corda.core.messaging.StateMachineUpdate
|
||||||
import net.corda.core.then
|
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.jackson.JacksonSupport
|
import net.corda.jackson.JacksonSupport
|
||||||
import net.corda.jackson.StringToMethodCallParser
|
import net.corda.jackson.StringToMethodCallParser
|
||||||
@ -382,7 +385,7 @@ object InteractiveShell {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun printAndFollowRPCResponse(response: Any?, toStream: PrintWriter): ListenableFuture<Unit>? {
|
private fun printAndFollowRPCResponse(response: Any?, toStream: PrintWriter): CordaFuture<Unit>? {
|
||||||
val printerFun = { obj: Any? -> yamlMapper.writeValueAsString(obj) }
|
val printerFun = { obj: Any? -> yamlMapper.writeValueAsString(obj) }
|
||||||
toStream.println(printerFun(response))
|
toStream.println(printerFun(response))
|
||||||
toStream.flush()
|
toStream.flush()
|
||||||
@ -391,7 +394,7 @@ object InteractiveShell {
|
|||||||
|
|
||||||
private class PrintingSubscriber(private val printerFun: (Any?) -> String, private val toStream: PrintWriter) : Subscriber<Any>() {
|
private class PrintingSubscriber(private val printerFun: (Any?) -> String, private val toStream: PrintWriter) : Subscriber<Any>() {
|
||||||
private var count = 0
|
private var count = 0
|
||||||
val future: SettableFuture<Unit> = SettableFuture.create()
|
val future = openFuture<Unit>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// The future is public and can be completed by something else to indicate we don't wish to follow
|
// The future is public and can be completed by something else to indicate we don't wish to follow
|
||||||
@ -422,7 +425,7 @@ object InteractiveShell {
|
|||||||
|
|
||||||
// Kotlin bug: USELESS_CAST warning is generated below but the IDE won't let us remove it.
|
// Kotlin bug: USELESS_CAST warning is generated below but the IDE won't let us remove it.
|
||||||
@Suppress("USELESS_CAST", "UNCHECKED_CAST")
|
@Suppress("USELESS_CAST", "UNCHECKED_CAST")
|
||||||
private fun maybeFollow(response: Any?, printerFun: (Any?) -> String, toStream: PrintWriter): SettableFuture<Unit>? {
|
private fun maybeFollow(response: Any?, printerFun: (Any?) -> String, toStream: PrintWriter): OpenFuture<Unit>? {
|
||||||
// Match on a couple of common patterns for "important" observables. It's tough to do this in a generic
|
// Match on a couple of common patterns for "important" observables. It's tough to do this in a generic
|
||||||
// way because observables can be embedded anywhere in the object graph, and can emit other arbitrary
|
// way because observables can be embedded anywhere in the object graph, and can emit other arbitrary
|
||||||
// object graphs that contain yet more observables. So we just look for top level responses that follow
|
// object graphs that contain yet more observables. So we just look for top level responses that follow
|
||||||
|
@ -4,7 +4,6 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import co.paralleluniverse.strands.SettableFuture
|
import co.paralleluniverse.strands.SettableFuture
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.internal.until
|
import net.corda.core.internal.until
|
||||||
import net.corda.core.then
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscriber
|
import rx.Subscriber
|
||||||
import rx.subscriptions.Subscriptions
|
import rx.subscriptions.Subscriptions
|
||||||
@ -12,7 +11,6 @@ import java.time.Clock
|
|||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.concurrent.*
|
import java.util.concurrent.*
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
import java.util.function.BiConsumer
|
|
||||||
import com.google.common.util.concurrent.SettableFuture as GuavaSettableFuture
|
import com.google.common.util.concurrent.SettableFuture as GuavaSettableFuture
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,17 +104,11 @@ fun Clock.awaitWithDeadline(deadline: Instant, future: Future<*> = GuavaSettable
|
|||||||
* We need this so that we do not block the actual thread when calling get(), but instead allow a Quasar context
|
* We need this so that we do not block the actual thread when calling get(), but instead allow a Quasar context
|
||||||
* switch. There's no need to checkpoint our Fibers as there's no external effect of waiting.
|
* switch. There's no need to checkpoint our Fibers as there's no external effect of waiting.
|
||||||
*/
|
*/
|
||||||
private fun <T : Any> makeStrandFriendlySettableFuture(future: Future<T>): SettableFuture<Boolean> {
|
private fun <T : Any> makeStrandFriendlySettableFuture(future: Future<T>) = SettableFuture<Boolean>().also { g ->
|
||||||
return if (future is ListenableFuture) {
|
when (future) {
|
||||||
val settable = SettableFuture<Boolean>()
|
is ListenableFuture -> future.addListener(Runnable { g.set(true) }, Executor { it.run() })
|
||||||
future.then { settable.set(true) }
|
is CompletionStage<*> -> future.whenComplete { _, _ -> g.set(true) }
|
||||||
settable
|
else -> throw IllegalArgumentException("Cannot make future $future Fiber friendly.")
|
||||||
} else if (future is CompletableFuture) {
|
|
||||||
val settable = SettableFuture<Boolean>()
|
|
||||||
future.whenComplete(BiConsumer { _, _ -> settable.set(true) })
|
|
||||||
settable
|
|
||||||
} else {
|
|
||||||
throw IllegalArgumentException("Cannot make future $future Fiber friendly.")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,13 +7,13 @@ import net.corda.core.crypto.isFulfilledBy
|
|||||||
import net.corda.core.crypto.keys
|
import net.corda.core.crypto.keys
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.StateMachineRunId
|
import net.corda.core.flows.StateMachineRunId
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.messaging.*
|
import net.corda.core.messaging.*
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.node.services.queryBy
|
import net.corda.core.node.services.queryBy
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
import net.corda.core.transactions.SignedTransaction
|
|
||||||
import net.corda.flows.CashIssueFlow
|
import net.corda.flows.CashIssueFlow
|
||||||
import net.corda.flows.CashPaymentFlow
|
import net.corda.flows.CashPaymentFlow
|
||||||
import net.corda.node.internal.CordaRPCOpsImpl
|
import net.corda.node.internal.CordaRPCOpsImpl
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.node
|
package net.corda.node
|
||||||
|
|
||||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
|
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.flows.FlowInitiator
|
import net.corda.core.flows.FlowInitiator
|
||||||
@ -92,7 +92,7 @@ class InteractiveShellTest {
|
|||||||
get() = throw UnsupportedOperationException()
|
get() = throw UnsupportedOperationException()
|
||||||
override val id: StateMachineRunId
|
override val id: StateMachineRunId
|
||||||
get() = throw UnsupportedOperationException()
|
get() = throw UnsupportedOperationException()
|
||||||
override val resultFuture: ListenableFuture<Any?>
|
override val resultFuture: CordaFuture<Any?>
|
||||||
get() = throw UnsupportedOperationException()
|
get() = throw UnsupportedOperationException()
|
||||||
override val flowInitiator: FlowInitiator
|
override val flowInitiator: FlowInitiator
|
||||||
get() = throw UnsupportedOperationException()
|
get() = throw UnsupportedOperationException()
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.node.messaging
|
|||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.contracts.CommercialPaper
|
import net.corda.contracts.CommercialPaper
|
||||||
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.contracts.asset.CASH
|
import net.corda.contracts.asset.CASH
|
||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.contracts.asset.`issued by`
|
import net.corda.contracts.asset.`issued by`
|
||||||
@ -13,14 +14,13 @@ import net.corda.core.flows.FlowLogic
|
|||||||
import net.corda.core.flows.InitiatedBy
|
import net.corda.core.flows.InitiatedBy
|
||||||
import net.corda.core.flows.InitiatingFlow
|
import net.corda.core.flows.InitiatingFlow
|
||||||
import net.corda.core.flows.StateMachineRunId
|
import net.corda.core.flows.StateMachineRunId
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.AnonymousParty
|
import net.corda.core.identity.AnonymousParty
|
||||||
import net.corda.core.identity.AnonymousPartyAndPath
|
import net.corda.core.identity.AnonymousPartyAndPath
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FlowStateMachine
|
import net.corda.core.internal.FlowStateMachine
|
||||||
|
import net.corda.core.internal.concurrent.map
|
||||||
import net.corda.core.internal.rootCause
|
import net.corda.core.internal.rootCause
|
||||||
import net.corda.core.map
|
|
||||||
import net.corda.core.messaging.DataFeed
|
import net.corda.core.messaging.DataFeed
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
import net.corda.core.messaging.StateMachineTransactionMapping
|
import net.corda.core.messaging.StateMachineTransactionMapping
|
||||||
@ -32,6 +32,7 @@ import net.corda.core.transactions.SignedTransaction
|
|||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
import net.corda.core.utilities.days
|
import net.corda.core.utilities.days
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.toNonEmptySet
|
import net.corda.core.utilities.toNonEmptySet
|
||||||
import net.corda.core.utilities.unwrap
|
import net.corda.core.utilities.unwrap
|
||||||
import net.corda.flows.TwoPartyTradeFlow.Buyer
|
import net.corda.flows.TwoPartyTradeFlow.Buyer
|
||||||
@ -57,7 +58,6 @@ import java.io.ByteArrayOutputStream
|
|||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.Future
|
|
||||||
import java.util.jar.JarOutputStream
|
import java.util.jar.JarOutputStream
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -505,8 +505,8 @@ class TwoPartyTradeFlowTests {
|
|||||||
|
|
||||||
private data class RunResult(
|
private data class RunResult(
|
||||||
// The buyer is not created immediately, only when the seller starts running
|
// The buyer is not created immediately, only when the seller starts running
|
||||||
val buyer: Future<FlowStateMachine<*>>,
|
val buyer: CordaFuture<FlowStateMachine<*>>,
|
||||||
val sellerResult: Future<SignedTransaction>,
|
val sellerResult: CordaFuture<SignedTransaction>,
|
||||||
val sellerId: StateMachineRunId
|
val sellerId: StateMachineRunId
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -4,11 +4,11 @@ import net.corda.core.contracts.*
|
|||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.flows.NotaryChangeFlow
|
import net.corda.core.flows.NotaryChangeFlow
|
||||||
import net.corda.core.flows.StateReplacementException
|
import net.corda.core.flows.StateReplacementException
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.node.internal.AbstractNode
|
import net.corda.node.internal.AbstractNode
|
||||||
import net.corda.node.services.network.NetworkMapService
|
import net.corda.node.services.network.NetworkMapService
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package net.corda.node.services.messaging
|
package net.corda.node.services.messaging
|
||||||
|
|
||||||
import com.codahale.metrics.MetricRegistry
|
import com.codahale.metrics.MetricRegistry
|
||||||
import com.google.common.util.concurrent.Futures
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
|
import net.corda.core.internal.concurrent.doneFuture
|
||||||
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.node.services.RPCUserService
|
import net.corda.node.services.RPCUserService
|
||||||
@ -31,7 +31,6 @@ import org.junit.Rule
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.TemporaryFolder
|
import org.junit.rules.TemporaryFolder
|
||||||
import java.net.ServerSocket
|
import java.net.ServerSocket
|
||||||
import java.util.*
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue
|
import java.util.concurrent.LinkedBlockingQueue
|
||||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
@ -50,7 +49,7 @@ class ArtemisMessagingTests : TestDependencyInjectionBase() {
|
|||||||
lateinit var config: NodeConfiguration
|
lateinit var config: NodeConfiguration
|
||||||
lateinit var database: CordaPersistence
|
lateinit var database: CordaPersistence
|
||||||
lateinit var userService: RPCUserService
|
lateinit var userService: RPCUserService
|
||||||
lateinit var networkMapRegistrationFuture: ListenableFuture<Unit>
|
lateinit var networkMapRegistrationFuture: CordaFuture<Unit>
|
||||||
|
|
||||||
var messagingClient: NodeMessagingClient? = null
|
var messagingClient: NodeMessagingClient? = null
|
||||||
var messagingServer: ArtemisMessagingServer? = null
|
var messagingServer: ArtemisMessagingServer? = null
|
||||||
@ -71,7 +70,7 @@ class ArtemisMessagingTests : TestDependencyInjectionBase() {
|
|||||||
myLegalName = ALICE.name)
|
myLegalName = ALICE.name)
|
||||||
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
||||||
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties())
|
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties())
|
||||||
networkMapRegistrationFuture = Futures.immediateFuture(Unit)
|
networkMapRegistrationFuture = doneFuture(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@ -135,7 +134,7 @@ class ArtemisMessagingTests : TestDependencyInjectionBase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `client should be able to send message to itself before network map is available, and receive after`() {
|
fun `client should be able to send message to itself before network map is available, and receive after`() {
|
||||||
val settableFuture: SettableFuture<Unit> = SettableFuture.create()
|
val settableFuture = openFuture<Unit>()
|
||||||
networkMapRegistrationFuture = settableFuture
|
networkMapRegistrationFuture = settableFuture
|
||||||
|
|
||||||
val receivedMessages = LinkedBlockingQueue<Message>()
|
val receivedMessages = LinkedBlockingQueue<Message>()
|
||||||
@ -160,7 +159,7 @@ class ArtemisMessagingTests : TestDependencyInjectionBase() {
|
|||||||
fun `client should be able to send large numbers of messages to itself before network map is available and survive restart, then receive messages`() {
|
fun `client should be able to send large numbers of messages to itself before network map is available and survive restart, then receive messages`() {
|
||||||
// Crank the iteration up as high as you want... just takes longer to run.
|
// Crank the iteration up as high as you want... just takes longer to run.
|
||||||
val iterations = 100
|
val iterations = 100
|
||||||
networkMapRegistrationFuture = SettableFuture.create()
|
networkMapRegistrationFuture = openFuture()
|
||||||
|
|
||||||
val receivedMessages = LinkedBlockingQueue<Message>()
|
val receivedMessages = LinkedBlockingQueue<Message>()
|
||||||
|
|
||||||
@ -181,7 +180,7 @@ class ArtemisMessagingTests : TestDependencyInjectionBase() {
|
|||||||
messagingClient.stop()
|
messagingClient.stop()
|
||||||
messagingServer?.stop()
|
messagingServer?.stop()
|
||||||
|
|
||||||
networkMapRegistrationFuture = Futures.immediateFuture(Unit)
|
networkMapRegistrationFuture = doneFuture(Unit)
|
||||||
|
|
||||||
createAndStartClientAndServer(receivedMessages)
|
createAndStartClientAndServer(receivedMessages)
|
||||||
for (iter in 1..iterations) {
|
for (iter in 1..iterations) {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package net.corda.node.services.network
|
package net.corda.node.services.network
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.node.services.api.DEFAULT_SESSION_ID
|
import net.corda.node.services.api.DEFAULT_SESSION_ID
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.node.services.messaging.send
|
import net.corda.node.services.messaging.send
|
||||||
@ -210,7 +210,7 @@ abstract class AbstractNetworkMapServiceTest<out S : AbstractNetworkMapService>
|
|||||||
private var lastSerial = Long.MIN_VALUE
|
private var lastSerial = Long.MIN_VALUE
|
||||||
|
|
||||||
private fun MockNode.registration(addOrRemove: AddOrRemove,
|
private fun MockNode.registration(addOrRemove: AddOrRemove,
|
||||||
serial: Long? = null): ListenableFuture<RegistrationResponse> {
|
serial: Long? = null): CordaFuture<RegistrationResponse> {
|
||||||
val distinctSerial = if (serial == null) {
|
val distinctSerial = if (serial == null) {
|
||||||
++lastSerial
|
++lastSerial
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.corda.node.services.network
|
package net.corda.node.services.network
|
||||||
|
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.node.services.NetworkMapCache
|
import net.corda.core.node.services.NetworkMapCache
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.ALICE
|
import net.corda.testing.ALICE
|
||||||
import net.corda.testing.BOB
|
import net.corda.testing.BOB
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
|
@ -2,17 +2,16 @@ package net.corda.node.services.statemachine
|
|||||||
|
|
||||||
import co.paralleluniverse.fibers.Fiber
|
import co.paralleluniverse.fibers.Fiber
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.contracts.ContractState
|
import net.corda.core.contracts.ContractState
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.flatMap
|
|
||||||
import net.corda.core.flows.*
|
import net.corda.core.flows.*
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.map
|
import net.corda.core.internal.concurrent.flatMap
|
||||||
|
import net.corda.core.internal.concurrent.map
|
||||||
import net.corda.core.messaging.MessageRecipients
|
import net.corda.core.messaging.MessageRecipients
|
||||||
import net.corda.core.node.services.PartyInfo
|
import net.corda.core.node.services.PartyInfo
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
@ -25,6 +24,7 @@ import net.corda.core.transactions.TransactionBuilder
|
|||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
import net.corda.core.utilities.ProgressTracker.Change
|
import net.corda.core.utilities.ProgressTracker.Change
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.unwrap
|
import net.corda.core.utilities.unwrap
|
||||||
import net.corda.flows.CashIssueFlow
|
import net.corda.flows.CashIssueFlow
|
||||||
import net.corda.flows.CashPaymentFlow
|
import net.corda.flows.CashPaymentFlow
|
||||||
@ -706,13 +706,13 @@ class FlowFrameworkTests {
|
|||||||
return newNode.getSingleFlow<P>().first
|
return newNode.getSingleFlow<P>().first
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified P : FlowLogic<*>> MockNode.getSingleFlow(): Pair<P, ListenableFuture<*>> {
|
private inline fun <reified P : FlowLogic<*>> MockNode.getSingleFlow(): Pair<P, CordaFuture<*>> {
|
||||||
return smm.findStateMachines(P::class.java).single()
|
return smm.findStateMachines(P::class.java).single()
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified P : FlowLogic<*>> MockNode.registerFlowFactory(
|
private inline fun <reified P : FlowLogic<*>> MockNode.registerFlowFactory(
|
||||||
initiatingFlowClass: KClass<out FlowLogic<*>>,
|
initiatingFlowClass: KClass<out FlowLogic<*>>,
|
||||||
noinline flowFactory: (Party) -> P): ListenableFuture<P>
|
noinline flowFactory: (Party) -> P): CordaFuture<P>
|
||||||
{
|
{
|
||||||
val observable = internalRegisterFlowFactory(initiatingFlowClass.java, object : InitiatedFlowFactory<P> {
|
val observable = internalRegisterFlowFactory(initiatingFlowClass.java, object : InitiatedFlowFactory<P> {
|
||||||
override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): P {
|
override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): P {
|
||||||
@ -772,7 +772,7 @@ class FlowFrameworkTests {
|
|||||||
private infix fun MockNode.sent(message: SessionMessage): Pair<Int, SessionMessage> = Pair(id, message)
|
private infix fun MockNode.sent(message: SessionMessage): Pair<Int, SessionMessage> = Pair(id, message)
|
||||||
private infix fun Pair<Int, SessionMessage>.to(node: MockNode): SessionTransfer = SessionTransfer(first, second, node.network.myAddress)
|
private infix fun Pair<Int, SessionMessage>.to(node: MockNode): SessionTransfer = SessionTransfer(first, second, node.network.myAddress)
|
||||||
|
|
||||||
private val FlowLogic<*>.progressSteps: ListenableFuture<List<Notification<ProgressTracker.Step>>> get() {
|
private val FlowLogic<*>.progressSteps: CordaFuture<List<Notification<ProgressTracker.Step>>> get() {
|
||||||
return progressTracker!!.changes
|
return progressTracker!!.changes
|
||||||
.ofType(Change.Position::class.java)
|
.ofType(Change.Position::class.java)
|
||||||
.map { it.newStep }
|
.map { it.newStep }
|
||||||
|
@ -6,8 +6,8 @@ import io.atomix.copycat.client.CopycatClient
|
|||||||
import io.atomix.copycat.server.CopycatServer
|
import io.atomix.copycat.server.CopycatServer
|
||||||
import io.atomix.copycat.server.storage.Storage
|
import io.atomix.copycat.server.storage.Storage
|
||||||
import io.atomix.copycat.server.storage.StorageLevel
|
import io.atomix.copycat.server.storage.StorageLevel
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.node.services.network.NetworkMapService
|
import net.corda.node.services.network.NetworkMapService
|
||||||
import net.corda.node.utilities.CordaPersistence
|
import net.corda.node.utilities.CordaPersistence
|
||||||
import net.corda.node.utilities.configureDatabase
|
import net.corda.node.utilities.configureDatabase
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package net.corda.node.services.transactions
|
package net.corda.node.services.transactions
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
import net.corda.core.crypto.DigitalSignature
|
import net.corda.core.crypto.DigitalSignature
|
||||||
import net.corda.core.flows.NotaryError
|
import net.corda.core.flows.NotaryError
|
||||||
import net.corda.core.flows.NotaryException
|
import net.corda.core.flows.NotaryException
|
||||||
import net.corda.core.flows.NotaryFlow
|
import net.corda.core.flows.NotaryFlow
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.node.internal.AbstractNode
|
import net.corda.node.internal.AbstractNode
|
||||||
import net.corda.node.services.network.NetworkMapService
|
import net.corda.node.services.network.NetworkMapService
|
||||||
@ -132,7 +132,7 @@ class NotaryServiceTests {
|
|||||||
notaryError.conflict.verified()
|
notaryError.conflict.verified()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun runNotaryClient(stx: SignedTransaction): ListenableFuture<List<DigitalSignature.WithKey>> {
|
private fun runNotaryClient(stx: SignedTransaction): CordaFuture<List<DigitalSignature.WithKey>> {
|
||||||
val flow = NotaryFlow.Client(stx)
|
val flow = NotaryFlow.Client(stx)
|
||||||
val future = clientNode.services.startFlow(flow).resultFuture
|
val future = clientNode.services.startFlow(flow).resultFuture
|
||||||
mockNet.runNetwork()
|
mockNet.runNetwork()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.corda.node.services.transactions
|
package net.corda.node.services.transactions
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.contracts.Command
|
import net.corda.core.contracts.Command
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
@ -8,9 +8,9 @@ import net.corda.core.crypto.DigitalSignature
|
|||||||
import net.corda.core.flows.NotaryError
|
import net.corda.core.flows.NotaryError
|
||||||
import net.corda.core.flows.NotaryException
|
import net.corda.core.flows.NotaryException
|
||||||
import net.corda.core.flows.NotaryFlow
|
import net.corda.core.flows.NotaryFlow
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.node.internal.AbstractNode
|
import net.corda.node.internal.AbstractNode
|
||||||
import net.corda.node.services.issueInvalidState
|
import net.corda.node.services.issueInvalidState
|
||||||
@ -85,7 +85,7 @@ class ValidatingNotaryServiceTests {
|
|||||||
assertEquals(setOf(expectedMissingKey), missingKeys)
|
assertEquals(setOf(expectedMissingKey), missingKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun runClient(stx: SignedTransaction): ListenableFuture<List<DigitalSignature.WithKey>> {
|
private fun runClient(stx: SignedTransaction): CordaFuture<List<DigitalSignature.WithKey>> {
|
||||||
val flow = NotaryFlow.Client(stx)
|
val flow = NotaryFlow.Client(stx)
|
||||||
val future = clientNode.services.startFlow(flow).resultFuture
|
val future = clientNode.services.startFlow(flow).resultFuture
|
||||||
mockNet.runNetwork()
|
mockNet.runNetwork()
|
||||||
|
@ -5,7 +5,7 @@ import co.paralleluniverse.fibers.FiberExecutorScheduler
|
|||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import co.paralleluniverse.strands.Strand
|
import co.paralleluniverse.strands.Strand
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.hours
|
import net.corda.core.utilities.hours
|
||||||
import net.corda.core.utilities.minutes
|
import net.corda.core.utilities.minutes
|
||||||
import net.corda.testing.node.TestClock
|
import net.corda.testing.node.TestClock
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.corda.attachmentdemo
|
package net.corda.attachmentdemo
|
||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
|
import net.corda.core.internal.concurrent.transpose
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.DUMMY_BANK_A
|
import net.corda.testing.DUMMY_BANK_A
|
||||||
import net.corda.testing.DUMMY_BANK_B
|
import net.corda.testing.DUMMY_BANK_B
|
||||||
import net.corda.testing.DUMMY_NOTARY
|
import net.corda.testing.DUMMY_NOTARY
|
||||||
@ -19,11 +19,11 @@ class AttachmentDemoTest {
|
|||||||
val numOfExpectedBytes = 10_000_000
|
val numOfExpectedBytes = 10_000_000
|
||||||
driver(dsl = {
|
driver(dsl = {
|
||||||
val demoUser = listOf(User("demo", "demo", setOf(startFlowPermission<AttachmentDemoFlow>())))
|
val demoUser = listOf(User("demo", "demo", setOf(startFlowPermission<AttachmentDemoFlow>())))
|
||||||
val (nodeA, nodeB) = Futures.allAsList(
|
val (nodeA, nodeB) = listOf(
|
||||||
startNode(DUMMY_BANK_A.name, rpcUsers = demoUser),
|
startNode(DUMMY_BANK_A.name, rpcUsers = demoUser),
|
||||||
startNode(DUMMY_BANK_B.name, rpcUsers = demoUser),
|
startNode(DUMMY_BANK_B.name, rpcUsers = demoUser),
|
||||||
startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type)))
|
startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type)))
|
||||||
).getOrThrow()
|
).transpose().getOrThrow()
|
||||||
|
|
||||||
val senderThread = CompletableFuture.supplyAsync {
|
val senderThread = CompletableFuture.supplyAsync {
|
||||||
nodeA.rpcClientToNode().start(demoUser[0].username, demoUser[0].password).use {
|
nodeA.rpcClientToNode().start(demoUser[0].username, demoUser[0].password).use {
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
package net.corda.attachmentdemo
|
package net.corda.attachmentdemo
|
||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
|
||||||
import joptsimple.OptionParser
|
import joptsimple.OptionParser
|
||||||
import net.corda.client.rpc.CordaRPCClient
|
import net.corda.client.rpc.CordaRPCClient
|
||||||
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.contracts.Contract
|
import net.corda.core.contracts.Contract
|
||||||
import net.corda.core.contracts.ContractState
|
import net.corda.core.contracts.ContractState
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.flows.FinalityFlow
|
import net.corda.core.flows.FinalityFlow
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.StartableByRPC
|
import net.corda.core.flows.StartableByRPC
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.Emoji
|
import net.corda.core.internal.Emoji
|
||||||
@ -22,6 +21,7 @@ import net.corda.core.transactions.SignedTransaction
|
|||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.DUMMY_BANK_B
|
import net.corda.testing.DUMMY_BANK_B
|
||||||
import net.corda.testing.DUMMY_NOTARY
|
import net.corda.testing.DUMMY_NOTARY
|
||||||
import net.corda.testing.driver.poll
|
import net.corda.testing.driver.poll
|
||||||
@ -86,8 +86,8 @@ fun sender(rpc: CordaRPCOps, numOfClearBytes: Int = 1024) { // default size 1K.
|
|||||||
private fun sender(rpc: CordaRPCOps, inputStream: InputStream, hash: SecureHash.SHA256, executor: ScheduledExecutorService) {
|
private fun sender(rpc: CordaRPCOps, inputStream: InputStream, hash: SecureHash.SHA256, executor: ScheduledExecutorService) {
|
||||||
|
|
||||||
// Get the identity key of the other side (the recipient).
|
// Get the identity key of the other side (the recipient).
|
||||||
val notaryFuture: ListenableFuture<Party> = poll(executor, DUMMY_NOTARY.name.toString()) { rpc.partyFromX500Name(DUMMY_NOTARY.name) }
|
val notaryFuture: CordaFuture<Party> = poll(executor, DUMMY_NOTARY.name.toString()) { rpc.partyFromX500Name(DUMMY_NOTARY.name) }
|
||||||
val otherSideFuture: ListenableFuture<Party> = poll(executor, DUMMY_BANK_B.name.toString()) { rpc.partyFromX500Name(DUMMY_BANK_B.name) }
|
val otherSideFuture: CordaFuture<Party> = poll(executor, DUMMY_BANK_B.name.toString()) { rpc.partyFromX500Name(DUMMY_BANK_B.name) }
|
||||||
|
|
||||||
// Make sure we have the file in storage
|
// Make sure we have the file in storage
|
||||||
if (!rpc.attachmentExists(hash)) {
|
if (!rpc.attachmentExists(hash)) {
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package net.corda.bank
|
package net.corda.bank
|
||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
|
||||||
import net.corda.bank.api.BankOfCordaClientApi
|
import net.corda.bank.api.BankOfCordaClientApi
|
||||||
import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams
|
import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
|
import net.corda.core.internal.concurrent.transpose
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import net.corda.testing.driver.driver
|
||||||
import net.corda.node.services.transactions.SimpleNotaryService
|
import net.corda.node.services.transactions.SimpleNotaryService
|
||||||
import net.corda.testing.BOC
|
import net.corda.testing.BOC
|
||||||
import net.corda.testing.driver.driver
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
@ -15,10 +15,10 @@ class BankOfCordaHttpAPITest {
|
|||||||
@Test
|
@Test
|
||||||
fun `issuer flow via Http`() {
|
fun `issuer flow via Http`() {
|
||||||
driver(dsl = {
|
driver(dsl = {
|
||||||
val (nodeBankOfCorda) = Futures.allAsList(
|
val (nodeBankOfCorda) = listOf(
|
||||||
startNode(BOC.name, setOf(ServiceInfo(SimpleNotaryService.type))),
|
startNode(BOC.name, setOf(ServiceInfo(SimpleNotaryService.type))),
|
||||||
startNode(BIGCORP_LEGAL_NAME)
|
startNode(BIGCORP_LEGAL_NAME)
|
||||||
).getOrThrow()
|
).transpose().getOrThrow()
|
||||||
val anonymous = false
|
val anonymous = false
|
||||||
val nodeBankOfCordaApiAddr = startWebserver(nodeBankOfCorda).getOrThrow().listenAddress
|
val nodeBankOfCordaApiAddr = startWebserver(nodeBankOfCorda).getOrThrow().listenAddress
|
||||||
assertTrue(BankOfCordaClientApi(nodeBankOfCordaApiAddr).requestWebIssue(IssueRequestParams(1000, "USD", BIGCORP_LEGAL_NAME, "1", BOC.name, BOC.name, anonymous)))
|
assertTrue(BankOfCordaClientApi(nodeBankOfCordaApiAddr).requestWebIssue(IssueRequestParams(1000, "USD", BIGCORP_LEGAL_NAME, "1", BOC.name, BOC.name, anonymous)))
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package net.corda.bank
|
package net.corda.bank
|
||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
|
||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.messaging.vaultTrackBy
|
import net.corda.core.messaging.vaultTrackBy
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.node.services.vault.QueryCriteria
|
import net.corda.core.node.services.vault.QueryCriteria
|
||||||
|
import net.corda.core.internal.concurrent.transpose
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||||
import net.corda.node.services.startFlowPermission
|
import net.corda.node.services.startFlowPermission
|
||||||
import net.corda.node.services.transactions.SimpleNotaryService
|
import net.corda.node.services.transactions.SimpleNotaryService
|
||||||
@ -23,10 +23,10 @@ class BankOfCordaRPCClientTest {
|
|||||||
driver(dsl = {
|
driver(dsl = {
|
||||||
val bocManager = User("bocManager", "password1", permissions = setOf(startFlowPermission<IssuanceRequester>()))
|
val bocManager = User("bocManager", "password1", permissions = setOf(startFlowPermission<IssuanceRequester>()))
|
||||||
val bigCorpCFO = User("bigCorpCFO", "password2", permissions = emptySet())
|
val bigCorpCFO = User("bigCorpCFO", "password2", permissions = emptySet())
|
||||||
val (nodeBankOfCorda, nodeBigCorporation) = Futures.allAsList(
|
val (nodeBankOfCorda, nodeBigCorporation) = listOf(
|
||||||
startNode(BOC.name, setOf(ServiceInfo(SimpleNotaryService.type)), listOf(bocManager)),
|
startNode(BOC.name, setOf(ServiceInfo(SimpleNotaryService.type)), listOf(bocManager)),
|
||||||
startNode(BIGCORP_LEGAL_NAME, rpcUsers = listOf(bigCorpCFO))
|
startNode(BIGCORP_LEGAL_NAME, rpcUsers = listOf(bigCorpCFO))
|
||||||
).getOrThrow()
|
).transpose().getOrThrow()
|
||||||
|
|
||||||
// Bank of Corda RPC Client
|
// Bank of Corda RPC Client
|
||||||
val bocClient = nodeBankOfCorda.rpcClientToNode()
|
val bocClient = nodeBankOfCorda.rpcClientToNode()
|
||||||
|
@ -4,11 +4,11 @@ import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams
|
|||||||
import net.corda.client.rpc.CordaRPCClient
|
import net.corda.client.rpc.CordaRPCClient
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.currency
|
import net.corda.core.contracts.currency
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||||
import net.corda.testing.DUMMY_NOTARY
|
import net.corda.testing.DUMMY_NOTARY
|
||||||
import net.corda.testing.http.HttpApi
|
import net.corda.testing.http.HttpApi
|
||||||
|
@ -2,10 +2,10 @@ package net.corda.bank.api
|
|||||||
|
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.currency
|
import net.corda.core.contracts.currency
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package net.corda.irs
|
package net.corda.irs
|
||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
|
||||||
import net.corda.client.rpc.CordaRPCClient
|
import net.corda.client.rpc.CordaRPCClient
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.messaging.vaultTrackBy
|
import net.corda.core.messaging.vaultTrackBy
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.toFuture
|
import net.corda.core.toFuture
|
||||||
|
import net.corda.core.internal.concurrent.transpose
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.irs.api.NodeInterestRates
|
import net.corda.irs.api.NodeInterestRates
|
||||||
import net.corda.irs.contract.InterestRateSwap
|
import net.corda.irs.contract.InterestRateSwap
|
||||||
@ -37,19 +37,19 @@ class IRSDemoTest : IntegrationTestCategory {
|
|||||||
@Test
|
@Test
|
||||||
fun `runs IRS demo`() {
|
fun `runs IRS demo`() {
|
||||||
driver(useTestClock = true, isDebug = true) {
|
driver(useTestClock = true, isDebug = true) {
|
||||||
val (controller, nodeA, nodeB) = Futures.allAsList(
|
val (controller, nodeA, nodeB) = listOf(
|
||||||
startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.Oracle.type))),
|
startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.Oracle.type))),
|
||||||
startNode(DUMMY_BANK_A.name, rpcUsers = listOf(rpcUser)),
|
startNode(DUMMY_BANK_A.name, rpcUsers = listOf(rpcUser)),
|
||||||
startNode(DUMMY_BANK_B.name)
|
startNode(DUMMY_BANK_B.name)
|
||||||
).getOrThrow()
|
).transpose().getOrThrow()
|
||||||
|
|
||||||
println("All nodes started")
|
println("All nodes started")
|
||||||
|
|
||||||
val (controllerAddr, nodeAAddr, nodeBAddr) = Futures.allAsList(
|
val (controllerAddr, nodeAAddr, nodeBAddr) = listOf(
|
||||||
startWebserver(controller),
|
startWebserver(controller),
|
||||||
startWebserver(nodeA),
|
startWebserver(nodeA),
|
||||||
startWebserver(nodeB)
|
startWebserver(nodeB)
|
||||||
).getOrThrow().map { it.listenAddress }
|
).transpose().getOrThrow().map { it.listenAddress }
|
||||||
|
|
||||||
println("All webservers started")
|
println("All webservers started")
|
||||||
|
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
package net.corda.irs.api
|
package net.corda.irs.api
|
||||||
|
|
||||||
import net.corda.client.rpc.notUsed
|
|
||||||
import net.corda.core.contracts.filterStatesOfType
|
import net.corda.core.contracts.filterStatesOfType
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.messaging.vaultQueryBy
|
import net.corda.core.messaging.vaultQueryBy
|
||||||
import net.corda.core.node.services.vault.QueryCriteria
|
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.irs.contract.InterestRateSwap
|
import net.corda.irs.contract.InterestRateSwap
|
||||||
import net.corda.irs.flows.AutoOfferFlow
|
import net.corda.irs.flows.AutoOfferFlow
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.corda.irs
|
package net.corda.irs
|
||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
import net.corda.core.internal.concurrent.transpose
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.DUMMY_BANK_A
|
import net.corda.testing.DUMMY_BANK_A
|
||||||
import net.corda.testing.DUMMY_BANK_B
|
import net.corda.testing.DUMMY_BANK_B
|
||||||
import net.corda.testing.DUMMY_NOTARY
|
import net.corda.testing.DUMMY_NOTARY
|
||||||
@ -16,11 +16,11 @@ import net.corda.testing.driver.driver
|
|||||||
*/
|
*/
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
driver(dsl = {
|
driver(dsl = {
|
||||||
val (controller, nodeA, nodeB) = Futures.allAsList(
|
val (controller, nodeA, nodeB) = listOf(
|
||||||
startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.Oracle.type))),
|
startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.Oracle.type))),
|
||||||
startNode(DUMMY_BANK_A.name),
|
startNode(DUMMY_BANK_A.name),
|
||||||
startNode(DUMMY_BANK_B.name)
|
startNode(DUMMY_BANK_B.name)
|
||||||
).getOrThrow()
|
).transpose().getOrThrow()
|
||||||
|
|
||||||
startWebserver(controller)
|
startWebserver(controller)
|
||||||
startWebserver(nodeA)
|
startWebserver(nodeA)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.corda.irs.api
|
package net.corda.irs.api
|
||||||
|
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.irs.flows.UpdateBusinessDayFlow
|
import net.corda.irs.flows.UpdateBusinessDayFlow
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
|
@ -9,11 +9,11 @@ import net.corda.contracts.asset.`owned by`
|
|||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.MerkleTreeException
|
import net.corda.core.crypto.MerkleTreeException
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.irs.flows.RatesFixFlow
|
import net.corda.irs.flows.RatesFixFlow
|
||||||
import net.corda.node.utilities.CordaPersistence
|
import net.corda.node.utilities.CordaPersistence
|
||||||
import net.corda.node.utilities.configureDatabase
|
import net.corda.node.utilities.configureDatabase
|
||||||
|
@ -13,7 +13,6 @@ import javafx.stage.Stage
|
|||||||
import javafx.util.Duration
|
import javafx.util.Duration
|
||||||
import net.corda.core.crypto.commonName
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
import net.corda.core.then
|
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
import net.corda.netmap.VisualiserViewModel.Style
|
import net.corda.netmap.VisualiserViewModel.Style
|
||||||
import net.corda.netmap.simulation.IRSSimulation
|
import net.corda.netmap.simulation.IRSSimulation
|
||||||
|
@ -3,17 +3,15 @@ package net.corda.netmap.simulation
|
|||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import com.google.common.util.concurrent.*
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.flatMap
|
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.InitiatedBy
|
import net.corda.core.flows.InitiatedBy
|
||||||
import net.corda.core.flows.InitiatingFlow
|
import net.corda.core.flows.InitiatingFlow
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.internal.concurrent.*
|
||||||
import net.corda.core.internal.FlowStateMachine
|
import net.corda.core.internal.FlowStateMachine
|
||||||
import net.corda.core.map
|
|
||||||
import net.corda.core.node.services.queryBy
|
import net.corda.core.node.services.queryBy
|
||||||
import net.corda.core.thenMatch
|
|
||||||
import net.corda.core.toFuture
|
import net.corda.core.toFuture
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.flows.TwoPartyDealFlow.Acceptor
|
import net.corda.flows.TwoPartyDealFlow.Acceptor
|
||||||
@ -43,8 +41,8 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
|
|||||||
|
|
||||||
private val executeOnNextIteration = Collections.synchronizedList(LinkedList<() -> Unit>())
|
private val executeOnNextIteration = Collections.synchronizedList(LinkedList<() -> Unit>())
|
||||||
|
|
||||||
override fun startMainSimulation(): ListenableFuture<Unit> {
|
override fun startMainSimulation(): CordaFuture<Unit> {
|
||||||
val future = SettableFuture.create<Unit>()
|
val future = openFuture<Unit>()
|
||||||
om = JacksonSupport.createInMemoryMapper(InMemoryIdentityService((banks + regulators + networkMap).map { it.info.legalIdentityAndCert }, trustRoot = DUMMY_CA.certificate))
|
om = JacksonSupport.createInMemoryMapper(InMemoryIdentityService((banks + regulators + networkMap).map { it.info.legalIdentityAndCert }, trustRoot = DUMMY_CA.certificate))
|
||||||
|
|
||||||
startIRSDealBetween(0, 1).thenMatch({
|
startIRSDealBetween(0, 1).thenMatch({
|
||||||
@ -53,32 +51,30 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
|
|||||||
executeOnNextIteration.add {
|
executeOnNextIteration.add {
|
||||||
// Keep fixing until there's no more left to do.
|
// Keep fixing until there's no more left to do.
|
||||||
val initialFixFuture = doNextFixing(0, 1)
|
val initialFixFuture = doNextFixing(0, 1)
|
||||||
|
fun onFailure(t: Throwable) {
|
||||||
Futures.addCallback(initialFixFuture, object : FutureCallback<Unit> {
|
|
||||||
override fun onFailure(t: Throwable) {
|
|
||||||
future.setException(t) // Propagate the error.
|
future.setException(t) // Propagate the error.
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSuccess(result: Unit?) {
|
fun onSuccess(result: Unit?) {
|
||||||
// Pause for an iteration.
|
// Pause for an iteration.
|
||||||
executeOnNextIteration.add {}
|
executeOnNextIteration.add {}
|
||||||
executeOnNextIteration.add {
|
executeOnNextIteration.add {
|
||||||
val f = doNextFixing(0, 1)
|
val f = doNextFixing(0, 1)
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
Futures.addCallback(f, this, MoreExecutors.directExecutor())
|
f.thenMatch(::onSuccess, ::onFailure)
|
||||||
} else {
|
} else {
|
||||||
// All done!
|
// All done!
|
||||||
future.set(Unit)
|
future.set(Unit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, MoreExecutors.directExecutor())
|
initialFixFuture!!.thenMatch(::onSuccess, ::onFailure)
|
||||||
}
|
}
|
||||||
}, {})
|
}, {})
|
||||||
return future
|
return future
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doNextFixing(i: Int, j: Int): ListenableFuture<Unit>? {
|
private fun doNextFixing(i: Int, j: Int): CordaFuture<Unit>? {
|
||||||
println("Doing a fixing between $i and $j")
|
println("Doing a fixing between $i and $j")
|
||||||
val node1: SimulatedNode = banks[i]
|
val node1: SimulatedNode = banks[i]
|
||||||
val node2: SimulatedNode = banks[j]
|
val node2: SimulatedNode = banks[j]
|
||||||
@ -104,10 +100,10 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
|
|||||||
if (nextFixingDate > currentDateAndTime.toLocalDate())
|
if (nextFixingDate > currentDateAndTime.toLocalDate())
|
||||||
currentDateAndTime = nextFixingDate.atTime(15, 0)
|
currentDateAndTime = nextFixingDate.atTime(15, 0)
|
||||||
|
|
||||||
return Futures.allAsList(futA, futB).map { Unit }
|
return listOf(futA, futB).transpose().map { Unit }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startIRSDealBetween(i: Int, j: Int): ListenableFuture<SignedTransaction> {
|
private fun startIRSDealBetween(i: Int, j: Int): CordaFuture<SignedTransaction> {
|
||||||
val node1: SimulatedNode = banks[i]
|
val node1: SimulatedNode = banks[i]
|
||||||
val node2: SimulatedNode = banks[j]
|
val node2: SimulatedNode = banks[j]
|
||||||
|
|
||||||
@ -151,7 +147,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
|
|||||||
node1.services.legalIdentityKey)
|
node1.services.legalIdentityKey)
|
||||||
val instigatorTxFuture = node1.services.startFlow(instigator).resultFuture
|
val instigatorTxFuture = node1.services.startFlow(instigator).resultFuture
|
||||||
|
|
||||||
return Futures.allAsList(instigatorTxFuture, acceptorTxFuture).flatMap { instigatorTxFuture }
|
return listOf(instigatorTxFuture, acceptorTxFuture).transpose().flatMap { instigatorTxFuture }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun iterate(): InMemoryMessagingNetwork.MessageTransfer? {
|
override fun iterate(): InMemoryMessagingNetwork.MessageTransfer? {
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
package net.corda.netmap.simulation
|
package net.corda.netmap.simulation
|
||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
|
||||||
import net.corda.core.crypto.locationOrNull
|
import net.corda.core.crypto.locationOrNull
|
||||||
import net.corda.core.flatMap
|
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
import net.corda.core.node.CityDatabase
|
import net.corda.core.node.CityDatabase
|
||||||
import net.corda.core.node.WorldMapLocation
|
import net.corda.core.node.WorldMapLocation
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.containsType
|
import net.corda.core.node.services.containsType
|
||||||
|
import net.corda.core.internal.concurrent.doneFuture
|
||||||
|
import net.corda.core.internal.concurrent.flatMap
|
||||||
|
import net.corda.core.internal.concurrent.transpose
|
||||||
import net.corda.testing.DUMMY_MAP
|
import net.corda.testing.DUMMY_MAP
|
||||||
import net.corda.testing.DUMMY_NOTARY
|
import net.corda.testing.DUMMY_NOTARY
|
||||||
import net.corda.testing.DUMMY_REGULATOR
|
import net.corda.testing.DUMMY_REGULATOR
|
||||||
@ -260,10 +261,9 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val networkInitialisationFinished: ListenableFuture<*> =
|
val networkInitialisationFinished = mockNet.nodes.map { it.networkMapRegistrationFuture }.transpose()
|
||||||
Futures.allAsList(mockNet.nodes.map { it.networkMapRegistrationFuture })
|
|
||||||
|
|
||||||
fun start(): ListenableFuture<Unit> {
|
fun start(): CordaFuture<Unit> {
|
||||||
mockNet.startNodes()
|
mockNet.startNodes()
|
||||||
// Wait for all the nodes to have finished registering with the network map service.
|
// Wait for all the nodes to have finished registering with the network map service.
|
||||||
return networkInitialisationFinished.flatMap { startMainSimulation() }
|
return networkInitialisationFinished.flatMap { startMainSimulation() }
|
||||||
@ -273,8 +273,8 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
* Sub-classes should override this to trigger whatever they want to simulate. This method will be invoked once the
|
* Sub-classes should override this to trigger whatever they want to simulate. This method will be invoked once the
|
||||||
* network bringup has been simulated.
|
* network bringup has been simulated.
|
||||||
*/
|
*/
|
||||||
protected open fun startMainSimulation(): ListenableFuture<Unit> {
|
protected open fun startMainSimulation(): CordaFuture<Unit> {
|
||||||
return Futures.immediateFuture(Unit)
|
return doneFuture(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stop() {
|
fun stop() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.corda.netmap.simulation
|
package net.corda.netmap.simulation
|
||||||
|
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.LogHelper
|
import net.corda.testing.LogHelper
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package net.corda.notarydemo
|
package net.corda.notarydemo
|
||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
|
||||||
import net.corda.client.rpc.CordaRPCClient
|
import net.corda.client.rpc.CordaRPCClient
|
||||||
import net.corda.client.rpc.notUsed
|
import net.corda.client.rpc.notUsed
|
||||||
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.crypto.toStringShort
|
import net.corda.core.crypto.toStringShort
|
||||||
import net.corda.core.getOrThrow
|
|
||||||
import net.corda.core.map
|
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.core.internal.concurrent.map
|
||||||
|
import net.corda.core.internal.concurrent.transpose
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.notarydemo.flows.DummyIssueAndMove
|
import net.corda.notarydemo.flows.DummyIssueAndMove
|
||||||
import net.corda.notarydemo.flows.RPCStartableNotaryFlowClient
|
import net.corda.notarydemo.flows.RPCStartableNotaryFlowClient
|
||||||
import net.corda.testing.BOB
|
import net.corda.testing.BOB
|
||||||
@ -55,9 +55,9 @@ private class NotaryDemoClientApi(val rpc: CordaRPCOps) {
|
|||||||
* as it consumes the original asset and creates a copy with the new owner as its output.
|
* as it consumes the original asset and creates a copy with the new owner as its output.
|
||||||
*/
|
*/
|
||||||
private fun buildTransactions(count: Int): List<SignedTransaction> {
|
private fun buildTransactions(count: Int): List<SignedTransaction> {
|
||||||
return Futures.allAsList((1..count).map {
|
return (1..count).map {
|
||||||
rpc.startFlow(::DummyIssueAndMove, notary, counterpartyNode.legalIdentity, it).returnValue
|
rpc.startFlow(::DummyIssueAndMove, notary, counterpartyNode.legalIdentity, it).returnValue
|
||||||
}).getOrThrow()
|
}.transpose().getOrThrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,7 +66,7 @@ private class NotaryDemoClientApi(val rpc: CordaRPCOps) {
|
|||||||
*
|
*
|
||||||
* @return a list of encoded signer public keys - one for every transaction
|
* @return a list of encoded signer public keys - one for every transaction
|
||||||
*/
|
*/
|
||||||
private fun notariseTransactions(transactions: List<SignedTransaction>): List<ListenableFuture<List<String>>> {
|
private fun notariseTransactions(transactions: List<SignedTransaction>): List<CordaFuture<List<String>>> {
|
||||||
return transactions.map {
|
return transactions.map {
|
||||||
rpc.startFlow(::RPCStartableNotaryFlowClient, it).returnValue.map { it.map { it.by.toStringShort() } }
|
rpc.startFlow(::RPCStartableNotaryFlowClient, it).returnValue.map { it.map { it.by.toStringShort() } }
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user