From f3b09988a92cf85750df903d26f0172e21dd13cf Mon Sep 17 00:00:00 2001 From: Joel Dudley Date: Tue, 13 Nov 2018 11:50:24 +0000 Subject: [PATCH] Updates tutorial to reflect new template structure. Clean-up. (#4216) * Initial improvements. * Updates tutorials. * Missing imports. * Addresses review feedback. --- .../java/tutorial/helloworld/IOUFlow.java | 14 ++--- .../java/tutorial/helloworld/IOUState.java | 6 +-- .../java/tutorial/twoparty/IOUContract.java | 40 ++++++++------- .../docs/java/tutorial/twoparty/IOUFlow.java | 22 ++++---- .../docs/java/tutorial/twoparty/IOUState.java | 4 +- .../kotlin/tutorial/helloworld/IOUFlow.kt | 6 +-- .../kotlin/tutorial/helloworld/IOUState.kt | 2 +- .../kotlin/tutorial/twoparty/IOUContract.kt | 12 ++--- .../docs/kotlin/tutorial/twoparty/IOUFlow.kt | 15 +++--- .../tutorial/twoparty/IOUFlowResponder.kt | 5 +- docs/source/hello-world-flow.rst | 3 +- docs/source/hello-world-introduction.rst | 51 +++++++++++-------- docs/source/hello-world-running.rst | 25 ++++++--- docs/source/hello-world-state.rst | 8 +-- docs/source/hello-world-template.rst | 28 +++++----- docs/source/tut-two-party-contract.rst | 10 ++-- docs/source/tut-two-party-flow.rst | 5 +- docs/source/tut-two-party-introduction.rst | 4 +- 18 files changed, 136 insertions(+), 124 deletions(-) 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 5697aed05e..cadcae2ce2 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 @@ -2,16 +2,19 @@ package net.corda.docs.java.tutorial.helloworld; import co.paralleluniverse.fibers.Suspendable; import com.template.TemplateContract; -import net.corda.core.flows.*; +import net.corda.core.flows.FlowException; +import net.corda.core.flows.FlowLogic; +import net.corda.core.flows.InitiatingFlow; +import net.corda.core.flows.StartableByRPC; +import net.corda.core.utilities.ProgressTracker; // DOCSTART 01 // Add these imports: import net.corda.core.contracts.Command; -import net.corda.core.contracts.CommandData; +import net.corda.core.flows.FinalityFlow; import net.corda.core.identity.Party; import net.corda.core.transactions.SignedTransaction; import net.corda.core.transactions.TransactionBuilder; -import net.corda.core.utilities.ProgressTracker; // Replace Initiator's definition with: @InitiatingFlow @@ -46,13 +49,12 @@ public class IOUFlow extends FlowLogic { // We create the transaction components. IOUState outputState = new IOUState(iouValue, getOurIdentity(), otherParty); - CommandData cmdType = new TemplateContract.Commands.Action(); - Command cmd = new Command<>(cmdType, getOurIdentity().getOwningKey()); + Command command = new Command<>(new TemplateContract.Commands.Action(), getOurIdentity().getOwningKey()); // We create a transaction builder and add the components. TransactionBuilder txBuilder = new TransactionBuilder(notary) .addOutputState(outputState, TemplateContract.ID) - .addCommand(cmd); + .addCommand(command); // Signing the transaction. SignedTransaction signedTx = getServiceHub().signInitialTransaction(txBuilder); 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 f724508648..4e91806b7f 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 @@ -2,11 +2,11 @@ package net.corda.docs.java.tutorial.helloworld; import net.corda.core.contracts.ContractState; import net.corda.core.identity.AbstractParty; +import java.util.Arrays; import java.util.List; // DOCSTART 01 -// Add these imports: -import com.google.common.collect.ImmutableList; +// Add this import: import net.corda.core.identity.Party; // Replace TemplateState's definition with: @@ -35,7 +35,7 @@ public class IOUState implements ContractState { @Override public List getParticipants() { - return ImmutableList.of(lender, borrower); + return Arrays.asList(lender, borrower); } } // DOCEND 01 \ No newline at end of file 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 af2bb40daa..5f96ecd450 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 @@ -6,15 +6,14 @@ 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.Arrays; 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 { @@ -28,26 +27,29 @@ public class IOUContract implements Contract { public void verify(LedgerTransaction tx) { final CommandWithParties command = requireSingleCommand(tx.getCommands(), IOUContract.Create.class); - requireThat(check -> { - // Constraints on the shape of the transaction. - check.using("No inputs should be consumed when issuing an IOU.", tx.getInputs().isEmpty()); - check.using("There should be one output state of type IOUState.", tx.getOutputs().size() == 1); + // Constraints on the shape of the transaction. + if (!tx.getInputs().isEmpty()) + throw new IllegalArgumentException("No inputs should be consumed when issuing an IOU."); + if (!(tx.getOutputs().size() == 1)) + throw new IllegalArgumentException("There should be one output state of type IOUState."); - // IOU-specific constraints. - final IOUState out = tx.outputsOfType(IOUState.class).get(0); - final Party lender = out.getLender(); - final Party borrower = out.getBorrower(); - check.using("The IOU's value must be non-negative.", out.getValue() > 0); - check.using("The lender and the borrower cannot be the same entity.", lender != borrower); + // IOU-specific constraints. + final IOUState output = tx.outputsOfType(IOUState.class).get(0); + final Party lender = output.getLender(); + final Party borrower = output.getBorrower(); + if (output.getValue() <= 0) + throw new IllegalArgumentException("The IOU's value must be non-negative."); + if (lender.equals(borrower)) + throw new IllegalArgumentException("The lender and the borrower cannot be the same entity."); - // Constraints on the signers. - final List signers = command.getSigners(); - check.using("There must be two signers.", signers.size() == 2); - check.using("The borrower and lender must be signers.", signers.containsAll( - ImmutableList.of(borrower.getOwningKey(), lender.getOwningKey()))); + // Constraints on the signers. + final List requiredSigners = command.getSigners(); + final List expectedSigners = Arrays.asList(borrower.getOwningKey(), lender.getOwningKey()); + if (requiredSigners.size() != 2) + throw new IllegalArgumentException("There must be two signers."); + if (!(requiredSigners.containsAll(expectedSigners))) + throw new IllegalArgumentException("The borrower and lender must be signers."); - return null; - }); } } // DOCEND 01 \ No newline at end of file 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 eb5158d24b..8f5221c641 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 @@ -2,9 +2,7 @@ package net.corda.docs.java.tutorial.twoparty; // DOCSTART 01 import co.paralleluniverse.fibers.Suspendable; -import com.google.common.collect.ImmutableList; 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.transactions.SignedTransaction; @@ -12,6 +10,7 @@ import net.corda.core.transactions.TransactionBuilder; import net.corda.core.utilities.ProgressTracker; import java.security.PublicKey; +import java.util.Arrays; import java.util.List; // DOCEND 01 @@ -42,22 +41,19 @@ public class IOUFlow extends FlowLogic { @Suspendable @Override public Void call() throws FlowException { + // DOCSTART 02 // We retrieve the notary identity from the network map. Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); - // DOCSTART 02 - // We create a transaction builder. - TransactionBuilder txBuilder = new TransactionBuilder(); - txBuilder.setNotary(notary); - // We create the transaction components. IOUState outputState = new IOUState(iouValue, getOurIdentity(), otherParty); - StateAndContract outputContractAndState = new StateAndContract(outputState, IOUContract.ID); - List requiredSigners = ImmutableList.of(getOurIdentity().getOwningKey(), otherParty.getOwningKey()); - Command cmd = new Command<>(new IOUContract.Create(), requiredSigners); + List requiredSigners = Arrays.asList(getOurIdentity().getOwningKey(), otherParty.getOwningKey()); + Command command = new Command<>(new IOUContract.Create(), requiredSigners); - // We add the items to the builder. - txBuilder.withItems(outputContractAndState, cmd); + // We create a transaction builder and add the components. + TransactionBuilder txBuilder = new TransactionBuilder(notary) + .addOutputState(outputState, IOUContract.ID) + .addCommand(command); // Verifying the transaction. txBuilder.verify(getServiceHub()); @@ -70,7 +66,7 @@ public class IOUFlow extends FlowLogic { // Obtaining the counterparty's signature. SignedTransaction fullySignedTx = subFlow(new CollectSignaturesFlow( - signedTx, ImmutableList.of(otherPartySession), CollectSignaturesFlow.tracker())); + signedTx, Arrays.asList(otherPartySession), CollectSignaturesFlow.tracker())); // Finalising the transaction. subFlow(new FinalityFlow(fullySignedTx)); diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUState.java b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUState.java index 4cc6f9f76c..556746b139 100644 --- a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUState.java +++ b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUState.java @@ -1,10 +1,10 @@ package net.corda.docs.java.tutorial.twoparty; -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.Arrays; import java.util.List; public class IOUState implements ContractState { @@ -32,6 +32,6 @@ public class IOUState implements ContractState { @Override public List getParticipants() { - return ImmutableList.of(lender, borrower); + return Arrays.asList(lender, borrower); } } \ No newline at end of file diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlow.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlow.kt index 8d24d540f7..d3fef7f66d 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlow.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlow.kt @@ -8,13 +8,13 @@ import net.corda.core.flows.FinalityFlow import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC +import net.corda.core.utilities.ProgressTracker // 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 Initiator's definition with: @InitiatingFlow @@ -33,12 +33,12 @@ class IOUFlow(val iouValue: Int, // We create the transaction components. val outputState = IOUState(iouValue, ourIdentity, otherParty) - val cmd = Command(TemplateContract.Commands.Action(), ourIdentity.owningKey) + val command = Command(TemplateContract.Commands.Action(), ourIdentity.owningKey) // We create a transaction builder and add the components. val txBuilder = TransactionBuilder(notary = notary) .addOutputState(outputState, TemplateContract.ID) - .addCommand(cmd) + .addCommand(command) // We sign the transaction. val signedTx = serviceHub.signInitialTransaction(txBuilder) diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt index b66604a504..27a3a52e18 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt @@ -5,7 +5,7 @@ package net.corda.docs.kotlin.tutorial.helloworld import net.corda.core.contracts.ContractState // DOCSTART 01 -// Add these imports: +// Add this import: import net.corda.core.identity.Party // Replace TemplateState's definition with: diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUContract.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUContract.kt index 2cc42f6dd7..578039feb2 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUContract.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUContract.kt @@ -5,7 +5,7 @@ import net.corda.core.contracts.Contract import net.corda.core.transactions.LedgerTransaction // DOCSTART 01 -// Add these imports: +// Add this import: import net.corda.core.contracts.* class IOUContract : Contract { @@ -25,14 +25,14 @@ 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() - "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) + val output = tx.outputsOfType().single() + "The IOU's value must be non-negative." using (output.value > 0) + "The lender and the borrower cannot be the same entity." using (output.lender != output.borrower) // Constraints on the signers. + val expectedSigners = listOf(output.borrower.owningKey, output.lender.owningKey) "There must be two signers." using (command.signers.toSet().size == 2) - "The borrower and lender must be signers." using (command.signers.containsAll(listOf( - out.borrower.owningKey, out.lender.owningKey))) + "The borrower and lender must be signers." using (command.signers.containsAll(expectedSigners)) } } } diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt index ef1e9d9b03..6eb508b3f0 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt @@ -5,7 +5,6 @@ package net.corda.docs.kotlin.tutorial.twoparty // DOCSTART 01 import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.Command -import net.corda.core.contracts.StateAndContract import net.corda.core.flows.CollectSignaturesFlow import net.corda.core.flows.FinalityFlow import net.corda.core.flows.FlowLogic @@ -27,20 +26,18 @@ class IOUFlow(val iouValue: Int, /** The flow logic is encapsulated within the call() method. */ @Suspendable override fun call() { + // DOCSTART 02 // We retrieve the notary identity from the network map. val notary = serviceHub.networkMapCache.notaryIdentities[0] - // DOCSTART 02 - // We create a transaction builder. - val txBuilder = TransactionBuilder(notary = notary) - // We create the transaction components. val outputState = IOUState(iouValue, ourIdentity, otherParty) - val outputContractAndState = StateAndContract(outputState, IOUContract.ID) - val cmd = Command(IOUContract.Create(), listOf(ourIdentity.owningKey, otherParty.owningKey)) + val command = Command(IOUContract.Create(), listOf(ourIdentity.owningKey, otherParty.owningKey)) - // We add the items to the builder. - txBuilder.withItems(outputContractAndState, cmd) + // We create a transaction builder and add the components. + val txBuilder = TransactionBuilder(notary = notary) + .addOutputState(outputState, IOUContract.ID) + .addCommand(command) // Verifying the transaction. txBuilder.verify(serviceHub) diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt index c6ac0704b4..882d3061a5 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt @@ -3,10 +3,7 @@ package net.corda.docs.kotlin.tutorial.twoparty import co.paralleluniverse.fibers.Suspendable -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.flows.* import net.corda.docs.kotlin.tutorial.helloworld.IOUFlow import net.corda.docs.kotlin.tutorial.helloworld.IOUState diff --git a/docs/source/hello-world-flow.rst b/docs/source/hello-world-flow.rst index 10c3ba66f6..b6281a51d4 100644 --- a/docs/source/hello-world-flow.rst +++ b/docs/source/hello-world-flow.rst @@ -40,8 +40,7 @@ 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 ``Initiator.java`` or ``Flows.kt``. Delete the two existing flows in the -template (``Initiator`` and ``Responder``), and replace them with the following: +Let's define our ``IOUFlow``. Delete the existing ``Responder`` flow. Then replace the definition of ``Initiator`` with the following: .. container:: codeset diff --git a/docs/source/hello-world-introduction.rst b/docs/source/hello-world-introduction.rst index 06a9fcb46e..a2b7ea2a0f 100644 --- a/docs/source/hello-world-introduction.rst +++ b/docs/source/hello-world-introduction.rst @@ -13,29 +13,38 @@ By this point, :doc:`your dev environment should be set up `, yo :doc:`your first CorDapp `, and you're familiar with Corda's :doc:`key concepts `. What comes next? -If you're a developer, the next step is to write your own CorDapp. CorDapps are plugins that are installed on one or -more Corda nodes, and give the nodes' owners the ability to make their node conduct some new process - anything from +If you're a developer, the next step is to write your own CorDapp. CorDapps are applications that are installed on one or +more Corda nodes, and that allow the node's operator to instruct their node to perform some new process - anything from issuing a debt instrument to making a restaurant booking. Our use-case ------------ -Our CorDapp will model IOUs on-ledger. An IOU – short for “I O(we) (yo)U” – records the fact that one person owes -another person a given amount of money. Clearly this is sensitive information that we'd only want to communicate on -a need-to-know basis between the lender and the borrower. Fortunately, this is one of the areas where Corda excels. -Corda makes it easy to allow a small set of parties to agree on a shared fact without needing to share this fact with -everyone else on the network, as is the norm in blockchain platforms. +We will write a CorDapp to model IOUs on the blockchain. Each IOU – short for “I O(we) (yo)U” – will record the fact that one node owes +another node a certain amount. This simple CorDapp will showcase several key benefits of Corda as a blockchain platform: -To serve any useful function, our CorDapp will need at least two things: +* **Privacy** - Since IOUs represent sensitive information, we will be taking advantage of Corda's ability to only share + ledger updates with other nodes on a need-to-know basis, instead of using a gossip protocol to share this information with every node on + the network as you would with a traditional blockchain platform -* **States**, the shared facts that Corda nodes reach consensus over and are then stored on the ledger -* **Flows**, which encapsulate the procedure for carrying out a specific ledger update +* **Well-known identities** - Each Corda node has a well-known identity on the network. This allows us to write code in terms of real + identities, rather than anonymous public keys -Our IOU CorDapp is no exception. It will define both a state and a flow: +* **Re-use of existing, proven technologies** - We will be writing our CorDapp using standard Java. It will run on a Corda node, which is + simply a Java process and runs on a regular Java machine (e.g. on your local machine or in the cloud). The nodes will store their data in + a standard SQL database + +CorDapps usually define at least three things: + +* **States** - the (possibly shared) facts that are written to the ledger +* **Flows** - the procedures for carrying out specific ledger updates +* **Contracts** - the constraints governing how states of a given type can evolve over time + +Our IOU CorDapp is no exception. It will define the following components: The IOUState ^^^^^^^^^^^^ -Our state will be the ``IOUState``. It will store the value of the IOU, as well as the identities of the lender and the -borrower. We can visualize ``IOUState`` as follows: +Our state will be the ``IOUState``, representing an IOU. It will contain the IOU's value, its lender and its borrower. We can visualize +``IOUState`` as follows: .. image:: resources/tutorial-state.png :scale: 25% @@ -43,20 +52,20 @@ borrower. We can visualize ``IOUState`` as follows: The IOUFlow ^^^^^^^^^^^ -Our flow will be the ``IOUFlow``. This flow will completely automate the process of issuing a new IOU onto a ledger. It -is composed of the following steps: +Our flow will be the ``IOUFlow``. This flow will completely automate the process of issuing a new IOU onto a ledger. It has the following +steps: .. image:: resources/simple-tutorial-flow.png :scale: 25% :align: center -In traditional distributed ledger systems, where all data is broadcast to every network participant, you don’t need to -think about data flows – you simply package up your ledger update and send it to everyone else on the network. But in -Corda, where privacy is a core focus, flows allow us to carefully control who sees what during the process of -agreeing a ledger update. +The IOUContract +^^^^^^^^^^^^^^^ +For this tutorial, we will use the default ``TemplateContract``. We will update it to create a fully-fledged ``IOUContract`` in the next +tutorial. Progress so far --------------- -We've sketched out a simple CorDapp that will allow nodes to confidentially issue new IOUs onto a ledger. +We've designed a simple CorDapp that will allow nodes to agree new IOUs on the blockchain. -Next, we'll be taking a look at the template project we'll be using as the basis for our CorDapp. \ No newline at end of file +Next, we'll take a look at the template project we'll be using as the basis for our CorDapp. diff --git a/docs/source/hello-world-running.rst b/docs/source/hello-world-running.rst index d217dee102..b57979a7ec 100644 --- a/docs/source/hello-world-running.rst +++ b/docs/source/hello-world-running.rst @@ -107,11 +107,9 @@ commands. We want to create an IOU of 99 with PartyB. We start the ``IOUFlow`` by typing: -.. container:: codeset +.. code-block:: bash - .. code-block:: kotlin - - start IOUFlow iouValue: 99, otherParty: "O=PartyB,L=New York,C=US" + 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. @@ -122,7 +120,7 @@ We can check the contents of each node's vault by running: .. code-block:: bash - run vaultQuery contractStateType: com.template.IOUState + run vaultQuery contractStateType: com.template.IOUState The vaults of PartyA and PartyB should both display the following output: @@ -162,12 +160,27 @@ The vaults of PartyA and PartyB should both display the following output: This is the transaction issuing our ``IOUState`` onto a ledger. +However, if we run the same command on the other node (the notary), we will see the following: + +.. code:: bash + + { + "states" : [ ], + "statesMetadata" : [ ], + "totalStatesAvailable" : -1, + "stateTypes" : "UNCONSUMED", + "otherResults" : [ ] + } + +This is the result of Corda's privacy model. Because the notary was not involved in the transaction and had no need to see the data, the +transaction was not distributed to them. + Conclusion ---------- We have written a simple CorDapp that allows IOUs to be issued onto the ledger. Our CorDapp is made up of two key parts: -* The ``IOUState``, representing IOUs on the ledger +* The ``IOUState``, representing IOUs on the blockchain * The ``IOUFlow``, orchestrating the process of agreeing the creation of an IOU on-ledger After completing this tutorial, your CorDapp should look like this: diff --git a/docs/source/hello-world-state.rst b/docs/source/hello-world-state.rst index 0a2d9c4b12..1a72159201 100644 --- a/docs/source/hello-world-state.rst +++ b/docs/source/hello-world-state.rst @@ -7,7 +7,7 @@ Writing the state ================= -In Corda, shared facts on the ledger are represented as states. Our first task will be to define a new state type to +In Corda, shared facts on the blockchain are represented as states. Our first task will be to define a new state type to represent an IOU. The ContractState interface @@ -28,7 +28,7 @@ We can see that the ``ContractState`` interface has a single field, ``participan entities for which this state is relevant. Beyond this, our state is free to define any fields, methods, helpers or inner classes it requires to accurately -represent a given type of shared fact on the ledger. +represent a given type of shared fact on the blockchain. .. note:: @@ -46,7 +46,7 @@ represent a given type of shared fact on the ledger. Modelling IOUs -------------- -How should we define the ``IOUState`` representing IOUs on the ledger? Beyond implementing the ``ContractState`` +How should we define the ``IOUState`` representing IOUs on the blockchain? Beyond implementing the ``ContractState`` interface, our ``IOUState`` will also need properties to track the relevant features of the IOU: * The value of the IOU @@ -99,7 +99,7 @@ Corda are simply classes that implement the ``ContractState`` interface. They ca methods you like. All that's left to do is write the ``IOUFlow`` that will allow a node to orchestrate the creation of a new ``IOUState`` -on the ledger, while only sharing information on a need-to-know basis. +on the blockchain, while only sharing information on a need-to-know basis. What about the contract? ------------------------ diff --git a/docs/source/hello-world-template.rst b/docs/source/hello-world-template.rst index 5d421d0906..8ad3d76c65 100644 --- a/docs/source/hello-world-template.rst +++ b/docs/source/hello-world-template.rst @@ -7,41 +7,39 @@ The CorDapp Template ==================== -When writing a new CorDapp, you’ll generally want to base it on the standard templates: +When writing a new CorDapp, you’ll generally want to start from one of the standard templates: * The `Java Cordapp Template `_ * The `Kotlin Cordapp Template `_ -The Cordapp templates provide the required boilerplate for developing a CorDapp, and allow you to quickly deploy your -CorDapp onto a local test network of dummy nodes to test its functionality. +The Cordapp templates provide the boilerplate for developing a new CorDapp. CorDapps can be written in either Java or Kotlin. We will be +providing the code in both languages throughout this tutorial. -CorDapps can be written in both Java and Kotlin, and will be providing the code in both languages in this tutorial. - -Note that there's no need to download and install Corda itself. Corda's required libraries will be downloaded -automatically from an online Maven repository. +Note that there's no need to download and install Corda itself. The required libraries are automatically downloaded from an online Maven +repository and cached locally. Downloading the template ------------------------ -To download the template, open a terminal window in the directory where you want to download the CorDapp template, and -run the following command: +Open a terminal window in the directory where you want to download the CorDapp template, and run the following command: -.. code-block:: bash +.. container:: codeset - git clone https://github.com/corda/cordapp-template-java.git ; cd cordapp-template-java + .. code-block:: java - *or* + git clone https://github.com/corda/cordapp-template-java.git ; cd cordapp-template-java - git clone https://github.com/corda/cordapp-template-kotlin.git ; cd cordapp-template-kotlin + .. code-block:: kotlin + + git clone https://github.com/corda/cordapp-template-kotlin.git ; cd cordapp-template-kotlin Opening the template in IntelliJ -------------------------------- - Once the template is download, open it in IntelliJ by following the instructions here: https://docs.corda.net/tutorial-cordapp.html#opening-the-example-cordapp-in-intellij. Template structure ------------------ -The template has a number of files, but we can ignore most of them. We will only be modifying the following files: +For this tutorial, we will only be modifying the following files: .. container:: codeset diff --git a/docs/source/tut-two-party-contract.rst b/docs/source/tut-two-party-contract.rst index 8a94c75bad..720c40cb6f 100644 --- a/docs/source/tut-two-party-contract.rst +++ b/docs/source/tut-two-party-contract.rst @@ -154,7 +154,7 @@ Transaction constraints ~~~~~~~~~~~~~~~~~~~~~~~ We also want our transaction to have no inputs and only a single output - an issuance transaction. -To impose this and the subsequent constraints, we are using Corda's built-in ``requireThat`` block. ``requireThat`` +In Kotlin, we impose these and the subsequent constraints using Corda's built-in ``requireThat`` block. ``requireThat`` provides a terse way to write the following: * If the condition on the right-hand side doesn't evaluate to true... @@ -162,6 +162,8 @@ provides a terse way to write the following: As before, the act of throwing this exception causes the transaction to be considered invalid. +In Java, we simply throw an ``IllegalArgumentException`` manually instead. + IOU constraints ~~~~~~~~~~~~~~~ We want to impose two constraints on the ``IOUState`` itself: @@ -169,9 +171,7 @@ We want to impose two constraints on the ``IOUState`` itself: * Its value must be non-negative * The lender and the borrower cannot be the same entity -We impose these constraints in the same ``requireThat`` block as before. - -You can see that we're not restricted to only writing constraints in the ``requireThat`` block. We can also write +You can see that we're not restricted to only writing constraints inside ``verify``. We can also write other statements - in this case, extracting the transaction's single ``IOUState`` and assigning it to a variable. Signer constraints @@ -180,7 +180,7 @@ Finally, we require both the lender and the borrower to be required signers on t required signers is equal to the union of all the signers listed on the commands. We therefore extract the signers from the ``Create`` command we retrieved earlier. -This is an absolutely essential constraint - it ensures that no ``IOUState`` can ever be created on the ledger without +This is an absolutely essential constraint - it ensures that no ``IOUState`` can ever be created on the blockchain without the express agreement of both the lender and borrower nodes. Progress so far diff --git a/docs/source/tut-two-party-flow.rst b/docs/source/tut-two-party-flow.rst index 3a4cebb15d..7542eaed14 100644 --- a/docs/source/tut-two-party-flow.rst +++ b/docs/source/tut-two-party-flow.rst @@ -31,8 +31,7 @@ In ``IOUFlow.java``/``Flows.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 retrieval of the notary's identity from the network as -follows: +And update ``IOUFlow.call`` to the following: .. container:: codeset @@ -136,7 +135,7 @@ defined in ``IOUContract``. We can now re-run our updated CorDapp, using the :doc:`same instructions as before `. Our CorDapp now imposes restrictions on the issuance of IOUs. Most importantly, IOU issuance now requires agreement -from both the lender and the borrower before an IOU can be created on the ledger. This prevents either the lender or +from both the lender and the borrower before an IOU can be created on the blockchain. 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: diff --git a/docs/source/tut-two-party-introduction.rst b/docs/source/tut-two-party-introduction.rst index d44743b2e8..a12f022a08 100644 --- a/docs/source/tut-two-party-introduction.rst +++ b/docs/source/tut-two-party-introduction.rst @@ -6,10 +6,10 @@ Hello, World! Pt.2 - Contract constraints In the Hello, World tutorial, we built a CorDapp allowing us to model IOUs on ledger. Our CorDapp was made up of two elements: -* An ``IOUState``, representing IOUs on the ledger +* An ``IOUState``, representing IOUs on the blockchain * An ``IOUFlow``, orchestrating the process of agreeing the creation of an IOU on-ledger -However, our CorDapp did not impose any constraints on the evolution of IOUs on the ledger over time. Anyone was free +However, our CorDapp did not impose any constraints on the evolution of IOUs on the blockchain over time. Anyone was free to create IOUs of any value, between any party. In this tutorial, we'll write a contract to imposes rules on how an ``IOUState`` can change over time. In turn, this