From 221278197aaa1414dcc8b34bb4d31c5fc777ad0c Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Wed, 22 Feb 2017 13:57:15 +0000 Subject: [PATCH] Implement RPCOp getCashBalances(). --- .../net/corda/client/CordaRPCClientTest.kt | 38 +++++++++++++++++-- .../net/corda/core/messaging/CordaRPCOps.kt | 8 ++++ .../corda/node/internal/CordaRPCOpsImpl.kt | 8 ++++ .../node/services/messaging/RPCStructures.kt | 1 + 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/client/src/integration-test/kotlin/net/corda/client/CordaRPCClientTest.kt b/client/src/integration-test/kotlin/net/corda/client/CordaRPCClientTest.kt index 4d43730ea3..b9dee73411 100644 --- a/client/src/integration-test/kotlin/net/corda/client/CordaRPCClientTest.kt +++ b/client/src/integration-test/kotlin/net/corda/client/CordaRPCClientTest.kt @@ -10,9 +10,6 @@ import net.corda.core.random63BitValue import net.corda.core.serialization.OpaqueBytes import net.corda.flows.CashIssueFlow import net.corda.flows.CashPaymentFlow -import net.corda.node.driver.DriverBasedTest -import net.corda.node.driver.NodeHandle -import net.corda.node.driver.driver import net.corda.node.internal.Node import net.corda.node.services.User import net.corda.node.services.config.configureTestSSL @@ -22,8 +19,12 @@ import net.corda.node.services.transactions.ValidatingNotaryService import net.corda.testing.node.NodeBasedTest 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.* +import kotlin.test.assertEquals +import kotlin.test.assertTrue class CordaRPCClientTest : NodeBasedTest() { private val rpcUser = User("user1", "test", permissions = setOf( @@ -39,6 +40,11 @@ class CordaRPCClientTest : NodeBasedTest() { client = CordaRPCClient(node.configuration.artemisAddress, configureTestSSL()) } + @After + fun done() { + client.close() + } + @Test fun `log in with valid username and password`() { client.start(rpcUser.username, rpcUser.password) @@ -88,4 +94,30 @@ class CordaRPCClientTest : NodeBasedTest() { handle.returnValue.getOrThrow() } } + + @Test + fun `get cash balances`() { + println("Starting client") + client.start(rpcUser.username, rpcUser.password) + println("Creating proxy") + val proxy = client.proxy() + + val startCash = proxy.getCashBalances() + assertTrue(startCash.isEmpty(), "Should not start with any cash") + + val flowHandle = proxy.startFlow(::CashIssueFlow, + 123.DOLLARS, OpaqueBytes.of(0), + node.info.legalIdentity, node.info.legalIdentity + ) + println("Started issuing cash, waiting on result") + flowHandle.progress.subscribe { + println("CashIssue PROGRESS $it") + } + + val finishCash = proxy.getCashBalances() + println("Cash Balances: $finishCash") + assertEquals(1, finishCash.size) + assertEquals(123.DOLLARS, finishCash.get(Currency.getInstance("USD"))) + } + } diff --git a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt index eb66be0174..4f4f50362a 100644 --- a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt +++ b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt @@ -1,6 +1,7 @@ package net.corda.core.messaging import com.google.common.util.concurrent.ListenableFuture +import net.corda.core.contracts.Amount import net.corda.core.contracts.ContractState import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.UpgradedContract @@ -18,6 +19,7 @@ import rx.Observable import java.io.InputStream import java.io.OutputStream import java.time.Instant +import java.util.* data class StateMachineInfo( val id: StateMachineRunId, @@ -95,6 +97,12 @@ interface CordaRPCOps : RPCOps { */ fun getVaultTransactionNotes(txnId: SecureHash): Iterable + /* + * Returns a map of how much cash we have in each currency, ignoring details like issuer. Note: currencies for + * which we have no cash evaluate to null (not present in map), not 0. + */ + fun getCashBalances(): Map> + /** * Checks whether an attachment with the given hash is stored on the node. */ diff --git a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt index df4f40122d..cbbfb88104 100644 --- a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt @@ -1,5 +1,6 @@ package net.corda.node.internal +import net.corda.core.contracts.Amount import net.corda.core.contracts.ContractState import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.UpgradedContract @@ -27,6 +28,7 @@ import org.jetbrains.exposed.sql.Database import rx.Observable import java.io.InputStream import java.time.Instant +import java.util.* /** * Server side implementations of RPCs available to MQ based client tools. Execution takes place on the server @@ -90,6 +92,12 @@ class CordaRPCOpsImpl( } } + override fun getCashBalances(): Map> { + return databaseTransaction(database) { + services.vaultService.cashBalances + } + } + // TODO: Check that this flow is annotated as being intended for RPC invocation override fun startFlowDynamic(logicType: Class>, vararg args: Any?): FlowHandle { requirePermission(startFlowPermission(logicType)) diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt b/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt index ff91af2992..45f635fa4e 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt @@ -181,6 +181,7 @@ private class RPCKryo(observableSerializer: Serializer>? = null) register(UUID::class.java) register(UniqueIdentifier::class.java) register(LinkedHashSet::class.java) + register(LinkedHashMap::class.java) register(StateAndRef::class.java) register(setOf().javaClass) // EmptySet register(StateRef::class.java)