Added a method to NodeHandle to simplify using RPC in the Driver

This commit is contained in:
Shams Asari 2017-01-06 11:33:00 +00:00
parent 0867a05ad7
commit 59456cb6b1
17 changed files with 146 additions and 148 deletions

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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 }

View File

@ -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 = {
val (nodeA, nodeB) = Futures.allAsList(
startNode("Bank A"),
startNode("Bank B"),
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")
).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()

View File

@ -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)
}

View File

@ -1,38 +1,40 @@
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())
val bocClient = nodeBankOfCorda.rpcClientToNode()
bocClient.start("user1", "test")
val bocProxy = bocClient.proxy()
// Big Corporation RPC Client
val bigCorpClient = CordaRPCClient(nodeBankOfCordaApiAddr, configureTestSSL())
val bigCorpClient = nodeBankOfCorda.rpcClientToNode() // TODO This test is broken as this should be nodeBigCorporation
bigCorpClient.start("user1", "test")
val bigCorpProxy = bigCorpClient.proxy()
@ -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 }
}
)
}

View File

@ -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
@ -16,16 +16,17 @@ 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`() {
@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)
}
}

View File

@ -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")
}

View File

@ -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)
}
}

View File

@ -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()

View File

@ -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()