docs: Update Client RPC API tutorial with how to initiate protocols

This commit is contained in:
Andras Slemmer
2016-11-15 12:36:17 +00:00
parent dcd7a8a08a
commit e6f9570fff
3 changed files with 146 additions and 84 deletions

View File

@ -1,15 +1,32 @@
package net.corda.docs
import com.google.common.net.HostAndPort
import net.corda.client.CordaRPCClient
import net.corda.contracts.asset.Cash
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.node.services.ServiceInfo
import net.corda.core.serialization.OpaqueBytes
import net.corda.core.transactions.SignedTransaction
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.CordaRPCOps
import net.corda.node.services.messaging.startProtocol
import net.corda.node.services.startProtocolPermission
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.protocols.CashCommand
import net.corda.protocols.CashProtocol
import org.graphstream.graph.Edge
import org.graphstream.graph.Node
import org.graphstream.graph.implementations.SingleGraph
import org.graphstream.graph.implementations.MultiGraph
import rx.Observable
import java.nio.file.Paths
import java.util.concurrent.CompletableFuture
import java.util.*
import kotlin.concurrent.thread
/**
* This is example code for the Client RPC API tutorial. The START/END comments are important and used by the documentation!
@ -22,61 +39,100 @@ enum class PrintOrVisualise {
}
fun main(args: Array<String>) {
if (args.size < 2) {
throw IllegalArgumentException("Usage: <binary> <node address> [Print|Visualise]")
if (args.size < 1) {
throw IllegalArgumentException("Usage: <binary> [Print|Visualise]")
}
val nodeAddress = HostAndPort.fromString(args[0])
val printOrVisualise = PrintOrVisualise.valueOf(args[1])
val sslConfig = object : NodeSSLConfiguration {
override val certificatesPath = Paths.get("build/trader-demo/buyer/certificates")
override val keyStorePassword = "cordacadevpass"
override val trustStorePassword = "trustpass"
}
// END 1
val printOrVisualise = PrintOrVisualise.valueOf(args[0])
// START 2
val username = System.console().readLine("Enter username: ")
val password = String(System.console().readPassword("Enter password: "))
val client = CordaRPCClient(nodeAddress, sslConfig)
client.start(username, password)
val proxy = client.proxy()
// END 2
val baseDirectory = Paths.get("build/rpc-api-tutorial")
val user = User("user", "password", permissions = setOf(startProtocolPermission<CashProtocol>()))
// START 3
val (transactions: List<SignedTransaction>, futureTransactions: Observable<SignedTransaction>) = proxy.verifiedTransactions()
// END 3
// START 4
when (printOrVisualise) {
PrintOrVisualise.Print -> {
futureTransactions.startWith(transactions).subscribe { transaction ->
println("NODE ${transaction.id}")
transaction.tx.inputs.forEach { input ->
println("EDGE ${input.txhash} ${transaction.id}")
}
}
CompletableFuture<Unit>().get() // block indefinitely
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 4
// START 5
PrintOrVisualise.Visualise -> {
val graph = SingleGraph("transactions")
transactions.forEach { transaction ->
graph.addNode<Node>("${transaction.id}")
}
transactions.forEach { transaction ->
transaction.tx.inputs.forEach { ref ->
graph.addEdge<Edge>("$ref", "${ref.txhash}", "${transaction.id}")
// END 1
// START 2
val client = CordaRPCClient(FullNodeConfiguration(node.config).artemisAddress, sslConfig)
client.start("user", "password")
val proxy = client.proxy()
thread {
generateTransactions(proxy)
}
// END 2
// START 3
val (transactions: List<SignedTransaction>, futureTransactions: Observable<SignedTransaction>) = proxy.verifiedTransactions()
// END 3
// START 4
when (printOrVisualise) {
PrintOrVisualise.Print -> {
futureTransactions.startWith(transactions).subscribe { transaction ->
println("NODE ${transaction.id}")
transaction.tx.inputs.forEach { input ->
println("EDGE ${input.txhash} ${transaction.id}")
}
}
}
futureTransactions.subscribe { transaction ->
graph.addNode<Node>("${transaction.id}")
transaction.tx.inputs.forEach { ref ->
graph.addEdge<Edge>("$ref", "${ref.txhash}", "${transaction.id}")
// END 4
// START 5
PrintOrVisualise.Visualise -> {
val graph = MultiGraph("transactions")
transactions.forEach { transaction ->
graph.addNode<Node>("${transaction.id}")
}
transactions.forEach { transaction ->
transaction.tx.inputs.forEach { ref ->
graph.addEdge<Edge>("$ref", "${ref.txhash}", "${transaction.id}")
}
}
futureTransactions.subscribe { transaction ->
graph.addNode<Node>("${transaction.id}")
transaction.tx.inputs.forEach { ref ->
graph.addEdge<Edge>("$ref", "${ref.txhash}", "${transaction.id}")
}
}
graph.display()
}
graph.display()
}
waitForAllNodesToFinish()
}
}
// END 5
// START 6
fun generateTransactions(proxy: CordaRPCOps) {
var ownedQuantity = proxy.vaultAndUpdates().first.fold(0L) { sum, state ->
sum + (state.state.data as Cash.State).amount.quantity
}
val issueRef = OpaqueBytes.of(0)
val notary = proxy.networkMapUpdates().first.first { it.advertisedServices.any { it.info.type.isNotary() } }.notaryIdentity
val me = proxy.nodeIdentity().legalIdentity
val meAndRef = PartyAndReference(me, issueRef)
while (true) {
Thread.sleep(1000)
val random = SplittableRandom()
val n = random.nextDouble()
if (ownedQuantity > 10000 && n > 0.8) {
val quantity = Math.abs(random.nextLong()) % 2000
proxy.startProtocol(::CashProtocol, CashCommand.ExitCash(Amount(quantity, USD), issueRef))
ownedQuantity -= quantity
} else if (ownedQuantity > 1000 && n < 0.7) {
val quantity = Math.abs(random.nextLong() % Math.min(ownedQuantity, 2000))
proxy.startProtocol(::CashProtocol, CashCommand.PayCash(Amount(quantity, Issued(meAndRef, USD)), me))
} else {
val quantity = Math.abs(random.nextLong() % 1000)
proxy.startProtocol(::CashProtocol, CashCommand.IssueCash(Amount(quantity, USD), issueRef, me, notary))
ownedQuantity += quantity
}
}
}
// END 5
// END 6