mirror of
https://github.com/corda/corda.git
synced 2025-02-27 03:27:34 +00:00
Added a method to NodeHandle to simplify using RPC in the Driver
This commit is contained in:
parent
0867a05ad7
commit
59456cb6b1
@ -12,28 +12,21 @@ import net.corda.node.driver.DriverBasedTest
|
||||
import net.corda.node.driver.NodeHandle
|
||||
import net.corda.node.driver.driver
|
||||
import net.corda.node.services.User
|
||||
import net.corda.node.services.config.configureTestSSL
|
||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.toHostAndPort
|
||||
import net.corda.node.services.messaging.CordaRPCClient
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQSecurityException
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class CordaRPCClientTest : DriverBasedTest() {
|
||||
|
||||
private val rpcUser = User("user1", "test", permissions = setOf(startFlowPermission<CashFlow>()))
|
||||
private lateinit var node: NodeHandle
|
||||
private lateinit var client: CordaRPCClient
|
||||
private lateinit var driverInfo: NodeHandle
|
||||
|
||||
override fun setup() = driver(isDebug = true) {
|
||||
driverInfo = startNode(rpcUsers = listOf(rpcUser), advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type))).getOrThrow()
|
||||
client = CordaRPCClient(toHostAndPort(driverInfo.nodeInfo.address), configureTestSSL())
|
||||
node = startNode(rpcUsers = listOf(rpcUser), advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type))).getOrThrow()
|
||||
client = node.rpcClientToNode()
|
||||
runTest()
|
||||
}
|
||||
|
||||
@ -63,7 +56,9 @@ class CordaRPCClientTest : DriverBasedTest() {
|
||||
println("Creating proxy")
|
||||
val proxy = client.proxy()
|
||||
println("Starting flow")
|
||||
val flowHandle = proxy.startFlow(::CashFlow, CashCommand.IssueCash(20.DOLLARS, OpaqueBytes.of(0), driverInfo.nodeInfo.legalIdentity, driverInfo.nodeInfo.legalIdentity))
|
||||
val flowHandle = proxy.startFlow(
|
||||
::CashFlow,
|
||||
CashCommand.IssueCash(20.DOLLARS, OpaqueBytes.of(0), node.nodeInfo.legalIdentity, node.nodeInfo.legalIdentity))
|
||||
println("Started flow, waiting on result")
|
||||
flowHandle.progress.subscribe {
|
||||
println("PROGRESS $it")
|
||||
|
@ -3,13 +3,12 @@
|
||||
Client RPC API tutorial
|
||||
=======================
|
||||
|
||||
In this tutorial we will build a simple command line utility that
|
||||
connects to a node, creates some Cash transactions and meanwhile dumps
|
||||
the transaction graph to the standard output. We will then put some
|
||||
simple visualisation on top. For an explanation on how the RPC works
|
||||
see :doc:`clientrpc`.
|
||||
In this tutorial we will build a simple command line utility that connects to a node, creates some Cash transactions and
|
||||
meanwhile dumps the transaction graph to the standard output. We will then put some simple visualisation on top. For an
|
||||
explanation on how the RPC works see :doc:`clientrpc`.
|
||||
|
||||
We start off by connecting to the node itself. For the purposes of the tutorial we will use the Driver to start up a notary and a node that issues/exits and moves Cash around for herself. To authenticate we will use the certificates of the nodes directly.
|
||||
We start off by connecting to the node itself. For the purposes of the tutorial we will use the Driver to start up a notary
|
||||
and a node that issues/exits and moves Cash around for herself.
|
||||
|
||||
Note how we configure the node to create a user that has permission to start the CashFlow.
|
||||
|
||||
@ -25,14 +24,16 @@ Now we can connect to the node itself using a valid RPC login. We login using th
|
||||
:start-after: START 2
|
||||
:end-before: END 2
|
||||
|
||||
We start generating transactions in a different thread (``generateTransactions`` to be defined later) using ``proxy``, which exposes the full RPC interface of the node:
|
||||
We start generating transactions in a different thread (``generateTransactions`` to be defined later) using ``proxy``,
|
||||
which exposes the full RPC interface of the node:
|
||||
|
||||
.. literalinclude:: ../../node/src/main/kotlin/net/corda/node/services/messaging/CordaRPCOps.kt
|
||||
:language: kotlin
|
||||
:start-after: interface CordaRPCOps
|
||||
:end-before: }
|
||||
|
||||
.. warning:: This API is evolving and will continue to grow as new functionality and features added to Corda are made available to RPC clients.
|
||||
.. warning:: This API is evolving and will continue to grow as new functionality and features added to Corda are made
|
||||
available to RPC clients.
|
||||
|
||||
The one we need in order to dump the transaction graph is ``verifiedTransactions``. The type signature tells us that the
|
||||
RPC will return a list of transactions and an Observable stream. This is a general pattern, we query some data and the
|
||||
@ -65,9 +66,12 @@ We utilise several RPC functions here to query things like the notaries in the n
|
||||
|
||||
Then in a loop we generate randomly either an Issue, a Pay or an Exit transaction.
|
||||
|
||||
The RPC we need to initiate a Cash transaction is ``startFlowDynamic`` which may start an arbitrary flow, given sufficient permissions to do so. We won't use this function directly, but rather a type-safe wrapper around it ``startFlow`` that type-checks the arguments for us.
|
||||
The RPC we need to initiate a Cash transaction is ``startFlowDynamic`` which may start an arbitrary flow, given sufficient
|
||||
permissions to do so. We won't use this function directly, but rather a type-safe wrapper around it ``startFlow`` that
|
||||
type-checks the arguments for us.
|
||||
|
||||
Finally we have everything in place: we start a couple of nodes, connect to them, and start creating transactions while listening on successfully created ones, which are dumped to the console. We just need to run it!:
|
||||
Finally we have everything in place: we start a couple of nodes, connect to them, and start creating transactions while
|
||||
listening on successfully created ones, which are dumped to the console. We just need to run it!:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
package net.corda.docs
|
||||
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import net.corda.contracts.asset.Cash
|
||||
import net.corda.core.contracts.DOLLARS
|
||||
import net.corda.core.contracts.issuedBy
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.node.services.Vault
|
||||
@ -12,9 +14,6 @@ import net.corda.flows.CashFlow
|
||||
import net.corda.flows.CashFlowResult
|
||||
import net.corda.node.driver.driver
|
||||
import net.corda.node.services.User
|
||||
import net.corda.node.services.config.configureTestSSL
|
||||
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
||||
import net.corda.node.services.messaging.CordaRPCClient
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||
import net.corda.testing.expect
|
||||
@ -26,31 +25,25 @@ import kotlin.concurrent.thread
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class IntegrationTestingTutorial {
|
||||
|
||||
@Test
|
||||
fun aliceBobCashExchangeExample() {
|
||||
fun `alice bob cash exchange example`() {
|
||||
// START 1
|
||||
driver {
|
||||
val testUser = User("testUser", "testPassword", permissions = setOf(startFlowPermission<CashFlow>()))
|
||||
val aliceFuture = startNode("Alice", rpcUsers = listOf(testUser))
|
||||
val bobFuture = startNode("Bob", rpcUsers = listOf(testUser))
|
||||
val notaryFuture = startNode("Notary", advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type)))
|
||||
val alice = aliceFuture.get()
|
||||
val bob = bobFuture.get()
|
||||
val notary = notaryFuture.get()
|
||||
val (alice, bob, notary) = Futures.allAsList(
|
||||
startNode("Alice", rpcUsers = listOf(testUser)),
|
||||
startNode("Bob", rpcUsers = listOf(testUser)),
|
||||
startNode("Notary", advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type)))
|
||||
).getOrThrow()
|
||||
// END 1
|
||||
|
||||
// START 2
|
||||
val aliceClient = CordaRPCClient(
|
||||
host = ArtemisMessagingComponent.toHostAndPort(alice.nodeInfo.address),
|
||||
config = configureTestSSL()
|
||||
)
|
||||
val aliceClient = alice.rpcClientToNode()
|
||||
|
||||
aliceClient.start("testUser", "testPassword")
|
||||
val aliceProxy = aliceClient.proxy()
|
||||
val bobClient = CordaRPCClient(
|
||||
host = ArtemisMessagingComponent.toHostAndPort(bob.nodeInfo.address),
|
||||
config = configureTestSSL()
|
||||
)
|
||||
val bobClient = bob.rpcClientToNode()
|
||||
|
||||
bobClient.start("testUser", "testPassword")
|
||||
val bobProxy = bobClient.proxy()
|
||||
// END 2
|
||||
|
@ -6,7 +6,6 @@ import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.Issued
|
||||
import net.corda.core.contracts.PartyAndReference
|
||||
import net.corda.core.contracts.USD
|
||||
import net.corda.core.div
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
@ -17,9 +16,6 @@ import net.corda.flows.CashCommand
|
||||
import net.corda.flows.CashFlow
|
||||
import net.corda.node.driver.driver
|
||||
import net.corda.node.services.User
|
||||
import net.corda.node.services.config.FullNodeConfiguration
|
||||
import net.corda.node.services.config.NodeSSLConfiguration
|
||||
import net.corda.node.services.messaging.CordaRPCClient
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||
import org.graphstream.graph.Edge
|
||||
@ -41,9 +37,7 @@ enum class PrintOrVisualise {
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
if (args.size < 1) {
|
||||
throw IllegalArgumentException("Usage: <binary> [Print|Visualise]")
|
||||
}
|
||||
require(args.isNotEmpty()) { "Usage: <binary> [Print|Visualise]" }
|
||||
val printOrVisualise = PrintOrVisualise.valueOf(args[0])
|
||||
|
||||
val baseDirectory = Paths.get("build/rpc-api-tutorial")
|
||||
@ -52,15 +46,10 @@ fun main(args: Array<String>) {
|
||||
driver(driverDirectory = baseDirectory) {
|
||||
startNode("Notary", advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type)))
|
||||
val node = startNode("Alice", rpcUsers = listOf(user)).get()
|
||||
val sslConfig = object : NodeSSLConfiguration {
|
||||
override val certificatesPath = baseDirectory / "Alice" / "certificates"
|
||||
override val keyStorePassword = "cordacadevpass"
|
||||
override val trustStorePassword = "trustpass"
|
||||
}
|
||||
// END 1
|
||||
|
||||
// START 2
|
||||
val client = CordaRPCClient(FullNodeConfiguration(node.config).artemisAddress, sslConfig)
|
||||
val client = node.rpcClientToNode()
|
||||
client.start("user", "password")
|
||||
val proxy = client.proxy()
|
||||
|
||||
|
@ -35,7 +35,7 @@ notary directly, so there's no need to pass in the test ``User``.
|
||||
The ``startNode`` function returns a future that completes once the
|
||||
node is fully started. This allows starting of the nodes to be
|
||||
parallel. We wait on these futures as we need the information
|
||||
returned; their respective ``NodeInfo`` s.
|
||||
returned; their respective ``NodeHandles`` s.
|
||||
|
||||
.. literalinclude:: example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt
|
||||
:language: kotlin
|
||||
@ -46,9 +46,6 @@ Next we connect to Alice and Bob respectively from the test process
|
||||
using the test user we created. Then we establish RPC links that allow
|
||||
us to start flows and query state.
|
||||
|
||||
Note that Driver nodes start up with test server certificates, so
|
||||
it's enough to pass in ``configureTestSSL()`` for the clients.
|
||||
|
||||
.. literalinclude:: example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt
|
||||
:language: kotlin
|
||||
:start-after: START 3
|
||||
|
@ -53,7 +53,7 @@ class DriverTests {
|
||||
|
||||
@Test
|
||||
fun randomFreePortAllocationWorks() {
|
||||
val nodeInfo = driver(portAllocation = PortAllocation.RandomFree()) {
|
||||
val nodeInfo = driver(portAllocation = PortAllocation.RandomFree) {
|
||||
val nodeInfo = startNode("NoService")
|
||||
nodeMustBeUp(nodeInfo.getOrThrow().nodeInfo)
|
||||
nodeInfo.getOrThrow()
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.corda.node.services
|
||||
|
||||
import net.corda.core.bufferUntilSubscribed
|
||||
import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.POUNDS
|
||||
import net.corda.core.contracts.issuedBy
|
||||
import net.corda.core.crypto.Party
|
||||
@ -15,9 +16,6 @@ import net.corda.flows.CashFlowResult
|
||||
import net.corda.node.driver.DriverBasedTest
|
||||
import net.corda.node.driver.NodeHandle
|
||||
import net.corda.node.driver.driver
|
||||
import net.corda.node.services.config.configureTestSSL
|
||||
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
||||
import net.corda.node.services.messaging.CordaRPCClient
|
||||
import net.corda.node.services.transactions.RaftValidatingNotaryService
|
||||
import net.corda.testing.expect
|
||||
import net.corda.testing.expectEvents
|
||||
@ -28,14 +26,14 @@ import java.util.*
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class DistributedServiceTests : DriverBasedTest() {
|
||||
lateinit var alice: NodeInfo
|
||||
lateinit var alice: NodeHandle
|
||||
lateinit var notaries: List<NodeHandle>
|
||||
lateinit var aliceProxy: CordaRPCOps
|
||||
lateinit var raftNotaryIdentity: Party
|
||||
lateinit var notaryStateMachines: Observable<Pair<NodeInfo, StateMachineUpdate>>
|
||||
|
||||
override fun setup() = driver {
|
||||
// Start Alice and 3 raft notaries
|
||||
// Start Alice and 3 notaries in a RAFT cluster
|
||||
val clusterSize = 3
|
||||
val testUser = User("test", "test", permissions = setOf(startFlowPermission<CashFlow>()))
|
||||
val aliceFuture = startNode("Alice", rpcUsers = listOf(testUser))
|
||||
@ -46,7 +44,7 @@ class DistributedServiceTests : DriverBasedTest() {
|
||||
type = RaftValidatingNotaryService.type
|
||||
)
|
||||
|
||||
alice = aliceFuture.get().nodeInfo
|
||||
alice = aliceFuture.get()
|
||||
val (notaryIdentity, notaryNodes) = notariesFuture.get()
|
||||
raftNotaryIdentity = notaryIdentity
|
||||
notaries = notaryNodes
|
||||
@ -55,14 +53,14 @@ class DistributedServiceTests : DriverBasedTest() {
|
||||
assertEquals(notaries.size, notaries.map { it.nodeInfo.legalIdentity }.toSet().size)
|
||||
|
||||
// Connect to Alice and the notaries
|
||||
fun connectRpc(node: NodeInfo): CordaRPCOps {
|
||||
val client = CordaRPCClient(ArtemisMessagingComponent.toHostAndPort(node.address), configureTestSSL())
|
||||
fun connectRpc(node: NodeHandle): CordaRPCOps {
|
||||
val client = node.rpcClientToNode()
|
||||
client.start("test", "test")
|
||||
return client.proxy()
|
||||
}
|
||||
aliceProxy = connectRpc(alice)
|
||||
val notaryProxies = notaries.map { connectRpc(it.nodeInfo) }
|
||||
notaryStateMachines = Observable.from(notaryProxies.map { proxy ->
|
||||
val rpcClientsToNotaries = notaries.map(::connectRpc)
|
||||
notaryStateMachines = Observable.from(rpcClientsToNotaries.map { proxy ->
|
||||
proxy.stateMachinesAndUpdates().second.map { Pair(proxy.nodeIdentity(), it) }
|
||||
}).flatMap { it.onErrorResumeNext(Observable.empty()) }.bufferUntilSubscribed()
|
||||
|
||||
@ -74,11 +72,10 @@ class DistributedServiceTests : DriverBasedTest() {
|
||||
@Test
|
||||
fun `requests are distributed evenly amongst the nodes`() {
|
||||
// Issue 100 pounds, then pay ourselves 50x2 pounds
|
||||
val issueHandle = aliceProxy.startFlow(::CashFlow, CashCommand.IssueCash(100.POUNDS, OpaqueBytes.of(0), alice.legalIdentity, raftNotaryIdentity))
|
||||
require(issueHandle.returnValue.toBlocking().first() is CashFlowResult.Success)
|
||||
issueCash(100.POUNDS)
|
||||
|
||||
for (i in 1..50) {
|
||||
val payHandle = aliceProxy.startFlow(::CashFlow, CashCommand.PayCash(2.POUNDS.issuedBy(alice.legalIdentity.ref(0)), alice.legalIdentity))
|
||||
require(payHandle.returnValue.toBlocking().first() is CashFlowResult.Success)
|
||||
paySelf(2.POUNDS)
|
||||
}
|
||||
|
||||
// The state machines added in the notaries should map one-to-one to notarisation requests
|
||||
@ -104,11 +101,10 @@ class DistributedServiceTests : DriverBasedTest() {
|
||||
@Test
|
||||
fun `cluster survives if a notary is killed`() {
|
||||
// Issue 100 pounds, then pay ourselves 10x5 pounds
|
||||
val issueHandle = aliceProxy.startFlow(::CashFlow, CashCommand.IssueCash(100.POUNDS, OpaqueBytes.of(0), alice.legalIdentity, raftNotaryIdentity))
|
||||
require(issueHandle.returnValue.toBlocking().first() is CashFlowResult.Success)
|
||||
issueCash(100.POUNDS)
|
||||
|
||||
for (i in 1..10) {
|
||||
val payHandle = aliceProxy.startFlow(::CashFlow, CashCommand.PayCash(5.POUNDS.issuedBy(alice.legalIdentity.ref(0)), alice.legalIdentity))
|
||||
require(payHandle.returnValue.toBlocking().first() is CashFlowResult.Success)
|
||||
paySelf(5.POUNDS)
|
||||
}
|
||||
|
||||
// Now kill a notary
|
||||
@ -119,8 +115,7 @@ class DistributedServiceTests : DriverBasedTest() {
|
||||
|
||||
// Pay ourselves another 20x5 pounds
|
||||
for (i in 1..20) {
|
||||
val payHandle = aliceProxy.startFlow(::CashFlow, CashCommand.PayCash(5.POUNDS.issuedBy(alice.legalIdentity.ref(0)), alice.legalIdentity))
|
||||
require(payHandle.returnValue.toBlocking().first() is CashFlowResult.Success)
|
||||
paySelf(5.POUNDS)
|
||||
}
|
||||
|
||||
val notarisationsPerNotary = HashMap<Party, Int>()
|
||||
@ -137,4 +132,18 @@ class DistributedServiceTests : DriverBasedTest() {
|
||||
println("Notarisation distribution: $notarisationsPerNotary")
|
||||
require(notarisationsPerNotary.size == 3)
|
||||
}
|
||||
|
||||
private fun issueCash(amount: Amount<Currency>) {
|
||||
val issueHandle = aliceProxy.startFlow(
|
||||
::CashFlow,
|
||||
CashCommand.IssueCash(amount, OpaqueBytes.of(0), alice.nodeInfo.legalIdentity, raftNotaryIdentity))
|
||||
require(issueHandle.returnValue.toBlocking().first() is CashFlowResult.Success)
|
||||
}
|
||||
|
||||
private fun paySelf(amount: Amount<Currency>) {
|
||||
val payHandle = aliceProxy.startFlow(
|
||||
::CashFlow,
|
||||
CashCommand.PayCash(amount.issuedBy(alice.nodeInfo.legalIdentity.ref(0)), alice.nodeInfo.legalIdentity))
|
||||
require(payHandle.returnValue.toBlocking().first() is CashFlowResult.Success)
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ import net.corda.core.utilities.loggerFor
|
||||
import net.corda.node.services.User
|
||||
import net.corda.node.services.config.ConfigHelper
|
||||
import net.corda.node.services.config.FullNodeConfiguration
|
||||
import net.corda.node.services.messaging.CordaRPCClient
|
||||
import net.corda.node.services.messaging.NodeMessagingClient
|
||||
import net.corda.node.services.network.NetworkMapService
|
||||
import net.corda.node.services.transactions.RaftValidatingNotaryService
|
||||
@ -93,9 +94,11 @@ interface DriverDSLInternalInterface : DriverDSLExposedInterface {
|
||||
|
||||
data class NodeHandle(
|
||||
val nodeInfo: NodeInfo,
|
||||
val config: Config,
|
||||
val configuration: FullNodeConfiguration,
|
||||
val process: Process
|
||||
)
|
||||
) {
|
||||
fun rpcClientToNode(): CordaRPCClient = CordaRPCClient(configuration.artemisAddress, configuration)
|
||||
}
|
||||
|
||||
sealed class PortAllocation {
|
||||
abstract fun nextPort(): Int
|
||||
@ -106,7 +109,7 @@ sealed class PortAllocation {
|
||||
override fun nextPort() = portCounter.andIncrement
|
||||
}
|
||||
|
||||
class RandomFree() : PortAllocation() {
|
||||
object RandomFree : PortAllocation() {
|
||||
override fun nextPort(): Int {
|
||||
return ServerSocket().use {
|
||||
it.bind(InetSocketAddress(0))
|
||||
@ -364,16 +367,16 @@ open class DriverDSL(
|
||||
}
|
||||
) + customOverrides
|
||||
|
||||
val config = ConfigHelper.loadConfig(
|
||||
val configuration = FullNodeConfiguration(ConfigHelper.loadConfig(
|
||||
baseDirectoryPath = baseDirectory,
|
||||
allowMissingConfig = true,
|
||||
configOverrides = configOverrides
|
||||
)
|
||||
))
|
||||
|
||||
val startNode = startNode(executorService, FullNodeConfiguration(config), quasarJarPath, debugPort)
|
||||
val startNode = startNode(executorService, configuration, quasarJarPath, debugPort)
|
||||
registerProcess(startNode)
|
||||
return startNode.map {
|
||||
NodeHandle(queryNodeInfo(apiAddress)!!, config, it)
|
||||
NodeHandle(queryNodeInfo(apiAddress)!!, configuration, it)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,8 @@ class FullNodeConfiguration(val config: Config) : NodeConfiguration {
|
||||
val useHTTPS: Boolean by config
|
||||
val artemisAddress: HostAndPort by config
|
||||
val webAddress: HostAndPort by config
|
||||
// TODO This field is slightly redundant as artemisAddress is sufficient to hold the address of the node's MQ broker.
|
||||
// Instead this should be a Boolean indicating whether that broker is an internal one started by the node or an external one
|
||||
val messagingServerAddress: HostAndPort? by config.getOrElse { null }
|
||||
val extraAdvertisedServiceIds: String by config
|
||||
val useTestClock: Boolean by config.getOrElse { false }
|
||||
|
@ -1,31 +1,30 @@
|
||||
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.node.driver.driver
|
||||
import net.corda.node.services.transactions.SimpleNotaryService
|
||||
import net.corda.testing.getHostAndPort
|
||||
import org.junit.Test
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class AttachmentDemoTest {
|
||||
@Test fun `runs attachment demo`() {
|
||||
driver(dsl = {
|
||||
startNode("Notary", setOf(ServiceInfo(SimpleNotaryService.Companion.type)))
|
||||
val nodeAFuture = startNode("Bank A")
|
||||
val nodeBApiAddr = startNode("Bank B").getOrThrow().config.getHostAndPort("webAddress")
|
||||
|
||||
val nodeA = nodeAFuture.getOrThrow()
|
||||
val nodeAApiAddr = nodeA.config.getHostAndPort("webAddress")
|
||||
val (nodeA, nodeB) = Futures.allAsList(
|
||||
startNode("Bank A"),
|
||||
startNode("Bank B"),
|
||||
startNode("Notary", setOf(ServiceInfo(SimpleNotaryService.Companion.type)))
|
||||
).getOrThrow()
|
||||
|
||||
var recipientReturn: Boolean? = null
|
||||
var senderReturn: Boolean? = null
|
||||
val recipientThread = thread {
|
||||
recipientReturn = AttachmentDemoClientApi(nodeAApiAddr).runRecipient()
|
||||
recipientReturn = AttachmentDemoClientApi(nodeA.configuration.webAddress).runRecipient()
|
||||
}
|
||||
val senderThread = thread {
|
||||
val counterpartyKey = nodeA.nodeInfo.legalIdentity.owningKey.toBase58String()
|
||||
senderReturn = AttachmentDemoClientApi(nodeBApiAddr).runSender(counterpartyKey)
|
||||
senderReturn = AttachmentDemoClientApi(nodeB.configuration.webAddress).runSender(counterpartyKey)
|
||||
}
|
||||
recipientThread.join()
|
||||
senderThread.join()
|
||||
|
@ -1,19 +1,23 @@
|
||||
package net.corda.bank
|
||||
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import net.corda.bank.api.BankOfCordaClientApi
|
||||
import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.node.driver.driver
|
||||
import net.corda.node.services.transactions.SimpleNotaryService
|
||||
import net.corda.testing.getHostAndPort
|
||||
import org.junit.Test
|
||||
|
||||
class BankOfCordaHttpAPITest {
|
||||
@Test fun `test issuer flow via Http`() {
|
||||
@Test
|
||||
fun `issuer flow via Http`() {
|
||||
driver(dsl = {
|
||||
val nodeBankOfCorda = startNode("BankOfCorda", setOf(ServiceInfo(SimpleNotaryService.type))).get()
|
||||
val nodeBankOfCordaApiAddr = nodeBankOfCorda.config.getHostAndPort("webAddress")
|
||||
startNode("BigCorporation").get()
|
||||
val (nodeBankOfCorda) = Futures.allAsList(
|
||||
startNode("BankOfCorda", setOf(ServiceInfo(SimpleNotaryService.type))),
|
||||
startNode("BigCorporation")
|
||||
).getOrThrow()
|
||||
val nodeBankOfCordaApiAddr = nodeBankOfCorda.configuration.webAddress
|
||||
assert(BankOfCordaClientApi(nodeBankOfCordaApiAddr).requestWebIssue(IssueRequestParams(1000, "USD", "BigCorporation", "1", "BankOfCorda")))
|
||||
}, isDebug = true)
|
||||
}
|
||||
|
@ -1,39 +1,41 @@
|
||||
package net.corda.bank
|
||||
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import net.corda.core.contracts.DOLLARS
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||
import net.corda.node.driver.driver
|
||||
import net.corda.node.services.User
|
||||
import net.corda.node.services.config.configureTestSSL
|
||||
import net.corda.node.services.messaging.CordaRPCClient
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.SimpleNotaryService
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.BOC_PARTY_REF
|
||||
import net.corda.testing.expect
|
||||
import net.corda.testing.expectEvents
|
||||
import net.corda.testing.sequence
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class BankOfCordaRPCClientTest {
|
||||
|
||||
@Test fun `test issuer flow via RPC`() {
|
||||
@Test
|
||||
fun `issuer flow via RPC`() {
|
||||
driver(dsl = {
|
||||
val user = User("user1", "test", permissions = setOf(startFlowPermission<IssuanceRequester>()))
|
||||
val nodeBankOfCorda = startNode("BankOfCorda", setOf(ServiceInfo(SimpleNotaryService.type)), arrayListOf(user)).get()
|
||||
val nodeBankOfCordaApiAddr = nodeBankOfCorda.config.getHostAndPort("artemisAddress")
|
||||
val bankOfCordaParty = nodeBankOfCorda.nodeInfo.legalIdentity
|
||||
val nodeBigCorporation = startNode("BigCorporation", rpcUsers = arrayListOf(user)).get()
|
||||
val bigCorporationParty = nodeBigCorporation.nodeInfo.legalIdentity
|
||||
val (nodeBankOfCorda, nodeBigCorporation) = Futures.allAsList(
|
||||
startNode("BankOfCorda", setOf(ServiceInfo(SimpleNotaryService.type)), listOf(user)),
|
||||
startNode("BigCorporation", rpcUsers = listOf(user))
|
||||
).getOrThrow()
|
||||
|
||||
// Bank of Corda RPC Client
|
||||
val bocClient = CordaRPCClient(nodeBankOfCordaApiAddr, configureTestSSL())
|
||||
bocClient.start("user1","test")
|
||||
val bocClient = nodeBankOfCorda.rpcClientToNode()
|
||||
bocClient.start("user1", "test")
|
||||
val bocProxy = bocClient.proxy()
|
||||
|
||||
// Big Corporation RPC Client
|
||||
val bigCorpClient = CordaRPCClient(nodeBankOfCordaApiAddr, configureTestSSL())
|
||||
bigCorpClient.start("user1","test")
|
||||
val bigCorpClient = nodeBankOfCorda.rpcClientToNode() // TODO This test is broken as this should be nodeBigCorporation
|
||||
bigCorpClient.start("user1", "test")
|
||||
val bigCorpProxy = bigCorpClient.proxy()
|
||||
|
||||
// Register for Bank of Corda Vault updates
|
||||
@ -43,7 +45,12 @@ class BankOfCordaRPCClientTest {
|
||||
val vaultUpdatesBigCorp = bigCorpProxy.vaultAndUpdates().second
|
||||
|
||||
// Kick-off actual Issuer Flow
|
||||
val result = bocProxy.startFlow(::IssuanceRequester, 1000.DOLLARS, bigCorporationParty, BOC_PARTY_REF, bankOfCordaParty).returnValue.toBlocking().first()
|
||||
val result = bocProxy.startFlow(
|
||||
::IssuanceRequester,
|
||||
1000.DOLLARS,
|
||||
nodeBigCorporation.nodeInfo.legalIdentity,
|
||||
BOC_PARTY_REF,
|
||||
nodeBankOfCorda.nodeInfo.legalIdentity).returnValue.toBlocking().first()
|
||||
assertTrue { result is SignedTransaction }
|
||||
|
||||
// Check Bank of Corda Vault Updates
|
||||
@ -51,13 +58,13 @@ class BankOfCordaRPCClientTest {
|
||||
sequence(
|
||||
// ISSUE
|
||||
expect { update ->
|
||||
require(update.consumed.size == 0) { update.consumed.size }
|
||||
require(update.consumed.isEmpty()) { update.consumed.size }
|
||||
require(update.produced.size == 1) { update.produced.size }
|
||||
},
|
||||
// MOVE
|
||||
expect { update ->
|
||||
require(update.consumed.size == 1) { update.consumed.size }
|
||||
require(update.produced.size == 0) { update.produced.size }
|
||||
require(update.produced.isEmpty()) { update.produced.size }
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -67,13 +74,13 @@ class BankOfCordaRPCClientTest {
|
||||
sequence(
|
||||
// ISSUE
|
||||
expect { update ->
|
||||
require(update.consumed.size == 0) { update.consumed.size }
|
||||
require(update.consumed.isEmpty()) { update.consumed.size }
|
||||
require(update.produced.size == 1) { update.produced.size }
|
||||
},
|
||||
// MOVE
|
||||
expect { update ->
|
||||
require(update.consumed.size == 1) { update.consumed.size }
|
||||
require(update.produced.size == 0) { update.produced.size }
|
||||
require(update.produced.isEmpty()) { update.produced.size }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.corda.irs
|
||||
|
||||
import com.google.common.net.HostAndPort
|
||||
import com.typesafe.config.Config
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.irs.api.NodeInterestRates
|
||||
@ -15,17 +15,18 @@ import org.apache.commons.io.IOUtils
|
||||
import org.junit.Test
|
||||
import java.net.URL
|
||||
|
||||
class IRSDemoTest: IntegrationTestCategory {
|
||||
fun Config.getHostAndPort(name: String): HostAndPort = HostAndPort.fromString(getString(name))!!
|
||||
|
||||
@Test fun `runs IRS demo`() {
|
||||
class IRSDemoTest : IntegrationTestCategory {
|
||||
@Test
|
||||
fun `runs IRS demo`() {
|
||||
driver(dsl = {
|
||||
val controller = startNode("Notary", setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.type))).getOrThrow()
|
||||
val nodeA = startNode("Bank A").getOrThrow()
|
||||
val nodeB = startNode("Bank B").getOrThrow()
|
||||
runUploadRates(controller.config.getHostAndPort("webAddress"))
|
||||
runTrade(nodeA.config.getHostAndPort("webAddress"))
|
||||
runDateChange(nodeB.config.getHostAndPort("webAddress"))
|
||||
val (controller, nodeA, nodeB) = Futures.allAsList(
|
||||
startNode("Notary", setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.type))),
|
||||
startNode("Bank A"),
|
||||
startNode("Bank B")
|
||||
).getOrThrow()
|
||||
runUploadRates(controller.configuration.webAddress)
|
||||
runTrade(nodeA.configuration.webAddress)
|
||||
runDateChange(nodeB.configuration.webAddress)
|
||||
}, useTestClock = true, isDebug = true)
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import net.corda.node.driver.NodeHandle
|
||||
import net.corda.node.driver.driver
|
||||
import net.corda.node.services.transactions.SimpleNotaryService
|
||||
import net.corda.testing.IntegrationTestCategory
|
||||
import net.corda.testing.getHostAndPort
|
||||
import net.corda.testing.http.HttpApi
|
||||
import net.corda.vega.api.PortfolioApi
|
||||
import net.corda.vega.api.PortfolioApiUtils
|
||||
@ -45,7 +44,7 @@ class SimmValuationTest: IntegrationTestCategory {
|
||||
}
|
||||
|
||||
private fun getSimmNodeApi(futureNode: Future<NodeHandle>): HttpApi {
|
||||
val nodeAddr = futureNode.getOrThrow().config.getHostAndPort("webAddress")
|
||||
val nodeAddr = futureNode.getOrThrow().configuration.webAddress
|
||||
return HttpApi.fromHostAndPort(nodeAddr, "api/simmvaluationdemo")
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.traderdemo
|
||||
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.flows.IssuerFlow
|
||||
@ -7,21 +8,21 @@ import net.corda.node.driver.driver
|
||||
import net.corda.node.services.User
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.SimpleNotaryService
|
||||
import net.corda.testing.getHostAndPort
|
||||
import org.junit.Test
|
||||
|
||||
class TraderDemoTest {
|
||||
@Test fun `runs trader demo`() {
|
||||
driver(dsl = {
|
||||
startNode("Notary", setOf(ServiceInfo(SimpleNotaryService.type)))
|
||||
val nodeA = startNode("Bank A").getOrThrow()
|
||||
val nodeAApiAddr = nodeA.config.getHostAndPort("webAddress")
|
||||
val nodeBApiAddr = startNode("Bank B").getOrThrow().config.getHostAndPort("webAddress")
|
||||
val user = User("user1", "test", permissions = setOf(startFlowPermission<IssuerFlow.IssuanceRequester>()))
|
||||
startNode("BankOfCorda", rpcUsers = listOf(user)).getOrThrow()
|
||||
val (nodeA, nodeB) = Futures.allAsList(
|
||||
startNode("Bank A"),
|
||||
startNode("Bank B"),
|
||||
startNode("BankOfCorda", rpcUsers = listOf(user)),
|
||||
startNode("Notary", setOf(ServiceInfo(SimpleNotaryService.type)))
|
||||
).getOrThrow()
|
||||
|
||||
assert(TraderDemoClientApi(nodeAApiAddr).runBuyer())
|
||||
assert(TraderDemoClientApi(nodeBApiAddr).runSeller(counterparty = nodeA.nodeInfo.legalIdentity.name))
|
||||
assert(TraderDemoClientApi(nodeA.configuration.webAddress).runBuyer())
|
||||
assert(TraderDemoClientApi(nodeB.configuration.webAddress).runSeller(counterparty = nodeA.nodeInfo.legalIdentity.name))
|
||||
}, isDebug = true)
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ package net.corda.testing
|
||||
import com.google.common.net.HostAndPort
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.google.common.util.concurrent.SettableFuture
|
||||
import com.typesafe.config.Config
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.flows.FlowLogic
|
||||
@ -165,8 +164,6 @@ inline fun <reified P : FlowLogic<*>> AbstractNode.initiateSingleShotFlow(
|
||||
return future
|
||||
}
|
||||
|
||||
fun Config.getHostAndPort(name: String) = HostAndPort.fromString(getString(name))
|
||||
|
||||
inline fun elapsedTime(block: () -> Unit): Duration {
|
||||
val start = System.nanoTime()
|
||||
block()
|
||||
|
@ -26,9 +26,7 @@ import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||
import net.corda.node.driver.PortAllocation
|
||||
import net.corda.node.driver.driver
|
||||
import net.corda.node.services.User
|
||||
import net.corda.node.services.config.FullNodeConfiguration
|
||||
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
||||
import net.corda.node.services.messaging.CordaRPCClient
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.SimpleNotaryService
|
||||
import org.apache.commons.lang.SystemUtils
|
||||
@ -143,19 +141,19 @@ fun main(args: Array<String>) {
|
||||
println("Running simulation mode ...")
|
||||
|
||||
// Register with alice to use alice's RPC proxy to create random events.
|
||||
val aliceClient = CordaRPCClient(ArtemisMessagingComponent.toHostAndPort(aliceNode.nodeInfo.address), FullNodeConfiguration(aliceNode.config))
|
||||
val aliceClient = aliceNode.rpcClientToNode()
|
||||
aliceClient.start(user.username, user.password)
|
||||
val aliceRPC = aliceClient.proxy()
|
||||
|
||||
val bobClient = CordaRPCClient(ArtemisMessagingComponent.toHostAndPort(bobNode.nodeInfo.address), FullNodeConfiguration(bobNode.config))
|
||||
val bobClient = bobNode.rpcClientToNode()
|
||||
bobClient.start(user.username, user.password)
|
||||
val bobRPC = bobClient.proxy()
|
||||
|
||||
val issuerClientGBP = CordaRPCClient(ArtemisMessagingComponent.toHostAndPort(issuerNodeGBP.nodeInfo.address), FullNodeConfiguration(issuerNodeGBP.config))
|
||||
val issuerClientGBP = issuerNodeGBP.rpcClientToNode()
|
||||
issuerClientGBP.start(manager.username, manager.password)
|
||||
val issuerRPCGBP = issuerClientGBP.proxy()
|
||||
|
||||
val issuerClientUSD = CordaRPCClient(ArtemisMessagingComponent.toHostAndPort(issuerNodeGBP.nodeInfo.address), FullNodeConfiguration(issuerNodeUSD.config))
|
||||
val issuerClientUSD = issuerNodeGBP.rpcClientToNode() // TODO This should be issuerNodeUSD
|
||||
issuerClientUSD.start(manager.username, manager.password)
|
||||
val issuerRPCUSD = issuerClientUSD.proxy()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user