From 929341e7ee921f73e8c36916ef1347f766a1e15e Mon Sep 17 00:00:00 2001 From: Joel Dudley Date: Wed, 13 Dec 2017 16:22:40 +0000 Subject: [PATCH] Updates tutorials (general fixes, link to solutions repos) * Updates tutorial to make imports to be added clearer, and to reflect new repo structure. * Adds links to the solution repos for tut 1. * Further fixes based on dry-run. --- docs/source/example-code/build.gradle | 1 + .../template}/TemplateContract.java | 2 +- .../java/tutorial/helloworld/IOUFlow.java | 10 +++++--- .../java/tutorial/helloworld/IOUState.java | 10 +++++--- .../java/tutorial/twoparty/IOUContract.java | 13 +++++++--- .../docs/java/tutorial/twoparty/IOUFlow.java | 5 ++-- .../tutorial/twoparty/IOUFlowResponder.java | 4 +-- .../corda/docs/tutorial/helloworld/flow.kt | 7 ++++-- .../corda/docs/tutorial/helloworld/state.kt | 5 +++- .../corda/docs/tutorial/twoparty/contract.kt | 12 ++++++--- .../net/corda/docs/tutorial/twoparty/flow.kt | 17 +++++++++---- .../docs/tutorial/twoparty/flowResponder.kt | 9 ++++--- docs/source/hello-world-flow.rst | 8 +++--- docs/source/hello-world-running.rst | 25 +++++++++++-------- docs/source/hello-world-state.rst | 3 +-- docs/source/hello-world-template.rst | 21 ++++++++-------- docs/source/tut-two-party-contract.rst | 2 +- docs/source/tut-two-party-flow.rst | 10 ++++++-- 18 files changed, 102 insertions(+), 62 deletions(-) rename docs/source/example-code/src/main/java/{net/corda/docs/java/tutorial/helloworld => com/template}/TemplateContract.java (93%) diff --git a/docs/source/example-code/build.gradle b/docs/source/example-code/build.gradle index 6cad970f10..9757d433c7 100644 --- a/docs/source/example-code/build.gradle +++ b/docs/source/example-code/build.gradle @@ -33,6 +33,7 @@ dependencies { compile project(':core') compile project(':client:jfx') compile project(':node-driver') + compile project(':webserver') testCompile project(':verifier') testCompile project(':test-utils') diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/TemplateContract.java b/docs/source/example-code/src/main/java/com/template/TemplateContract.java similarity index 93% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/TemplateContract.java rename to docs/source/example-code/src/main/java/com/template/TemplateContract.java index a46712bb15..5c4278a408 100644 --- a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/TemplateContract.java +++ b/docs/source/example-code/src/main/java/com/template/TemplateContract.java @@ -1,4 +1,4 @@ -package net.corda.docs.java.tutorial.helloworld; +package com.template; import net.corda.core.contracts.CommandData; import net.corda.core.contracts.Contract; diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlow.java b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlow.java index cc0b20faed..fd35ab75ac 100644 --- a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlow.java +++ b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlow.java @@ -1,17 +1,21 @@ package net.corda.docs.java.tutorial.helloworld; -// DOCSTART 01 import co.paralleluniverse.fibers.Suspendable; +import com.template.TemplateContract; +import net.corda.core.flows.*; + +// DOCSTART 01 +// Add these imports: import net.corda.core.contracts.Command; import net.corda.core.contracts.CommandData; -import net.corda.core.flows.*; import net.corda.core.identity.Party; import net.corda.core.transactions.SignedTransaction; import net.corda.core.transactions.TransactionBuilder; import net.corda.core.utilities.ProgressTracker; -import static net.corda.docs.java.tutorial.helloworld.TemplateContract.TEMPLATE_CONTRACT_ID; +import static com.template.TemplateContract.TEMPLATE_CONTRACT_ID; +// Replace TemplateFlow's definition with: @InitiatingFlow @StartableByRPC public class IOUFlow extends FlowLogic { diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUState.java b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUState.java index 977457fd29..f724508648 100644 --- a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUState.java +++ b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUState.java @@ -1,13 +1,15 @@ package net.corda.docs.java.tutorial.helloworld; -// DOCSTART 01 -import com.google.common.collect.ImmutableList; import net.corda.core.contracts.ContractState; import net.corda.core.identity.AbstractParty; -import net.corda.core.identity.Party; - import java.util.List; +// DOCSTART 01 +// Add these imports: +import com.google.common.collect.ImmutableList; +import net.corda.core.identity.Party; + +// Replace TemplateState's definition with: public class IOUState implements ContractState { private final int value; private final Party lender; diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUContract.java b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUContract.java index b74dfd3ef4..ed0031dc48 100644 --- a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUContract.java +++ b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUContract.java @@ -1,20 +1,25 @@ package net.corda.docs.java.tutorial.twoparty; -// DOCSTART 01 -import com.google.common.collect.ImmutableList; import net.corda.core.contracts.CommandData; -import net.corda.core.contracts.CommandWithParties; import net.corda.core.contracts.Contract; -import net.corda.core.identity.Party; import net.corda.core.transactions.LedgerTransaction; +// DOCSTART 01 +// Add these imports: +import com.google.common.collect.ImmutableList; +import net.corda.core.contracts.CommandWithParties; +import net.corda.core.identity.Party; + import java.security.PublicKey; import java.util.List; import static net.corda.core.contracts.ContractsDSL.requireSingleCommand; import static net.corda.core.contracts.ContractsDSL.requireThat; +// Replace TemplateContract's definition with: public class IOUContract implements Contract { + public static final String IOU_CONTRACT_ID = "com.template.IOUContract"; + // Our Create command. public static class Create implements CommandData { } diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java index 4e0533d323..5ad1a12ce2 100644 --- a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java +++ b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java @@ -45,15 +45,14 @@ public class IOUFlow extends FlowLogic { // We retrieve the notary identity from the network map. final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); + // DOCSTART 02 // We create a transaction builder. final TransactionBuilder txBuilder = new TransactionBuilder(); txBuilder.setNotary(notary); - // DOCSTART 02 // We create the transaction components. IOUState outputState = new IOUState(iouValue, getOurIdentity(), otherParty); - String outputContract = IOUContract.class.getName(); - StateAndContract outputContractAndState = new StateAndContract(outputState, outputContract); + StateAndContract outputContractAndState = new StateAndContract(outputState, IOUContract.IOU_CONTRACT_ID); List requiredSigners = ImmutableList.of(getOurIdentity().getOwningKey(), otherParty.getOwningKey()); Command cmd = new Command<>(new IOUContract.Create(), requiredSigners); diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlowResponder.java b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlowResponder.java index ac1f312ab6..35b2a3f97b 100644 --- a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlowResponder.java +++ b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlowResponder.java @@ -1,16 +1,16 @@ package net.corda.docs.java.tutorial.twoparty; // DOCSTART 01 +// Add these imports: import co.paralleluniverse.fibers.Suspendable; import net.corda.core.contracts.ContractState; import net.corda.core.flows.*; import net.corda.core.transactions.SignedTransaction; import net.corda.core.utilities.ProgressTracker; -import net.corda.docs.java.tutorial.helloworld.IOUFlow; -import net.corda.docs.java.tutorial.helloworld.IOUState; import static net.corda.core.contracts.ContractsDSL.requireThat; +// Define IOUFlowResponder: @InitiatedBy(IOUFlow.class) public class IOUFlowResponder extends FlowLogic { private final FlowSession otherPartySession; diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/helloworld/flow.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/helloworld/flow.kt index 24832e76eb..676af37f4c 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/helloworld/flow.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/helloworld/flow.kt @@ -1,16 +1,19 @@ package net.corda.docs.tutorial.helloworld -// DOCSTART 01 import co.paralleluniverse.fibers.Suspendable -import net.corda.core.contracts.Command import net.corda.core.flows.FinalityFlow import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC + +// DOCSTART 01 +// Add these imports: +import net.corda.core.contracts.Command import net.corda.core.identity.Party import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.ProgressTracker +// Replace TemplateFlow's definition with: @InitiatingFlow @StartableByRPC class IOUFlow(val iouValue: Int, diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/helloworld/state.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/helloworld/state.kt index 447265a2ae..19f431bfb1 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/helloworld/state.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/helloworld/state.kt @@ -1,9 +1,12 @@ package net.corda.docs.tutorial.helloworld -// DOCSTART 01 import net.corda.core.contracts.ContractState + +// DOCSTART 01 +// Add these imports: import net.corda.core.identity.Party +// Replace TemplateState's definition with: class IOUState(val value: Int, val lender: Party, val borrower: Party) : ContractState { diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/twoparty/contract.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/twoparty/contract.kt index 96fb3482c1..05fb4af8bd 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/twoparty/contract.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/twoparty/contract.kt @@ -1,12 +1,16 @@ package net.corda.docs.tutorial.twoparty -// DOCSTART 01 import net.corda.core.contracts.CommandData import net.corda.core.contracts.Contract -import net.corda.core.contracts.requireSingleCommand -import net.corda.core.contracts.requireThat import net.corda.core.transactions.LedgerTransaction +// DOCSTART 01 +// Add these imports: +import net.corda.core.contracts.* + +// Replace IOUContract's contract ID and definition with: +val IOU_CONTRACT_ID = "com.template.IOUContract" + class IOUContract : Contract { // Our Create command. class Create : CommandData @@ -20,7 +24,7 @@ class IOUContract : Contract { "There should be one output state of type IOUState." using (tx.outputs.size == 1) // IOU-specific constraints. - val out = tx.outputsOfType().single() + val out = tx.outputsOfType().single() "The IOU's value must be non-negative." using (out.value > 0) "The lender and the borrower cannot be the same entity." using (out.lender != out.borrower) diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/twoparty/flow.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/twoparty/flow.kt index 0d8ac221ad..27f4705501 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/twoparty/flow.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/twoparty/flow.kt @@ -6,9 +6,17 @@ import net.corda.core.contracts.Command import net.corda.core.contracts.StateAndContract import net.corda.core.flows.* import net.corda.core.identity.Party +import net.corda.core.messaging.CordaRPCOps +import net.corda.core.serialization.SerializationWhitelist import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.ProgressTracker -import kotlin.reflect.jvm.jvmName +import net.corda.webserver.services.WebServerPluginRegistry +import java.util.function.Function +import javax.ws.rs.GET +import javax.ws.rs.Path +import javax.ws.rs.Produces +import javax.ws.rs.core.MediaType +import javax.ws.rs.core.Response // DOCEND 01 @InitiatingFlow @@ -25,14 +33,13 @@ class IOUFlow(val iouValue: Int, // We retrieve the notary identity from the network map. val notary = serviceHub.networkMapCache.notaryIdentities[0] - // We create a transaction builder + // DOCSTART 02 + // We create a transaction builder. val txBuilder = TransactionBuilder(notary = notary) - // DOCSTART 02 // We create the transaction components. val outputState = IOUState(iouValue, ourIdentity, otherParty) - val outputContract = IOUContract::class.jvmName - val outputContractAndState = StateAndContract(outputState, outputContract) + val outputContractAndState = StateAndContract(outputState, IOU_CONTRACT_ID) val cmd = Command(IOUContract.Create(), listOf(ourIdentity.owningKey, otherParty.owningKey)) // We add the items to the builder. diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/twoparty/flowResponder.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/twoparty/flowResponder.kt index b8007cc2ec..f2ff5ecdc9 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/twoparty/flowResponder.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/tutorial/twoparty/flowResponder.kt @@ -1,16 +1,19 @@ package net.corda.docs.tutorial.twoparty -// DOCSTART 01 import co.paralleluniverse.fibers.Suspendable -import net.corda.core.contracts.requireThat import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowSession import net.corda.core.flows.InitiatedBy import net.corda.core.flows.SignTransactionFlow -import net.corda.core.transactions.SignedTransaction import net.corda.docs.tutorial.helloworld.IOUFlow import net.corda.docs.tutorial.helloworld.IOUState +// DOCSTART 01 +// Add these imports: +import net.corda.core.contracts.requireThat +import net.corda.core.transactions.SignedTransaction + +// Define IOUFlowResponder: @InitiatedBy(IOUFlow::class) class IOUFlowResponder(val otherPartySession: FlowSession) : FlowLogic() { @Suspendable diff --git a/docs/source/hello-world-flow.rst b/docs/source/hello-world-flow.rst index 9d79832605..817de0545a 100644 --- a/docs/source/hello-world-flow.rst +++ b/docs/source/hello-world-flow.rst @@ -6,8 +6,8 @@ Writing the flow ================ -A flow encodes a sequence of steps that a node can run to achieve a specific ledger update. By installing new flows on -a node, we allow the node to handle new business processes. The flow we define will allow a node to issue an +A flow encodes a sequence of steps that a node can perform to achieve a specific ledger update. By installing new flows +on a node, we allow the node to handle new business processes. The flow we define will allow a node to issue an ``IOUState`` onto the ledger. Flow outline @@ -40,8 +40,8 @@ FlowLogic --------- All flows must subclass ``FlowLogic``. You then define the steps taken by the flow by overriding ``FlowLogic.call``. -Let's define our ``IOUFlow`` in either ``TemplateFlow.java`` or ``App.kt``. Delete both the existing flows in the -template, and replace them with the following: +Let's define our ``IOUFlow`` in either ``TemplateFlow.java`` or ``App.kt``. Delete the two existing flows in the +template (``Initiator`` and ``Responder``), and replace them with the following: .. container:: codeset diff --git a/docs/source/hello-world-running.rst b/docs/source/hello-world-running.rst index 17d506471d..592cfee44c 100644 --- a/docs/source/hello-world-running.rst +++ b/docs/source/hello-world-running.rst @@ -107,9 +107,15 @@ commands. We want to create an IOU of 100 with PartyB. We start the ``IOUFlow`` by typing: -.. code:: bash +.. container:: codeset - start IOUFlow iouValue: 99, otherParty: "O=PartyB,L=New York,C=US" + .. code-block:: java + + start IOUFlow arg0: 99, arg1: "O=PartyB,L=New York,C=US" + + .. code-block:: kotlin + + start IOUFlow iouValue: 99, otherParty: "O=PartyB,L=New York,C=US" This single command will cause PartyA and PartyB to automatically agree an IOU. This is one of the great advantages of the flow framework - it allows you to reduce complex negotiation and update processes into a single function call. @@ -118,13 +124,7 @@ If the flow worked, it should have recorded a new IOU in the vaults of both Part We can check the contents of each node's vault by running: -.. container:: codeset - - .. code-block:: java - - run vaultQuery contractStateType: com.template.state.IOUState - - .. code-block:: kotlin +.. code-block:: base run vaultQuery contractStateType: com.template.IOUState @@ -174,6 +174,11 @@ parts: * The ``IOUState``, representing IOUs on the ledger * The ``IOUFlow``, orchestrating the process of agreeing the creation of an IOU on-ledger +After completing this tutorial, your CorDapp should look like this: + +* Java: https://github.com/corda/corda-tut1-solution-java +* Kotlin: https://github.com/corda/corda-tut1-solution-kotlin + Next steps ---------- There are a number of improvements we could make to this CorDapp: @@ -183,4 +188,4 @@ There are a number of improvements we could make to this CorDapp: * We could add an API, to make it easier to interact with the CorDapp But for now, the biggest priority is to add an ``IOUContract`` imposing constraints on the evolution of each -``IOUState`` over time. This will be the focus of our next tutorial. +``IOUState`` over time. This will be the focus of our next tutorial. \ No newline at end of file diff --git a/docs/source/hello-world-state.rst b/docs/source/hello-world-state.rst index 5d9148d333..fb078f0780 100644 --- a/docs/source/hello-world-state.rst +++ b/docs/source/hello-world-state.rst @@ -24,7 +24,6 @@ interface is defined as follows: val participants: List } -<<<<<<< HEAD The first thing you'll probably notice about this interface declaration is that its not written in Java or another common language. The core Corda platform, including the interface declaration above, is entirely written in Kotlin. @@ -70,7 +69,7 @@ later is often as simple as adding an additional property to your class definiti Defining IOUState ----------------- -Let's get started by opening ``TemplateState.java`` (for Java) or ``App.kt`` (for Kotlin) and updating +Let's get started by opening ``TemplateState.java`` (for Java) or ``StatesAndContracts.kt`` (for Kotlin) and updating ``TemplateState`` to define an ``IOUState``: .. container:: codeset diff --git a/docs/source/hello-world-template.rst b/docs/source/hello-world-template.rst index 18ad47f515..cf34d8c892 100644 --- a/docs/source/hello-world-template.rst +++ b/docs/source/hello-world-template.rst @@ -41,34 +41,33 @@ https://docs.corda.net/tutorial-cordapp.html#opening-the-example-cordapp-in-inte Template structure ------------------ -The template has a number of files, but we can ignore most of them. To implement our IOU CorDapp in Java, we'll only -need to modify two files. For Kotlin, we'll simply be modifying the ``App.kt`` file: +The template has a number of files, but we can ignore most of them. We will only be modifying the following files: .. container:: codeset .. code-block:: java // 1. The state - src/main/java/com/template/TemplateState.java + cordapp-contracts-states/src/main/java/com/template/TemplateState.java // 2. The flow - src/main/java/com/template/TemplateFlow.java + cordapp/src/main/java/com/template/TemplateFlow.java .. code-block:: kotlin - src/main/kotlin/com/template/App.kt + // 1. The state + cordapp-contracts-states/src/main/kotlin/com/template/StatesAndContracts.kt + + // 2. The flow + cordapp/src/main/kotlin/com/template/App.kt Clean up -------- To prevent build errors later on, we should delete the following files before we begin: -* Java: - * ``src/main/java/com/template/TemplateClient.java`` - * ``src/test/java/com/template/FlowTests.java`` +* Java: ``cordapp/src/main/java/com/template/TemplateClient.java`` -* Kotlin: - * ``src/main/kotlin/com/template/TemplateClient.kt`` - * ``src/test/kotlin/com/template/FlowTests.kt`` +* Kotlin: ``cordapp/src/main/kotlin/com/template/TemplateClient.kt`` Progress so far --------------- diff --git a/docs/source/tut-two-party-contract.rst b/docs/source/tut-two-party-contract.rst index 2011f73c55..17e4bc77f2 100644 --- a/docs/source/tut-two-party-contract.rst +++ b/docs/source/tut-two-party-contract.rst @@ -77,7 +77,7 @@ We can picture this transaction as follows: Defining IOUContract -------------------- Let's write a contract that enforces these constraints. We'll do this by modifying either ``TemplateContract.java`` or -``App.kt`` and updating ``TemplateContract`` to define an ``IOUContract``: +``StatesAndContracts.kt`` and updating ``TemplateContract`` to define an ``IOUContract``: .. container:: codeset diff --git a/docs/source/tut-two-party-flow.rst b/docs/source/tut-two-party-flow.rst index 84f373047c..4b6e1c3cda 100644 --- a/docs/source/tut-two-party-flow.rst +++ b/docs/source/tut-two-party-flow.rst @@ -17,7 +17,7 @@ We'll do this by modifying the flow we wrote in the previous tutorial. Verifying the transaction ------------------------- -In ``IOUFlow.java``/``IOUFlow.kt``, change the imports block to the following: +In ``IOUFlow.java``/``App.kt``, change the imports block to the following: .. container:: codeset @@ -31,7 +31,8 @@ In ``IOUFlow.java``/``IOUFlow.kt``, change the imports block to the following: :start-after: DOCSTART 01 :end-before: DOCEND 01 -And update ``IOUFlow.call`` by changing the code following the creation of the ``TransactionBuilder`` as follows: +And update ``IOUFlow.call`` by changing the code following the retrieval of the notary's identity from the network as +follows: .. container:: codeset @@ -138,6 +139,11 @@ Our CorDapp now imposes restrictions on the issuance of IOUs. Most importantly, from both the lender and the borrower before an IOU can be created on the ledger. This prevents either the lender or the borrower from unilaterally updating the ledger in a way that only benefits themselves. +After completing this tutorial, your CorDapp should look like this: + +* Java: https://github.com/corda/corda-tut2-solution-java +* Kotlin: https://github.com/corda/corda-tut2-solution-kotlin + You should now be ready to develop your own CorDapps. You can also find a list of sample CorDapps `here `_. As you write CorDapps, you'll also want to learn more about the :doc:`Corda API `.