From 550b446b878311e979e71bb122764ecbc2863911 Mon Sep 17 00:00:00 2001 From: Christian Sailer Date: Tue, 9 Jun 2020 17:39:51 +0100 Subject: [PATCH] NOTICK Remove example code (#6327) * Remove example code --- docs/example-code/README.md | 5 + docs/example-code/build.gradle | 112 --- .../test/JavaIntegrationTestingTutorial.java | 125 ---- .../test/TutorialFlowAsyncOperationTest.java | 41 -- .../test/KotlinIntegrationTestingTutorial.kt | 95 --- .../test/TutorialFlowAsyncOperationTest.kt | 30 - .../java/com/template/TemplateContract.java | 23 - .../net/corda/docs/java/ClientRpcExample.java | 31 - .../docs/java/FinalityFlowMigration.java | 137 ---- .../net/corda/docs/java/FlowCookbook.java | 689 ------------------ .../corda/docs/java/LaunchSpaceshipFlow.java | 133 ---- .../docs/java/MockNetworkTestsTutorial.java | 35 - .../tutorial/contract/CommercialPaper.java | 101 --- .../docs/java/tutorial/contract/State.java | 90 --- .../flowstatemachines/ExampleSummingFlow.java | 19 - .../flowstatemachines/SummingOperation.java | 32 - .../SummingOperationThrowing.java | 31 - .../TutorialFlowStateMachines.java | 39 - .../java/tutorial/helloworld/IOUFlow.java | 67 -- .../tutorial/helloworld/IOUFlowResponder.java | 25 - .../java/tutorial/helloworld/IOUState.java | 41 -- .../java/tutorial/twoparty/IOUContract.java | 55 -- .../docs/java/tutorial/twoparty/IOUFlow.java | 77 -- .../tutorial/twoparty/IOUFlowResponder.java | 49 -- .../docs/java/tutorial/twoparty/IOUState.java | 37 - .../net/corda/docs/kotlin/ClientRpcExample.kt | 31 - .../corda/docs/kotlin/ClientRpcTutorial.kt | 150 ---- .../docs/kotlin/FinalityFlowMigration.kt | 93 --- .../net/corda/docs/kotlin/FlowCookbook.kt | 664 ----------------- .../docs/kotlin/FxTransactionBuildTutorial.kt | 259 ------- .../corda/docs/kotlin/LaunchSpaceshipFlow.kt | 101 --- .../docs/kotlin/MockNetworkTestsTutorial.kt | 33 - .../tutorial/contract/TutorialContract.kt | 136 ---- .../TutorialFlowAsyncOperation.kt | 31 - .../TutorialFlowStateMachines.kt | 66 -- .../kotlin/tutorial/helloworld/IOUFlow.kt | 53 -- .../tutorial/helloworld/IOUFlowResponder.kt | 20 - .../kotlin/tutorial/helloworld/IOUState.kt | 17 - .../tutorial/tearoffs/TutorialTearOffs.kt | 47 -- .../kotlin/tutorial/twoparty/IOUContract.kt | 39 - .../docs/kotlin/tutorial/twoparty/IOUFlow.kt | 58 -- .../tutorial/twoparty/IOUFlowResponder.kt | 32 - .../docs/kotlin/tutorial/twoparty/IOUState.kt | 10 - .../WorkflowTransactionBuildTutorial.kt | 262 ------- .../docs/kotlin/vault/CustomVaultQuery.kt | 149 ---- .../example-node-with-networkservices.conf | 25 - .../src/main/resources/example-node.conf | 21 - .../src/main/resources/example-verifier.conf | 3 - .../tutorial/testdsl/TutorialTestDSL.java | 334 --------- .../net/corda/docs/ExampleConfigTest.kt | 36 - .../kotlin/FxTransactionBuildTutorialTest.kt | 92 --- .../tutorial/testdsl/TutorialTestDSL.kt | 316 -------- .../WorkflowTransactionBuildTutorialTest.kt | 99 --- .../docs/kotlin/vault/CustomVaultQueryTest.kt | 108 --- settings.gradle | 2 - 55 files changed, 5 insertions(+), 5401 deletions(-) create mode 100644 docs/example-code/README.md delete mode 100644 docs/example-code/build.gradle delete mode 100644 docs/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/JavaIntegrationTestingTutorial.java delete mode 100644 docs/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/TutorialFlowAsyncOperationTest.java delete mode 100644 docs/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/KotlinIntegrationTestingTutorial.kt delete mode 100644 docs/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/TutorialFlowAsyncOperationTest.kt delete mode 100644 docs/example-code/src/main/java/com/template/TemplateContract.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/ClientRpcExample.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/FinalityFlowMigration.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/LaunchSpaceshipFlow.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/tutorial/contract/CommercialPaper.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/tutorial/contract/State.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/ExampleSummingFlow.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperation.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperationThrowing.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/TutorialFlowStateMachines.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlow.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlowResponder.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUState.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUContract.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlowResponder.java delete mode 100644 docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUState.java delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcExample.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcTutorial.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FinalityFlowMigration.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorial.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/LaunchSpaceshipFlow.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/contract/TutorialContract.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowAsyncOperation.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowStateMachines.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlow.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlowResponder.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/tearoffs/TutorialTearOffs.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUContract.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUState.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorial.kt delete mode 100644 docs/example-code/src/main/kotlin/net/corda/docs/kotlin/vault/CustomVaultQuery.kt delete mode 100644 docs/example-code/src/main/resources/example-node-with-networkservices.conf delete mode 100644 docs/example-code/src/main/resources/example-node.conf delete mode 100644 docs/example-code/src/main/resources/example-verifier.conf delete mode 100644 docs/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java delete mode 100644 docs/example-code/src/test/kotlin/net/corda/docs/ExampleConfigTest.kt delete mode 100644 docs/example-code/src/test/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorialTest.kt delete mode 100644 docs/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt delete mode 100644 docs/example-code/src/test/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorialTest.kt delete mode 100644 docs/example-code/src/test/kotlin/net/corda/docs/kotlin/vault/CustomVaultQueryTest.kt diff --git a/docs/example-code/README.md b/docs/example-code/README.md new file mode 100644 index 0000000000..8dcef34bbf --- /dev/null +++ b/docs/example-code/README.md @@ -0,0 +1,5 @@ +# Code examples for the documentation + +The code-examples directory has been removed as the documentation has been moved to its own repo (see [here](../README.md)). + +If you're looking for this code, look at the history of this document, it was introduced in the same commit as the code was removed. \ No newline at end of file diff --git a/docs/example-code/build.gradle b/docs/example-code/build.gradle deleted file mode 100644 index 0a4143ea28..0000000000 --- a/docs/example-code/build.gradle +++ /dev/null @@ -1,112 +0,0 @@ -apply plugin: 'kotlin' -apply plugin: 'application' -apply plugin: 'net.corda.plugins.cordformation' -apply plugin: 'net.corda.plugins.quasar-utils' - -configurations { - integrationTestCompile.extendsFrom testCompile - integrationTestRuntime.extendsFrom testRuntime - - compile { - // We already have a SLF4J implementation on our runtime classpath, - // and we don't need another one. - exclude group: "org.apache.logging.log4j" - } -} - -sourceSets { - integrationTest { - kotlin { - compileClasspath += main.output + test.output - runtimeClasspath += main.output + test.output - srcDir file('src/integration-test/kotlin') - } - java { - compileClasspath += main.output + test.output - runtimeClasspath += main.output + test.output - srcDir file('src/integration-test/java') - } - } -} - -compileTestJava.dependsOn tasks.getByPath(':node:capsule:buildCordaJAR') - -dependencies { - // Cordformation needs a SLF4J implementation when executing the Network - // Bootstrapper, but Log4J doesn't shutdown completely from within Gradle. - // Use a much simpler SLF4J implementation here instead. - cordaRuntime "org.slf4j:slf4j-simple:$slf4j_version" - - compile project(':core') - compile project(':client:jfx') - compile project(':node-driver') - compile project(':testing:testserver') - - testCompile project(':test-utils') - - compile "org.graphstream:gs-core:1.3" - compile("org.graphstream:gs-ui:1.3") { - exclude group: "bouncycastle" - exclude group: "junit" - } - - cordaRuntime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - cordaRuntime project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts') - - // CorDapps: dependent flows and services - compile project(':finance:contracts') - compile project(':finance:workflows') -} - -mainClassName = "net.corda.docs.ClientRpcTutorialKt" - -task getClientRpcTutorial(type: CreateStartScripts) { - dependsOn(classes) - mainClassName = "net.corda.docs.ClientRpcTutorialKt" - applicationName = "client-rpc-tutorial" - defaultJvmOpts = [] - outputDir = new File(project.buildDir, 'scripts') - classpath = jar.outputs.files + project.configurations.runtime -} - -applicationDistribution.into("bin") { - from(getClientRpcTutorial) - fileMode = 0755 -} - -task integrationTest(type: Test) { - testClassesDirs = sourceSets.integrationTest.output.classesDirs - classpath = sourceSets.integrationTest.runtimeClasspath -} - -task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { - directory "./build/nodes" - node { - name "O=Notary Service,OU=corda,L=London,C=GB" - notary = [validating : true] - p2pPort 10002 - rpcSettings { - address "localhost:10003" - adminAddress "localhost:10013" - } - webPort 10004 - extraConfig = ['h2Settings.address' : 'localhost:10014'] - cordapps = [] - } - node { - name "O=Alice Corp,L=London,C=GB" - p2pPort 10005 - rpcSettings { - address "localhost:10006" - adminAddress "localhost:10016" - } - webPort 10007 - extraConfig = ['h2Settings.address' : 'localhost:10017'] - cordapps = [] - rpcUsers = [ - ['username' : "user", - 'password' : "password", - 'permissions' : ["StartFlow.net.corda.finance.flows.CashFlow"]] - ] - } -} diff --git a/docs/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/JavaIntegrationTestingTutorial.java b/docs/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/JavaIntegrationTestingTutorial.java deleted file mode 100644 index c1253193f0..0000000000 --- a/docs/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/JavaIntegrationTestingTutorial.java +++ /dev/null @@ -1,125 +0,0 @@ -package net.corda.docs.java.tutorial.test; - -import net.corda.client.rpc.CordaRPCClient; -import net.corda.core.concurrent.CordaFuture; -import net.corda.core.contracts.Amount; -import net.corda.core.contracts.Issued; -import net.corda.core.contracts.Structures; -import net.corda.core.messaging.CordaRPCOps; -import net.corda.core.node.services.Vault; -import net.corda.core.utilities.OpaqueBytes; -import net.corda.finance.contracts.asset.Cash; -import net.corda.finance.flows.CashIssueAndPaymentFlow; -import net.corda.finance.flows.CashPaymentFlow; -import net.corda.testing.driver.DriverParameters; -import net.corda.testing.driver.NodeHandle; -import net.corda.testing.driver.NodeParameters; -import net.corda.testing.node.User; -import org.junit.Test; -import rx.Observable; - -import java.util.Currency; -import java.util.HashSet; -import java.util.List; - -import static java.util.Arrays.asList; -import static java.util.Collections.singletonList; -import static net.corda.finance.Currencies.DOLLARS; -import static net.corda.node.services.Permissions.invokeRpc; -import static net.corda.node.services.Permissions.startFlow; -import static net.corda.testing.core.ExpectKt.expect; -import static net.corda.testing.core.ExpectKt.expectEvents; -import static net.corda.testing.core.TestConstants.ALICE_NAME; -import static net.corda.testing.core.TestConstants.BOB_NAME; -import static net.corda.testing.driver.Driver.driver; -import static net.corda.testing.node.internal.InternalTestUtilsKt.FINANCE_CORDAPPS; -import static org.junit.Assert.assertEquals; - -public class JavaIntegrationTestingTutorial { - @Test - public void aliceBobCashExchangeExample() { - // START 1 - driver(new DriverParameters() - .withStartNodesInProcess(true) - .withCordappsForAllNodes(FINANCE_CORDAPPS), dsl -> { - - User aliceUser = new User("aliceUser", "testPassword1", new HashSet<>(asList( - startFlow(CashIssueAndPaymentFlow.class), - invokeRpc("vaultTrack") - ))); - - User bobUser = new User("bobUser", "testPassword2", new HashSet<>(asList( - startFlow(CashPaymentFlow.class), - invokeRpc("vaultTrack") - ))); - - try { - List> nodeHandleFutures = asList( - dsl.startNode(new NodeParameters().withProvidedName(ALICE_NAME).withRpcUsers(singletonList(aliceUser))), - dsl.startNode(new NodeParameters().withProvidedName(BOB_NAME).withRpcUsers(singletonList(bobUser))) - ); - - NodeHandle alice = nodeHandleFutures.get(0).get(); - NodeHandle bob = nodeHandleFutures.get(1).get(); - // END 1 - - // START 2 - CordaRPCClient aliceClient = new CordaRPCClient(alice.getRpcAddress()); - CordaRPCOps aliceProxy = aliceClient.start("aliceUser", "testPassword1").getProxy(); - - CordaRPCClient bobClient = new CordaRPCClient(bob.getRpcAddress()); - CordaRPCOps bobProxy = bobClient.start("bobUser", "testPassword2").getProxy(); - // END 2 - - // START 3 - Observable> bobVaultUpdates = bobProxy.vaultTrack(Cash.State.class).getUpdates(); - Observable> aliceVaultUpdates = aliceProxy.vaultTrack(Cash.State.class).getUpdates(); - // END 3 - - // START 4 - OpaqueBytes issueRef = OpaqueBytes.of((byte)0); - aliceProxy.startFlowDynamic( - CashIssueAndPaymentFlow.class, - DOLLARS(1000), - issueRef, - bob.getNodeInfo().getLegalIdentities().get(0), - true, - dsl.getDefaultNotaryIdentity() - ).getReturnValue().get(); - - @SuppressWarnings("unchecked") - Class> cashVaultUpdateClass = (Class>)(Class)Vault.Update.class; - - expectEvents(bobVaultUpdates, true, () -> - expect(cashVaultUpdateClass, update -> true, update -> { - System.out.println("Bob got vault update of " + update); - Amount> amount = update.getProduced().iterator().next().getState().getData().getAmount(); - assertEquals(DOLLARS(1000), Structures.withoutIssuer(amount)); - return null; - }) - ); - // END 4 - - // START 5 - bobProxy.startFlowDynamic( - CashPaymentFlow.class, - DOLLARS(1000), - alice.getNodeInfo().getLegalIdentities().get(0) - ).getReturnValue().get(); - - expectEvents(aliceVaultUpdates, true, () -> - expect(cashVaultUpdateClass, update -> true, update -> { - System.out.println("Alice got vault update of " + update); - Amount> amount = update.getProduced().iterator().next().getState().getData().getAmount(); - assertEquals(DOLLARS(1000), Structures.withoutIssuer(amount)); - return null; - }) - ); - // END 5 - } catch (Exception e) { - throw new RuntimeException("Exception thrown in driver DSL", e); - } - return null; - }); - } -} diff --git a/docs/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/TutorialFlowAsyncOperationTest.java b/docs/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/TutorialFlowAsyncOperationTest.java deleted file mode 100644 index 9336e2b104..0000000000 --- a/docs/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/TutorialFlowAsyncOperationTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.corda.docs.java.tutorial.test; - -import net.corda.client.rpc.CordaRPCClient; -import net.corda.core.messaging.CordaRPCOps; -import net.corda.core.utilities.KotlinUtilsKt; -import net.corda.docs.java.tutorial.flowstatemachines.ExampleSummingFlow; -import net.corda.node.services.Permissions; -import net.corda.testing.driver.*; -import net.corda.testing.node.User; -import org.junit.Test; - -import java.util.concurrent.Future; - -import static java.util.Collections.singleton; -import static java.util.Collections.singletonList; -import static net.corda.testing.core.TestConstants.ALICE_NAME; -import static net.corda.testing.driver.Driver.driver; -import static net.corda.testing.node.internal.InternalTestUtilsKt.cordappWithPackages; -import static org.junit.Assert.assertEquals; - -public class TutorialFlowAsyncOperationTest { - // DOCSTART summingWorks - @Test - public void summingWorks() { - driver(new DriverParameters(singletonList(cordappWithPackages("net.corda.docs.java.tutorial.flowstatemachines"))), (DriverDSL dsl) -> { - User aliceUser = new User("aliceUser", "testPassword1", singleton(Permissions.all())); - Future aliceFuture = dsl.startNode(new NodeParameters() - .withProvidedName(ALICE_NAME) - .withRpcUsers(singletonList(aliceUser)) - ); - NodeHandle alice = KotlinUtilsKt.getOrThrow(aliceFuture, null); - CordaRPCClient aliceClient = new CordaRPCClient(alice.getRpcAddress()); - CordaRPCOps aliceProxy = aliceClient.start("aliceUser", "testPassword1").getProxy(); - Future answerFuture = aliceProxy.startFlowDynamic(ExampleSummingFlow.class).getReturnValue(); - int answer = KotlinUtilsKt.getOrThrow(answerFuture, null); - assertEquals(3, answer); - return null; - }); - } - // DOCEND summingWorks -} diff --git a/docs/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/KotlinIntegrationTestingTutorial.kt b/docs/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/KotlinIntegrationTestingTutorial.kt deleted file mode 100644 index fc37a5c760..0000000000 --- a/docs/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/KotlinIntegrationTestingTutorial.kt +++ /dev/null @@ -1,95 +0,0 @@ -package net.corda.docs.kotlin.tutorial.test - -import net.corda.client.rpc.CordaRPCClient -import net.corda.core.contracts.Amount -import net.corda.core.contracts.Issued -import net.corda.core.contracts.withoutIssuer -import net.corda.core.messaging.CordaRPCOps -import net.corda.core.messaging.startFlow -import net.corda.core.messaging.vaultTrackBy -import net.corda.core.node.services.Vault -import net.corda.core.utilities.OpaqueBytes -import net.corda.core.utilities.getOrThrow -import net.corda.finance.DOLLARS -import net.corda.finance.contracts.asset.Cash -import net.corda.finance.flows.CashIssueAndPaymentFlow -import net.corda.finance.flows.CashPaymentFlow -import net.corda.node.services.Permissions.Companion.invokeRpc -import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.testing.core.* -import net.corda.testing.driver.DriverParameters -import net.corda.testing.driver.driver -import net.corda.testing.node.User -import net.corda.testing.node.internal.FINANCE_CORDAPPS -import org.junit.Test -import rx.Observable -import java.util.* -import kotlin.test.assertEquals - -class KotlinIntegrationTestingTutorial { - @Test(timeout=300_000) - fun `alice bob cash exchange example`() { - // START 1 - driver(DriverParameters(startNodesInProcess = true, cordappsForAllNodes = FINANCE_CORDAPPS)) { - val aliceUser = User("aliceUser", "testPassword1", permissions = setOf( - startFlow(), - invokeRpc("vaultTrackBy") - )) - - val bobUser = User("bobUser", "testPassword2", permissions = setOf( - startFlow(), - invokeRpc("vaultTrackBy") - )) - - val (alice, bob) = listOf( - startNode(providedName = ALICE_NAME, rpcUsers = listOf(aliceUser)), - startNode(providedName = BOB_NAME, rpcUsers = listOf(bobUser)) - ).map { it.getOrThrow() } - // END 1 - - // START 2 - val aliceClient = CordaRPCClient(alice.rpcAddress) - val aliceProxy: CordaRPCOps = aliceClient.start("aliceUser", "testPassword1").proxy - - val bobClient = CordaRPCClient(bob.rpcAddress) - val bobProxy: CordaRPCOps = bobClient.start("bobUser", "testPassword2").proxy - // END 2 - - // START 3 - val bobVaultUpdates: Observable> = bobProxy.vaultTrackBy().updates - val aliceVaultUpdates: Observable> = aliceProxy.vaultTrackBy().updates - // END 3 - - // START 4 - val issueRef = OpaqueBytes.of(0) - aliceProxy.startFlow(::CashIssueAndPaymentFlow, - 1000.DOLLARS, - issueRef, - bob.nodeInfo.singleIdentity(), - true, - defaultNotaryIdentity - ).returnValue.getOrThrow() - - bobVaultUpdates.expectEvents { - expect { update -> - println("Bob got vault update of $update") - val amount: Amount> = update.produced.first().state.data.amount - assertEquals(1000.DOLLARS, amount.withoutIssuer()) - } - } - // END 4 - - // START 5 - bobProxy.startFlow(::CashPaymentFlow, 1000.DOLLARS, alice.nodeInfo.singleIdentity()).returnValue.getOrThrow() - - aliceVaultUpdates.expectEvents { - expect { update -> - println("Alice got vault update of $update") - val amount: Amount> = update.produced.first().state.data.amount - assertEquals(1000.DOLLARS, amount.withoutIssuer()) - } - } - // END 5 - } - } -} diff --git a/docs/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/TutorialFlowAsyncOperationTest.kt b/docs/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/TutorialFlowAsyncOperationTest.kt deleted file mode 100644 index 5c87b0ce1e..0000000000 --- a/docs/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/TutorialFlowAsyncOperationTest.kt +++ /dev/null @@ -1,30 +0,0 @@ -package net.corda.docs.kotlin.tutorial.test - -import net.corda.client.rpc.CordaRPCClient -import net.corda.core.messaging.startFlow -import net.corda.core.utilities.getOrThrow -import net.corda.docs.kotlin.tutorial.flowstatemachines.ExampleSummingFlow -import net.corda.node.services.Permissions -import net.corda.testing.core.ALICE_NAME -import net.corda.testing.driver.DriverParameters -import net.corda.testing.driver.driver -import net.corda.testing.node.User -import net.corda.testing.node.internal.cordappWithPackages -import org.junit.Test -import kotlin.test.assertEquals - -class TutorialFlowAsyncOperationTest { - // DOCSTART summingWorks - @Test(timeout=300_000) - fun summingWorks() { - driver(DriverParameters(startNodesInProcess = true, cordappsForAllNodes = listOf(cordappWithPackages("net.corda.docs.kotlin.tutorial.flowstatemachines")))) { - val aliceUser = User("aliceUser", "testPassword1", permissions = setOf(Permissions.all())) - val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(aliceUser)).getOrThrow() - val aliceClient = CordaRPCClient(alice.rpcAddress) - val aliceProxy = aliceClient.start("aliceUser", "testPassword1").proxy - val answer = aliceProxy.startFlow(::ExampleSummingFlow).returnValue.getOrThrow() - assertEquals(3, answer) - } - } - // DOCEND summingWorks -} diff --git a/docs/example-code/src/main/java/com/template/TemplateContract.java b/docs/example-code/src/main/java/com/template/TemplateContract.java deleted file mode 100644 index 3153d771fb..0000000000 --- a/docs/example-code/src/main/java/com/template/TemplateContract.java +++ /dev/null @@ -1,23 +0,0 @@ -// We purposefully have this template here as part of progressing through the tutorial -package com.template; - -import net.corda.core.contracts.CommandData; -import net.corda.core.contracts.Contract; -import net.corda.core.transactions.LedgerTransaction; -import org.jetbrains.annotations.NotNull; - -public class TemplateContract implements Contract { - // This is used to identify our contract when building a transaction. - public static final String ID = "com.template.TemplateContract"; - - /** - * A transaction is considered valid if the verify() function of the contract of each of the transaction's input - * and output states does not throw an exception. - */ - @Override - public void verify(@NotNull LedgerTransaction tx) {} - - public interface Commands extends CommandData { - class Action implements Commands {} - } -} diff --git a/docs/example-code/src/main/java/net/corda/docs/java/ClientRpcExample.java b/docs/example-code/src/main/java/net/corda/docs/java/ClientRpcExample.java deleted file mode 100644 index 224dbccf45..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/ClientRpcExample.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.corda.docs.java; - -// START 1 -import net.corda.client.rpc.CordaRPCClient; -import net.corda.client.rpc.CordaRPCConnection; -import net.corda.core.messaging.CordaRPCOps; -import net.corda.core.utilities.NetworkHostAndPort; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class ClientRpcExample { - private static final Logger logger = LoggerFactory.getLogger(ClientRpcExample.class); - - public static void main(String[] args) { - if (args.length != 3) { - throw new IllegalArgumentException("Usage: TemplateClient "); - } - final NetworkHostAndPort nodeAddress = NetworkHostAndPort.parse(args[0]); - String username = args[1]; - String password = args[2]; - - final CordaRPCClient client = new CordaRPCClient(nodeAddress); - final CordaRPCConnection connection = client.start(username, password); - final CordaRPCOps cordaRPCOperations = connection.getProxy(); - - logger.info(cordaRPCOperations.currentNodeTime().toString()); - - connection.notifyServerAndClose(); - } -} -// END 1 \ No newline at end of file diff --git a/docs/example-code/src/main/java/net/corda/docs/java/FinalityFlowMigration.java b/docs/example-code/src/main/java/net/corda/docs/java/FinalityFlowMigration.java deleted file mode 100644 index 2923792ec3..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/FinalityFlowMigration.java +++ /dev/null @@ -1,137 +0,0 @@ -package net.corda.docs.java; - -import co.paralleluniverse.fibers.Suspendable; -import net.corda.core.flows.*; -import net.corda.core.identity.Party; -import net.corda.core.transactions.SignedTransaction; -import org.jetbrains.annotations.NotNull; - -import static java.util.Collections.singletonList; - -@SuppressWarnings("ALL") -public class FinalityFlowMigration { - public static SignedTransaction dummyTransactionWithParticipant(Party party) { - throw new UnsupportedOperationException(); - } - - // DOCSTART SimpleFlowUsingOldApi - public static class SimpleFlowUsingOldApi extends FlowLogic { - private final Party counterparty; - - @Suspendable - @Override - public SignedTransaction call() throws FlowException { - SignedTransaction stx = dummyTransactionWithParticipant(counterparty); - return subFlow(new FinalityFlow(stx)); - } - // DOCEND SimpleFlowUsingOldApi - - public SimpleFlowUsingOldApi(Party counterparty) { - this.counterparty = counterparty; - } - } - - // DOCSTART SimpleFlowUsingNewApi - // Notice how the flow *must* now be an initiating flow even when it wasn't before. - @InitiatingFlow - public static class SimpleFlowUsingNewApi extends FlowLogic { - private final Party counterparty; - - @Suspendable - @Override - public SignedTransaction call() throws FlowException { - SignedTransaction stx = dummyTransactionWithParticipant(counterparty); - // For each non-local participant in the transaction we must initiate a flow session with them. - FlowSession session = initiateFlow(counterparty); - return subFlow(new FinalityFlow(stx, session)); - } - // DOCEND SimpleFlowUsingNewApi - - public SimpleFlowUsingNewApi(Party counterparty) { - this.counterparty = counterparty; - } - } - // DOCSTART SimpleNewResponderFlow - // All participants will run this flow to receive and record the finalised transaction into their vault. - @InitiatedBy(SimpleFlowUsingNewApi.class) - public static class SimpleNewResponderFlow extends FlowLogic { - private final FlowSession otherSide; - - @Suspendable - @Override - public Void call() throws FlowException { - subFlow(new ReceiveFinalityFlow(otherSide)); - return null; - } - // DOCEND SimpleNewResponderFlow - - public SimpleNewResponderFlow(FlowSession otherSide) { - this.otherSide = otherSide; - } - } - - // DOCSTART ExistingInitiatingFlow - // Assuming the previous version of the flow was 1 (the default if none is specified), we increment the version number to 2 - // to allow for backwards compatibility with nodes running the old CorDapp. - @InitiatingFlow(version = 2) - public static class ExistingInitiatingFlow extends FlowLogic { - private final Party counterparty; - - @Suspendable - @Override - public SignedTransaction call() throws FlowException { - SignedTransaction partiallySignedTx = dummyTransactionWithParticipant(counterparty); - FlowSession session = initiateFlow(counterparty); - SignedTransaction fullySignedTx = subFlow(new CollectSignaturesFlow(partiallySignedTx, singletonList(session))); - // Determine which version of the flow that other side is using. - if (session.getCounterpartyFlowInfo().getFlowVersion() == 1) { - // Use the old API if the other side is using the previous version of the flow. - return subFlow(new FinalityFlow(fullySignedTx)); - } else { - // Otherwise they're at least on version 2 and so we can send the finalised transaction on the existing session. - return subFlow(new FinalityFlow(fullySignedTx, session)); - } - } - // DOCEND ExistingInitiatingFlow - - public ExistingInitiatingFlow(Party counterparty) { - this.counterparty = counterparty; - } - } - - @InitiatedBy(ExistingInitiatingFlow.class) - public static class ExistingResponderFlow extends FlowLogic { - private final FlowSession otherSide; - - public ExistingResponderFlow(FlowSession otherSide) { - this.otherSide = otherSide; - } - - @Suspendable - @Override - public Void call() throws FlowException { - - // DOCSTART ExistingResponderFlow - // First we have to run the SignTransactionFlow, which will return a SignedTransaction. - SignedTransaction txWeJustSigned = subFlow(new SignTransactionFlow(otherSide) { - @Suspendable - @Override - protected void checkTransaction(@NotNull SignedTransaction stx) throws FlowException { - // Implement responder flow transaction checks here - } - }); - - if (otherSide.getCounterpartyFlowInfo().getFlowVersion() >= 2) { - // The other side is not using the old CorDapp so call ReceiveFinalityFlow to record the finalised transaction. - // If SignTransactionFlow is used then we can verify the tranaction we receive for recording is the same one - // that was just signed by passing the transaction id to ReceiveFinalityFlow. - subFlow(new ReceiveFinalityFlow(otherSide, txWeJustSigned.getId())); - } else { - // Otherwise the other side is running the old CorDapp and so we don't need to do anything further. The node - // will automatically record the finalised transaction using the old insecure mechanism. - } - // DOCEND ExistingResponderFlow - return null; - } - } -} diff --git a/docs/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java b/docs/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java deleted file mode 100644 index cabd3d301f..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java +++ /dev/null @@ -1,689 +0,0 @@ -package net.corda.docs.java; - -import co.paralleluniverse.fibers.Suspendable; -import com.google.common.collect.ImmutableList; -import net.corda.core.contracts.*; -import net.corda.core.crypto.SecureHash; -import net.corda.core.crypto.TransactionSignature; -import net.corda.core.flows.*; -import net.corda.core.identity.CordaX500Name; -import net.corda.core.identity.Party; -import net.corda.core.identity.PartyAndCertificate; -import net.corda.core.internal.FetchDataFlow; -import net.corda.core.node.services.Vault; -import net.corda.core.node.services.Vault.Page; -import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria; -import net.corda.core.transactions.LedgerTransaction; -import net.corda.core.transactions.SignedTransaction; -import net.corda.core.transactions.TransactionBuilder; -import net.corda.core.utilities.ProgressTracker; -import net.corda.core.utilities.ProgressTracker.Step; -import net.corda.core.utilities.UntrustworthyData; -import net.corda.finance.contracts.asset.Cash; -import net.corda.testing.contracts.DummyContract; -import net.corda.testing.contracts.DummyState; -import org.jetbrains.annotations.NotNull; - -import java.security.GeneralSecurityException; -import java.security.PublicKey; -import java.time.Duration; -import java.time.Instant; -import java.util.Arrays; -import java.util.List; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Collections.*; -import static net.corda.core.contracts.ContractsDSL.requireThat; -import static net.corda.core.crypto.Crypto.generateKeyPair; - -@SuppressWarnings("unused") -public class FlowCookbook { - // ``InitiatorFlow`` is our first flow, and will communicate with - // ``ResponderFlow``, below. - // We mark ``InitiatorFlow`` as an ``InitiatingFlow``, allowing it to be - // started directly by the node. - @InitiatingFlow - // We also mark ``InitiatorFlow`` as ``StartableByRPC``, allowing the - // node's owner to start the flow via RPC. - @StartableByRPC - // Every flow must subclass ``FlowLogic``. The generic indicates the - // flow's return type. - public static class InitiatorFlow extends FlowLogic { - - private final boolean arg1; - private final int arg2; - private final Party counterparty; - private final Party regulator; - - public InitiatorFlow(boolean arg1, int arg2, Party counterparty, Party regulator) { - this.arg1 = arg1; - this.arg2 = arg2; - this.counterparty = counterparty; - this.regulator = regulator; - } - - /*---------------------------------- - * WIRING UP THE PROGRESS TRACKER * - ----------------------------------*/ - // Giving our flow a progress tracker allows us to see the flow's - // progress visually in our node's CRaSH shell. - // DOCSTART 17 - private static final Step ID_OTHER_NODES = new Step("Identifying other nodes on the network."); - private static final Step SENDING_AND_RECEIVING_DATA = new Step("Sending data between parties."); - private static final Step EXTRACTING_VAULT_STATES = new Step("Extracting states from the vault."); - private static final Step OTHER_TX_COMPONENTS = new Step("Gathering a transaction's other components."); - private static final Step TX_BUILDING = new Step("Building a transaction."); - private static final Step TX_SIGNING = new Step("Signing a transaction."); - private static final Step TX_VERIFICATION = new Step("Verifying a transaction."); - private static final Step SIGS_GATHERING = new Step("Gathering a transaction's signatures.") { - // Wiring up a child progress tracker allows us to see the - // subflow's progress steps in our flow's progress tracker. - @Override - public ProgressTracker childProgressTracker() { - return CollectSignaturesFlow.tracker(); - } - }; - private static final Step VERIFYING_SIGS = new Step("Verifying a transaction's signatures."); - private static final Step FINALISATION = new Step("Finalising a transaction.") { - @Override - public ProgressTracker childProgressTracker() { - return FinalityFlow.tracker(); - } - }; - - private final ProgressTracker progressTracker = new ProgressTracker( - ID_OTHER_NODES, - SENDING_AND_RECEIVING_DATA, - EXTRACTING_VAULT_STATES, - OTHER_TX_COMPONENTS, - TX_BUILDING, - TX_SIGNING, - TX_VERIFICATION, - SIGS_GATHERING, - FINALISATION - ); - // DOCEND 17 - - @Suspendable - @Override - public Void call() throws FlowException { - // We'll be using a dummy public key for demonstration purposes. - PublicKey dummyPubKey = generateKeyPair().getPublic(); - - /*--------------------------- - * IDENTIFYING OTHER NODES * - ---------------------------*/ - // DOCSTART 18 - progressTracker.setCurrentStep(ID_OTHER_NODES); - // DOCEND 18 - - // Every transaction needs a notary: - // - To prevent double-spends if the transaction has inputs - // - To serve as a timestamping authority if the transaction has a - // time-window - // We retrieve a notary from the network map. - // DOCSTART 01 - CordaX500Name notaryName = new CordaX500Name("Notary Service", "London", "GB"); - Party notary = getServiceHub().getNetworkMapCache().getNotary(notaryName); - // DOCEND 01 - - // We may also need to identify a specific counterparty. We do so - // using the identity service. - // DOCSTART 02 - CordaX500Name counterPartyName = new CordaX500Name("NodeA", "London", "GB"); - Party namedCounterparty = getServiceHub().getIdentityService().wellKnownPartyFromX500Name(counterPartyName); - Party keyedCounterparty = getServiceHub().getIdentityService().partyFromKey(dummyPubKey); - // DOCEND 02 - - /*------------------------------ - * SENDING AND RECEIVING DATA * - ------------------------------*/ - progressTracker.setCurrentStep(SENDING_AND_RECEIVING_DATA); - - // We start by initiating a flow session with the counterparty. We - // will use this session to send and receive messages from the - // counterparty. - // DOCSTART initiateFlow - FlowSession counterpartySession = initiateFlow(counterparty); - // DOCEND initiateFlow - - // We can send arbitrary data to a counterparty. - // If this is the first ``send``, the counterparty will either: - // 1. Ignore the message if they are not registered to respond - // to messages from this flow. - // 2. Start the flow they have registered to respond to this flow, - // and run the flow until the first call to ``receive``, at - // which point they process the message. - // In other words, we are assuming that the counterparty is - // registered to respond to this flow, and has a corresponding - // ``receive`` call. - // DOCSTART 04 - counterpartySession.send(new Object()); - // DOCEND 04 - - // We can wait to receive arbitrary data of a specific type from a - // counterparty. Again, this implies a corresponding ``send`` call - // in the counterparty's flow. A few scenarios: - // - We never receive a message back. In the current design, the - // flow is paused until the node's owner kills the flow. - // - Instead of sending a message back, the counterparty throws a - // ``FlowException``. This exception is propagated back to us, - // and we can use the error message to establish what happened. - // - We receive a message back, but it's of the wrong type. In - // this case, a ``FlowException`` is thrown. - // - We receive back a message of the correct type. All is good. - // - // Upon calling ``receive()`` (or ``sendAndReceive()``), the - // ``FlowLogic`` is suspended until it receives a response. - // - // We receive the data wrapped in an ``UntrustworthyData`` - // instance. This is a reminder that the data we receive may not - // be what it appears to be! We must unwrap the - // ``UntrustworthyData`` using a lambda. - // DOCSTART 05 - UntrustworthyData packet1 = counterpartySession.receive(Integer.class); - Integer integer = packet1.unwrap(data -> { - // Perform checking on the object received. - // T O D O: Check the received object. - // Return the object. - return data; - }); - // DOCEND 05 - - // We can also use a single call to send data to a counterparty - // and wait to receive data of a specific type back. The type of - // data sent doesn't need to match the type of the data received - // back. - // DOCSTART 07 - UntrustworthyData packet2 = counterpartySession.sendAndReceive(Boolean.class, "You can send and receive any class!"); - Boolean bool = packet2.unwrap(data -> { - // Perform checking on the object received. - // T O D O: Check the received object. - // Return the object. - return data; - }); - // DOCEND 07 - - // We're not limited to sending to and receiving from a single - // counterparty. A flow can send messages to as many parties as it - // likes, and each party can invoke a different response flow. - // DOCSTART 06 - FlowSession regulatorSession = initiateFlow(regulator); - regulatorSession.send(new Object()); - UntrustworthyData packet3 = regulatorSession.receive(Object.class); - // DOCEND 06 - - /*------------------------------------ - * EXTRACTING STATES FROM THE VAULT * - ------------------------------------*/ - progressTracker.setCurrentStep(EXTRACTING_VAULT_STATES); - - // Let's assume there are already some ``DummyState``s in our - // node's vault, stored there as a result of running past flows, - // and we want to consume them in a transaction. There are many - // ways to extract these states from our vault. - - // For example, we would extract any unconsumed ``DummyState``s - // from our vault as follows: - VaultQueryCriteria criteria = new VaultQueryCriteria(Vault.StateStatus.UNCONSUMED); - Page results = getServiceHub().getVaultService().queryBy(DummyState.class, criteria); - List> dummyStates = results.getStates(); - - // For a full list of the available ways of extracting states from - // the vault, see the Vault Query docs page. - - // When building a transaction, input states are passed in as - // ``StateRef`` instances, which pair the hash of the transaction - // that generated the state with the state's index in the outputs - // of that transaction. In practice, we'd pass the transaction hash - // or the ``StateRef`` as a parameter to the flow, or extract the - // ``StateRef`` from our vault. - // DOCSTART 20 - StateRef ourStateRef = new StateRef(SecureHash.sha256("DummyTransactionHash"), 0); - // DOCEND 20 - // A ``StateAndRef`` pairs a ``StateRef`` with the state it points to. - // DOCSTART 21 - StateAndRef ourStateAndRef = getServiceHub().toStateAndRef(ourStateRef); - // DOCEND 21 - - /*------------------------------------------ - * GATHERING OTHER TRANSACTION COMPONENTS * - ------------------------------------------*/ - progressTracker.setCurrentStep(OTHER_TX_COMPONENTS); - - // Reference input states are constructed from StateAndRefs. - // DOCSTART 55 - ReferencedStateAndRef referenceState = ourStateAndRef.referenced(); - // DOCEND 55 - // Output states are constructed from scratch. - // DOCSTART 22 - DummyState ourOutputState = new DummyState(); - // DOCEND 22 - // Or as copies of other states with some properties changed. - // DOCSTART 23 - DummyState ourOtherOutputState = ourOutputState.copy(77); - // DOCEND 23 - - // We then need to pair our output state with a contract. - // DOCSTART 47 - StateAndContract ourOutput = new StateAndContract(ourOutputState, DummyContract.PROGRAM_ID); - // DOCEND 47 - - // Commands pair a ``CommandData`` instance with a list of - // public keys. To be valid, the transaction requires a signature - // matching every public key in all of the transaction's commands. - // DOCSTART 24 - DummyContract.Commands.Create commandData = new DummyContract.Commands.Create(); - PublicKey ourPubKey = getServiceHub().getMyInfo().getLegalIdentitiesAndCerts().get(0).getOwningKey(); - PublicKey counterpartyPubKey = counterparty.getOwningKey(); - List requiredSigners = ImmutableList.of(ourPubKey, counterpartyPubKey); - Command ourCommand = new Command<>(commandData, requiredSigners); - // DOCEND 24 - - // ``CommandData`` can either be: - // 1. Of type ``TypeOnlyCommandData``, in which case it only - // serves to attach signers to the transaction and possibly - // fork the contract's verification logic. - TypeOnlyCommandData typeOnlyCommandData = new DummyContract.Commands.Create(); - // 2. Include additional data which can be used by the contract - // during verification, alongside fulfilling the roles above - CommandData commandDataWithData = new Cash.Commands.Issue(); - - // Attachments are identified by their hash. - // The attachment with the corresponding hash must have been - // uploaded ahead of time via the node's RPC interface. - // DOCSTART 25 - SecureHash ourAttachment = SecureHash.sha256("DummyAttachment"); - // DOCEND 25 - - // Time windows represent the period of time during which a - // transaction must be notarised. They can have a start and an end - // time, or be open at either end. - // DOCSTART 26 - TimeWindow ourTimeWindow = TimeWindow.between(Instant.MIN, Instant.MAX); - TimeWindow ourAfter = TimeWindow.fromOnly(Instant.MIN); - TimeWindow ourBefore = TimeWindow.untilOnly(Instant.MAX); - // DOCEND 26 - - // We can also define a time window as an ``Instant`` +/- a time - // tolerance (e.g. 30 seconds): - // DOCSTART 42 - TimeWindow ourTimeWindow2 = TimeWindow.withTolerance(getServiceHub().getClock().instant(), Duration.ofSeconds(30)); - // DOCEND 42 - // Or as a start-time plus a duration: - // DOCSTART 43 - TimeWindow ourTimeWindow3 = TimeWindow.fromStartAndDuration(getServiceHub().getClock().instant(), Duration.ofSeconds(30)); - // DOCEND 43 - - /*------------------------ - * TRANSACTION BUILDING * - ------------------------*/ - progressTracker.setCurrentStep(TX_BUILDING); - - // If our transaction has input states or a time-window, we must instantiate it with a - // notary. - // DOCSTART 19 - TransactionBuilder txBuilder = new TransactionBuilder(notary); - // DOCEND 19 - - // Otherwise, we can choose to instantiate it without one: - // DOCSTART 46 - TransactionBuilder txBuilderNoNotary = new TransactionBuilder(); - // DOCEND 46 - - // We add items to the transaction builder using ``TransactionBuilder.withItems``: - // DOCSTART 27 - txBuilder.withItems( - // Inputs, as ``StateAndRef``s that reference to the outputs of previous transactions - ourStateAndRef, - // Outputs, as ``StateAndContract``s - ourOutput, - // Commands, as ``Command``s - ourCommand, - // Attachments, as ``SecureHash``es - ourAttachment, - // A time-window, as ``TimeWindow`` - ourTimeWindow - ); - // DOCEND 27 - - // We can also add items using methods for the individual components. - - // The individual methods for adding input states and attachments: - // DOCSTART 28 - txBuilder.addInputState(ourStateAndRef); - txBuilder.addAttachment(ourAttachment); - // DOCEND 28 - - // An output state can be added as a ``ContractState``, contract class name and notary. - // DOCSTART 49 - txBuilder.addOutputState(ourOutputState, DummyContract.PROGRAM_ID, notary); - // DOCEND 49 - // We can also leave the notary field blank, in which case the transaction's default - // notary is used. - // DOCSTART 50 - txBuilder.addOutputState(ourOutputState, DummyContract.PROGRAM_ID); - // DOCEND 50 - // Or we can add the output state as a ``TransactionState``, which already specifies - // the output's contract and notary. - // DOCSTART 51 - TransactionState txState = new TransactionState(ourOutputState, DummyContract.PROGRAM_ID, notary); - // DOCEND 51 - - // Commands can be added as ``Command``s. - // DOCSTART 52 - txBuilder.addCommand(ourCommand); - // DOCEND 52 - // Or as ``CommandData`` and a ``vararg PublicKey``. - // DOCSTART 53 - txBuilder.addCommand(commandData, ourPubKey, counterpartyPubKey); - // DOCEND 53 - - // We can set a time-window directly. - // DOCSTART 44 - txBuilder.setTimeWindow(ourTimeWindow); - // DOCEND 44 - // Or as a start time plus a duration (e.g. 45 seconds). - // DOCSTART 45 - txBuilder.setTimeWindow(getServiceHub().getClock().instant(), Duration.ofSeconds(45)); - // DOCEND 45 - - /*----------------------- - * TRANSACTION SIGNING * - -----------------------*/ - progressTracker.setCurrentStep(TX_SIGNING); - - // We finalise the transaction by signing it, - // converting it into a ``SignedTransaction``. - // DOCSTART 29 - SignedTransaction onceSignedTx = getServiceHub().signInitialTransaction(txBuilder); - // DOCEND 29 - // We can also sign the transaction using a different public key: - // DOCSTART 30 - PartyAndCertificate otherIdentity = getServiceHub().getKeyManagementService().freshKeyAndCert(getOurIdentityAndCert(), false); - SignedTransaction onceSignedTx2 = getServiceHub().signInitialTransaction(txBuilder, otherIdentity.getOwningKey()); - // DOCEND 30 - - // If instead this was a ``SignedTransaction`` that we'd received - // from a counterparty and we needed to sign it, we would add our - // signature using: - // DOCSTART 38 - SignedTransaction twiceSignedTx = getServiceHub().addSignature(onceSignedTx); - // DOCEND 38 - // Or, if we wanted to use a different public key: - PartyAndCertificate otherIdentity2 = getServiceHub().getKeyManagementService().freshKeyAndCert(getOurIdentityAndCert(), false); - // DOCSTART 39 - SignedTransaction twiceSignedTx2 = getServiceHub().addSignature(onceSignedTx, otherIdentity2.getOwningKey()); - // DOCEND 39 - - // We can also generate a signature over the transaction without - // adding it to the transaction itself. We may do this when - // sending just the signature in a flow instead of returning the - // entire transaction with our signature. This way, the receiving - // node does not need to check we haven't changed anything in the - // transaction. - // DOCSTART 40 - TransactionSignature sig = getServiceHub().createSignature(onceSignedTx); - // DOCEND 40 - // And again, if we wanted to use a different public key: - // DOCSTART 41 - TransactionSignature sig2 = getServiceHub().createSignature(onceSignedTx, otherIdentity2.getOwningKey()); - // DOCEND 41 - - /*---------------------------- - * TRANSACTION VERIFICATION * - ----------------------------*/ - progressTracker.setCurrentStep(TX_VERIFICATION); - - // Verifying a transaction will also verify every transaction in - // the transaction's dependency chain, which will require - // transaction data access on counterparty's node. The - // ``SendTransactionFlow`` can be used to automate the sending and - // data vending process. The ``SendTransactionFlow`` will listen - // for data request until the transaction is resolved and verified - // on the other side: - // DOCSTART 12 - subFlow(new SendTransactionFlow(counterpartySession, twiceSignedTx)); - - // Optional request verification to further restrict data access. - subFlow(new SendTransactionFlow(counterpartySession, twiceSignedTx) { - @Override - protected void verifyDataRequest(@NotNull FetchDataFlow.Request.Data dataRequest) { - // Extra request verification. - } - }); - // DOCEND 12 - - // We can receive the transaction using ``ReceiveTransactionFlow``, - // which will automatically download all the dependencies and verify - // the transaction and then record in our vault - // DOCSTART 13 - SignedTransaction verifiedTransaction = subFlow(new ReceiveTransactionFlow(counterpartySession)); - // DOCEND 13 - - // We can also send and receive a `StateAndRef` dependency chain and automatically resolve its dependencies. - // DOCSTART 14 - subFlow(new SendStateAndRefFlow(counterpartySession, dummyStates)); - - // On the receive side ... - List> resolvedStateAndRef = subFlow(new ReceiveStateAndRefFlow<>(counterpartySession)); - // DOCEND 14 - - try { - - // We can now verify the transaction to ensure that it satisfies - // the contracts of all the transaction's input and output states. - // DOCSTART 33 - twiceSignedTx.verify(getServiceHub()); - // DOCEND 33 - - // We'll often want to perform our own additional verification - // too. Just because a transaction is valid based on the contract - // rules and requires our signature doesn't mean we have to - // sign it! We need to make sure the transaction represents an - // agreement we actually want to enter into. - - // To do this, we need to convert our ``SignedTransaction`` - // into a ``LedgerTransaction``. This will use our ServiceHub - // to resolve the transaction's inputs and attachments into - // actual objects, rather than just references. - // DOCSTART 32 - LedgerTransaction ledgerTx = twiceSignedTx.toLedgerTransaction(getServiceHub()); - // DOCEND 32 - - // We can now perform our additional verification. - // DOCSTART 34 - DummyState outputState = ledgerTx.outputsOfType(DummyState.class).get(0); - if (outputState.getMagicNumber() != 777) { - // ``FlowException`` is a special exception type. It will be - // propagated back to any counterparty flows waiting for a - // message from this flow, notifying them that the flow has - // failed. - throw new FlowException("We expected a magic number of 777."); - } - // DOCEND 34 - - } catch (GeneralSecurityException e) { - // Handle this as required. - } - - // Of course, if you are not a required signer on the transaction, - // you have no power to decide whether it is valid or not. If it - // requires signatures from all the required signers and is - // contractually valid, it's a valid ledger update. - - /*------------------------ - * GATHERING SIGNATURES * - ------------------------*/ - progressTracker.setCurrentStep(SIGS_GATHERING); - - // The list of parties who need to sign a transaction is dictated - // by the transaction's commands. Once we've signed a transaction - // ourselves, we can automatically gather the signatures of the - // other required signers using ``CollectSignaturesFlow``. - // The responder flow will need to call ``SignTransactionFlow``. - // DOCSTART 15 - SignedTransaction fullySignedTx = subFlow(new CollectSignaturesFlow(twiceSignedTx, emptySet(), SIGS_GATHERING.childProgressTracker())); - // DOCEND 15 - - /*------------------------ - * VERIFYING SIGNATURES * - ------------------------*/ - progressTracker.setCurrentStep(VERIFYING_SIGS); - - try { - - // We can verify that a transaction has all the required - // signatures, and that they're all valid, by running: - // DOCSTART 35 - fullySignedTx.verifyRequiredSignatures(); - // DOCEND 35 - - // If the transaction is only partially signed, we have to pass in - // a vararg of the public keys corresponding to the missing - // signatures, explicitly telling the system not to check them. - // DOCSTART 36 - onceSignedTx.verifySignaturesExcept(counterpartyPubKey); - // DOCEND 36 - - // There is also an overload of ``verifySignaturesExcept`` which accepts - // a ``Collection`` of the public keys corresponding to the missing - // signatures. In the example below, we could also use - // ``Arrays.asList(counterpartyPubKey)`` instead of - // ``Collections.singletonList(counterpartyPubKey)``. - // DOCSTART 54 - onceSignedTx.verifySignaturesExcept(singletonList(counterpartyPubKey)); - // DOCEND 54 - - // We can also choose to only check the signatures that are - // present. BE VERY CAREFUL - this function provides no guarantees - // that the signatures are correct, or that none are missing. - // DOCSTART 37 - twiceSignedTx.checkSignaturesAreValid(); - // DOCEND 37 - } catch (GeneralSecurityException e) { - // Handle this as required. - } - - /*------------------------------ - * FINALISING THE TRANSACTION * - ------------------------------*/ - progressTracker.setCurrentStep(FINALISATION); - - // We notarise the transaction and get it recorded in the vault of - // the participants of all the transaction's states. - // DOCSTART 09 - SignedTransaction notarisedTx1 = subFlow(new FinalityFlow(fullySignedTx, singleton(counterpartySession), FINALISATION.childProgressTracker())); - // DOCEND 09 - // We can also choose to send it to additional parties who aren't one - // of the state's participants. - // DOCSTART 10 - List partySessions = Arrays.asList(counterpartySession, initiateFlow(regulator)); - SignedTransaction notarisedTx2 = subFlow(new FinalityFlow(fullySignedTx, partySessions, FINALISATION.childProgressTracker())); - // DOCEND 10 - - // DOCSTART FlowSession porting - send(regulator, new Object()); // Old API - // becomes - FlowSession session = initiateFlow(regulator); - session.send(new Object()); - // DOCEND FlowSession porting - - return null; - } - } - - // ``ResponderFlow`` is our second flow, and will communicate with - // ``InitiatorFlow``. - // We mark ``ResponderFlow`` as an ``InitiatedByFlow``, meaning that it - // can only be started in response to a message from its initiating flow. - // That's ``InitiatorFlow`` in this case. - // Each node also has several flow pairs registered by default - see - // ``AbstractNode.installCoreFlows``. - @InitiatedBy(InitiatorFlow.class) - public static class ResponderFlow extends FlowLogic { - - private final FlowSession counterpartySession; - - public ResponderFlow(FlowSession counterpartySession) { - this.counterpartySession = counterpartySession; - } - - private static final Step RECEIVING_AND_SENDING_DATA = new Step("Sending data between parties."); - private static final Step SIGNING = new Step("Responding to CollectSignaturesFlow."); - private static final Step FINALISATION = new Step("Finalising a transaction."); - - private final ProgressTracker progressTracker = new ProgressTracker( - RECEIVING_AND_SENDING_DATA, - SIGNING, - FINALISATION - ); - - @Suspendable - @Override - public Void call() throws FlowException { - // The ``ResponderFlow` has all the same APIs available. It looks - // up network information, sends and receives data, and constructs - // transactions in exactly the same way. - - /*------------------------------ - * SENDING AND RECEIVING DATA * - -----------------------------*/ - progressTracker.setCurrentStep(RECEIVING_AND_SENDING_DATA); - - // We need to respond to the messages sent by the initiator: - // 1. They sent us an ``Object`` instance - // 2. They waited to receive an ``Integer`` instance back - // 3. They sent a ``String`` instance and waited to receive a - // ``Boolean`` instance back - // Our side of the flow must mirror these calls. - // DOCSTART 08 - Object obj = counterpartySession.receive(Object.class).unwrap(data -> data); - String string = counterpartySession.sendAndReceive(String.class, 99).unwrap(data -> data); - counterpartySession.send(true); - // DOCEND 08 - - /*----------------------------------------- - * RESPONDING TO COLLECT_SIGNATURES_FLOW * - -----------------------------------------*/ - progressTracker.setCurrentStep(SIGNING); - - // The responder will often need to respond to a call to - // ``CollectSignaturesFlow``. It does so my invoking its own - // ``SignTransactionFlow`` subclass. - // DOCSTART 16 - class SignTxFlow extends SignTransactionFlow { - private SignTxFlow(FlowSession otherSession, ProgressTracker progressTracker) { - super(otherSession, progressTracker); - } - - @Override - protected void checkTransaction(SignedTransaction stx) { - requireThat(require -> { - // Any additional checking we see fit... - DummyState outputState = (DummyState) stx.getTx().getOutputs().get(0).getData(); - checkArgument(outputState.getMagicNumber() == 777); - return null; - }); - } - } - - SecureHash idOfTxWeSigned = subFlow(new SignTxFlow(counterpartySession, SignTransactionFlow.tracker())).getId(); - // DOCEND 16 - - /*------------------------------ - * FINALISING THE TRANSACTION * - ------------------------------*/ - progressTracker.setCurrentStep(FINALISATION); - - // As the final step the responder waits to receive the notarised transaction from the sending party - // Since it knows the ID of the transaction it just signed, the transaction ID is specified to ensure the correct - // transaction is received and recorded. - // DOCSTART ReceiveFinalityFlow - subFlow(new ReceiveFinalityFlow(counterpartySession, idOfTxWeSigned)); - // DOCEND ReceiveFinalityFlow - - return null; - } - } -} diff --git a/docs/example-code/src/main/java/net/corda/docs/java/LaunchSpaceshipFlow.java b/docs/example-code/src/main/java/net/corda/docs/java/LaunchSpaceshipFlow.java deleted file mode 100644 index 9ef0d72864..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/LaunchSpaceshipFlow.java +++ /dev/null @@ -1,133 +0,0 @@ -package net.corda.docs.java; - -import co.paralleluniverse.fibers.Suspendable; -import net.corda.core.flows.*; -import net.corda.core.identity.Party; - -@SuppressWarnings("ALL") -// DOCSTART LaunchSpaceshipFlow -@InitiatingFlow -class LaunchSpaceshipFlow extends FlowLogic { - @Suspendable - @Override - public Void call() throws FlowException { - boolean shouldLaunchSpaceship = receive(Boolean.class, getPresident()).unwrap(s -> s); - if (shouldLaunchSpaceship) { - launchSpaceship(); - } - return null; - } - - public void launchSpaceship() { - } - - public Party getPresident() { - throw new AbstractMethodError(); - } -} - -@InitiatedBy(LaunchSpaceshipFlow.class) -@InitiatingFlow -class PresidentSpaceshipFlow extends FlowLogic { - private final Party launcher; - - public PresidentSpaceshipFlow(Party launcher) { - this.launcher = launcher; - } - - @Suspendable - @Override - public Void call() { - boolean needCoffee = true; - send(getSecretary(), needCoffee); - boolean shouldLaunchSpaceship = false; - send(launcher, shouldLaunchSpaceship); - return null; - } - - public Party getSecretary() { - throw new AbstractMethodError(); - } -} - -@InitiatedBy(PresidentSpaceshipFlow.class) -class SecretaryFlow extends FlowLogic { - private final Party president; - - public SecretaryFlow(Party president) { - this.president = president; - } - - @Suspendable - @Override - public Void call() { - // ignore - return null; - } -} -// DOCEND LaunchSpaceshipFlow - -@SuppressWarnings("ALL") -// DOCSTART LaunchSpaceshipFlowCorrect -@InitiatingFlow -class LaunchSpaceshipFlowCorrect extends FlowLogic { - @Suspendable - @Override - public Void call() throws FlowException { - FlowSession presidentSession = initiateFlow(getPresident()); - boolean shouldLaunchSpaceship = presidentSession.receive(Boolean.class).unwrap(s -> s); - if (shouldLaunchSpaceship) { - launchSpaceship(); - } - return null; - } - - public void launchSpaceship() { - } - - public Party getPresident() { - throw new AbstractMethodError(); - } -} - -@InitiatedBy(LaunchSpaceshipFlowCorrect.class) -@InitiatingFlow -class PresidentSpaceshipFlowCorrect extends FlowLogic { - private final FlowSession launcherSession; - - public PresidentSpaceshipFlowCorrect(FlowSession launcherSession) { - this.launcherSession = launcherSession; - } - - @Suspendable - @Override - public Void call() { - boolean needCoffee = true; - FlowSession secretarySession = initiateFlow(getSecretary()); - secretarySession.send(needCoffee); - boolean shouldLaunchSpaceship = false; - launcherSession.send(shouldLaunchSpaceship); - return null; - } - - public Party getSecretary() { - throw new AbstractMethodError(); - } -} - -@InitiatedBy(PresidentSpaceshipFlowCorrect.class) -class SecretaryFlowCorrect extends FlowLogic { - private final FlowSession presidentSession; - - public SecretaryFlowCorrect(FlowSession presidentSession) { - this.presidentSession = presidentSession; - } - - @Suspendable - @Override - public Void call() { - // ignore - return null; - } -} -// DOCEND LaunchSpaceshipFlowCorrect diff --git a/docs/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java b/docs/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java deleted file mode 100644 index 6ee5480d67..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java +++ /dev/null @@ -1,35 +0,0 @@ -package net.corda.docs.java; - -// DOCSTART 1 -import net.corda.core.identity.CordaX500Name; -import net.corda.testing.node.MockNetwork; -import net.corda.testing.node.MockNetworkParameters; -import net.corda.testing.node.StartedMockNode; -import org.junit.After; -import org.junit.Before; - -import static java.util.Collections.singletonList; -import static net.corda.testing.node.TestCordapp.findCordapp; - -public class MockNetworkTestsTutorial { - - private final MockNetwork mockNet = new MockNetwork(new MockNetworkParameters(singletonList(findCordapp("com.mycordapp.package")))); - - @After - public void cleanUp() { - mockNet.stopNodes(); - } -// DOCEND 1 - -// DOCSTART 2 - private StartedMockNode nodeA; - private StartedMockNode nodeB; - - @Before - public void setUp() { - nodeA = mockNet.createNode(); - // We can optionally give the node a name. - nodeB = mockNet.createNode(new CordaX500Name("Bank B", "London", "GB")); - } -// DOCEND 2 -} diff --git a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/contract/CommercialPaper.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/contract/CommercialPaper.java deleted file mode 100644 index 0a3a2d992c..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/contract/CommercialPaper.java +++ /dev/null @@ -1,101 +0,0 @@ -package net.corda.docs.java.tutorial.contract; - -import net.corda.core.contracts.*; -import net.corda.core.transactions.LedgerTransaction; -import net.corda.core.transactions.LedgerTransaction.InOutGroup; - -import java.time.Instant; -import java.util.Currency; -import java.util.List; - -import static net.corda.core.contracts.ContractsDSL.requireSingleCommand; -import static net.corda.core.contracts.ContractsDSL.requireThat; -import static net.corda.finance.contracts.utils.StateSumming.sumCashBy; - -public class CommercialPaper implements Contract { - // DOCSTART 1 - public static final String IOU_CONTRACT_ID = "com.example.contract.IOUContract"; - // DOCEND 1 - - // DOCSTART 3 - @Override - public void verify(LedgerTransaction tx) { - List> groups = tx.groupStates(State.class, State::withoutOwner); - CommandWithParties cmd = requireSingleCommand(tx.getCommands(), Commands.class); - // DOCEND 3 - - // DOCSTART 4 - TimeWindow timeWindow = tx.getTimeWindow(); - - for (InOutGroup group : groups) { - List inputs = group.getInputs(); - List outputs = group.getOutputs(); - - if (cmd.getValue() instanceof Commands.Move) { - State input = inputs.get(0); - requireThat(require -> { - require.using("the transaction is signed by the owner of the CP", cmd.getSigners().contains(input.getOwner().getOwningKey())); - require.using("the state is propagated", outputs.size() == 1); - // Don't need to check anything else, as if outputs.size == 1 then the output is equal to - // the input ignoring the owner field due to the grouping. - return null; - }); - - } else if (cmd.getValue() instanceof Commands.Redeem) { - // Redemption of the paper requires movement of on-ledger cash. - State input = inputs.get(0); - Amount> received = sumCashBy(tx.getOutputStates(), input.getOwner()); - if (timeWindow == null) throw new IllegalArgumentException("Redemptions must be timestamped"); - Instant time = timeWindow.getFromTime(); - requireThat(require -> { - require.using("the paper must have matured", time.isAfter(input.getMaturityDate())); - require.using("the received amount equals the face value", received == input.getFaceValue()); - require.using("the paper must be destroyed", outputs.isEmpty()); - require.using("the transaction is signed by the owner of the CP", cmd.getSigners().contains(input.getOwner().getOwningKey())); - return null; - }); - } else if (cmd.getValue() instanceof Commands.Issue) { - State output = outputs.get(0); - if (timeWindow == null) throw new IllegalArgumentException("Issuances must have a time-window"); - Instant time = timeWindow.getUntilTime(); - requireThat(require -> { - // Don't allow people to issue commercial paper under other entities identities. - require.using("output states are issued by a command signer", cmd.getSigners().contains(output.getIssuance().getParty().getOwningKey())); - require.using("output values sum to more than the inputs", output.getFaceValue().getQuantity() > 0); - require.using("the maturity date is not in the past", time.isBefore(output.getMaturityDate())); - // Don't allow an existing CP state to be replaced by this issuance. - require.using("can't reissue an existing state", inputs.isEmpty()); - return null; - }); - } else { - throw new IllegalArgumentException("Unrecognised command"); - } - } - // DOCEND 4 - } - - // DOCSTART 2 - public static class Commands implements CommandData { - public static class Move extends Commands { - @Override - public boolean equals(Object obj) { - return obj instanceof Move; - } - } - - public static class Redeem extends Commands { - @Override - public boolean equals(Object obj) { - return obj instanceof Redeem; - } - } - - public static class Issue extends Commands { - @Override - public boolean equals(Object obj) { - return obj instanceof Issue; - } - } - } - // DOCEND 2 -} \ No newline at end of file diff --git a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/contract/State.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/contract/State.java deleted file mode 100644 index 295fba8700..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/contract/State.java +++ /dev/null @@ -1,90 +0,0 @@ -package net.corda.docs.java.tutorial.contract; - -import com.google.common.collect.ImmutableList; -import net.corda.core.contracts.*; -import net.corda.core.crypto.NullKeys; -import net.corda.core.identity.AbstractParty; -import net.corda.core.identity.AnonymousParty; -import org.jetbrains.annotations.NotNull; - -import java.time.Instant; -import java.util.Currency; -import java.util.List; - -// DOCSTART 1 -public class State implements OwnableState { - private PartyAndReference issuance; - private AbstractParty owner; - private Amount> faceValue; - private Instant maturityDate; - - public State() { - } // For serialization - - public State(PartyAndReference issuance, AbstractParty owner, Amount> faceValue, - Instant maturityDate) { - this.issuance = issuance; - this.owner = owner; - this.faceValue = faceValue; - this.maturityDate = maturityDate; - } - - public State copy() { - return new State(this.issuance, this.owner, this.faceValue, this.maturityDate); - } - - public State withoutOwner() { - return new State(this.issuance, new AnonymousParty(NullKeys.NullPublicKey.INSTANCE), this.faceValue, this.maturityDate); - } - - @NotNull - @Override - public CommandAndState withNewOwner(@NotNull AbstractParty newOwner) { - return new CommandAndState(new CommercialPaper.Commands.Move(), new State(this.issuance, newOwner, this.faceValue, this.maturityDate)); - } - - public PartyAndReference getIssuance() { - return issuance; - } - - public AbstractParty getOwner() { - return owner; - } - - public Amount> getFaceValue() { - return faceValue; - } - - public Instant getMaturityDate() { - return maturityDate; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - State state = (State) o; - - if (issuance != null ? !issuance.equals(state.issuance) : state.issuance != null) return false; - if (owner != null ? !owner.equals(state.owner) : state.owner != null) return false; - if (faceValue != null ? !faceValue.equals(state.faceValue) : state.faceValue != null) return false; - return !(maturityDate != null ? !maturityDate.equals(state.maturityDate) : state.maturityDate != null); - } - - @Override - public int hashCode() { - int result = issuance != null ? issuance.hashCode() : 0; - result = 31 * result + (owner != null ? owner.hashCode() : 0); - result = 31 * result + (faceValue != null ? faceValue.hashCode() : 0); - result = 31 * result + (maturityDate != null ? maturityDate.hashCode() : 0); - return result; - } - - @NotNull - @Override - public List getParticipants() { - return ImmutableList.of(this.owner); - } -} -// DOCEND 1 \ No newline at end of file diff --git a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/ExampleSummingFlow.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/ExampleSummingFlow.java deleted file mode 100644 index c8e93d7025..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/ExampleSummingFlow.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.corda.docs.java.tutorial.flowstatemachines; - -import co.paralleluniverse.fibers.Suspendable; -import net.corda.core.flows.FlowLogic; -import net.corda.core.flows.StartableByRPC; -import net.corda.core.internal.FlowAsyncOperationKt; -import org.jetbrains.annotations.NotNull; - -// DOCSTART ExampleSummingFlow -@StartableByRPC -public final class ExampleSummingFlow extends FlowLogic { - @Suspendable - @NotNull - @Override - public Integer call() { - return FlowAsyncOperationKt.executeAsync(this, new SummingOperation(1, 2), false); - } -} -// DOCEND ExampleSummingFlow diff --git a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperation.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperation.java deleted file mode 100644 index 7b23e22efe..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperation.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.corda.docs.java.tutorial.flowstatemachines; - -import net.corda.core.concurrent.CordaFuture; -import net.corda.core.internal.FlowAsyncOperation; -import net.corda.core.internal.concurrent.CordaFutureImplKt; -import org.jetbrains.annotations.NotNull; - -// DOCSTART SummingOperation -public final class SummingOperation implements FlowAsyncOperation { - private final int a; - private final int b; - - @NotNull - @Override - public CordaFuture execute(String deduplicationId) { - return CordaFutureImplKt.doneFuture(this.a + this.b); - } - - public final int getA() { - return this.a; - } - - public final int getB() { - return this.b; - } - - public SummingOperation(int a, int b) { - this.a = a; - this.b = b; - } -} -// DOCEND SummingOperation diff --git a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperationThrowing.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperationThrowing.java deleted file mode 100644 index 91c30eaf4c..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperationThrowing.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.corda.docs.java.tutorial.flowstatemachines; - -import net.corda.core.concurrent.CordaFuture; -import net.corda.core.internal.FlowAsyncOperation; -import org.jetbrains.annotations.NotNull; - -// DOCSTART SummingOperationThrowing -public final class SummingOperationThrowing implements FlowAsyncOperation { - private final int a; - private final int b; - - @NotNull - @Override - public CordaFuture execute(String deduplicationId) { - throw new IllegalStateException("You shouldn't be calling me"); - } - - public final int getA() { - return this.a; - } - - public final int getB() { - return this.b; - } - - public SummingOperationThrowing(int a, int b) { - this.a = a; - this.b = b; - } -} -// DOCEND SummingOperationThrowing diff --git a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/TutorialFlowStateMachines.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/TutorialFlowStateMachines.java deleted file mode 100644 index 468a0c5711..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/TutorialFlowStateMachines.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.corda.docs.java.tutorial.flowstatemachines; - -import net.corda.core.flows.SignTransactionFlow; -import net.corda.core.utilities.ProgressTracker; -import org.jetbrains.annotations.Nullable; - -@SuppressWarnings("ALL") -public class TutorialFlowStateMachines { - // DOCSTART 1 - private final ProgressTracker progressTracker = new ProgressTracker( - RECEIVING, - VERIFYING, - SIGNING, - COLLECTING_SIGNATURES, - RECORDING - ); - - private static final ProgressTracker.Step RECEIVING = new ProgressTracker.Step( - "Waiting for seller trading info"); - private static final ProgressTracker.Step VERIFYING = new ProgressTracker.Step( - "Verifying seller assets"); - private static final ProgressTracker.Step SIGNING = new ProgressTracker.Step( - "Generating and signing transaction proposal"); - private static final ProgressTracker.Step COLLECTING_SIGNATURES = new ProgressTracker.Step( - "Collecting signatures from other parties"); - private static final ProgressTracker.Step RECORDING = new ProgressTracker.Step( - "Recording completed transaction"); - // DOCEND 1 - - // DOCSTART 2 - private static final ProgressTracker.Step VERIFYING_AND_SIGNING = new ProgressTracker.Step("Verifying and signing transaction proposal") { - @Nullable - @Override - public ProgressTracker childProgressTracker() { - return SignTransactionFlow.Companion.tracker(); - } - }; - // DOCEND 2 -} diff --git a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlow.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlow.java deleted file mode 100644 index e077de4878..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlow.java +++ /dev/null @@ -1,67 +0,0 @@ -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.utilities.ProgressTracker; - -// DOCSTART 01 -// Add these imports: -import net.corda.core.contracts.Command; -import net.corda.core.identity.Party; -import net.corda.core.transactions.SignedTransaction; -import net.corda.core.transactions.TransactionBuilder; - -// Replace Initiator's definition with: -@InitiatingFlow -@StartableByRPC -public class IOUFlow extends FlowLogic { - private final Integer iouValue; - private final Party otherParty; - - /** - * The progress tracker provides checkpoints indicating the progress of the flow to observers. - */ - private final ProgressTracker progressTracker = new ProgressTracker(); - - public IOUFlow(Integer iouValue, Party otherParty) { - this.iouValue = iouValue; - this.otherParty = otherParty; - } - - @Override - public ProgressTracker getProgressTracker() { - return progressTracker; - } - - /** - * The flow logic is encapsulated within the call() method. - */ - @Suspendable - @Override - public Void call() throws FlowException { - // We retrieve the notary identity from the network map. - Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); - - // We create the transaction components. - IOUState outputState = new IOUState(iouValue, getOurIdentity(), otherParty); - 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(command); - - // Signing the transaction. - SignedTransaction signedTx = getServiceHub().signInitialTransaction(txBuilder); - - // Creating a session with the other party. - FlowSession otherPartySession = initiateFlow(otherParty); - - // We finalise the transaction and then send it to the counterparty. - subFlow(new FinalityFlow(signedTx, otherPartySession)); - - return null; - } -} -// DOCEND 01 diff --git a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlowResponder.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlowResponder.java deleted file mode 100644 index b4343808c0..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlowResponder.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.corda.docs.java.tutorial.helloworld; - -import co.paralleluniverse.fibers.Suspendable; -import net.corda.core.flows.*; - -@SuppressWarnings("unused") -// DOCSTART 01 -// Replace Responder's definition with: -@InitiatedBy(IOUFlow.class) -public class IOUFlowResponder extends FlowLogic { - private final FlowSession otherPartySession; - - public IOUFlowResponder(FlowSession otherPartySession) { - this.otherPartySession = otherPartySession; - } - - @Suspendable - @Override - public Void call() throws FlowException { - subFlow(new ReceiveFinalityFlow(otherPartySession)); - - return null; - } -} -// DOCEND 01 diff --git a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUState.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUState.java deleted file mode 100644 index 4e91806b7f..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUState.java +++ /dev/null @@ -1,41 +0,0 @@ -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 this import: -import net.corda.core.identity.Party; - -// Replace TemplateState's definition with: -public class IOUState implements ContractState { - private final int value; - private final Party lender; - private final Party borrower; - - public IOUState(int value, Party lender, Party borrower) { - this.value = value; - this.lender = lender; - this.borrower = borrower; - } - - public int getValue() { - return value; - } - - public Party getLender() { - return lender; - } - - public Party getBorrower() { - return borrower; - } - - @Override - public List getParticipants() { - return Arrays.asList(lender, borrower); - } -} -// DOCEND 01 \ No newline at end of file diff --git a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUContract.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUContract.java deleted file mode 100644 index 5f96ecd450..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUContract.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.corda.docs.java.tutorial.twoparty; - -import net.corda.core.contracts.CommandData; -import net.corda.core.contracts.Contract; -import net.corda.core.transactions.LedgerTransaction; - -// DOCSTART 01 -// Add these imports: -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; - -// Replace TemplateContract's definition with: -public class IOUContract implements Contract { - public static final String ID = "com.template.IOUContract"; - - // Our Create command. - public static class Create implements CommandData { - } - - @Override - public void verify(LedgerTransaction tx) { - final CommandWithParties command = requireSingleCommand(tx.getCommands(), IOUContract.Create.class); - - // 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 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 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."); - - } -} -// DOCEND 01 \ No newline at end of file diff --git a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java deleted file mode 100644 index f762bcdb4e..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java +++ /dev/null @@ -1,77 +0,0 @@ -package net.corda.docs.java.tutorial.twoparty; - -// DOCSTART 01 -import co.paralleluniverse.fibers.Suspendable; -import net.corda.core.contracts.Command; -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 java.security.PublicKey; -import java.util.Arrays; -import java.util.List; -// DOCEND 01 - -@InitiatingFlow -@StartableByRPC -public class IOUFlow extends FlowLogic { - private final Integer iouValue; - private final Party otherParty; - - /** - * The progress tracker provides checkpoints indicating the progress of the flow to observers. - */ - private final ProgressTracker progressTracker = new ProgressTracker(); - - public IOUFlow(Integer iouValue, Party otherParty) { - this.iouValue = iouValue; - this.otherParty = otherParty; - } - - @Override - public ProgressTracker getProgressTracker() { - return progressTracker; - } - - /** - * The flow logic is encapsulated within the call() method. - */ - @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); - - // We create the transaction components. - IOUState outputState = new IOUState(iouValue, getOurIdentity(), otherParty); - List requiredSigners = Arrays.asList(getOurIdentity().getOwningKey(), otherParty.getOwningKey()); - Command command = new Command<>(new IOUContract.Create(), requiredSigners); - - // 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()); - - // Signing the transaction. - SignedTransaction signedTx = getServiceHub().signInitialTransaction(txBuilder); - - // Creating a session with the other party. - FlowSession otherPartySession = initiateFlow(otherParty); - - // Obtaining the counterparty's signature. - SignedTransaction fullySignedTx = subFlow(new CollectSignaturesFlow( - signedTx, Arrays.asList(otherPartySession), CollectSignaturesFlow.tracker())); - - // Finalising the transaction. - subFlow(new FinalityFlow(fullySignedTx, otherPartySession)); - - return null; - // DOCEND 02 - } -} diff --git a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlowResponder.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlowResponder.java deleted file mode 100644 index 1f7396f7d7..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlowResponder.java +++ /dev/null @@ -1,49 +0,0 @@ -package net.corda.docs.java.tutorial.twoparty; - -import co.paralleluniverse.fibers.Suspendable; -import net.corda.core.contracts.ContractState; -import net.corda.core.crypto.SecureHash; -import net.corda.core.flows.*; -import net.corda.core.transactions.SignedTransaction; - -import static net.corda.core.contracts.ContractsDSL.requireThat; - -@SuppressWarnings("unused") -// Define IOUFlowResponder: -@InitiatedBy(IOUFlow.class) -public class IOUFlowResponder extends FlowLogic { - private final FlowSession otherPartySession; - - public IOUFlowResponder(FlowSession otherPartySession) { - this.otherPartySession = otherPartySession; - } - - // DOCSTART 1 - @Suspendable - @Override - public Void call() throws FlowException { - class SignTxFlow extends SignTransactionFlow { - private SignTxFlow(FlowSession otherPartySession) { - super(otherPartySession); - } - - @Override - protected void checkTransaction(SignedTransaction stx) { - requireThat(require -> { - ContractState output = stx.getTx().getOutputs().get(0).getData(); - require.using("This must be an IOU transaction.", output instanceof IOUState); - IOUState iou = (IOUState) output; - require.using("The IOU's value can't be too high.", iou.getValue() < 100); - return null; - }); - } - } - - SecureHash expectedTxId = subFlow(new SignTxFlow(otherPartySession)).getId(); - - subFlow(new ReceiveFinalityFlow(otherPartySession, expectedTxId)); - - return null; - } - // DOCEND 1 -} diff --git a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUState.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUState.java deleted file mode 100644 index 556746b139..0000000000 --- a/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUState.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.corda.docs.java.tutorial.twoparty; - -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 { - private final int value; - private final Party lender; - private final Party borrower; - - public IOUState(int value, Party lender, Party borrower) { - this.value = value; - this.lender = lender; - this.borrower = borrower; - } - - public int getValue() { - return value; - } - - public Party getLender() { - return lender; - } - - public Party getBorrower() { - return borrower; - } - - @Override - public List getParticipants() { - return Arrays.asList(lender, borrower); - } -} \ No newline at end of file diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcExample.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcExample.kt deleted file mode 100644 index 14c7c599b4..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcExample.kt +++ /dev/null @@ -1,31 +0,0 @@ -@file:Suppress("unused") - -package net.corda.docs.kotlin - -// START 1 -import net.corda.client.rpc.CordaRPCClient -import net.corda.core.utilities.NetworkHostAndPort.Companion.parse -import net.corda.core.utilities.loggerFor -import org.slf4j.Logger - -class ClientRpcExample { - companion object { - val logger: Logger = loggerFor() - } - - fun main(args: Array) { - require(args.size == 3) { "Usage: TemplateClient " } - val nodeAddress = parse(args[0]) - val username = args[1] - val password = args[2] - - val client = CordaRPCClient(nodeAddress) - val connection = client.start(username, password) - val cordaRPCOperations = connection.proxy - - logger.info(cordaRPCOperations.currentNodeTime().toString()) - - connection.notifyServerAndClose() - } -} -// END 1 \ No newline at end of file diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcTutorial.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcTutorial.kt deleted file mode 100644 index b194b7956f..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcTutorial.kt +++ /dev/null @@ -1,150 +0,0 @@ -@file:Suppress("unused") - -package net.corda.docs.kotlin - -import net.corda.client.rpc.CordaRPCClient -import net.corda.core.contracts.Amount -import net.corda.core.messaging.CordaRPCOps -import net.corda.core.messaging.startFlow -import net.corda.core.messaging.vaultQueryBy -import net.corda.core.serialization.CordaSerializable -import net.corda.core.serialization.SerializationWhitelist -import net.corda.core.transactions.SignedTransaction -import net.corda.core.utilities.OpaqueBytes -import net.corda.finance.USD -import net.corda.finance.contracts.asset.Cash -import net.corda.finance.flows.CashExitFlow -import net.corda.finance.flows.CashIssueFlow -import net.corda.finance.flows.CashPaymentFlow -import net.corda.node.services.Permissions.Companion.invokeRpc -import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.testing.core.ALICE_NAME -import net.corda.testing.driver.DriverParameters -import net.corda.testing.node.User -import net.corda.testing.driver.driver -import net.corda.testing.node.internal.FINANCE_CORDAPPS -import org.graphstream.graph.Edge -import org.graphstream.graph.Node -import org.graphstream.graph.implementations.MultiGraph -import rx.Observable -import java.nio.file.Paths -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! - */ - -// START 1 -enum class PrintOrVisualise { - Print, - Visualise -} - -@Suppress("DEPRECATION") -fun main(args: Array) { - require(args.isNotEmpty()) { "Usage: [Print|Visualise]" } - val printOrVisualise = PrintOrVisualise.valueOf(args[0]) - - val baseDirectory = Paths.get("build/rpc-api-tutorial") - val user = User("user", "password", permissions = setOf(startFlow(), - startFlow(), - startFlow(), - invokeRpc(CordaRPCOps::nodeInfo) - )) - driver(DriverParameters(driverDirectory = baseDirectory, cordappsForAllNodes = FINANCE_CORDAPPS, waitForAllNodesToFinish = true)) { - val node = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).get() - // END 1 - - // START 2 - val client = CordaRPCClient(node.rpcAddress) - val proxy = client.start("user", "password").proxy - - thread { - generateTransactions(proxy) - } - // END 2 - - // START 3 - val (transactions: List, futureTransactions: Observable) = proxy.internalVerifiedTransactionsFeed() - // END 3 - - // START 4 - when (printOrVisualise) { - PrintOrVisualise.Print -> { - futureTransactions.startWith(transactions).subscribe { transaction -> - println("NODE ${transaction.id}") - transaction.tx.inputs.forEach { (txhash) -> - println("EDGE $txhash ${transaction.id}") - } - } - } - // END 4 - // START 5 - PrintOrVisualise.Visualise -> { - val graph = MultiGraph("transactions") - transactions.forEach { transaction -> - graph.addNode("${transaction.id}") - } - transactions.forEach { transaction -> - transaction.tx.inputs.forEach { ref -> - graph.addEdge("$ref", "${ref.txhash}", "${transaction.id}") - } - } - futureTransactions.subscribe { transaction -> - graph.addNode("${transaction.id}") - transaction.tx.inputs.forEach { ref -> - graph.addEdge("$ref", "${ref.txhash}", "${transaction.id}") - } - } - graph.display() - } - } - // END 5 - Unit - } -} - -// START 6 -fun generateTransactions(proxy: CordaRPCOps) { - val vault = proxy.vaultQueryBy().states - - var ownedQuantity = vault.fold(0L) { sum, state -> - sum + state.state.data.amount.quantity - } - val issueRef = OpaqueBytes.of(0) - val notary = proxy.notaryIdentities().first() - val me = proxy.nodeInfo().legalIdentities.first() - 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.startFlow(::CashExitFlow, Amount(quantity, USD), issueRef) - ownedQuantity -= quantity - } else if (ownedQuantity > 1000 && n < 0.7) { - val quantity = Math.abs(random.nextLong() % Math.min(ownedQuantity, 2000)) - proxy.startFlow(::CashPaymentFlow, Amount(quantity, USD), me) - } else { - val quantity = Math.abs(random.nextLong() % 1000) - proxy.startFlow(::CashIssueFlow, Amount(quantity, USD), issueRef, notary) - ownedQuantity += quantity - } - } -} -// END 6 - -// START 7 -// Not annotated, so need to whitelist manually. -data class ExampleRPCValue(val foo: String) - -// Annotated, so no need to whitelist manually. -@CordaSerializable -data class ExampleRPCValue2(val bar: Int) - -class ExampleRPCSerializationWhitelist : SerializationWhitelist { - // Add classes like this. - override val whitelist = listOf(ExampleRPCValue::class.java) -} -// END 7 \ No newline at end of file diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FinalityFlowMigration.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FinalityFlowMigration.kt deleted file mode 100644 index 64f52fc38e..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FinalityFlowMigration.kt +++ /dev/null @@ -1,93 +0,0 @@ -@file:Suppress("DEPRECATION", "unused", "UNUSED_PARAMETER") - -package net.corda.docs.kotlin - -import co.paralleluniverse.fibers.Suspendable -import net.corda.core.flows.* -import net.corda.core.identity.Party -import net.corda.core.transactions.SignedTransaction - -private fun dummyTransactionWithParticipant(party: Party): SignedTransaction = TODO() - -// DOCSTART SimpleFlowUsingOldApi -class SimpleFlowUsingOldApi(private val counterparty: Party) : FlowLogic() { - @Suspendable - override fun call(): SignedTransaction { - val stx = dummyTransactionWithParticipant(counterparty) - return subFlow(FinalityFlow(stx)) - } -} -// DOCEND SimpleFlowUsingOldApi - -// DOCSTART SimpleFlowUsingNewApi -// Notice how the flow *must* now be an initiating flow even when it wasn't before. -@InitiatingFlow -class SimpleFlowUsingNewApi(private val counterparty: Party) : FlowLogic() { - @Suspendable - override fun call(): SignedTransaction { - val stx = dummyTransactionWithParticipant(counterparty) - // For each non-local participant in the transaction we must initiate a flow session with them. - val session = initiateFlow(counterparty) - return subFlow(FinalityFlow(stx, session)) - } -} -// DOCEND SimpleFlowUsingNewApi - -// DOCSTART SimpleNewResponderFlow -// All participants will run this flow to receive and record the finalised transaction into their vault. -@InitiatedBy(SimpleFlowUsingNewApi::class) -class SimpleNewResponderFlow(private val otherSide: FlowSession) : FlowLogic() { - @Suspendable - override fun call() { - subFlow(ReceiveFinalityFlow(otherSide)) - } -} -// DOCEND SimpleNewResponderFlow - -// DOCSTART ExistingInitiatingFlow -// Assuming the previous version of the flow was 1 (the default if none is specified), we increment the version number to 2 -// to allow for backwards compatibility with nodes running the old CorDapp. -@InitiatingFlow(version = 2) -class ExistingInitiatingFlow(private val counterparty: Party) : FlowLogic() { - @Suspendable - override fun call(): SignedTransaction { - val partiallySignedTx = dummyTransactionWithParticipant(counterparty) - val session = initiateFlow(counterparty) - val fullySignedTx = subFlow(CollectSignaturesFlow(partiallySignedTx, listOf(session))) - // Determine which version of the flow that other side is using. - return if (session.getCounterpartyFlowInfo().flowVersion == 1) { - // Use the old API if the other side is using the previous version of the flow. - subFlow(FinalityFlow(fullySignedTx)) - } else { - // Otherwise they're at least on version 2 and so we can send the finalised transaction on the existing session. - subFlow(FinalityFlow(fullySignedTx, session)) - } - } -} -// DOCEND ExistingInitiatingFlow - -@InitiatedBy(ExistingInitiatingFlow::class) -class ExistingResponderFlow(private val otherSide: FlowSession) : FlowLogic() { - @Suspendable - override fun call() { - // DOCSTART ExistingResponderFlow - // First we have to run the SignTransactionFlow, which will return a SignedTransaction. - val txWeJustSigned = subFlow(object : SignTransactionFlow(otherSide) { - @Suspendable - override fun checkTransaction(stx: SignedTransaction) { - // Implement responder flow transaction checks here - } - }) - - if (otherSide.getCounterpartyFlowInfo().flowVersion >= 2) { - // The other side is not using the old CorDapp so call ReceiveFinalityFlow to record the finalised transaction. - // If SignTransactionFlow is used then we can verify the tranaction we receive for recording is the same one - // that was just signed. - subFlow(ReceiveFinalityFlow(otherSide, expectedTxId = txWeJustSigned.id)) - } else { - // Otherwise the other side is running the old CorDapp and so we don't need to do anything further. The node - // will automatically record the finalised transaction using the old insecure mechanism. - } - // DOCEND ExistingResponderFlow - } -} diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt deleted file mode 100644 index e417f74300..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt +++ /dev/null @@ -1,664 +0,0 @@ -@file:Suppress("UNUSED_VARIABLE", "unused", "DEPRECATION") - -package net.corda.docs.kotlin - -import co.paralleluniverse.fibers.Suspendable -import net.corda.core.contracts.* -import net.corda.core.crypto.SecureHash -import net.corda.core.crypto.TransactionSignature -import net.corda.core.crypto.generateKeyPair -import net.corda.core.flows.* -import net.corda.core.identity.CordaX500Name -import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate -import net.corda.core.internal.FetchDataFlow -import net.corda.core.node.services.Vault.Page -import net.corda.core.node.services.queryBy -import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria -import net.corda.core.transactions.LedgerTransaction -import net.corda.core.transactions.SignedTransaction -import net.corda.core.transactions.TransactionBuilder -import net.corda.core.utilities.ProgressTracker -import net.corda.core.utilities.ProgressTracker.Step -import net.corda.core.utilities.UntrustworthyData -import net.corda.core.utilities.seconds -import net.corda.core.utilities.unwrap -import net.corda.finance.contracts.asset.Cash -import net.corda.testing.contracts.DummyContract -import net.corda.testing.contracts.DummyState -import java.security.PublicKey -import java.security.Signature -import java.time.Instant - -// ``InitiatorFlow`` is our first flow, and will communicate with -// ``ResponderFlow``, below. -// We mark ``InitiatorFlow`` as an ``InitiatingFlow``, allowing it to be -// started directly by the node. -@InitiatingFlow -// We also mark ``InitiatorFlow`` as ``StartableByRPC``, allowing the -// node's owner to start the flow via RPC. -@StartableByRPC -// Every flow must subclass ``FlowLogic``. The generic indicates the -// flow's return type. -class InitiatorFlow(val arg1: Boolean, val arg2: Int, private val counterparty: Party, val regulator: Party) : FlowLogic() { - - /**--------------------------------- - * WIRING UP THE PROGRESS TRACKER * - ---------------------------------**/ - // Giving our flow a progress tracker allows us to see the flow's - // progress visually in our node's CRaSH shell. - // DOCSTART 17 - companion object { - object ID_OTHER_NODES : Step("Identifying other nodes on the network.") - object SENDING_AND_RECEIVING_DATA : Step("Sending data between parties.") - object EXTRACTING_VAULT_STATES : Step("Extracting states from the vault.") - object OTHER_TX_COMPONENTS : Step("Gathering a transaction's other components.") - object TX_BUILDING : Step("Building a transaction.") - object TX_SIGNING : Step("Signing a transaction.") - object TX_VERIFICATION : Step("Verifying a transaction.") - object SIGS_GATHERING : Step("Gathering a transaction's signatures.") { - // Wiring up a child progress tracker allows us to see the - // subflow's progress steps in our flow's progress tracker. - override fun childProgressTracker() = CollectSignaturesFlow.tracker() - } - - object VERIFYING_SIGS : Step("Verifying a transaction's signatures.") - object FINALISATION : Step("Finalising a transaction.") { - override fun childProgressTracker() = FinalityFlow.tracker() - } - - fun tracker() = ProgressTracker( - ID_OTHER_NODES, - SENDING_AND_RECEIVING_DATA, - EXTRACTING_VAULT_STATES, - OTHER_TX_COMPONENTS, - TX_BUILDING, - TX_SIGNING, - TX_VERIFICATION, - SIGS_GATHERING, - VERIFYING_SIGS, - FINALISATION - ) - } - // DOCEND 17 - - override val progressTracker: ProgressTracker = tracker() - - @Suppress("RemoveExplicitTypeArguments") - @Suspendable - override fun call() { - // We'll be using a dummy public key for demonstration purposes. - val dummyPubKey: PublicKey = generateKeyPair().public - - /**-------------------------- - * IDENTIFYING OTHER NODES * - --------------------------**/ - // DOCSTART 18 - progressTracker.currentStep = ID_OTHER_NODES - // DOCEND 18 - - // Every transaction needs a notary: - // - To prevent double-spends if the transaction has inputs - // - To serve as a timestamping authority if the transaction has a - // time-window - // We retrieve the notary from the network map. - // DOCSTART 01 - val notaryName: CordaX500Name = CordaX500Name( - organisation = "Notary Service", - locality = "London", - country = "GB") - val notary: Party = serviceHub.networkMapCache.getNotary(notaryName)!! - // DOCEND 01 - - // We may also need to identify a specific counterparty. We do so - // using the identity service. - // DOCSTART 02 - val counterpartyName: CordaX500Name = CordaX500Name( - organisation = "NodeA", - locality = "London", - country = "GB") - val namedCounterparty: Party = serviceHub.identityService.wellKnownPartyFromX500Name(counterpartyName) ?: - throw IllegalArgumentException("Couldn't find counterparty for NodeA in identity service") - val keyedCounterparty: Party = serviceHub.identityService.partyFromKey(dummyPubKey) ?: - throw IllegalArgumentException("Couldn't find counterparty with key: $dummyPubKey in identity service") - // DOCEND 02 - - /**----------------------------- - * SENDING AND RECEIVING DATA * - -----------------------------**/ - progressTracker.currentStep = SENDING_AND_RECEIVING_DATA - - // We start by initiating a flow session with the counterparty. We - // will use this session to send and receive messages from the - // counterparty. - // DOCSTART initiateFlow - val counterpartySession: FlowSession = initiateFlow(counterparty) - // DOCEND initiateFlow - - // We can send arbitrary data to a counterparty. - // If this is the first ``send``, the counterparty will either: - // 1. Ignore the message if they are not registered to respond - // to messages from this flow. - // 2. Start the flow they have registered to respond to this flow, - // and run the flow until the first call to ``receive``, at - // which point they process the message. - // In other words, we are assuming that the counterparty is - // registered to respond to this flow, and has a corresponding - // ``receive`` call. - // DOCSTART 04 - counterpartySession.send(Any()) - // DOCEND 04 - - // We can wait to receive arbitrary data of a specific type from a - // counterparty. Again, this implies a corresponding ``send`` call - // in the counterparty's flow. A few scenarios: - // - We never receive a message back. In the current design, the - // flow is paused until the node's owner kills the flow. - // - Instead of sending a message back, the counterparty throws a - // ``FlowException``. This exception is propagated back to us, - // and we can use the error message to establish what happened. - // - We receive a message back, but it's of the wrong type. In - // this case, a ``FlowException`` is thrown. - // - We receive back a message of the correct type. All is good. - // - // Upon calling ``receive()`` (or ``sendAndReceive()``), the - // ``FlowLogic`` is suspended until it receives a response. - // - // We receive the data wrapped in an ``UntrustworthyData`` - // instance. This is a reminder that the data we receive may not - // be what it appears to be! We must unwrap the - // ``UntrustworthyData`` using a lambda. - // DOCSTART 05 - val packet1: UntrustworthyData = counterpartySession.receive() - val int: Int = packet1.unwrap { data -> - // Perform checking on the object received. - // T O D O: Check the received object. - // Return the object. - data - } - // DOCEND 05 - - // We can also use a single call to send data to a counterparty - // and wait to receive data of a specific type back. The type of - // data sent doesn't need to match the type of the data received - // back. - // DOCSTART 07 - val packet2: UntrustworthyData = counterpartySession.sendAndReceive("You can send and receive any class!") - val boolean: Boolean = packet2.unwrap { data -> - // Perform checking on the object received. - // T O D O: Check the received object. - // Return the object. - data - } - // DOCEND 07 - - // We're not limited to sending to and receiving from a single - // counterparty. A flow can send messages to as many parties as it - // likes, and each party can invoke a different response flow. - // DOCSTART 06 - val regulatorSession: FlowSession = initiateFlow(regulator) - regulatorSession.send(Any()) - val packet3: UntrustworthyData = regulatorSession.receive() - // DOCEND 06 - - // We may also batch receives in order to increase performance. This - // ensures that only a single checkpoint is created for all received - // messages. - // Type-safe variant: - val signatures: List> = - receiveAll(Signature::class.java, listOf(counterpartySession, regulatorSession)) - // Dynamic variant: - val messages: Map> = - receiveAllMap(mapOf( - counterpartySession to Boolean::class.java, - regulatorSession to String::class.java - )) - - /**----------------------------------- - * EXTRACTING STATES FROM THE VAULT * - -----------------------------------**/ - progressTracker.currentStep = EXTRACTING_VAULT_STATES - - // Let's assume there are already some ``DummyState``s in our - // node's vault, stored there as a result of running past flows, - // and we want to consume them in a transaction. There are many - // ways to extract these states from our vault. - - // For example, we would extract any unconsumed ``DummyState``s - // from our vault as follows: - val criteria: VaultQueryCriteria = VaultQueryCriteria() // default is UNCONSUMED - val results: Page = serviceHub.vaultService.queryBy(criteria) - val dummyStates: List> = results.states - - // For a full list of the available ways of extracting states from - // the vault, see the Vault Query docs page. - - // When building a transaction, input states are passed in as - // ``StateRef`` instances, which pair the hash of the transaction - // that generated the state with the state's index in the outputs - // of that transaction. In practice, we'd pass the transaction hash - // or the ``StateRef`` as a parameter to the flow, or extract the - // ``StateRef`` from our vault. - // DOCSTART 20 - val ourStateRef: StateRef = StateRef(SecureHash.sha256("DummyTransactionHash"), 0) - // DOCEND 20 - // A ``StateAndRef`` pairs a ``StateRef`` with the state it points to. - // DOCSTART 21 - val ourStateAndRef: StateAndRef = serviceHub.toStateAndRef(ourStateRef) - // DOCEND 21 - - /**----------------------------------------- - * GATHERING OTHER TRANSACTION COMPONENTS * - -----------------------------------------**/ - progressTracker.currentStep = OTHER_TX_COMPONENTS - - // Reference input states are constructed from StateAndRefs. - // DOCSTART 55 - val referenceState: ReferencedStateAndRef = ourStateAndRef.referenced() - // DOCEND 55 - // Output states are constructed from scratch. - // DOCSTART 22 - val ourOutputState: DummyState = DummyState() - // DOCEND 22 - // Or as copies of other states with some properties changed. - @Suppress("MagicNumber") // literally a magic number - // DOCSTART 23 - val ourOtherOutputState: DummyState = ourOutputState.copy(magicNumber = 77) - // DOCEND 23 - - // We then need to pair our output state with a contract. - // DOCSTART 47 - val ourOutput: StateAndContract = StateAndContract(ourOutputState, DummyContract.PROGRAM_ID) - // DOCEND 47 - - // Commands pair a ``CommandData`` instance with a list of - // public keys. To be valid, the transaction requires a signature - // matching every public key in all of the transaction's commands. - // DOCSTART 24 - val commandData: DummyContract.Commands.Create = DummyContract.Commands.Create() - val ourPubKey: PublicKey = serviceHub.myInfo.legalIdentitiesAndCerts.first().owningKey - val counterpartyPubKey: PublicKey = counterparty.owningKey - val requiredSigners: List = listOf(ourPubKey, counterpartyPubKey) - val ourCommand: Command = Command(commandData, requiredSigners) - // DOCEND 24 - - // ``CommandData`` can either be: - // 1. Of type ``TypeOnlyCommandData``, in which case it only - // serves to attach signers to the transaction and possibly - // fork the contract's verification logic. - val typeOnlyCommandData: TypeOnlyCommandData = DummyContract.Commands.Create() - // 2. Include additional data which can be used by the contract - // during verification, alongside fulfilling the roles above. - val commandDataWithData: CommandData = Cash.Commands.Issue() - - // Attachments are identified by their hash. - // The attachment with the corresponding hash must have been - // uploaded ahead of time via the node's RPC interface. - // DOCSTART 25 - val ourAttachment: SecureHash = SecureHash.sha256("DummyAttachment") - // DOCEND 25 - - // Time windows can have a start and end time, or be open at either end. - // DOCSTART 26 - val ourTimeWindow: TimeWindow = TimeWindow.between(Instant.MIN, Instant.MAX) - val ourAfter: TimeWindow = TimeWindow.fromOnly(Instant.MIN) - val ourBefore: TimeWindow = TimeWindow.untilOnly(Instant.MAX) - // DOCEND 26 - - // We can also define a time window as an ``Instant`` +/- a time - // tolerance (e.g. 30 seconds): - // DOCSTART 42 - val ourTimeWindow2: TimeWindow = TimeWindow.withTolerance(serviceHub.clock.instant(), 30.seconds) - // DOCEND 42 - // Or as a start-time plus a duration: - // DOCSTART 43 - val ourTimeWindow3: TimeWindow = TimeWindow.fromStartAndDuration(serviceHub.clock.instant(), 30.seconds) - // DOCEND 43 - - /**----------------------- - * TRANSACTION BUILDING * - -----------------------**/ - progressTracker.currentStep = TX_BUILDING - - // If our transaction has input states or a time-window, we must instantiate it with a - // notary. - // DOCSTART 19 - val txBuilder: TransactionBuilder = TransactionBuilder(notary) - // DOCEND 19 - - // Otherwise, we can choose to instantiate it without one: - // DOCSTART 46 - val txBuilderNoNotary: TransactionBuilder = TransactionBuilder() - // DOCEND 46 - - // We add items to the transaction builder using ``TransactionBuilder.withItems``: - // DOCSTART 27 - txBuilder.withItems( - // Inputs, as ``StateAndRef``s that reference the outputs of previous transactions - ourStateAndRef, - // Outputs, as ``StateAndContract``s - ourOutput, - // Commands, as ``Command``s - ourCommand, - // Attachments, as ``SecureHash``es - ourAttachment, - // A time-window, as ``TimeWindow`` - ourTimeWindow - ) - // DOCEND 27 - - // We can also add items using methods for the individual components. - - // The individual methods for adding input states and attachments: - // DOCSTART 28 - txBuilder.addInputState(ourStateAndRef) - txBuilder.addAttachment(ourAttachment) - // DOCEND 28 - - // An output state can be added as a ``ContractState``, contract class name and notary. - // DOCSTART 49 - txBuilder.addOutputState(ourOutputState, DummyContract.PROGRAM_ID, notary) - // DOCEND 49 - // We can also leave the notary field blank, in which case the transaction's default - // notary is used. - // DOCSTART 50 - txBuilder.addOutputState(ourOutputState, DummyContract.PROGRAM_ID) - // DOCEND 50 - // Or we can add the output state as a ``TransactionState``, which already specifies - // the output's contract and notary. - // DOCSTART 51 - val txState: TransactionState = TransactionState(ourOutputState, DummyContract.PROGRAM_ID, notary) - // DOCEND 51 - - // Commands can be added as ``Command``s. - // DOCSTART 52 - txBuilder.addCommand(ourCommand) - // DOCEND 52 - // Or as ``CommandData`` and a ``vararg PublicKey``. - // DOCSTART 53 - txBuilder.addCommand(commandData, ourPubKey, counterpartyPubKey) - // DOCEND 53 - - // We can set a time-window directly. - // DOCSTART 44 - txBuilder.setTimeWindow(ourTimeWindow) - // DOCEND 44 - // Or as a start time plus a duration (e.g. 45 seconds). - // DOCSTART 45 - txBuilder.setTimeWindow(serviceHub.clock.instant(), 45.seconds) - // DOCEND 45 - - /**---------------------- - * TRANSACTION SIGNING * - ----------------------**/ - progressTracker.currentStep = TX_SIGNING - - // We finalise the transaction by signing it, converting it into a - // ``SignedTransaction``. - // DOCSTART 29 - val onceSignedTx: SignedTransaction = serviceHub.signInitialTransaction(txBuilder) - // DOCEND 29 - // We can also sign the transaction using a different public key: - // DOCSTART 30 - val otherIdentity: PartyAndCertificate = serviceHub.keyManagementService.freshKeyAndCert(ourIdentityAndCert, false) - val onceSignedTx2: SignedTransaction = serviceHub.signInitialTransaction(txBuilder, otherIdentity.owningKey) - // DOCEND 30 - - // If instead this was a ``SignedTransaction`` that we'd received - // from a counterparty and we needed to sign it, we would add our - // signature using: - // DOCSTART 38 - val twiceSignedTx: SignedTransaction = serviceHub.addSignature(onceSignedTx) - // DOCEND 38 - // Or, if we wanted to use a different public key: - val otherIdentity2: PartyAndCertificate = serviceHub.keyManagementService.freshKeyAndCert(ourIdentityAndCert, false) - // DOCSTART 39 - val twiceSignedTx2: SignedTransaction = serviceHub.addSignature(onceSignedTx, otherIdentity2.owningKey) - // DOCEND 39 - - // We can also generate a signature over the transaction without - // adding it to the transaction itself. We may do this when - // sending just the signature in a flow instead of returning the - // entire transaction with our signature. This way, the receiving - // node does not need to check we haven't changed anything in the - // transaction. - // DOCSTART 40 - val sig: TransactionSignature = serviceHub.createSignature(onceSignedTx) - // DOCEND 40 - // And again, if we wanted to use a different public key: - // DOCSTART 41 - val sig2: TransactionSignature = serviceHub.createSignature(onceSignedTx, otherIdentity2.owningKey) - // DOCEND 41 - - // In practice, however, the process of gathering every signature - // but the first can be automated using ``CollectSignaturesFlow``. - // See the "Gathering Signatures" section below. - - /**--------------------------- - * TRANSACTION VERIFICATION * - ---------------------------**/ - progressTracker.currentStep = TX_VERIFICATION - - // Verifying a transaction will also verify every transaction in - // the transaction's dependency chain, which will require - // transaction data access on counterparty's node. The - // ``SendTransactionFlow`` can be used to automate the sending and - // data vending process. The ``SendTransactionFlow`` will listen - // for data request until the transaction is resolved and verified - // on the other side: - // DOCSTART 12 - subFlow(SendTransactionFlow(counterpartySession, twiceSignedTx)) - - // Optional request verification to further restrict data access. - subFlow(object : SendTransactionFlow(counterpartySession, twiceSignedTx) { - override fun verifyDataRequest(dataRequest: FetchDataFlow.Request.Data) { - // Extra request verification. - } - }) - // DOCEND 12 - - // We can receive the transaction using ``ReceiveTransactionFlow``, - // which will automatically download all the dependencies and verify - // the transaction - // DOCSTART 13 - val verifiedTransaction = subFlow(ReceiveTransactionFlow(counterpartySession)) - // DOCEND 13 - - // We can also send and receive a `StateAndRef` dependency chain - // and automatically resolve its dependencies. - // DOCSTART 14 - subFlow(SendStateAndRefFlow(counterpartySession, dummyStates)) - - // On the receive side ... - val resolvedStateAndRef = subFlow(ReceiveStateAndRefFlow(counterpartySession)) - // DOCEND 14 - - // We can now verify the transaction to ensure that it satisfies - // the contracts of all the transaction's input and output states. - // DOCSTART 33 - twiceSignedTx.verify(serviceHub) - // DOCEND 33 - - // We'll often want to perform our own additional verification - // too. Just because a transaction is valid based on the contract - // rules and requires our signature doesn't mean we have to - // sign it! We need to make sure the transaction represents an - // agreement we actually want to enter into. - - // To do this, we need to convert our ``SignedTransaction`` - // into a ``LedgerTransaction``. This will use our ServiceHub - // to resolve the transaction's inputs and attachments into - // actual objects, rather than just references. - // DOCSTART 32 - val ledgerTx: LedgerTransaction = twiceSignedTx.toLedgerTransaction(serviceHub) - // DOCEND 32 - - // We can now perform our additional verification. - // DOCSTART 34 - val outputState: DummyState = ledgerTx.outputsOfType().single() - if (outputState.magicNumber == 777) { - // ``FlowException`` is a special exception type. It will be - // propagated back to any counterparty flows waiting for a - // message from this flow, notifying them that the flow has - // failed. - throw FlowException("We expected a magic number of 777.") - } - // DOCEND 34 - - // Of course, if you are not a required signer on the transaction, - // you have no power to decide whether it is valid or not. If it - // requires signatures from all the required signers and is - // contractually valid, it's a valid ledger update. - - /**----------------------- - * GATHERING SIGNATURES * - -----------------------**/ - progressTracker.currentStep = SIGS_GATHERING - - // The list of parties who need to sign a transaction is dictated - // by the transaction's commands. Once we've signed a transaction - // ourselves, we can automatically gather the signatures of the - // other required signers using ``CollectSignaturesFlow``. - // The responder flow will need to call ``SignTransactionFlow``. - // DOCSTART 15 - val fullySignedTx: SignedTransaction = subFlow(CollectSignaturesFlow(twiceSignedTx, setOf(counterpartySession, regulatorSession), SIGS_GATHERING.childProgressTracker())) - // DOCEND 15 - - /**----------------------- - * VERIFYING SIGNATURES * - -----------------------**/ - progressTracker.currentStep = VERIFYING_SIGS - - // We can verify that a transaction has all the required - // signatures, and that they're all valid, by running: - // DOCSTART 35 - fullySignedTx.verifyRequiredSignatures() - // DOCEND 35 - - // If the transaction is only partially signed, we have to pass in - // a vararg of the public keys corresponding to the missing - // signatures, explicitly telling the system not to check them. - // DOCSTART 36 - onceSignedTx.verifySignaturesExcept(counterpartyPubKey) - // DOCEND 36 - - // There is also an overload of ``verifySignaturesExcept`` which accepts - // a ``Collection`` of the public keys corresponding to the missing - // signatures. - // DOCSTART 54 - onceSignedTx.verifySignaturesExcept(listOf(counterpartyPubKey)) - // DOCEND 54 - - // We can also choose to only check the signatures that are - // present. BE VERY CAREFUL - this function provides no guarantees - // that the signatures are correct, or that none are missing. - // DOCSTART 37 - twiceSignedTx.checkSignaturesAreValid() - // DOCEND 37 - - /**----------------------------- - * FINALISING THE TRANSACTION * - -----------------------------**/ - progressTracker.currentStep = FINALISATION - - // We notarise the transaction and get it recorded in the vault of - // the participants of all the transaction's states. - // DOCSTART 09 - val notarisedTx1: SignedTransaction = subFlow(FinalityFlow(fullySignedTx, listOf(counterpartySession), FINALISATION.childProgressTracker())) - // DOCEND 09 - // We can also choose to send it to additional parties who aren't one - // of the state's participants. - // DOCSTART 10 - val partySessions: List = listOf(counterpartySession, initiateFlow(regulator)) - val notarisedTx2: SignedTransaction = subFlow(FinalityFlow(fullySignedTx, partySessions, FINALISATION.childProgressTracker())) - // DOCEND 10 - - // DOCSTART FlowSession porting - send(regulator, Any()) // Old API - // becomes - val session = initiateFlow(regulator) - session.send(Any()) - // DOCEND FlowSession porting - } -} - -// ``ResponderFlow`` is our second flow, and will communicate with -// ``InitiatorFlow``. -// We mark ``ResponderFlow`` as an ``InitiatedByFlow``, meaning that it -// can only be started in response to a message from its initiating flow. -// That's ``InitiatorFlow`` in this case. -// Each node also has several flow pairs registered by default - see -// ``AbstractNode.installCoreFlows``. -@InitiatedBy(InitiatorFlow::class) -class ResponderFlow(val counterpartySession: FlowSession) : FlowLogic() { - - companion object { - object RECEIVING_AND_SENDING_DATA : Step("Sending data between parties.") - object SIGNING : Step("Responding to CollectSignaturesFlow.") - object FINALISATION : Step("Finalising a transaction.") - - fun tracker() = ProgressTracker( - RECEIVING_AND_SENDING_DATA, - SIGNING, - FINALISATION - ) - } - - override val progressTracker: ProgressTracker = tracker() - - @Suspendable - override fun call() { - // The ``ResponderFlow` has all the same APIs available. It looks - // up network information, sends and receives data, and constructs - // transactions in exactly the same way. - - /**----------------------------- - * SENDING AND RECEIVING DATA * - -----------------------------**/ - progressTracker.currentStep = RECEIVING_AND_SENDING_DATA - - // We need to respond to the messages sent by the initiator: - // 1. They sent us an ``Any`` instance - // 2. They waited to receive an ``Integer`` instance back - // 3. They sent a ``String`` instance and waited to receive a - // ``Boolean`` instance back - // Our side of the flow must mirror these calls. - // DOCSTART 08 - val any: Any = counterpartySession.receive().unwrap { data -> data } - val string: String = counterpartySession.sendAndReceive(99).unwrap { data -> data } - counterpartySession.send(true) - // DOCEND 08 - - /**---------------------------------------- - * RESPONDING TO COLLECT_SIGNATURES_FLOW * - ----------------------------------------**/ - progressTracker.currentStep = SIGNING - - // The responder will often need to respond to a call to - // ``CollectSignaturesFlow``. It does so my invoking its own - // ``SignTransactionFlow`` subclass. - // DOCSTART 16 - val signTransactionFlow: SignTransactionFlow = object : SignTransactionFlow(counterpartySession) { - override fun checkTransaction(stx: SignedTransaction) = requireThat { - // Any additional checking we see fit... - val outputState = stx.tx.outputsOfType().single() - require(outputState.magicNumber == 777) - } - } - - val idOfTxWeSigned = subFlow(signTransactionFlow).id - // DOCEND 16 - - /**----------------------------- - * FINALISING THE TRANSACTION * - -----------------------------**/ - progressTracker.currentStep = FINALISATION - - // As the final step the responder waits to receive the notarised transaction from the sending party - // Since it knows the ID of the transaction it just signed, the transaction ID is specified to ensure the correct - // transaction is received and recorded. - // DOCSTART ReceiveFinalityFlow - subFlow(ReceiveFinalityFlow(counterpartySession, expectedTxId = idOfTxWeSigned)) - // DOCEND ReceiveFinalityFlow - } -} diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorial.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorial.kt deleted file mode 100644 index b3496c41b4..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorial.kt +++ /dev/null @@ -1,259 +0,0 @@ -package net.corda.docs.kotlin - -import co.paralleluniverse.fibers.Suspendable -import net.corda.core.contracts.Amount -import net.corda.core.contracts.Issued -import net.corda.core.contracts.StateAndContract -import net.corda.core.contracts.StateAndRef -import net.corda.core.contracts.withoutIssuer -import net.corda.core.crypto.SecureHash -import net.corda.core.crypto.TransactionSignature -import net.corda.core.flows.FinalityFlow -import net.corda.core.flows.FlowLogic -import net.corda.core.flows.FlowSession -import net.corda.core.flows.InitiatedBy -import net.corda.core.flows.InitiatingFlow -import net.corda.core.flows.ReceiveFinalityFlow -import net.corda.core.flows.ReceiveStateAndRefFlow -import net.corda.core.flows.ReceiveTransactionFlow -import net.corda.core.flows.SendStateAndRefFlow -import net.corda.core.flows.SendTransactionFlow -import net.corda.core.identity.AbstractParty -import net.corda.core.identity.Party -import net.corda.core.node.ServiceHub -import net.corda.core.node.services.vault.QueryCriteria -import net.corda.core.node.services.vault.builder -import net.corda.core.serialization.CordaSerializable -import net.corda.core.transactions.SignedTransaction -import net.corda.core.transactions.TransactionBuilder -import net.corda.core.utilities.unwrap -import net.corda.finance.contracts.asset.Cash -import net.corda.finance.schemas.CashSchemaV1 -import net.corda.testing.core.singleIdentity -import java.util.* - -@CordaSerializable -private data class FxRequest(val tradeId: String, - val amount: Amount>, - val owner: Party, - val counterparty: Party, - val notary: Party) - -// DOCSTART 1 -// This is equivalent to the Cash.generateSpend -// Which is brought here to make the filtering logic more visible in the example -private fun gatherOurInputs(serviceHub: ServiceHub, - lockId: UUID, - amountRequired: Amount>, - notary: Party?): Pair>, Long> { - // extract our identity for convenience - val ourKeys = serviceHub.keyManagementService.keys - val ourParties = ourKeys.map { serviceHub.identityService.partyFromKey(it) ?: throw IllegalStateException("Unable to resolve party from key") } - val fungibleCriteria = QueryCriteria.FungibleAssetQueryCriteria(owner = ourParties) - - val vaultCriteria: QueryCriteria = QueryCriteria.VaultQueryCriteria(notary = listOf(notary as AbstractParty)) - - val logicalExpression = builder { CashSchemaV1.PersistentCashState::currency.equal(amountRequired.token.product.currencyCode) } - val cashCriteria = QueryCriteria.VaultCustomQueryCriteria(logicalExpression) - - val fullCriteria = fungibleCriteria.and(vaultCriteria).and(cashCriteria) - - val eligibleStates = serviceHub.vaultService.tryLockFungibleStatesForSpending(lockId, fullCriteria, amountRequired.withoutIssuer(), Cash.State::class.java) - - check(eligibleStates.isNotEmpty()) { "Insufficient funds" } - val amount = eligibleStates.fold(0L) { tot, (state) -> tot + state.data.amount.quantity } - val change = amount - amountRequired.quantity - - return Pair(eligibleStates, change) -} -// DOCEND 1 - -private fun prepareOurInputsAndOutputs(serviceHub: ServiceHub, lockId: UUID, request: FxRequest): Pair>, List> { - // Create amount with correct issuer details - val sellAmount = request.amount - - // DOCSTART 2 - // Gather our inputs. We would normally use VaultService.generateSpend - // to carry out the build in a single step. To be more explicit - // we will use query manually in the helper function below. - // Putting this into a non-suspendable function also prevents issues when - // the flow is suspended. - val (inputs, residual) = gatherOurInputs(serviceHub, lockId, sellAmount, request.notary) - - // Build and an output state for the counterparty - val transferredFundsOutput = Cash.State(sellAmount, request.counterparty) - - val outputs = if (residual > 0L) { - // Build an output state for the residual change back to us - val residualAmount = Amount(residual, sellAmount.token) - val residualOutput = Cash.State(residualAmount, serviceHub.myInfo.singleIdentity()) - listOf(transferredFundsOutput, residualOutput) - } else { - listOf(transferredFundsOutput) - } - return Pair(inputs, outputs) - // DOCEND 2 -} - -// A flow representing creating a transaction that -// carries out exchange of cash assets. -@InitiatingFlow -class ForeignExchangeFlow(private val tradeId: String, - private val baseCurrencyAmount: Amount>, - private val quoteCurrencyAmount: Amount>, - private val counterparty: Party, - private val weAreBaseCurrencySeller: Boolean, - private val notary: Party) : FlowLogic() { - @Suspendable - override fun call(): SecureHash { - // Select correct sides of the Fx exchange to query for. - // Specifically we own the assets we wish to sell. - // Also prepare the other side query - val (localRequest, remoteRequest) = if (weAreBaseCurrencySeller) { - val local = FxRequest(tradeId, baseCurrencyAmount, ourIdentity, counterparty, notary) - val remote = FxRequest(tradeId, quoteCurrencyAmount, counterparty, ourIdentity, notary) - Pair(local, remote) - } else { - val local = FxRequest(tradeId, quoteCurrencyAmount, ourIdentity, counterparty, notary) - val remote = FxRequest(tradeId, baseCurrencyAmount, counterparty, ourIdentity, notary) - Pair(local, remote) - } - - // Call the helper method to identify suitable inputs and make the outputs - val (ourInputStates, ourOutputStates) = prepareOurInputsAndOutputs(serviceHub, runId.uuid, localRequest) - - // identify the notary for our states - val notary = ourInputStates.first().state.notary - // ensure request to other side is for a consistent notary - val remoteRequestWithNotary = remoteRequest.copy(notary = notary) - - // Send the request to the counterparty to verify and call their version of prepareOurInputsAndOutputs - // Then they can return their candidate states - val counterpartySession = initiateFlow(counterparty) - counterpartySession.send(remoteRequestWithNotary) - val theirInputStates = subFlow(ReceiveStateAndRefFlow(counterpartySession)) - val theirOutputStates = counterpartySession.receive>().unwrap { - require(theirInputStates.all { it.state.notary == notary }) { - "notary of remote states must be same as for our states" - } - require(theirInputStates.all { it.state.data.amount.token == remoteRequestWithNotary.amount.token }) { - "Inputs not of the correct currency" - } - require(it.all { it.amount.token == remoteRequestWithNotary.amount.token }) { - "Outputs not of the correct currency" - } - require(theirInputStates.map { it.state.data.amount.quantity }.sum() - >= remoteRequestWithNotary.amount.quantity) { - "the provided inputs don't provide sufficient funds" - } - val sum = it.filter { it.owner.let { it is Party && serviceHub.myInfo.isLegalIdentity(it) } }.map { it.amount.quantity }.sum() - require(sum == remoteRequestWithNotary.amount.quantity) { - "the provided outputs don't provide the request quantity" - } - it // return validated response - } - - // having collated the data create the full transaction. - val signedTransaction = buildTradeProposal(ourInputStates, ourOutputStates, theirInputStates, theirOutputStates) - - // pass transaction details to the counterparty to revalidate and confirm with a signature - // Allow counterparty to access our data to resolve the transaction. - subFlow(SendTransactionFlow(counterpartySession, signedTransaction)) - val allPartySignedTx = counterpartySession.receive().unwrap { - val withNewSignature = signedTransaction + it - // check all signatures are present except the notary - withNewSignature.verifySignaturesExcept(withNewSignature.tx.notary!!.owningKey) - - // This verifies that the transaction is contract-valid, even though it is missing signatures. - // In a full solution there would be states tracking the trade request which - // would be included in the transaction and enforce the amounts and tradeId - withNewSignature.tx.toLedgerTransaction(serviceHub).verify() - - withNewSignature // return the almost complete transaction - } - - // Initiate the standard protocol to notarise and distribute to the involved parties. - subFlow(FinalityFlow(allPartySignedTx, counterpartySession)) - - return allPartySignedTx.id - } - - // DOCSTART 3 - private fun buildTradeProposal(ourInputStates: List>, - ourOutputState: List, - theirInputStates: List>, - theirOutputState: List): SignedTransaction { - // This is the correct way to create a TransactionBuilder, - // do not construct directly. - // We also set the notary to match the input notary - val builder = TransactionBuilder(ourInputStates.first().state.notary) - - // Add the move commands and key to indicate all the respective owners and need to sign - val ourSigners = ourInputStates.map { it.state.data.owner.owningKey }.toSet() - val theirSigners = theirInputStates.map { it.state.data.owner.owningKey }.toSet() - builder.addCommand(Cash.Commands.Move(), (ourSigners + theirSigners).toList()) - - // Build and add the inputs and outputs - builder.withItems(*ourInputStates.toTypedArray()) - builder.withItems(*theirInputStates.toTypedArray()) - builder.withItems(*ourOutputState.map { StateAndContract(it, Cash.PROGRAM_ID) }.toTypedArray()) - builder.withItems(*theirOutputState.map { StateAndContract(it, Cash.PROGRAM_ID) }.toTypedArray()) - - // We have already validated their response and trust our own data - // so we can sign. Note the returned SignedTransaction is still not fully signed - // and would not pass full verification yet. - return serviceHub.signInitialTransaction(builder, ourSigners.single()) - } - // DOCEND 3 -} - -@InitiatedBy(ForeignExchangeFlow::class) -class ForeignExchangeRemoteFlow(private val source: FlowSession) : FlowLogic() { - @Suspendable - override fun call() { - // Initial receive from remote party - val request = source.receive().unwrap { - // We would need to check that this is a known trade ID here! - // Also that the amounts and source are correct with the trade details. - // In a production system there would be other Corda contracts tracking - // the lifecycle of the Fx trades which would be included in the transaction - - // Check request is for us - require(serviceHub.myInfo.isLegalIdentity(it.owner)) { - "Request does not include the correct counterparty" - } - require(source.counterparty == it.counterparty) { - "Request does not include the correct counterparty" - } - it // return validated request - } - - // Gather our inputs. We would normally use VaultService.generateSpend - // to carry out the build in a single step. To be more explicit - // we will use query manually in the helper function below. - // Putting this into a non-suspendable function also prevent issues when - // the flow is suspended. - val (ourInputState, ourOutputState) = prepareOurInputsAndOutputs(serviceHub, runId.uuid, request) - - // Send back our proposed states and await the full transaction to verify - val ourKey = serviceHub.keyManagementService.filterMyKeys(ourInputState.flatMap { it.state.data.participants }.map { it.owningKey }).single() - // SendStateAndRefFlow allows counterparty to access our transaction data to resolve the transaction. - subFlow(SendStateAndRefFlow(source, ourInputState)) - source.send(ourOutputState) - val proposedTrade = subFlow(ReceiveTransactionFlow(source, checkSufficientSignatures = false)).let { - val wtx = it.tx - // check all signatures are present except our own and the notary - it.verifySignaturesExcept(ourKey, wtx.notary!!.owningKey) - it // return the SignedTransaction - } - - // assuming we have completed state and business level validation we can sign the trade - val ourSignature = serviceHub.createSignature(proposedTrade, ourKey) - - // send the other side our signature. - source.send(ourSignature) - - // and then finally stored the finalised transaction into our vault - subFlow(ReceiveFinalityFlow(source)) - } -} diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/LaunchSpaceshipFlow.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/LaunchSpaceshipFlow.kt deleted file mode 100644 index c5b7f3a637..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/LaunchSpaceshipFlow.kt +++ /dev/null @@ -1,101 +0,0 @@ -@file:Suppress("DEPRECATION", "MemberVisibilityCanBePrivate", "unused") - -package net.corda.docs.kotlin - -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.InitiatingFlow -import net.corda.core.identity.Party -import net.corda.core.utilities.unwrap - -// DOCSTART LaunchSpaceshipFlow -@InitiatingFlow -class LaunchSpaceshipFlow : FlowLogic() { - @Suspendable - override fun call() { - val shouldLaunchSpaceship = receive(getPresident()).unwrap { it } - if (shouldLaunchSpaceship) { - launchSpaceship() - } - } - - fun launchSpaceship() { - } - - fun getPresident(): Party { - TODO() - } -} - -@InitiatedBy(LaunchSpaceshipFlow::class) -@InitiatingFlow -class PresidentSpaceshipFlow(val launcher: Party) : FlowLogic() { - @Suspendable - override fun call() { - val needCoffee = true - send(getSecretary(), needCoffee) - val shouldLaunchSpaceship = false - send(launcher, shouldLaunchSpaceship) - } - - fun getSecretary(): Party { - TODO() - } -} - -@InitiatedBy(PresidentSpaceshipFlow::class) -class SecretaryFlow(val president: Party) : FlowLogic() { - @Suspendable - override fun call() { - // ignore - } -} -// DOCEND LaunchSpaceshipFlow - -// DOCSTART LaunchSpaceshipFlowCorrect -@InitiatingFlow -class LaunchSpaceshipFlowCorrect : FlowLogic() { - @Suspendable - override fun call() { - val presidentSession = initiateFlow(getPresident()) - val shouldLaunchSpaceship = presidentSession.receive().unwrap { it } - if (shouldLaunchSpaceship) { - launchSpaceship() - } - } - - fun launchSpaceship() { - } - - fun getPresident(): Party { - TODO() - } -} - -@InitiatedBy(LaunchSpaceshipFlowCorrect::class) -@InitiatingFlow -class PresidentSpaceshipFlowCorrect(val launcherSession: FlowSession) : FlowLogic() { - @Suspendable - override fun call() { - val needCoffee = true - val secretarySession = initiateFlow(getSecretary()) - secretarySession.send(needCoffee) - val shouldLaunchSpaceship = false - launcherSession.send(shouldLaunchSpaceship) - } - - fun getSecretary(): Party { - TODO() - } -} - -@InitiatedBy(PresidentSpaceshipFlowCorrect::class) -class SecretaryFlowCorrect(val presidentSession: FlowSession) : FlowLogic() { - @Suspendable - override fun call() { - // ignore - } -} -// DOCEND LaunchSpaceshipFlowCorrect diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt deleted file mode 100644 index 1a22076d9c..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt +++ /dev/null @@ -1,33 +0,0 @@ -package net.corda.docs.kotlin - -// DOCSTART 1 -import net.corda.core.identity.CordaX500Name -import net.corda.testing.node.MockNetwork -import net.corda.testing.node.MockNetworkParameters -import net.corda.testing.node.StartedMockNode -import net.corda.testing.node.TestCordapp.Companion.findCordapp -import org.junit.After -import org.junit.Before - -class MockNetworkTestsTutorial { - - private val mockNet = MockNetwork(MockNetworkParameters(listOf(findCordapp("com.mycordapp.package")))) - - @After - fun cleanUp() { - mockNet.stopNodes() - } -// DOCEND 1 - -// DOCSTART 2 - private lateinit var nodeA: StartedMockNode - private lateinit var nodeB: StartedMockNode - - @Before - fun setUp() { - nodeA = mockNet.createNode() - // We can optionally give the node a name. - nodeB = mockNet.createNode(CordaX500Name("Bank B", "London", "GB")) - } -// DOCEND 2 -} diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/contract/TutorialContract.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/contract/TutorialContract.kt deleted file mode 100644 index db26abf399..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/contract/TutorialContract.kt +++ /dev/null @@ -1,136 +0,0 @@ -package net.corda.docs.kotlin.tutorial.contract - -import net.corda.core.contracts.* -import net.corda.core.crypto.NullKeys -import net.corda.core.identity.AbstractParty -import net.corda.core.identity.AnonymousParty -import net.corda.core.identity.Party -import net.corda.core.node.ServiceHub -import net.corda.core.transactions.LedgerTransaction -import net.corda.core.transactions.TransactionBuilder -import net.corda.finance.contracts.utils.sumCashBy -import net.corda.finance.workflows.asset.CashUtils -import net.corda.testing.core.singleIdentityAndCert -import java.time.Instant -import java.util.* - -class CommercialPaper : Contract { - // DOCSTART 8 - companion object { - const val CP_PROGRAM_ID: ContractClassName = "net.corda.finance.contracts.CommercialPaper" - } - // DOCEND 8 - - // DOCSTART 3 - override fun verify(tx: LedgerTransaction) { - // Group by everything except owner: any modification to the CP at all is considered changing it fundamentally. - val groups = tx.groupStates(State::withoutOwner) - - // There are two possible things that can be done with this CP. The first is trading it. The second is redeeming - // it for cash on or after the maturity date. - val command = tx.commands.requireSingleCommand() - // DOCEND 3 - - // DOCSTART 4 - val timeWindow: TimeWindow? = tx.timeWindow - - for ((inputs, outputs, _) in groups) { - when (command.value) { - is Commands.Move -> { - val input = inputs.single() - requireThat { - "the transaction is signed by the owner of the CP" using (input.owner.owningKey in command.signers) - "the state is propagated" using (outputs.size == 1) - // Don't need to check anything else, as if outputs.size == 1 then the output is equal to - // the input ignoring the owner field due to the grouping. - } - } - - is Commands.Redeem -> { - // Redemption of the paper requires movement of on-ledger cash. - val input = inputs.single() - val received = tx.outputs.map { it.data }.sumCashBy(input.owner) - val time = timeWindow?.fromTime ?: throw IllegalArgumentException("Redemptions must be timestamped") - requireThat { - "the paper must have matured" using (time >= input.maturityDate) - "the received amount equals the face value" using (received == input.faceValue) - "the paper must be destroyed" using outputs.isEmpty() - "the transaction is signed by the owner of the CP" using (input.owner.owningKey in command.signers) - } - } - - is Commands.Issue -> { - val output = outputs.single() - val time = timeWindow?.untilTime ?: throw IllegalArgumentException("Issuances must be timestamped") - requireThat { - // Don't allow people to issue commercial paper under other entities identities. - "output states are issued by a command signer" using (output.issuance.party.owningKey in command.signers) - "output values sum to more than the inputs" using (output.faceValue.quantity > 0) - "the maturity date is not in the past" using (time < output.maturityDate) - // Don't allow an existing CP state to be replaced by this issuance. - "can't reissue an existing state" using inputs.isEmpty() - } - } - - else -> throw IllegalArgumentException("Unrecognised command") - } - } - // DOCEND 4 - } - - // DOCSTART 2 - interface Commands : CommandData { - class Move : TypeOnlyCommandData(), Commands - class Redeem : TypeOnlyCommandData(), Commands - class Issue : TypeOnlyCommandData(), Commands - } - // DOCEND 2 - - // DOCSTART 5 - fun generateIssue(issuance: PartyAndReference, faceValue: Amount>, maturityDate: Instant, - notary: Party): TransactionBuilder { - val state = State(issuance, issuance.party, faceValue, maturityDate) - val stateAndContract = StateAndContract(state, CP_PROGRAM_ID) - return TransactionBuilder(notary = notary).withItems(stateAndContract, Command(Commands.Issue(), issuance.party.owningKey)) - } - // DOCEND 5 - - // DOCSTART 6 - fun generateMove(tx: TransactionBuilder, paper: StateAndRef, newOwner: AbstractParty) { - tx.addInputState(paper) - val outputState = paper.state.data.withNewOwner(newOwner).ownableState - tx.addOutputState(outputState, CP_PROGRAM_ID) - tx.addCommand(Command(Commands.Move(), paper.state.data.owner.owningKey)) - } - // DOCEND 6 - - // DOCSTART 7 - @Throws(InsufficientBalanceException::class) - fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef, services: ServiceHub) { - // Add the cash movement using the states in our vault. - CashUtils.generateSpend( - services = services, - tx = tx, - amount = paper.state.data.faceValue.withoutIssuer(), - ourIdentity = services.myInfo.singleIdentityAndCert(), - to = paper.state.data.owner - ) - tx.addInputState(paper) - tx.addCommand(Command(Commands.Redeem(), paper.state.data.owner.owningKey)) - } - // DOCEND 7 -} - -// DOCSTART 1 -data class State( - val issuance: PartyAndReference, - override val owner: AbstractParty, - val faceValue: Amount>, - val maturityDate: Instant -) : OwnableState { - override val participants = listOf(owner) - - fun withoutOwner() = copy(owner = AnonymousParty(NullKeys.NullPublicKey)) - override fun withNewOwner(newOwner: AbstractParty) = CommandAndState(CommercialPaper.Commands.Move(), copy(owner = newOwner)) -} -// DOCEND 1 \ No newline at end of file diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowAsyncOperation.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowAsyncOperation.kt deleted file mode 100644 index c4b2d00716..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowAsyncOperation.kt +++ /dev/null @@ -1,31 +0,0 @@ -package net.corda.docs.kotlin.tutorial.flowstatemachines - -import co.paralleluniverse.fibers.Suspendable -import net.corda.core.flows.FlowExternalAsyncOperation -import net.corda.core.flows.FlowLogic -import net.corda.core.flows.StartableByRPC -import java.util.concurrent.CompletableFuture - -class SummingOperation(val a: Int, val b: Int) : FlowExternalAsyncOperation { - override fun execute(deduplicationId: String): CompletableFuture { - return CompletableFuture.completedFuture(a + b) - } -} - -// DOCSTART SummingOperationThrowing -class SummingOperationThrowing(val a: Int, val b: Int) : FlowExternalAsyncOperation { - override fun execute(deduplicationId: String): CompletableFuture { - throw IllegalStateException("You shouldn't be calling me") - } -} -// DOCEND SummingOperationThrowing - -@StartableByRPC -class ExampleSummingFlow : FlowLogic() { - @Suspendable - override fun call(): Int { - val answer = await(SummingOperation(1, 2)) - return answer // hopefully 3 - } -} - diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowStateMachines.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowStateMachines.kt deleted file mode 100644 index 23c0e12dc9..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowStateMachines.kt +++ /dev/null @@ -1,66 +0,0 @@ -@file:Suppress("unused", "MemberVisibilityCanBePrivate") - -package net.corda.docs.kotlin.tutorial.flowstatemachines - -import co.paralleluniverse.fibers.Suspendable -import net.corda.core.contracts.Amount -import net.corda.core.contracts.OwnableState -import net.corda.core.contracts.StateAndRef -import net.corda.core.flows.FlowException -import net.corda.core.flows.FlowLogic -import net.corda.core.flows.FlowSession -import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate -import net.corda.core.serialization.CordaSerializable -import net.corda.core.transactions.SignedTransaction -import net.corda.core.utilities.ProgressTracker -import net.corda.finance.flows.TwoPartyTradeFlow -import java.util.* - -// DOCSTART 1 -object TwoPartyTradeFlow { - class UnacceptablePriceException(givenPrice: Amount) : FlowException("Unacceptable price: $givenPrice") - class AssetMismatchException(val expectedTypeName: String, val typeName: String) : FlowException() { - override fun toString() = "The submitted asset didn't match the expected type: $expectedTypeName vs $typeName" - } - - /** - * This object is serialised to the network and is the first flow message the seller sends to the buyer. - * - * @param payToIdentity anonymous identity of the seller, for payment to be sent to. - */ - @CordaSerializable - data class SellerTradeInfo( - val price: Amount, - val payToIdentity: PartyAndCertificate - ) - - open class Seller(private val otherSideSession: FlowSession, - private val assetToSell: StateAndRef, - private val price: Amount, - private val myParty: PartyAndCertificate, - override val progressTracker: ProgressTracker = TwoPartyTradeFlow.Seller.tracker()) : FlowLogic() { - - companion object { - fun tracker() = ProgressTracker() - } - - @Suspendable - override fun call(): SignedTransaction { - TODO() - } - } - - open class Buyer(private val sellerSession: FlowSession, - private val notary: Party, - private val acceptablePrice: Amount, - private val typeToBuy: Class, - private val anonymous: Boolean) : FlowLogic() { - - @Suspendable - override fun call(): SignedTransaction { - TODO() - } - } -} -// DOCEND 1 \ No newline at end of file diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlow.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlow.kt deleted file mode 100644 index 38e18fc805..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlow.kt +++ /dev/null @@ -1,53 +0,0 @@ -@file:Suppress("MemberVisibilityCanBePrivate") - -package net.corda.docs.kotlin.tutorial.helloworld - -import co.paralleluniverse.fibers.Suspendable -import com.template.TemplateContract -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 - -// Replace Initiator's definition with: -@InitiatingFlow -@StartableByRPC -class IOUFlow(val iouValue: Int, - val otherParty: Party) : FlowLogic() { - - /** The progress tracker provides checkpoints indicating the progress of the flow to observers. */ - override val progressTracker = ProgressTracker() - - /** The flow logic is encapsulated within the call() method. */ - @Suspendable - override fun call() { - // We retrieve the notary identity from the network map. - val notary = serviceHub.networkMapCache.notaryIdentities[0] - - // We create the transaction components. - val outputState = IOUState(iouValue, ourIdentity, otherParty) - 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(command) - - // We sign the transaction. - val signedTx = serviceHub.signInitialTransaction(txBuilder) - - // Creating a session with the other party. - val otherPartySession = initiateFlow(otherParty) - - // We finalise the transaction and then send it to the counterparty. - subFlow(FinalityFlow(signedTx, otherPartySession)) - } -} -// DOCEND 01 diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlowResponder.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlowResponder.kt deleted file mode 100644 index 7cb59fb180..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlowResponder.kt +++ /dev/null @@ -1,20 +0,0 @@ -@file:Suppress("unused") - -package net.corda.docs.kotlin.tutorial.helloworld - -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.ReceiveFinalityFlow - -// DOCSTART 01 -// Replace Responder's definition with: -@InitiatedBy(IOUFlow::class) -class IOUFlowResponder(private val otherPartySession: FlowSession) : FlowLogic() { - @Suspendable - override fun call() { - subFlow(ReceiveFinalityFlow(otherPartySession)) - } -} -// DOCEND 01 diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt deleted file mode 100644 index 27a3a52e18..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt +++ /dev/null @@ -1,17 +0,0 @@ -@file:Suppress("MemberVisibilityCanBePrivate") - -package net.corda.docs.kotlin.tutorial.helloworld - -import net.corda.core.contracts.ContractState - -// DOCSTART 01 -// Add this import: -import net.corda.core.identity.Party - -// Replace TemplateState's definition with: -class IOUState(val value: Int, - val lender: Party, - val borrower: Party) : ContractState { - override val participants get() = listOf(lender, borrower) -} -// DOCEND 01 diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/tearoffs/TutorialTearOffs.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/tearoffs/TutorialTearOffs.kt deleted file mode 100644 index 82ee763780..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/tearoffs/TutorialTearOffs.kt +++ /dev/null @@ -1,47 +0,0 @@ -@file:Suppress("UNUSED_VARIABLE") - -package net.corda.docs.kotlin.tutorial.tearoffs - -import net.corda.core.contracts.Command -import net.corda.core.contracts.StateRef -import net.corda.core.contracts.TimeWindow -import net.corda.core.crypto.MerkleTreeException -import net.corda.core.identity.AbstractParty -import net.corda.core.transactions.FilteredTransaction -import net.corda.core.transactions.FilteredTransactionVerificationException -import net.corda.core.transactions.SignedTransaction -import net.corda.finance.contracts.Fix -import java.util.function.Predicate - -fun main(args: Array) { - // Type alias to make the example coherent. - val oracle = Any() as AbstractParty - val stx = Any() as SignedTransaction - - // DOCSTART 1 - val filtering = Predicate { - when (it) { - is Command<*> -> oracle.owningKey in it.signers && it.value is Fix - else -> false - } - } - // DOCEND 1 - - // DOCSTART 2 - val ftx: FilteredTransaction = stx.buildFilteredTransaction(filtering) - // DOCEND 2 - - // DOCSTART 3 - // Direct access to included commands, inputs, outputs, attachments etc. - val cmds: List> = ftx.commands - val ins: List = ftx.inputs - val timeWindow: TimeWindow? = ftx.timeWindow - // ... - // DOCEND 3 - - try { - ftx.verify() - } catch (e: FilteredTransactionVerificationException) { - throw MerkleTreeException("Rate Fix Oracle: Couldn't verify partial Merkle tree.") - } -} diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUContract.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUContract.kt deleted file mode 100644 index 578039feb2..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUContract.kt +++ /dev/null @@ -1,39 +0,0 @@ -package net.corda.docs.kotlin.tutorial.twoparty - -import net.corda.core.contracts.CommandData -import net.corda.core.contracts.Contract -import net.corda.core.transactions.LedgerTransaction - -// DOCSTART 01 -// Add this import: -import net.corda.core.contracts.* - -class IOUContract : Contract { - companion object { - const val ID = "com.template.IOUContract" - } - - // Our Create command. - class Create : CommandData - - override fun verify(tx: LedgerTransaction) { - val command = tx.commands.requireSingleCommand() - - requireThat { - // Constraints on the shape of the transaction. - "No inputs should be consumed when issuing an IOU." using (tx.inputs.isEmpty()) - "There should be one output state of type IOUState." using (tx.outputs.size == 1) - - // IOU-specific constraints. - 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(expectedSigners)) - } - } -} -// DOCEND 01 \ No newline at end of file diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt deleted file mode 100644 index 17c806d7d3..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt +++ /dev/null @@ -1,58 +0,0 @@ -@file:Suppress("MemberVisibilityCanBePrivate") - -package net.corda.docs.kotlin.tutorial.twoparty - -// DOCSTART 01 -import co.paralleluniverse.fibers.Suspendable -import net.corda.core.contracts.Command -import net.corda.core.flows.CollectSignaturesFlow -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.identity.Party -import net.corda.core.transactions.TransactionBuilder -import net.corda.core.utilities.ProgressTracker -// DOCEND 01 - -@InitiatingFlow -@StartableByRPC -class IOUFlow(val iouValue: Int, - val otherParty: Party) : FlowLogic() { - - /** The progress tracker provides checkpoints indicating the progress of the flow to observers. */ - override val progressTracker = ProgressTracker() - - /** 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] - - // We create the transaction components. - val outputState = IOUState(iouValue, ourIdentity, otherParty) - val command = Command(IOUContract.Create(), listOf(ourIdentity.owningKey, otherParty.owningKey)) - - // 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) - - // Signing the transaction. - val signedTx = serviceHub.signInitialTransaction(txBuilder) - - // Creating a session with the other party. - val otherPartySession = initiateFlow(otherParty) - - // Obtaining the counterparty's signature. - val fullySignedTx = subFlow(CollectSignaturesFlow(signedTx, listOf(otherPartySession), CollectSignaturesFlow.tracker())) - - // Finalising the transaction. - subFlow(FinalityFlow(fullySignedTx, otherPartySession)) - // DOCEND 02 - } -} diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt deleted file mode 100644 index f5d0c92315..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt +++ /dev/null @@ -1,32 +0,0 @@ -@file:Suppress("unused") - -package net.corda.docs.kotlin.tutorial.twoparty - -import co.paralleluniverse.fibers.Suspendable -import net.corda.core.flows.* -import net.corda.docs.kotlin.tutorial.helloworld.IOUFlow -import net.corda.docs.kotlin.tutorial.helloworld.IOUState - -// 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() { - // DOCSTART 1 - @Suspendable - override fun call() { - val signTransactionFlow = object : SignTransactionFlow(otherPartySession) { - override fun checkTransaction(stx: SignedTransaction) = requireThat { - val output = stx.tx.outputs.single().data - "This must be an IOU transaction." using (output is IOUState) - val iou = output as IOUState - "The IOU's value can't be too high." using (iou.value < 100) - } - } - val expectedTxId = subFlow(signTransactionFlow).id - subFlow(ReceiveFinalityFlow(otherPartySession, expectedTxId)) - } - // DOCEND 1 -} diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUState.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUState.kt deleted file mode 100644 index b1a631d025..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUState.kt +++ /dev/null @@ -1,10 +0,0 @@ -package net.corda.docs.kotlin.tutorial.twoparty - -import net.corda.core.contracts.ContractState -import net.corda.core.identity.Party - -class IOUState(val value: Int, - val lender: Party, - val borrower: Party) : ContractState { - override val participants get() = listOf(lender, borrower) -} \ No newline at end of file diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorial.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorial.kt deleted file mode 100644 index ba8b081158..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorial.kt +++ /dev/null @@ -1,262 +0,0 @@ -@file:Suppress("unused") - -package net.corda.docs.kotlin.txbuild - -import co.paralleluniverse.fibers.Suspendable -import net.corda.core.contracts.Command -import net.corda.core.contracts.CommandData -import net.corda.core.contracts.Contract -import net.corda.core.contracts.LinearState -import net.corda.core.contracts.StateAndContract -import net.corda.core.contracts.StateAndRef -import net.corda.core.contracts.StateRef -import net.corda.core.contracts.TypeOnlyCommandData -import net.corda.core.contracts.UniqueIdentifier -import net.corda.core.contracts.requireSingleCommand -import net.corda.core.contracts.requireThat -import net.corda.core.crypto.TransactionSignature -import net.corda.core.flows.FinalityFlow -import net.corda.core.flows.FlowLogic -import net.corda.core.flows.FlowSession -import net.corda.core.flows.InitiatedBy -import net.corda.core.flows.InitiatingFlow -import net.corda.core.flows.ReceiveFinalityFlow -import net.corda.core.identity.AbstractParty -import net.corda.core.identity.Party -import net.corda.core.node.services.queryBy -import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria -import net.corda.core.serialization.CordaSerializable -import net.corda.core.transactions.LedgerTransaction -import net.corda.core.transactions.SignedTransaction -import net.corda.core.transactions.TransactionBuilder -import net.corda.core.utilities.seconds -import net.corda.core.utilities.unwrap - -// Minimal state model of a manual approval process -@CordaSerializable -enum class WorkflowState { - NEW, - APPROVED, - REJECTED -} - -const val TRADE_APPROVAL_PROGRAM_ID = "net.corda.docs.kotlin.txbuild.TradeApprovalContract" - -/** - * Minimal contract to encode a simple workflow with one initial state and two possible eventual states. - * It is assumed one party unilaterally submits and the other manually retrieves the deal and completes it. - */ -data class TradeApprovalContract(val blank: Unit? = null) : Contract { - - interface Commands : CommandData { - class Issue : TypeOnlyCommandData(), Commands // Record receipt of deal details - class Completed : TypeOnlyCommandData(), Commands // Record match - } - - /** - * Truly minimal state that just records a tradeId string and the parties involved. - */ - data class State(val tradeId: String, - val source: Party, - val counterparty: Party, - val state: WorkflowState = WorkflowState.NEW, - override val linearId: UniqueIdentifier = UniqueIdentifier(tradeId)) : LinearState { - override val participants: List get() = listOf(source, counterparty) - } - - /** - * The verify method locks down the allowed transactions to contain just a single proposal being - * created/modified and the only modification allowed is to the state field. - */ - override fun verify(tx: LedgerTransaction) { - val command = tx.commands.requireSingleCommand() - requireNotNull(tx.timeWindow) { "must have a time-window" } - when (command.value) { - is Commands.Issue -> { - requireThat { - "Issue of new WorkflowContract must not include any inputs" using (tx.inputs.isEmpty()) - "Issue of new WorkflowContract must be in a unique transaction" using (tx.outputs.size == 1) - } - val issued = tx.outputsOfType().single() - requireThat { - "Issue requires the source Party as signer" using (command.signers.contains(issued.source.owningKey)) - "Initial Issue state must be NEW" using (issued.state == WorkflowState.NEW) - } - } - is Commands.Completed -> { - val stateGroups = tx.groupStates(TradeApprovalContract.State::class.java) { it.linearId } - require(stateGroups.size == 1) { "Must be only a single proposal in transaction" } - for ((inputs, outputs) in stateGroups) { - val before = inputs.single() - val after = outputs.single() - requireThat { - "Only a non-final trade can be modified" using (before.state == WorkflowState.NEW) - "Output must be a final state" using (after.state in setOf(WorkflowState.APPROVED, WorkflowState.REJECTED)) - "Completed command can only change state" using (before == after.copy(state = before.state)) - "Completed command requires the source Party as signer" using (command.signers.contains(before.source.owningKey)) - "Completed command requires the counterparty as signer" using (command.signers.contains(before.counterparty.owningKey)) - } - } - } - else -> throw IllegalArgumentException("Unrecognised Command $command") - } - } -} - -/** - * Simple flow to create a workflow state, sign and notarise it. - * The protocol then sends a copy to the other node. We don't require the other party to sign - * as their approval/rejection is to follow. - */ -@InitiatingFlow -class SubmitTradeApprovalFlow(private val tradeId: String, - private val counterparty: Party, - private val notary: Party) : FlowLogic>() { - @Suspendable - override fun call(): StateAndRef { - // Manufacture an initial state - val tradeProposal = TradeApprovalContract.State(tradeId, ourIdentity, counterparty) - // Create the TransactionBuilder and populate with the new state. - val tx = TransactionBuilder(notary).withItems( - StateAndContract(tradeProposal, TRADE_APPROVAL_PROGRAM_ID), - Command(TradeApprovalContract.Commands.Issue(), listOf(tradeProposal.source.owningKey))) - tx.setTimeWindow(serviceHub.clock.instant(), 60.seconds) - // We can automatically sign as there is no untrusted data. - val signedTx = serviceHub.signInitialTransaction(tx) - // Notarise and distribute. - subFlow(FinalityFlow(signedTx, initiateFlow(counterparty))) - // Return the initial state - return signedTx.tx.outRef(0) - } -} - -@InitiatedBy(SubmitTradeApprovalFlow::class) -class SubmitTradeApprovalResponderFlow(private val otherSide: FlowSession) : FlowLogic() { - @Suspendable - override fun call() { - subFlow(ReceiveFinalityFlow(otherSide)) - } -} - -/** - * Simple flow to complete a proposal submitted by another party and ensure both nodes - * end up with a fully signed copy of the state either as APPROVED, or REJECTED - */ -@InitiatingFlow -class SubmitCompletionFlow(private val ref: StateRef, private val verdict: WorkflowState) : FlowLogic>() { - init { - require(verdict in setOf(WorkflowState.APPROVED, WorkflowState.REJECTED)) { - "Verdict must be a final state" - } - } - - @Suspendable - override fun call(): StateAndRef { - // DOCSTART 1 - val criteria = VaultQueryCriteria(stateRefs = listOf(ref)) - val latestRecord = serviceHub.vaultService.queryBy(criteria).states.single() - // DOCEND 1 - - // Check the protocol hasn't already been run - require(latestRecord.ref == ref) { - "Input trade $ref is not latest version $latestRecord" - } - // Require that the state is still modifiable - require(latestRecord.state.data.state == WorkflowState.NEW) { - "Input trade not modifiable ${latestRecord.state.data.state}" - } - // Check we are the correct Party to run the protocol. Note they will counter check this too. - require(serviceHub.myInfo.isLegalIdentity(latestRecord.state.data.counterparty)) { - "The counterparty must give the verdict" - } - - // DOCSTART 2 - // Modify the state field for new output. We use copy, to ensure no other modifications. - // It is especially important for a LinearState that the linearId is copied across, - // not accidentally assigned a new random id. - val newState = latestRecord.state.data.copy(state = verdict) - - // We have to use the original notary for the new transaction - val notary = latestRecord.state.notary - - // Get and populate the new TransactionBuilder - // To destroy the old proposal state and replace with the new completion state. - // Also add the Completed command with keys of all parties to signal the Tx purpose - // to the Contract verify method. - val tx = TransactionBuilder(notary). - withItems( - latestRecord, - StateAndContract(newState, TRADE_APPROVAL_PROGRAM_ID), - Command(TradeApprovalContract.Commands.Completed(), - listOf(ourIdentity.owningKey, latestRecord.state.data.source.owningKey))) - tx.setTimeWindow(serviceHub.clock.instant(), 60.seconds) - // We can sign this transaction immediately as we have already checked all the fields and the decision - // is ultimately a manual one from the caller. - // As a SignedTransaction we can pass the data around certain that it cannot be modified, - // although we do require further signatures to complete the process. - val selfSignedTx = serviceHub.signInitialTransaction(tx) - //DOCEND 2 - // Send the signed transaction to the originator and await their signature to confirm - val sourceSession = initiateFlow(newState.source) - val allPartySignedTx = sourceSession.sendAndReceive(selfSignedTx).unwrap { - // Add their signature to our unmodified transaction. To check they signed the same tx. - val agreedTx = selfSignedTx + it - // Receive back their signature and confirm that it is for an unmodified transaction - // Also that the only missing signature is from teh Notary - agreedTx.verifySignaturesExcept(notary.owningKey) - // Recheck the data of the transaction. Note we run toLedgerTransaction on the WireTransaction - // as we do not have all the signature. - agreedTx.tx.toLedgerTransaction(serviceHub).verify() - // return the SignedTransaction to notarise - agreedTx - } - // DOCSTART 4 - // Notarise and distribute the completed transaction. - subFlow(FinalityFlow(allPartySignedTx, sourceSession)) - // DOCEND 4 - // Return back the details of the completed state/transaction. - return allPartySignedTx.tx.outRef(0) - } -} - -/** - * Simple flow to receive the final decision on a proposal. - * Then after checking to sign it and eventually store the fully notarised - * transaction to the ledger. - */ -@InitiatedBy(SubmitCompletionFlow::class) -class RecordCompletionFlow(private val sourceSession: FlowSession) : FlowLogic() { - @Suspendable - override fun call() { - // DOCSTART 3 - // First we receive the verdict transaction signed by their single key - val completeTx = sourceSession.receive().unwrap { - // Check the transaction is signed apart from our own key and the notary - it.verifySignaturesExcept(ourIdentity.owningKey, it.tx.notary!!.owningKey) - // Check the transaction data is correctly formed - val ltx = it.toLedgerTransaction(serviceHub, false) - ltx.verify() - // Confirm that this is the expected type of transaction - require(ltx.commands.single().value is TradeApprovalContract.Commands.Completed) { - "Transaction must represent a workflow completion" - } - // Check the context dependent parts of the transaction as the - // Contract verify method must not use serviceHub queries. - val state = ltx.outRef(0) - require(serviceHub.myInfo.isLegalIdentity(state.state.data.source)) { - "Proposal not one of our original proposals" - } - require(state.state.data.counterparty == sourceSession.counterparty) { - "Proposal not for sent from correct source" - } - it - } - // DOCEND 3 - // Having verified the SignedTransaction passed to us we can sign it too - val ourSignature = serviceHub.createSignature(completeTx) - // Send our signature to the other party. - sourceSession.send(ourSignature) - - subFlow(ReceiveFinalityFlow(sourceSession)) - } -} diff --git a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/vault/CustomVaultQuery.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/vault/CustomVaultQuery.kt deleted file mode 100644 index a18fb2fbd5..0000000000 --- a/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/vault/CustomVaultQuery.kt +++ /dev/null @@ -1,149 +0,0 @@ -@file:Suppress("unused", "MemberVisibilityCanBePrivate") - -package net.corda.docs.kotlin.vault - -import co.paralleluniverse.fibers.Suspendable -import net.corda.core.contracts.Amount -import net.corda.core.flows.* -import net.corda.core.identity.Party -import net.corda.core.node.AppServiceHub -import net.corda.core.node.services.CordaService -import net.corda.core.serialization.CordaSerializable -import net.corda.core.serialization.SingletonSerializeAsToken -import net.corda.core.transactions.SignedTransaction -import net.corda.core.utilities.* -import net.corda.finance.flows.AbstractCashFlow -import net.corda.finance.flows.CashException -import net.corda.finance.flows.CashIssueFlow -import net.corda.finance.flows.CashPaymentFlow -import java.util.* - -// DOCSTART CustomVaultQuery -object CustomVaultQuery { - - @CordaService - class Service(val services: AppServiceHub) : SingletonSerializeAsToken() { - private companion object { - private val log = contextLogger() - } - - fun rebalanceCurrencyReserves(): List> { - val nativeQuery = """ - select - cashschema.ccy_code, - sum(cashschema.pennies) - from - vault_states vaultschema - join - contract_cash_states cashschema - where - vaultschema.output_index=cashschema.output_index - and vaultschema.transaction_id=cashschema.transaction_id - and vaultschema.state_status=0 - group by - cashschema.ccy_code - order by - sum(cashschema.pennies) desc - """ - log.info("SQL to execute: $nativeQuery") - val session = services.jdbcSession() - return session.prepareStatement(nativeQuery).use { prepStatement -> - prepStatement.executeQuery().use { rs -> - val topUpLimits: MutableList> = mutableListOf() - while (rs.next()) { - val currencyStr = rs.getString(1) - val amount = rs.getLong(2) - log.info("$currencyStr : $amount") - topUpLimits.add(Amount(amount, Currency.getInstance(currencyStr))) - } - topUpLimits - } - } - } - } -} -// DOCEND CustomVaultQuery - -/** - * This is a slightly modified version of the IssuerFlow, which uses a 3rd party custom query to - * retrieve a list of currencies and top up amounts to be used in the issuance. - */ -object TopupIssuerFlow { - @CordaSerializable - data class TopupRequest(val issueToParty: Party, - val issuerPartyRef: OpaqueBytes, - val notaryParty: Party) - - @InitiatingFlow - @StartableByRPC - class TopupIssuanceRequester(val issueToParty: Party, - val issueToPartyRef: OpaqueBytes, - val issuerBankParty: Party, - val notaryParty: Party) : FlowLogic>() { - @Suspendable - @Throws(CashException::class) - override fun call(): List { - val topupRequest = TopupRequest(issueToParty, issueToPartyRef, notaryParty) - return initiateFlow(issuerBankParty).sendAndReceive>(topupRequest).unwrap { it } - } - } - - @InitiatedBy(TopupIssuanceRequester::class) - class TopupIssuer(val otherPartySession: FlowSession) : FlowLogic>() { - companion object { - object AWAITING_REQUEST : ProgressTracker.Step("Awaiting issuance request") - object ISSUING : ProgressTracker.Step("Issuing asset") - object TRANSFERRING : ProgressTracker.Step("Transferring asset to issuance requester") - object SENDING_TOP_UP_ISSUE_REQUEST : ProgressTracker.Step("Requesting asset issue top up") - - fun tracker() = ProgressTracker(AWAITING_REQUEST, ISSUING, TRANSFERRING, SENDING_TOP_UP_ISSUE_REQUEST) - } - - override val progressTracker: ProgressTracker = tracker() - - // DOCSTART TopupIssuer - @Suspendable - @Throws(CashException::class) - override fun call(): List { - progressTracker.currentStep = AWAITING_REQUEST - val topupRequest = otherPartySession.receive().unwrap { - it - } - - val customVaultQueryService = serviceHub.cordaService(CustomVaultQuery.Service::class.java) - val reserveLimits = customVaultQueryService.rebalanceCurrencyReserves() - - val txns: List = reserveLimits.map { amount -> - // request asset issue - logger.info("Requesting currency issue $amount") - val txn = issueCashTo(amount, topupRequest.issueToParty, topupRequest.issuerPartyRef, topupRequest.notaryParty) - progressTracker.currentStep = SENDING_TOP_UP_ISSUE_REQUEST - return@map txn.stx - } - - otherPartySession.send(txns) - return txns - } - // DOCEND TopupIssuer - - @Suspendable - private fun issueCashTo(amount: Amount, - issueTo: Party, - issuerPartyRef: OpaqueBytes, - notaryParty: Party): AbstractCashFlow.Result { - // invoke Cash subflow to issue Asset - progressTracker.currentStep = ISSUING - val issueCashFlow = CashIssueFlow(amount, issuerPartyRef, notaryParty) - val issueTx = subFlow(issueCashFlow) - // NOTE: issueCashFlow performs a Broadcast (which stores a local copy of the txn to the ledger) - // short-circuit when issuing to self - if (serviceHub.myInfo.isLegalIdentity(issueTo)) - return issueTx - // now invoke Cash subflow to Move issued assetType to issue requester - progressTracker.currentStep = TRANSFERRING - val moveCashFlow = CashPaymentFlow(amount, issueTo, anonymous = false) - // NOTE: CashFlow PayCash calls FinalityFlow which performs a Broadcast (which stores a local copy of the txn to the ledger) - return subFlow(moveCashFlow) - } - } -} diff --git a/docs/example-code/src/main/resources/example-node-with-networkservices.conf b/docs/example-code/src/main/resources/example-node-with-networkservices.conf deleted file mode 100644 index cf91614e2c..0000000000 --- a/docs/example-code/src/main/resources/example-node-with-networkservices.conf +++ /dev/null @@ -1,25 +0,0 @@ -myLegalName = "O=Bank A,L=London,C=GB" -keyStorePassword = "cordacadevpass" -trustStorePassword = "trustpass" -crlCheckSoftFail = true -dataSourceProperties { - dataSourceClassName = org.h2.jdbcx.JdbcDataSource - dataSource.url = "jdbc:h2:file:"${baseDirectory}"/persistence" - dataSource.user = sa - dataSource.password = "" -} -p2pAddress = "my-corda-node:10002" -rpcSettings { - useSsl = false - standAloneBroker = false - address = "my-corda-node:10003" - adminAddress = "my-corda-node:10004" -} -rpcUsers = [ - { username=user1, password=letmein, permissions=[ StartFlow.net.corda.protocols.CashProtocol ] } -] -devMode = false -networkServices { - doormanURL = "https://registration.example.com" - networkMapURL = "https://cz.example.com" -} diff --git a/docs/example-code/src/main/resources/example-node.conf b/docs/example-code/src/main/resources/example-node.conf deleted file mode 100644 index 39083999a7..0000000000 --- a/docs/example-code/src/main/resources/example-node.conf +++ /dev/null @@ -1,21 +0,0 @@ -myLegalName = "O=Bank A,L=London,C=GB" -keyStorePassword = "cordacadevpass" -trustStorePassword = "trustpass" -crlCheckSoftFail = true -dataSourceProperties { - dataSourceClassName = org.h2.jdbcx.JdbcDataSource - dataSource.url = "jdbc:h2:file:"${baseDirectory}"/persistence" - dataSource.user = sa - dataSource.password = "" -} -p2pAddress = "my-corda-node:10002" -rpcSettings { - useSsl = false - standAloneBroker = false - address = "my-corda-node:10003" - adminAddress = "my-corda-node:10004" -} -rpcUsers = [ - { username=user1, password=letmein, permissions=[ StartFlow.net.corda.protocols.CashProtocol ] } -] -devMode = true diff --git a/docs/example-code/src/main/resources/example-verifier.conf b/docs/example-code/src/main/resources/example-verifier.conf deleted file mode 100644 index 456f5cc613..0000000000 --- a/docs/example-code/src/main/resources/example-verifier.conf +++ /dev/null @@ -1,3 +0,0 @@ -nodeHostAndPort = "my-corda-node:10002" -keyStorePassword = "cordacadevpass" -trustStorePassword = "trustpass" diff --git a/docs/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java b/docs/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java deleted file mode 100644 index ae35a39668..0000000000 --- a/docs/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java +++ /dev/null @@ -1,334 +0,0 @@ -package net.corda.docs.java.tutorial.testdsl; - -import kotlin.Unit; -import net.corda.core.contracts.PartyAndReference; -import net.corda.core.contracts.TransactionVerificationException; -import net.corda.core.identity.CordaX500Name; -import net.corda.finance.contracts.ICommercialPaperState; -import net.corda.finance.contracts.JavaCommercialPaper; -import net.corda.finance.contracts.asset.Cash; -import net.corda.testing.core.TestIdentity; -import net.corda.testing.node.MockServices; -import org.junit.Before; -import org.junit.Test; - -import java.time.Instant; -import java.time.temporal.ChronoUnit; - -import static java.util.Collections.singletonList; -import static net.corda.finance.Currencies.DOLLARS; -import static net.corda.finance.Currencies.issuedBy; -import static net.corda.finance.contracts.JavaCommercialPaper.JCP_PROGRAM_ID; -import static net.corda.testing.core.TestConstants.ALICE_NAME; -import static net.corda.testing.core.TestConstants.BOB_NAME; -import static net.corda.testing.node.MockServicesKt.makeTestIdentityService; -import static net.corda.testing.node.NodeTestUtils.ledger; -import static net.corda.testing.node.NodeTestUtils.transaction; - -public class TutorialTestDSL { - private static final TestIdentity alice = new TestIdentity(ALICE_NAME, 70L); - // DOCSTART 14 - private static final TestIdentity bigCorp = new TestIdentity(new CordaX500Name("BigCorp", "New York", "GB")); - // DOCEND 14 - private static final TestIdentity bob = new TestIdentity(BOB_NAME, 80L); - private static final TestIdentity megaCorp = new TestIdentity(new CordaX500Name("MegaCorp", "London", "GB")); - private final byte[] defaultRef = {123}; - private static final Instant TEST_TX_TIME = Instant.parse("2015-04-17T12:00:00.00Z"); - private MockServices ledgerServices; - - @Before - public void setUp() { - // DOCSTART 11 - ledgerServices = new MockServices( - // A list of packages to scan for cordapps - singletonList("net.corda.finance.contracts"), - // The identity represented by this set of mock services. Defaults to a test identity. - // You can also use the alternative parameter initialIdentityName which accepts a - // [CordaX500Name] - megaCorp, - // An implementation of [IdentityService], which contains a list of all identities known - // to the node. Use [makeTestIdentityService] which returns an implementation of - // [InMemoryIdentityService] with the given identities - makeTestIdentityService(megaCorp.getIdentity()) - ); - // DOCEND 11 - } - - @SuppressWarnings("unused") - // DOCSTART 12 - private final MockServices simpleLedgerServices = new MockServices( - // This is the identity of the node - megaCorp, - // Other identities the test node knows about - bigCorp, - alice - ); - // DOCEND 12 - - // DOCSTART 1 - private ICommercialPaperState getPaper() { - return new JavaCommercialPaper.State( - megaCorp.ref(defaultRef), - megaCorp.getParty(), - issuedBy(DOLLARS(1000), megaCorp.ref(defaultRef)), - TEST_TX_TIME.plus(7, ChronoUnit.DAYS) - ); - } - // DOCEND 1 - - // DOCSTART 2 - // This example test will fail with this exception. - @Test(expected = IllegalStateException.class) - public void simpleCP() { - ICommercialPaperState inState = getPaper(); - ledger(ledgerServices, l -> { - l.transaction(tx -> { - tx.attachments(JCP_PROGRAM_ID); - tx.input(JCP_PROGRAM_ID, inState); - return tx.verifies(); - }); - return Unit.INSTANCE; - }); - } - // DOCEND 2 - - // DOCSTART 3 - // This example test will fail with this exception. - @Test(expected = TransactionVerificationException.ContractRejection.class) - public void simpleCPMove() { - ICommercialPaperState inState = getPaper(); - ledger(ledgerServices, l -> { - l.transaction(tx -> { - tx.input(JCP_PROGRAM_ID, inState); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Move()); - tx.attachments(JCP_PROGRAM_ID); - return tx.verifies(); - }); - return Unit.INSTANCE; - }); - } - // DOCEND 3 - - // DOCSTART 4 - @Test - public void simpleCPMoveFails() { - ICommercialPaperState inState = getPaper(); - ledger(ledgerServices, l -> { - l.transaction(tx -> { - tx.input(JCP_PROGRAM_ID, inState); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Move()); - tx.attachments(JCP_PROGRAM_ID); - return tx.failsWith("the state is propagated"); - }); - return Unit.INSTANCE; - }); - } - // DOCEND 4 - - // DOCSTART 5 - @Test - public void simpleCPMoveSuccessAndFailure() { - ICommercialPaperState inState = getPaper(); - ledger(ledgerServices, l -> { - l.transaction(tx -> { - tx.input(JCP_PROGRAM_ID, inState); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Move()); - tx.attachments(JCP_PROGRAM_ID); - tx.failsWith("the state is propagated"); - tx.output(JCP_PROGRAM_ID, "alice's paper", inState.withOwner(alice.getParty())); - return tx.verifies(); - }); - return Unit.INSTANCE; - }); - } - // DOCEND 5 - - // DOCSTART 13 - @Test - public void simpleCPMoveSuccess() { - ICommercialPaperState inState = getPaper(); - ledger(ledgerServices, l -> { - l.transaction(tx -> { - tx.input(JCP_PROGRAM_ID, inState); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Move()); - tx.attachments(JCP_PROGRAM_ID); - tx.timeWindow(TEST_TX_TIME); - tx.output(JCP_PROGRAM_ID, "alice's paper", inState.withOwner(alice.getParty())); - return tx.verifies(); - }); - return Unit.INSTANCE; - }); - } - // DOCEND 13 - - // DOCSTART 6 - @Test - public void simpleIssuanceWithTweak() { - ledger(ledgerServices, l -> { - l.transaction(tx -> { - tx.output(JCP_PROGRAM_ID, "paper", getPaper()); // Some CP is issued onto the ledger by MegaCorp. - tx.attachments(JCP_PROGRAM_ID); - tx.tweak(tw -> { - tw.command(bigCorp.getPublicKey(), new JavaCommercialPaper.Commands.Issue()); - tw.timeWindow(TEST_TX_TIME); - return tw.failsWith("output states are issued by a command signer"); - }); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Issue()); - tx.timeWindow(TEST_TX_TIME); - return tx.verifies(); - }); - return Unit.INSTANCE; - }); - } - // DOCEND 6 - - // DOCSTART 7 - @Test - public void simpleIssuanceWithTweakTopLevelTx() { - transaction(ledgerServices, tx -> { - tx.output(JCP_PROGRAM_ID, "paper", getPaper()); // Some CP is issued onto the ledger by MegaCorp. - tx.attachments(JCP_PROGRAM_ID); - tx.tweak(tw -> { - tw.command(bigCorp.getPublicKey(), new JavaCommercialPaper.Commands.Issue()); - tw.timeWindow(TEST_TX_TIME); - return tw.failsWith("output states are issued by a command signer"); - }); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Issue()); - tx.timeWindow(TEST_TX_TIME); - return tx.verifies(); - }); - } - // DOCEND 7 - - // DOCSTART 8 - @Test - public void chainCommercialPaper() { - PartyAndReference issuer = megaCorp.ref(defaultRef); - ledger(ledgerServices, l -> { - l.unverifiedTransaction(tx -> { - tx.output(Cash.PROGRAM_ID, "alice's $900", - new Cash.State(issuedBy(DOLLARS(900), issuer), alice.getParty())); - tx.attachments(Cash.PROGRAM_ID); - return Unit.INSTANCE; - }); - - // Some CP is issued onto the ledger by MegaCorp. - l.transaction("Issuance", tx -> { - tx.output(JCP_PROGRAM_ID, "paper", getPaper()); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Issue()); - tx.attachments(JCP_PROGRAM_ID); - tx.timeWindow(TEST_TX_TIME); - return tx.verifies(); - }); - - l.transaction("Trade", tx -> { - tx.input("paper"); - tx.input("alice's $900"); - tx.output(Cash.PROGRAM_ID, "borrowed $900", new Cash.State(issuedBy(DOLLARS(900), issuer), megaCorp.getParty())); - JavaCommercialPaper.State inputPaper = l.retrieveOutput(JavaCommercialPaper.State.class, "paper"); - tx.output(JCP_PROGRAM_ID, "alice's paper", inputPaper.withOwner(alice.getParty())); - tx.command(alice.getPublicKey(), new Cash.Commands.Move()); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Move()); - return tx.verifies(); - }); - return Unit.INSTANCE; - }); - } - // DOCEND 8 - - // DOCSTART 9 - @Test - public void chainCommercialPaperDoubleSpend() { - PartyAndReference issuer = megaCorp.ref(defaultRef); - ledger(ledgerServices, l -> { - l.unverifiedTransaction(tx -> { - tx.output(Cash.PROGRAM_ID, "alice's $900", - new Cash.State(issuedBy(DOLLARS(900), issuer), alice.getParty())); - tx.attachments(Cash.PROGRAM_ID); - return Unit.INSTANCE; - }); - - // Some CP is issued onto the ledger by MegaCorp. - l.transaction("Issuance", tx -> { - tx.output(JCP_PROGRAM_ID, "paper", getPaper()); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Issue()); - tx.attachments(JCP_PROGRAM_ID); - tx.timeWindow(TEST_TX_TIME); - return tx.verifies(); - }); - - l.transaction("Trade", tx -> { - tx.input("paper"); - tx.input("alice's $900"); - tx.output(Cash.PROGRAM_ID, "borrowed $900", new Cash.State(issuedBy(DOLLARS(900), issuer), megaCorp.getParty())); - JavaCommercialPaper.State inputPaper = l.retrieveOutput(JavaCommercialPaper.State.class, "paper"); - tx.output(JCP_PROGRAM_ID, "alice's paper", inputPaper.withOwner(alice.getParty())); - tx.command(alice.getPublicKey(), new Cash.Commands.Move()); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Move()); - return tx.verifies(); - }); - - l.transaction(tx -> { - tx.input("paper"); - JavaCommercialPaper.State inputPaper = l.retrieveOutput(JavaCommercialPaper.State.class, "paper"); - // We moved a paper to other pubkey. - tx.output(JCP_PROGRAM_ID, "bob's paper", inputPaper.withOwner(bob.getParty())); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Move()); - return tx.verifies(); - }); - l.fails(); - return Unit.INSTANCE; - }); - } - // DOCEND 9 - - // DOCSTART 10 - @Test - public void chainCommercialPaperTweak() { - PartyAndReference issuer = megaCorp.ref(defaultRef); - ledger(ledgerServices, l -> { - l.unverifiedTransaction(tx -> { - tx.output(Cash.PROGRAM_ID, "alice's $900", - new Cash.State(issuedBy(DOLLARS(900), issuer), alice.getParty())); - tx.attachments(Cash.PROGRAM_ID); - return Unit.INSTANCE; - }); - - // Some CP is issued onto the ledger by MegaCorp. - l.transaction("Issuance", tx -> { - tx.output(JCP_PROGRAM_ID, "paper", getPaper()); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Issue()); - tx.attachments(JCP_PROGRAM_ID); - tx.timeWindow(TEST_TX_TIME); - return tx.verifies(); - }); - - l.transaction("Trade", tx -> { - tx.input("paper"); - tx.input("alice's $900"); - tx.output(Cash.PROGRAM_ID, "borrowed $900", new Cash.State(issuedBy(DOLLARS(900), issuer), megaCorp.getParty())); - JavaCommercialPaper.State inputPaper = l.retrieveOutput(JavaCommercialPaper.State.class, "paper"); - tx.output(JCP_PROGRAM_ID, "alice's paper", inputPaper.withOwner(alice.getParty())); - tx.command(alice.getPublicKey(), new Cash.Commands.Move(JavaCommercialPaper.class)); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Move()); - return tx.verifies(); - }); - - l.tweak(lw -> { - lw.transaction(tx -> { - tx.input("paper"); - JavaCommercialPaper.State inputPaper = l.retrieveOutput(JavaCommercialPaper.State.class, "paper"); - // We moved a paper to another pubkey. - tx.output(JCP_PROGRAM_ID, "bob's paper", inputPaper.withOwner(bob.getParty())); - tx.command(megaCorp.getPublicKey(), new JavaCommercialPaper.Commands.Move()); - return tx.verifies(); - }); - lw.fails(); - return Unit.INSTANCE; - }); - l.verifies(); - return Unit.INSTANCE; - }); - } - // DOCEND 10 -} \ No newline at end of file diff --git a/docs/example-code/src/test/kotlin/net/corda/docs/ExampleConfigTest.kt b/docs/example-code/src/test/kotlin/net/corda/docs/ExampleConfigTest.kt deleted file mode 100644 index 10e998fa8e..0000000000 --- a/docs/example-code/src/test/kotlin/net/corda/docs/ExampleConfigTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -package net.corda.docs - -import net.corda.core.internal.toPath -import net.corda.node.services.config.ConfigHelper -import net.corda.node.services.config.parseAsNodeConfiguration -import org.assertj.core.api.Assertions.assertThat -import org.junit.Test -import java.nio.file.Path -import java.nio.file.Paths -import kotlin.reflect.KVisibility -import kotlin.reflect.full.declaredMemberProperties - -class ExampleConfigTest { - - private fun readAndCheckConfigurations(vararg configFilenames: String, loadConfig: (Path) -> A) { - configFilenames.forEach { - println("Checking $it") - val configFileResource = ExampleConfigTest::class.java.classLoader.getResource(it) - val config = loadConfig(configFileResource.toPath()) - // Force the config fields as they are resolved lazily - config.javaClass.kotlin.declaredMemberProperties.forEach { member -> - if (member.visibility == KVisibility.PUBLIC) { - member.get(config) - } - } - } - } - - @Test(timeout=300_000) - fun `example node_confs parses fine`() { - readAndCheckConfigurations("example-node.conf") { - val baseDirectory = Paths.get("some-example-base-dir") - assertThat(ConfigHelper.loadConfig(baseDirectory = baseDirectory, configFile = it).parseAsNodeConfiguration().isValid).isTrue() - } - } -} \ No newline at end of file diff --git a/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorialTest.kt b/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorialTest.kt deleted file mode 100644 index 275c6e1304..0000000000 --- a/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorialTest.kt +++ /dev/null @@ -1,92 +0,0 @@ -package net.corda.docs.kotlin - -import net.corda.core.identity.Party -import net.corda.core.toFuture -import net.corda.core.utilities.OpaqueBytes -import net.corda.core.utilities.getOrThrow -import net.corda.finance.* -import net.corda.finance.workflows.getCashBalances -import net.corda.finance.flows.CashIssueFlow -import net.corda.testing.core.singleIdentity -import net.corda.testing.node.MockNetwork -import net.corda.testing.node.StartedMockNode -import org.junit.After -import org.junit.Before -import org.junit.Test -import kotlin.test.assertEquals - -class FxTransactionBuildTutorialTest { - private lateinit var mockNet: MockNetwork - private lateinit var nodeA: StartedMockNode - private lateinit var nodeB: StartedMockNode - private lateinit var notary: Party - - @Before - fun setup() { - mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance")) - nodeA = mockNet.createPartyNode() - nodeB = mockNet.createPartyNode() - nodeB.registerInitiatedFlow(ForeignExchangeRemoteFlow::class.java) - notary = mockNet.defaultNotaryIdentity - } - - @After - fun cleanUp() { - mockNet.stopNodes() - } - - @Test(timeout=300_000) - fun `Run ForeignExchangeFlow to completion`() { - // Use NodeA as issuer and create some dollars and wait for the flow to stop - nodeA.startFlow(CashIssueFlow(DOLLARS(1000), - OpaqueBytes.of(0x01), - notary)).getOrThrow() - printBalances() - - // Using NodeB as Issuer create some pounds and wait for the flow to stop - nodeB.startFlow(CashIssueFlow(POUNDS(1000), - OpaqueBytes.of(0x01), - notary)).getOrThrow() - printBalances() - - // Setup some futures on the vaults to await the arrival of the exchanged funds at both nodes - val nodeAVaultUpdate = nodeA.services.vaultService.updates.toFuture() - val nodeBVaultUpdate = nodeB.services.vaultService.updates.toFuture() - - // Now run the actual Fx exchange and wait for the flow to finish - nodeA.startFlow(ForeignExchangeFlow("trade1", - POUNDS(100).issuedBy(nodeB.info.singleIdentity().ref(0x01)), - DOLLARS(200).issuedBy(nodeA.info.singleIdentity().ref(0x01)), - nodeB.info.singleIdentity(), - weAreBaseCurrencySeller = false, - notary = mockNet.defaultNotaryIdentity)).getOrThrow() - // wait for the flow to finish and the vault updates to be done - // Get the balances when the vault updates - nodeAVaultUpdate.get() - val balancesA = nodeA.transaction { - nodeA.services.getCashBalances() - } - nodeBVaultUpdate.get() - val balancesB = nodeB.transaction { - nodeB.services.getCashBalances() - } - - println("BalanceA\n$balancesA") - println("BalanceB\n$balancesB") - // Verify the transfers occurred as expected - assertEquals(POUNDS(100), balancesA[GBP]) - assertEquals(DOLLARS(1000 - 200), balancesA[USD]) - assertEquals(POUNDS(1000 - 100), balancesB[GBP]) - assertEquals(DOLLARS(200), balancesB[USD]) - } - - private fun printBalances() { - // Print out the balances - nodeA.transaction { - println("BalanceA\n" + nodeA.services.getCashBalances()) - } - nodeB.transaction { - println("BalanceB\n" + nodeB.services.getCashBalances()) - } - } -} diff --git a/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt b/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt deleted file mode 100644 index dc7e657ad5..0000000000 --- a/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt +++ /dev/null @@ -1,316 +0,0 @@ -@file:Suppress("MemberVisibilityCanBePrivate") - -package net.corda.docs.kotlin.tutorial.testdsl - -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever -import net.corda.core.contracts.TransactionVerificationException -import net.corda.core.identity.CordaX500Name -import net.corda.core.node.services.IdentityService -import net.corda.core.utilities.days -import net.corda.finance.DOLLARS -import net.corda.finance.`issued by` -import net.corda.finance.contracts.CP_PROGRAM_ID -import net.corda.finance.contracts.CommercialPaper -import net.corda.finance.contracts.ICommercialPaperState -import net.corda.finance.contracts.asset.CASH -import net.corda.finance.contracts.asset.Cash -import net.corda.testing.core.* -import net.corda.testing.node.MockServices -import net.corda.testing.node.ledger -import net.corda.testing.node.transaction -import org.junit.Rule -import org.junit.Test -import java.time.Instant - -class TutorialTestDSL { - private companion object { - val alice = TestIdentity(ALICE_NAME, 70) - val bob = TestIdentity(BOB_NAME, 80) - // DOCSTART 14 - val bigCorp = TestIdentity((CordaX500Name("BigCorp", "New York", "GB"))) - // DOCEND 14 - val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20) - val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB")) - val TEST_TX_TIME: Instant = Instant.parse("2015-04-17T12:00:00.00Z") - } - - @Rule - @JvmField - val testSerialization = SerializationEnvironmentRule() - // DOCSTART 11 - private val ledgerServices = MockServices( - // A list of packages to scan for cordapps - listOf("net.corda.finance.contracts"), - // The identity represented by this set of mock services. Defaults to a test identity. - // You can also use the alternative parameter initialIdentityName which accepts a - // [CordaX500Name] - megaCorp, - mock().also { - doReturn(megaCorp.party).whenever(it).partyFromKey(megaCorp.publicKey) - doReturn(null).whenever(it).partyFromKey(bigCorp.publicKey) - doReturn(null).whenever(it).partyFromKey(alice.publicKey) - }) - // DOCEND 11 - - // DOCSTART 12 - @Suppress("unused") - private val simpleLedgerServices = MockServices( - // This is the identity of the node - megaCorp, - // Other identities the test node knows about - bigCorp, - alice - ) - // DOCEND 12 - - // DOCSTART 1 - fun getPaper(): ICommercialPaperState = CommercialPaper.State( - issuance = megaCorp.party.ref(123), - owner = megaCorp.party, - faceValue = 1000.DOLLARS `issued by` megaCorp.party.ref(123), - maturityDate = TEST_TX_TIME + 7.days - ) - // DOCEND 1 - - // DOCSTART 2 - // This example test will fail with this exception. - @Test(expected = IllegalStateException::class, timeout=300_000) - fun simpleCP() { - val inState = getPaper() - ledgerServices.ledger(dummyNotary.party) { - transaction { - attachments(CP_PROGRAM_ID) - input(CP_PROGRAM_ID, inState) - verifies() - } - } - } - // DOCEND 2 - - // DOCSTART 3 - // This example test will fail with this exception. - @Test(expected = TransactionVerificationException.ContractRejection::class, timeout=300_000) - fun simpleCPMove() { - val inState = getPaper() - ledgerServices.ledger(dummyNotary.party) { - transaction { - input(CP_PROGRAM_ID, inState) - command(megaCorp.publicKey, CommercialPaper.Commands.Move()) - attachments(CP_PROGRAM_ID) - verifies() - } - } - } - // DOCEND 3 - - // DOCSTART 4 - @Test(timeout=300_000) - fun simpleCPMoveFails() { - val inState = getPaper() - ledgerServices.ledger(dummyNotary.party) { - transaction { - input(CP_PROGRAM_ID, inState) - command(megaCorp.publicKey, CommercialPaper.Commands.Move()) - attachments(CP_PROGRAM_ID) - `fails with`("the state is propagated") - } - } - } - // DOCEND 4 - - // DOCSTART 5 - @Test(timeout=300_000) - fun simpleCPMoveFailureAndSuccess() { - val inState = getPaper() - ledgerServices.ledger(dummyNotary.party) { - transaction { - input(CP_PROGRAM_ID, inState) - command(megaCorp.publicKey, CommercialPaper.Commands.Move()) - attachments(CP_PROGRAM_ID) - `fails with`("the state is propagated") - output(CP_PROGRAM_ID, "alice's paper", inState.withOwner(alice.party)) - verifies() - } - } - } - // DOCEND 5 - - // DOCSTART 13 - @Test(timeout=300_000) - fun simpleCPMoveSuccess() { - val inState = getPaper() - ledgerServices.ledger(dummyNotary.party) { - transaction { - input(CP_PROGRAM_ID, inState) - command(megaCorp.publicKey, CommercialPaper.Commands.Move()) - attachments(CP_PROGRAM_ID) - timeWindow(TEST_TX_TIME) - output(CP_PROGRAM_ID, "alice's paper", inState.withOwner(alice.party)) - verifies() - } - } - } - // DOCEND 13 - - // DOCSTART 6 - @Test(timeout=300_000) - fun `simple issuance with tweak`() { - ledgerServices.ledger(dummyNotary.party) { - transaction { - output(CP_PROGRAM_ID, "paper", getPaper()) // Some CP is issued onto the ledger by MegaCorp. - attachments(CP_PROGRAM_ID) - tweak { - // The wrong pubkey. - command(bigCorp.publicKey, CommercialPaper.Commands.Issue()) - timeWindow(TEST_TX_TIME) - `fails with`("output states are issued by a command signer") - } - command(megaCorp.publicKey, CommercialPaper.Commands.Issue()) - timeWindow(TEST_TX_TIME) - verifies() - } - } - } - // DOCEND 6 - - // DOCSTART 7 - @Test(timeout=300_000) - fun `simple issuance with tweak and top level transaction`() { - ledgerServices.transaction(dummyNotary.party) { - output(CP_PROGRAM_ID, "paper", getPaper()) // Some CP is issued onto the ledger by MegaCorp. - attachments(CP_PROGRAM_ID) - tweak { - // The wrong pubkey. - command(bigCorp.publicKey, CommercialPaper.Commands.Issue()) - timeWindow(TEST_TX_TIME) - `fails with`("output states are issued by a command signer") - } - command(megaCorp.publicKey, CommercialPaper.Commands.Issue()) - timeWindow(TEST_TX_TIME) - verifies() - } - } - // DOCEND 7 - - // DOCSTART 8 - @Test(timeout=300_000) - fun `chain commercial paper`() { - val issuer = megaCorp.party.ref(123) - ledgerServices.ledger(dummyNotary.party) { - unverifiedTransaction { - attachments(Cash.PROGRAM_ID) - output(Cash.PROGRAM_ID, "alice's $900", 900.DOLLARS.CASH issuedBy issuer ownedBy alice.party) - } - - // Some CP is issued onto the ledger by MegaCorp. - transaction("Issuance") { - output(CP_PROGRAM_ID, "paper", getPaper()) - command(megaCorp.publicKey, CommercialPaper.Commands.Issue()) - attachments(CP_PROGRAM_ID) - timeWindow(TEST_TX_TIME) - verifies() - } - - - transaction("Trade") { - input("paper") - input("alice's $900") - output(Cash.PROGRAM_ID, "borrowed $900", 900.DOLLARS.CASH issuedBy issuer ownedBy megaCorp.party) - output(CP_PROGRAM_ID, "alice's paper", "paper".output().withOwner(alice.party)) - command(alice.publicKey, Cash.Commands.Move()) - command(megaCorp.publicKey, CommercialPaper.Commands.Move()) - verifies() - } - } - } - // DOCEND 8 - - // DOCSTART 9 - @Test(timeout=300_000) - fun `chain commercial paper double spend`() { - val issuer = megaCorp.party.ref(123) - ledgerServices.ledger(dummyNotary.party) { - unverifiedTransaction { - attachments(Cash.PROGRAM_ID) - output(Cash.PROGRAM_ID, "alice's $900", 900.DOLLARS.CASH issuedBy issuer ownedBy alice.party) - } - - // Some CP is issued onto the ledger by MegaCorp. - transaction("Issuance") { - output(CP_PROGRAM_ID, "paper", getPaper()) - command(megaCorp.publicKey, CommercialPaper.Commands.Issue()) - attachments(CP_PROGRAM_ID) - timeWindow(TEST_TX_TIME) - verifies() - } - - transaction("Trade") { - input("paper") - input("alice's $900") - output(Cash.PROGRAM_ID, "borrowed $900", 900.DOLLARS.CASH issuedBy issuer ownedBy megaCorp.party) - output(CP_PROGRAM_ID, "alice's paper", "paper".output().withOwner(alice.party)) - command(alice.publicKey, Cash.Commands.Move()) - command(megaCorp.publicKey, CommercialPaper.Commands.Move()) - verifies() - } - - transaction { - input("paper") - // We moved a paper to another pubkey. - output(CP_PROGRAM_ID, "bob's paper", "paper".output().withOwner(bob.party)) - command(megaCorp.publicKey, CommercialPaper.Commands.Move()) - verifies() - } - - fails() - } - } - // DOCEND 9 - - // DOCSTART 10 - @Test(timeout=300_000) - fun `chain commercial tweak`() { - val issuer = megaCorp.party.ref(123) - ledgerServices.ledger(dummyNotary.party) { - unverifiedTransaction { - attachments(Cash.PROGRAM_ID) - output(Cash.PROGRAM_ID, "alice's $900", 900.DOLLARS.CASH issuedBy issuer ownedBy alice.party) - } - - // Some CP is issued onto the ledger by MegaCorp. - transaction("Issuance") { - output(CP_PROGRAM_ID, "paper", getPaper()) - command(megaCorp.publicKey, CommercialPaper.Commands.Issue()) - attachments(CP_PROGRAM_ID) - timeWindow(TEST_TX_TIME) - verifies() - } - - transaction("Trade") { - input("paper") - input("alice's $900") - output(Cash.PROGRAM_ID, "borrowed $900", 900.DOLLARS.CASH issuedBy issuer ownedBy megaCorp.party) - output(CP_PROGRAM_ID, "alice's paper", "paper".output().withOwner(alice.party)) - command(alice.publicKey, Cash.Commands.Move(CommercialPaper::class.java)) - command(megaCorp.publicKey, CommercialPaper.Commands.Move()) - verifies() - } - - tweak { - transaction { - input("paper") - // We moved a paper to another pubkey. - output(CP_PROGRAM_ID, "bob's paper", "paper".output().withOwner(bob.party)) - command(megaCorp.publicKey, CommercialPaper.Commands.Move()) - verifies() - } - fails() - } - - verifies() - } - } - // DOCEND 10 -} diff --git a/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorialTest.kt b/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorialTest.kt deleted file mode 100644 index 4a302257b4..0000000000 --- a/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorialTest.kt +++ /dev/null @@ -1,99 +0,0 @@ -package net.corda.docs.kotlin.txbuild - -import net.corda.core.contracts.LinearState -import net.corda.core.contracts.StateAndRef -import net.corda.core.contracts.UniqueIdentifier -import net.corda.core.identity.Party -import net.corda.core.internal.packageName_ -import net.corda.core.node.ServiceHub -import net.corda.core.node.services.queryBy -import net.corda.core.node.services.vault.QueryCriteria -import net.corda.core.toFuture -import net.corda.core.utilities.getOrThrow -import net.corda.testing.core.ALICE_NAME -import net.corda.testing.core.BOB_NAME -import net.corda.testing.node.MockNetwork -import net.corda.testing.node.StartedMockNode -import org.junit.After -import org.junit.Before -import org.junit.Test -import kotlin.test.assertEquals - -class WorkflowTransactionBuildTutorialTest { - private lateinit var mockNet: MockNetwork - private lateinit var aliceNode: StartedMockNode - private lateinit var bobNode: StartedMockNode - private lateinit var alice: Party - private lateinit var bob: Party - - // Helper method to locate the latest Vault version of a LinearState - private inline fun ServiceHub.latest(ref: UniqueIdentifier): StateAndRef { - val linearHeads = vaultService.queryBy(QueryCriteria.LinearStateQueryCriteria(uuid = listOf(ref.id))) - return linearHeads.states.single() - } - - @Before - fun setup() { - mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf(javaClass.packageName_)) - aliceNode = mockNet.createPartyNode(ALICE_NAME) - bobNode = mockNet.createPartyNode(BOB_NAME) - alice = aliceNode.services.myInfo.identityFromX500Name(ALICE_NAME) - bob = bobNode.services.myInfo.identityFromX500Name(BOB_NAME) - } - - @After - fun cleanUp() { - mockNet.stopNodes() - } - - @Test(timeout=300_000) - fun `Run workflow to completion`() { - // Setup a vault subscriber to wait for successful upload of the proposal to NodeB - val nodeBVaultUpdate = bobNode.services.vaultService.updates.toFuture() - // Kick of the proposal flow - val flow1 = aliceNode.startFlow(SubmitTradeApprovalFlow("1234", bob, mockNet.defaultNotaryIdentity)) - // Wait for the flow to finish - val proposalRef = flow1.getOrThrow() - val proposalLinearId = proposalRef.state.data.linearId - // Wait for NodeB to include it's copy in the vault - nodeBVaultUpdate.get() - // Fetch the latest copy of the state from both nodes - val latestFromA = aliceNode.transaction { - aliceNode.services.latest(proposalLinearId) - } - val latestFromB = bobNode.transaction { - bobNode.services.latest(proposalLinearId) - } - // Confirm the state as as expected - assertEquals(WorkflowState.NEW, proposalRef.state.data.state) - assertEquals("1234", proposalRef.state.data.tradeId) - assertEquals(alice, proposalRef.state.data.source) - assertEquals(bob, proposalRef.state.data.counterparty) - assertEquals(proposalRef, latestFromA) - assertEquals(proposalRef, latestFromB) - // Setup a vault subscriber to pause until the final update is in NodeA and NodeB - val nodeAVaultUpdate = aliceNode.services.vaultService.updates.toFuture() - val secondNodeBVaultUpdate = bobNode.services.vaultService.updates.toFuture() - // Run the manual completion flow from NodeB - val flow2 = bobNode.startFlow(SubmitCompletionFlow(latestFromB.ref, WorkflowState.APPROVED)) - // wait for the flow to end - val completedRef = flow2.getOrThrow() - // wait for the vault updates to stabilise - nodeAVaultUpdate.get() - secondNodeBVaultUpdate.get() - // Fetch the latest copies from the vault - val finalFromA = aliceNode.transaction { - aliceNode.services.latest(proposalLinearId) - } - val finalFromB = bobNode.transaction { - bobNode.services.latest(proposalLinearId) - } - // Confirm the state is as expected - assertEquals(WorkflowState.APPROVED, completedRef.state.data.state) - assertEquals("1234", completedRef.state.data.tradeId) - assertEquals(alice, completedRef.state.data.source) - assertEquals(bob, completedRef.state.data.counterparty) - assertEquals(completedRef, finalFromA) - assertEquals(completedRef, finalFromB) - } -} diff --git a/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/vault/CustomVaultQueryTest.kt b/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/vault/CustomVaultQueryTest.kt deleted file mode 100644 index 27715a16bc..0000000000 --- a/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/vault/CustomVaultQueryTest.kt +++ /dev/null @@ -1,108 +0,0 @@ -package net.corda.docs.kotlin.vault - -import net.corda.core.contracts.Amount -import net.corda.core.contracts.ContractState -import net.corda.core.identity.Party -import net.corda.core.internal.packageName -import net.corda.core.internal.packageName_ -import net.corda.core.node.services.queryBy -import net.corda.core.node.services.vault.* -import net.corda.core.utilities.OpaqueBytes -import net.corda.core.utilities.getOrThrow -import net.corda.docs.kotlin.tutorial.helloworld.IOUFlow -import net.corda.finance.* -import net.corda.finance.workflows.getCashBalances -import net.corda.finance.flows.CashIssueFlow -import net.corda.node.services.vault.VaultSchemaV1 -import net.corda.testing.core.singleIdentity -import net.corda.testing.node.MockNetwork -import net.corda.testing.node.StartedMockNode -import org.assertj.core.api.Assertions.assertThatCode -import org.junit.After -import org.junit.Assert.assertEquals -import org.junit.Before -import org.junit.Test -import java.util.* - -class CustomVaultQueryTest { - private lateinit var mockNet: MockNetwork - private lateinit var nodeA: StartedMockNode - private lateinit var nodeB: StartedMockNode - private lateinit var notary: Party - - @Before - fun setup() { - mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance", IOUFlow::class.packageName, javaClass.packageName_, "com.template")) - nodeA = mockNet.createPartyNode() - nodeB = mockNet.createPartyNode() - notary = mockNet.defaultNotaryIdentity - } - - @After - fun cleanUp() { - mockNet.stopNodes() - } - - @Test(timeout=300_000) - fun `query by max recorded time`() { - nodeA.startFlow(IOUFlow(1000, nodeB.info.singleIdentity())).getOrThrow() - nodeA.startFlow(IOUFlow(500, nodeB.info.singleIdentity())).getOrThrow() - - val max = builder { VaultSchemaV1.VaultStates::recordedTime.max() } - val maxCriteria = QueryCriteria.VaultCustomQueryCriteria(max) - - val results = nodeA.transaction { - val pageSpecification = PageSpecification(pageNumber = DEFAULT_PAGE_NUM, pageSize = DEFAULT_PAGE_SIZE) - nodeA.services.vaultService.queryBy(criteria = maxCriteria, paging = pageSpecification) - } - assertThatCode { results.otherResults.single() }.doesNotThrowAnyException() - } - - @Test(timeout=300_000) - fun `test custom vault query`() { - // issue some cash in several currencies - issueCashForCurrency(POUNDS(1000)) - issueCashForCurrency(DOLLARS(900)) - issueCashForCurrency(SWISS_FRANCS(800)) - val (cashBalancesOriginal, _) = getBalances() - - // top up all currencies (by double original) - topUpCurrencies() - val (cashBalancesAfterTopup, _) = getBalances() - - assertEquals(cashBalancesOriginal[GBP]?.times(2), cashBalancesAfterTopup[GBP]) - assertEquals(cashBalancesOriginal[USD]?.times(2) , cashBalancesAfterTopup[USD]) - assertEquals(cashBalancesOriginal[CHF]?.times( 2), cashBalancesAfterTopup[CHF]) - } - - private fun issueCashForCurrency(amountToIssue: Amount) { - // Use NodeA as issuer and create some dollars - nodeA.startFlow(CashIssueFlow(amountToIssue, - OpaqueBytes.of(0x01), - notary)).getOrThrow() - } - - private fun topUpCurrencies() { - nodeA.startFlow(TopupIssuerFlow.TopupIssuanceRequester( - nodeA.info.singleIdentity(), - OpaqueBytes.of(0x01), - nodeA.info.singleIdentity(), - notary) - ).getOrThrow() - } - - private fun getBalances(): Pair>, Map>> { - // Print out the balances - val balancesNodesA = nodeA.transaction { - nodeA.services.getCashBalances() - } - println("BalanceA\n$balancesNodesA") - - val balancesNodesB = nodeB.transaction { - nodeB.services.getCashBalances() - } - println("BalanceB\n$balancesNodesB") - - return Pair(balancesNodesA, balancesNodesB) - } -} diff --git a/settings.gradle b/settings.gradle index d582cee14e..ae6dad0838 100644 --- a/settings.gradle +++ b/settings.gradle @@ -61,8 +61,6 @@ include 'tools:network-builder' include 'tools:cliutils' include 'tools:worldmap' include 'tools:checkpoint-agent' -include 'example-code' -project(':example-code').projectDir = file("$settingsDir/docs/source/example-code") include 'samples:attachment-demo:contracts' include 'samples:attachment-demo:workflows' include 'samples:trader-demo:workflows-trader'