diff --git a/Accounts/README.md b/Accounts/README.md index 81a297d5..f304320a 100644 --- a/Accounts/README.md +++ b/Accounts/README.md @@ -6,7 +6,7 @@ This folder features Corda Accounts sample projects. Learn more about [Accounts] This CorDapp mimics a supply chain transaction, where the deal is incorporated among different teams in the companies on both side of the trade.

- Corda + Corda

### [Tic Tac Thor](./tictacthor): @@ -15,3 +15,7 @@ This CorDapp recreates the game of Tic Tac Toe via Corda. It primarily demonstra

Corda

+ +### [World Cup Ticket Booking](./worldcupticketbooking): + +This sample shows you how to integrate accounts and tokens. This sample talks about a scenario where typically when the Cricket season starts, BCCI (Board of Control for Cricket) starts selling tickets. As of now there are multiple dealers whom the BCCI issues tickets and further these dealers sell tickets to their client. We are trying to simulate similar functionality maintaining the entire issuance and selling of the tickets on Corda Platform. \ No newline at end of file diff --git a/Accounts/constants.properties b/Accounts/constants.properties index 2cd5a28c..adcdb361 100644 --- a/Accounts/constants.properties +++ b/Accounts/constants.properties @@ -1,12 +1,12 @@ cordaReleaseGroup=net.corda cordaCoreReleaseGroup=net.corda -cordaVersion=4.6 -cordaCoreVersion=4.6 +cordaVersion=4.10 +cordaCoreVersion=4.10 gradlePluginsVersion=5.0.12 kotlinVersion=1.2.71 junitVersion=4.12 quasarVersion=0.7.10 -log4jVersion =2.11.2 -platformVersion=8 +log4jVersion =2.17.1 +platformVersion=12 slf4jVersion=1.7.25 nettyVersion=4.1.22.Final diff --git a/Accounts/supplychain/Business Flow.png b/Accounts/supplychain/Business_Flow.png similarity index 100% rename from Accounts/supplychain/Business Flow.png rename to Accounts/supplychain/Business_Flow.png diff --git a/Accounts/supplychain/README.md b/Accounts/supplychain/README.md index cc8730a4..87168170 100644 --- a/Accounts/supplychain/README.md +++ b/Accounts/supplychain/README.md @@ -1,6 +1,6 @@ # Accounts_SupplyChain -For More information regarding the Accounts Library, please read at: https://github.com/corda/accounts/blob/master/docs.md +For more information regarding the Accounts Library, please read at: https://github.com/corda/accounts/blob/master/docs.md This sample describes a mock/simple supply chain business flow. @@ -10,10 +10,15 @@ This sample describes a mock/simple supply chain business flow. From the above chart, you can see the flow is going back and forth between different parties' accounts. Please follow the instruction below to experience the [Accounts](https://training.corda.net/libraries/accounts-lib/) library. -# Setting up + +## Pre-Requisites + +For development environment setup, please refer to: [Setup Guide](https://docs.r3.com/en/platform/corda/4.9/community/getting-set-up.html). + +## Runnning the nodes Go into the project directory and build the project ``` -./gradlew clean deployNodes +./gradlew clean build deployNodes ``` Run the project ``` @@ -21,7 +26,7 @@ Run the project ``` Now, you should have four Corda terminals opened automatically. -# Shell Instructions (Part 1) - Creating & Sharing Accounts +## Shell Instructions (Part 1) - Creating & Sharing Accounts Go to the Buyer's node terminal and paste in the following code: (You can select all 7 lines and copy to the terminal all at once) ``` flow start CreateNewAccount acctName: BuyerProcurement @@ -33,7 +38,7 @@ flow start ShareAccountTo acctNameShared: BuyerFinance, shareTo: Seller flow start ShareAccountTo acctNameShared: BuyerWarehouse, shareTo: ShippingCo flow start ShareAccountTo acctNameShared: BuyerWarehouse, shareTo: Seller ``` -This is creating 3 accounts under Buyer's node and sharing with their specific conterpartie's node or account. +This is creating 3 accounts under Buyer's node and sharing with their specific counterparty's node or account. Go to the Seller's node terminal and paste in the following code: ``` @@ -45,14 +50,14 @@ flow start ShareAccountTo acctNameShared: SellerSales, shareTo: Buyer flow start ShareAccountTo acctNameShared: SellerFinance, shareTo: Buyer flow start ShareAccountTo acctNameShared: SellerInventory, shareTo: ShippingCo ``` -This is creating 3 accounts under Seller's node and sharing with their specific conterparty's node or account. +This is creating 3 accounts under Seller's node and sharing with their specific counterparty's node or account. [Optional]: You can run a vaultQuery to see the [AccountInfo](https://training.corda.net/libraries/accounts-lib/#design) that been stored at each node by using: ``` run vaultQuery contractStateType: com.r3.corda.lib.accounts.contracts.states.AccountInfo ``` -# Shell Instructions (Part 2) - Executing Business Flows -## Step 1: Seller's sales team send inovice of $500 to Buyer's procurement team +## Shell Instructions (Part 2) - Executing Business Flows +### Step 1: Seller's sales team send invoice for $500 to Buyer's procurement team navigate to Seller's node terminal and run ``` flow start SendInvoice whoAmI: SellerSales, whereTo: BuyerProcurement, amount: 500 @@ -63,42 +68,42 @@ flow start ViewInboxByAccount acctname: BuyerProcurement ``` You see that the invoice state amount 500 is returned. You can also replace the BuyerProcurement with BuyerWarehouse to see that the non-relevant accounts has no visiblity about the invoice state. -## Step 2: Buyer's procurement team will send an internal message to Buyer's Buyer's finance team +### Step 2: Buyer's procurement team will send an internal message to Buyer's Buyer's finance team Navigate to Buyer's node terminal and type in: ``` flow start InternalMessage fromWho: BuyerProcurement, whereTo: BuyerFinance, message: Send 500 to SellerFinance ``` [Optional verification]: run ```flow start ViewInboxByAccount acctname: BuyerFinance``` at Buyer' node terminal -## Step 3: Buyer's finance team send a payment to Seller's finance team +### Step 3: Buyer's finance team send a payment to Seller's finance team Navigate to Buyer's node terminal and type in: ``` flow start SendPayment whoAmI: BuyerFinance, whereTo: SellerFinance, amount: 500 ``` [Optional verification]: run ```flow start ViewInboxByAccount acctname: SellerFinance``` at Seller's node terminal -## Step 4: Seller's finance team send an internal message to Seller's inventory team to instruct them to send the cargo +### Step 4: Seller's finance team send an internal message to Seller's inventory team to instruct them to send the cargo Navigate to Seller's node terminal and type in ``` flow start InternalMessage fromWho: SellerFinance, whereTo: SellerInventory, message: send Cargo to Buyer ``` [Optional verification]: run ```flow start ViewInboxByAccount acctname: SellerInventory``` at Seller's node terminal -## step 5: Seller's inventory team send a shipping work order for shipping company +### step 5: Seller's inventory team send a shipping work order for shipping company Navigate to Seller's node terminal and type in ``` flow start SendShippingRequest whoAmI: SellerInventory, whereTo: BuyerWarehouse, shipper: ShippingCo, Cargo: 10 boxes of Books ``` [Optional verification]: run ```run vaultQuery contractStateType: ShippingRequestState``` at ShippingCo's node terminal -## Step 6: Shipping company sends the cargo to Buyer's warehouse +### Step 6: Shipping company sends the cargo to Buyer's warehouse Navigate to ShippingCo's node terminal and type in ``` flow start SendCargo pickupFrom: SellerInventory, shipTo: BuyerWarehouse, cargo: Books ``` [Optional verification]: run ```flow start ViewInboxByAccount acctname: BuyerWarehouse``` at Buyer's node terminal -## Now, the entire business chain is completed. +### Now, the entire business chain is completed. diff --git a/Accounts/supplychain/build.gradle b/Accounts/supplychain/build.gradle index 67dde5d5..4d70ff49 100644 --- a/Accounts/supplychain/build.gradle +++ b/Accounts/supplychain/build.gradle @@ -26,8 +26,7 @@ buildscript { repositories { mavenLocal() mavenCentral() - jcenter() - maven { url 'https://software.r3.com/artifactory/corda-releases' } + maven { url 'https://download.corda.net/maven/corda-releases' } } dependencies { @@ -43,12 +42,12 @@ allprojects { repositories { mavenLocal() - jcenter() + mavenCentral() - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } maven { url 'https://jitpack.io' } //SDK lib - maven { url 'https://software.r3.com/artifactory/corda-lib' } + maven { url 'https://download.corda.net/maven/corda-lib' } //Gradle Plugins maven { url 'https://repo.gradle.org/gradle/libs-releases' } } @@ -90,6 +89,8 @@ dependencies { cordaCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" cordaCompile "org.apache.logging.log4j:log4j-web:${log4j_version}" cordaCompile "org.slf4j:jul-to-slf4j:$slf4j_version" + cordaDriver "net.corda:corda-shell:4.10" + //accounts cordapp "$accounts_release_group:accounts-contracts:$accounts_release_version" diff --git a/Accounts/supplychain/repositories.gradle b/Accounts/supplychain/repositories.gradle index 206b9c68..9797c0ea 100644 --- a/Accounts/supplychain/repositories.gradle +++ b/Accounts/supplychain/repositories.gradle @@ -1,8 +1,7 @@ repositories { mavenLocal() mavenCentral() - jcenter() maven { url 'https://jitpack.io' } - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } maven { url 'https://repo.gradle.org/gradle/libs-releases' } } diff --git a/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/InternalMessage.java b/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/InternalMessage.java index 140fcf18..eadf9f59 100644 --- a/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/InternalMessage.java +++ b/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/InternalMessage.java @@ -6,6 +6,7 @@ import com.r3.corda.lib.accounts.workflows.flows.RequestKeyForAccount; import com.r3.corda.lib.accounts.workflows.services.KeyManagementBackedAccountService; import com.sun.istack.NotNull; +import net.corda.core.identity.CordaX500Name; import net.corda.samples.supplychain.accountUtilities.NewKeyForAccount; import net.corda.samples.supplychain.contracts.InternalMessageStateContract; import net.corda.samples.supplychain.states.InternalMessageState; @@ -81,13 +82,8 @@ public String call() throws FlowException { InternalMessageState output = new InternalMessageState(message,new AnonymousParty(myKey),targetAcctAnonymousParty); // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flow or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); TransactionBuilder txbuilder = new TransactionBuilder(notary) .addOutputState(output) diff --git a/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendCargo.java b/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendCargo.java index d59c269c..d51f2527 100644 --- a/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendCargo.java +++ b/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendCargo.java @@ -6,6 +6,7 @@ import com.r3.corda.lib.accounts.workflows.flows.RequestKeyForAccount; import com.r3.corda.lib.accounts.workflows.services.KeyManagementBackedAccountService; import com.sun.istack.NotNull; +import net.corda.core.identity.CordaX500Name; import net.corda.samples.supplychain.accountUtilities.NewKeyForAccount; import net.corda.samples.supplychain.contracts.CargoStateContract; import net.corda.samples.supplychain.states.CargoState; @@ -58,13 +59,8 @@ public String call() throws FlowException { CargoState output = new CargoState(new AnonymousParty(myKey),targetAcctAnonymousParty,cargo,getOurIdentity()); // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flow or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); TransactionBuilder txbuilder = new TransactionBuilder(notary) .addOutputState(output) diff --git a/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendInvoice.java b/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendInvoice.java index 6162258a..5d17627c 100644 --- a/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendInvoice.java +++ b/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendInvoice.java @@ -6,6 +6,7 @@ import com.r3.corda.lib.accounts.workflows.flows.RequestKeyForAccount; import com.r3.corda.lib.accounts.workflows.services.KeyManagementBackedAccountService; import com.sun.istack.NotNull; +import net.corda.core.identity.CordaX500Name; import net.corda.samples.supplychain.accountUtilities.NewKeyForAccount; import net.corda.samples.supplychain.contracts.InvoiceStateContract; import net.corda.samples.supplychain.states.InvoiceState; @@ -58,13 +59,8 @@ public String call() throws FlowException { InvoiceState output = new InvoiceState(amount,new AnonymousParty(myKey),targetAcctAnonymousParty, UUID.randomUUID()); // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flow or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); TransactionBuilder txbuilder = new TransactionBuilder(notary) .addOutputState(output) diff --git a/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendPayment.java b/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendPayment.java index dfca4452..9a65d6df 100644 --- a/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendPayment.java +++ b/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendPayment.java @@ -6,6 +6,7 @@ import com.r3.corda.lib.accounts.workflows.flows.RequestKeyForAccount; import com.r3.corda.lib.accounts.workflows.services.KeyManagementBackedAccountService; import com.sun.istack.NotNull; +import net.corda.core.identity.CordaX500Name; import net.corda.samples.supplychain.accountUtilities.NewKeyForAccount; import net.corda.samples.supplychain.contracts.PaymentStateContract; import net.corda.samples.supplychain.states.PaymentState; @@ -57,13 +58,8 @@ public String call() throws FlowException { PaymentState output = new PaymentState(amount,new AnonymousParty(myKey),targetAcctAnonymousParty); // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flow or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); TransactionBuilder txbuilder = new TransactionBuilder(notary) .addOutputState(output) diff --git a/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendShippingRequest.java b/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendShippingRequest.java index 9db64235..962770ee 100644 --- a/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendShippingRequest.java +++ b/Accounts/supplychain/workflows/src/main/java/net/corda/samples/supplychain/flows/SendShippingRequest.java @@ -5,6 +5,7 @@ import com.r3.corda.lib.accounts.workflows.services.AccountService; import com.r3.corda.lib.accounts.workflows.services.KeyManagementBackedAccountService; import com.sun.istack.NotNull; +import net.corda.core.identity.CordaX500Name; import net.corda.samples.supplychain.accountUtilities.NewKeyForAccount; import net.corda.samples.supplychain.contracts.ShippingRequestStateContract; import net.corda.samples.supplychain.states.ShippingRequestState; @@ -84,13 +85,8 @@ public String call() throws FlowException { ShippingRequestState output = new ShippingRequestState(new AnonymousParty(myKey),whereTo,shipper,cargo); // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flow or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); TransactionBuilder txbuilder = new TransactionBuilder(notary) .addOutputState(output) diff --git a/Accounts/supplychain/workflows/src/test/java/net/corda/samples/supplychain/FlowTests.java b/Accounts/supplychain/workflows/src/test/java/net/corda/samples/supplychain/FlowTests.java index 5dbb7cc6..5332c1fb 100644 --- a/Accounts/supplychain/workflows/src/test/java/net/corda/samples/supplychain/FlowTests.java +++ b/Accounts/supplychain/workflows/src/test/java/net/corda/samples/supplychain/FlowTests.java @@ -6,6 +6,7 @@ import com.r3.corda.lib.accounts.workflows.services.KeyManagementBackedAccountService; import net.corda.core.contracts.StateAndRef; import net.corda.core.contracts.UniqueIdentifier; +import net.corda.core.identity.CordaX500Name; import net.corda.core.node.NetworkParameters; import net.corda.core.node.services.Vault; import net.corda.core.node.services.vault.QueryCriteria; @@ -13,13 +14,11 @@ import net.corda.samples.supplychain.accountUtilities.ShareAccountTo; import net.corda.samples.supplychain.flows.SendInvoice; import net.corda.samples.supplychain.states.InvoiceState; -import net.corda.testing.node.MockNetwork; -import net.corda.testing.node.MockNetworkParameters; -import net.corda.testing.node.TestCordapp; +import net.corda.testing.node.*; import org.junit.After; import org.junit.Before; import org.junit.Test; -import net.corda.testing.node.StartedMockNode; + import java.util.*; import java.time.Instant; import java.util.concurrent.ExecutionException; @@ -42,7 +41,9 @@ public void setup() { TestCordapp.findCordapp("net.corda.samples.supplychain.contracts"), TestCordapp.findCordapp("net.corda.samples.supplychain.flows"), TestCordapp.findCordapp("com.r3.corda.lib.accounts.contracts"), - TestCordapp.findCordapp("com.r3.corda.lib.accounts.workflows"))).withNetworkParameters(testNetworkParameters)); + TestCordapp.findCordapp("com.r3.corda.lib.accounts.workflows"))).withNetworkParameters(testNetworkParameters) + .withNotarySpecs(ImmutableList.of(new MockNetworkNotarySpec(CordaX500Name.parse("O=Notary,L=London,C=GB")))) + ); a = network.createPartyNode(null); b = network.createPartyNode(null); network.runNetwork(); diff --git a/Accounts/tictacthor/README.md b/Accounts/tictacthor/README.md index b989e03f..5c388345 100644 --- a/Accounts/tictacthor/README.md +++ b/Accounts/tictacthor/README.md @@ -1,31 +1,36 @@ # Tic Tac Thor -This CorDapp recreates the game of Tic Tac Toe via Corda. It primarilly demonstrates how you can have [LinearState](https://docs.corda.net/docs/corda-os/api-states.html#linearstate) transactions between cross-node accounts. +This CorDapp recreates the game of Tic Tac Toe via Corda. It primarily demonstrates how you can have [LinearState](https://docs.corda.net/docs/corda-os/api-states.html#linearstate) transactions between cross-node accounts.

Corda

+ +## Pre-Requisites + +For development environment setup, please refer to: [Setup Guide](https://docs.r3.com/en/platform/corda/4.9/community/getting-set-up.html). + ## Running the sample Deploy and run the nodes by: ``` -./gradlew deployNodes +./gradlew clean build deployNodes ./build/nodes/runnodes ``` -Then you will need to also start the spring server for the Cordapp by running the following commands seperately: +Then you will need to also start the spring server for the CorDapp by running the following commands separately: `./gradlew bootRunDevRel`will have the DevRel server running on 8080 port , and `./gradlew bootRunSOE`will start the Solution Engineering server on 8090 port -## Operating the Cordapp -Now go to postman and excute the following in order: (All of the API are POST request!) +## Operating the CorDapp +Now go to postman and execute the following in order: (All the APIs are POST requests!) 1. Create an account on DevRel node: `http://localhost:8080/createAccount/PeterLi` 2. Create an account on SoE node: `http://localhost:8090/createAccount/DavidWinner` 3. Peter now requests game with David: `http://localhost:8080/requestGameWith/PeterLi/SolutionEng/DavidWinner` -4. David has to accept the challenege: `http://localhost:8090/acceptGameInvite/DavidWinner/DevRel/PeterLi` +4. David has to accept the challenge: `http://localhost:8090/acceptGameInvite/DavidWinner/DevRel/PeterLi` 5. Game Starts, and Peter makes the first move: `http://localhost:8080/startGameAndFirstMove/PeterLi/DavidWinner/0` 6. David's turn: `http://localhost:8090/submitMove/DavidWinner/PeterLi/4` API Syntax: `http://localhost:8080/submitMove/WHO-AM-I/MY-COUNTERPART/POSITION` -From here, you can start play the game by changing the very last number from the `submitMove`API call. The game board is representated by an 1-D array: What we just ran can transfer into a tic-tac-toe game board like the one we see on the right. +From here, you can start play the game by changing the very last number from the `submitMove`API call. The game board is represented by an 1-D array: What we just ran can transfer into a tic-tac-toe game board like the one we see on the right. ``` │0│1│2│ │O│ │ │ │3│4│5│ -> │ │X│ │ @@ -34,7 +39,7 @@ From here, you can start play the game by changing the very last number from the The Game will automatically end when one player wins the game. You can also run `run vaultQuery contractStateType: net.corda.samples.tictacthor.states.BoardState` at any given time to see the board games stored in vault. -now if you want to fast forward the game, Play the following moves in order: +now if you want to fast-forward the game, Play the following moves in order: According to syntax: we should have `http://localhost:8080/submitMove/PeterLi/DavidWinner/3` for the first move below. ``` * Peter: 3 │O│ │ │ @@ -49,7 +54,7 @@ We can play a bit more about the accounts. Now let's create two accounts, a new * Create an account on SoE node: `http://localhost:8090/createAccount/ThorG` Now, try to have Anthony play a game with Thor while start a new game between Peter and David. It worked! -One key feature about account is that, each account's data is segregated, meaning that it can be enforced that each account will not be able to see other account's data. In this sample cordapp, the game is queried by account name. Therefore, we see that each account only knows about the game that he participated. Account Peter doesn't know anything about the game between Thor and Anthony. +One key feature about account is that, each account's data is segregated, meaning that it can be enforced that each account will not be able to see other account's data. In this sample CorDapp, the game is queried by account name. Therefore, we see that each account only knows about the game that he participated. Account Peter doesn't know anything about the game between Thor and Anthony. ## Credit This project is inspired and evolved from a simple [tic-tac-toe](https://github.com/thorgilman/tictactoe) game on Corda by Thor Gilman. diff --git a/Accounts/tictacthor/build.gradle b/Accounts/tictacthor/build.gradle index 3c1b415c..b33c32b0 100644 --- a/Accounts/tictacthor/build.gradle +++ b/Accounts/tictacthor/build.gradle @@ -31,8 +31,8 @@ buildscript { repositories { mavenLocal() mavenCentral() - jcenter() - maven { url 'https://software.r3.com/artifactory/corda-releases' } + + maven { url 'https://download.corda.net/maven/corda-releases' } } dependencies { @@ -50,12 +50,12 @@ allprojects { repositories { mavenLocal() - jcenter() + mavenCentral() - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } maven { url 'https://jitpack.io' } //SDK lib - maven { url 'https://software.r3.com/artifactory/corda-lib' } + maven { url 'https://download.corda.net/maven/corda-lib' } //Gradle Plugins maven { url 'https://repo.gradle.org/gradle/libs-releases' } } @@ -100,6 +100,7 @@ dependencies { cordaCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" cordaCompile "org.apache.logging.log4j:log4j-web:${log4j_version}" cordaCompile "org.slf4j:jul-to-slf4j:$slf4j_version" + cordaDriver "net.corda:corda-shell:4.10" //Account lib cordapp "$confidential_id_release_group:ci-workflows:$confidential_id_release_version" @@ -117,7 +118,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { cordapp("$confidential_id_release_group:ci-workflows:$confidential_id_release_version") cordapp("$accounts_release_group:accounts-contracts:$accounts_release_version") cordapp("$accounts_release_group:accounts-workflows:$accounts_release_version") - runSchemaMigration = true + runSchemaMigration = true } node { name "O=Notary,L=London,C=GB" diff --git a/Accounts/tictacthor/clients/build.gradle b/Accounts/tictacthor/clients/build.gradle index 5bc011bd..bbba1aea 100644 --- a/Accounts/tictacthor/clients/build.gradle +++ b/Accounts/tictacthor/clients/build.gradle @@ -8,6 +8,12 @@ sourceSets { } } +configurations { + all { + exclude group: 'ch.qos.logback', module: 'logback-classic' + } +} + dependencies { // Corda dependencies. compile "$corda_release_group:corda-rpc:$corda_release_version" diff --git a/Accounts/tictacthor/repositories.gradle b/Accounts/tictacthor/repositories.gradle index 206b9c68..8be7b630 100644 --- a/Accounts/tictacthor/repositories.gradle +++ b/Accounts/tictacthor/repositories.gradle @@ -1,8 +1,8 @@ repositories { mavenLocal() mavenCentral() - jcenter() + maven { url 'https://jitpack.io' } - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } maven { url 'https://repo.gradle.org/gradle/libs-releases' } } diff --git a/Accounts/tictacthor/workflows/src/main/java/net/corda/samples/tictacthor/flows/EndGameFlow.java b/Accounts/tictacthor/workflows/src/main/java/net/corda/samples/tictacthor/flows/EndGameFlow.java index bc6bb5f4..3f9d6ab6 100644 --- a/Accounts/tictacthor/workflows/src/main/java/net/corda/samples/tictacthor/flows/EndGameFlow.java +++ b/Accounts/tictacthor/workflows/src/main/java/net/corda/samples/tictacthor/flows/EndGameFlow.java @@ -6,6 +6,7 @@ import com.r3.corda.lib.accounts.workflows.flows.RequestKeyForAccount; import com.r3.corda.lib.accounts.workflows.services.KeyManagementBackedAccountService; import com.sun.istack.NotNull; +import net.corda.core.identity.CordaX500Name; import net.corda.samples.tictacthor.accountUtilities.NewKeyForAccount; import net.corda.samples.tictacthor.contracts.BoardContract; import net.corda.samples.tictacthor.states.BoardState; @@ -94,13 +95,8 @@ public String call() throws FlowException { //generating State for transfer // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flow or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + Party notary = inputBoardStateAndRef.getState().getNotary(); TransactionBuilder txbuilder = new TransactionBuilder(notary) .addInputState(inputBoardStateAndRef) diff --git a/Accounts/tictacthor/workflows/src/main/java/net/corda/samples/tictacthor/flows/StartGameFlow.java b/Accounts/tictacthor/workflows/src/main/java/net/corda/samples/tictacthor/flows/StartGameFlow.java index 4a6f0e0b..76ba4367 100644 --- a/Accounts/tictacthor/workflows/src/main/java/net/corda/samples/tictacthor/flows/StartGameFlow.java +++ b/Accounts/tictacthor/workflows/src/main/java/net/corda/samples/tictacthor/flows/StartGameFlow.java @@ -6,6 +6,7 @@ import com.r3.corda.lib.accounts.workflows.flows.RequestKeyForAccount; import com.r3.corda.lib.accounts.workflows.services.KeyManagementBackedAccountService; import com.sun.istack.NotNull; +import net.corda.core.identity.CordaX500Name; import net.corda.samples.tictacthor.accountUtilities.NewKeyForAccount; import net.corda.samples.tictacthor.contracts.BoardContract; import net.corda.samples.tictacthor.states.BoardState; @@ -93,13 +94,8 @@ public UniqueIdentifier call() throws FlowException { targetAcctAnonymousParty); // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flow or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); TransactionBuilder txbuilder = new TransactionBuilder(notary) .addOutputState(initialBoardState) diff --git a/Accounts/tictacthor/workflows/src/main/java/net/corda/samples/tictacthor/flows/SubmitTurnFlow.java b/Accounts/tictacthor/workflows/src/main/java/net/corda/samples/tictacthor/flows/SubmitTurnFlow.java index dbfed5a4..477f3a6a 100644 --- a/Accounts/tictacthor/workflows/src/main/java/net/corda/samples/tictacthor/flows/SubmitTurnFlow.java +++ b/Accounts/tictacthor/workflows/src/main/java/net/corda/samples/tictacthor/flows/SubmitTurnFlow.java @@ -106,13 +106,7 @@ public String call() throws FlowException { BoardState outputBoardState = inputBoardState.returnNewBoardAfterMove(new Pair<>(x,y),new AnonymousParty(myKey), targetAcctAnonymousParty); // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flow or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + Party notary = inputBoardStateAndRef.getState().getNotary(); TransactionBuilder txbuilder = new TransactionBuilder(notary) .addInputState(inputBoardStateAndRef) diff --git a/Accounts/tictacthor/workflows/src/test/java/net/corda/samples/tictacthor/FlowTests.java b/Accounts/tictacthor/workflows/src/test/java/net/corda/samples/tictacthor/FlowTests.java index 841c3ca0..71f10d38 100644 --- a/Accounts/tictacthor/workflows/src/test/java/net/corda/samples/tictacthor/FlowTests.java +++ b/Accounts/tictacthor/workflows/src/test/java/net/corda/samples/tictacthor/FlowTests.java @@ -6,19 +6,18 @@ import com.r3.corda.lib.accounts.workflows.services.KeyManagementBackedAccountService; import net.corda.core.contracts.StateAndRef; import net.corda.core.contracts.UniqueIdentifier; +import net.corda.core.identity.CordaX500Name; import net.corda.core.node.NetworkParameters; import net.corda.core.node.services.vault.QueryCriteria; import net.corda.samples.tictacthor.accountUtilities.CreateNewAccount; import net.corda.samples.tictacthor.accountUtilities.ShareAccountTo; import net.corda.samples.tictacthor.flows.StartGameFlow; import net.corda.samples.tictacthor.states.BoardState; -import net.corda.testing.node.MockNetwork; -import net.corda.testing.node.MockNetworkParameters; -import net.corda.testing.node.TestCordapp; +import net.corda.testing.node.*; import org.junit.After; import org.junit.Before; import org.junit.Test; -import net.corda.testing.node.StartedMockNode; + import java.util.*; import java.time.Instant; import java.util.concurrent.ExecutionException; @@ -40,7 +39,9 @@ public void setup() { TestCordapp.findCordapp("net.corda.samples.tictacthor.contracts"), TestCordapp.findCordapp("net.corda.samples.tictacthor.flows"), TestCordapp.findCordapp("com.r3.corda.lib.accounts.contracts"), - TestCordapp.findCordapp("com.r3.corda.lib.accounts.workflows"))).withNetworkParameters(testNetworkParameters)); + TestCordapp.findCordapp("com.r3.corda.lib.accounts.workflows"))).withNetworkParameters(testNetworkParameters) + .withNotarySpecs(ImmutableList.of(new MockNetworkNotarySpec(CordaX500Name.parse("O=Notary,L=London,C=GB")))) + ); a = network.createPartyNode(null); b = network.createPartyNode(null); network.runNetwork(); diff --git a/Accounts/worldcupticketbooking/README.md b/Accounts/worldcupticketbooking/README.md index 5cf3797a..324533db 100644 --- a/Accounts/worldcupticketbooking/README.md +++ b/Accounts/worldcupticketbooking/README.md @@ -1,4 +1,4 @@ -# T20 Cricket World Cup Ticket Booking Cordapp [](https://ide.corda.net/?folder=/home/coder/samples-java/Accounts/worldcupticketbooking) +# T20 Cricket World Cup Ticket Booking CorDapp ## Introduction @@ -11,10 +11,10 @@ of the tickets on Corda Platform. Nodes: * BCCI node: source of ticket creation. All the tickets in the market are created by this node. -* Bank Node: souce of money. All the money that is transacted between each individual is issued by this node. +* Bank Node: source of money. All the money that is transacted between each individual is issued by this node. * Dealer1 Node: Dealer Agency 1 and it includes - * agent1 account: who will get ticket from the BCCI and sell to others. (To demostrate same node account token transaction.) - * buyer1 account: who will get the ticket from agent1 and later sell to buyer3 (To demostrate cross node account token transaction) + * agent1 account: who will get ticket from the BCCI and sell to others. (To demonstrate same node account token transaction.) + * buyer1 account: who will get the ticket from agent1 and later sell to buyer3 (To demonstrate cross node account token transaction) * buyer2 account: who will buy the ticket from buyer3. * Dealer2 Node: Dealer Agency 2 and it includes * buyer3 account: who will get the ticket from buyer1 and sell to buyer2 @@ -23,41 +23,49 @@ Nodes: Corda

+## Pre-Requisites + +For development environment setup, please refer to: [Setup Guide](https://docs.r3.com/en/platform/corda/4.9/community/getting-set-up.html). + +## Running the sample +Deploy and run the nodes by: +``` +./gradlew clean build deployNodes +./build/nodes/runnodes +``` ### Step 1 +Run the below flow in Dealer1's interactive node shell. This will create the agent1, buyer1 and buyer2 accounts on the Dealer1 node and share this account info with BCCI, Bank, and Dealer2 node respectively. ``` flow start CreateAndShareAccountFlow accountName: agent1, partyToShareAccountInfoToList: [BCCI, Dealer2] flow start CreateAndShareAccountFlow accountName: buyer1, partyToShareAccountInfoToList: [Bank, Dealer2] flow start CreateAndShareAccountFlow accountName: buyer2, partyToShareAccountInfoToList: [Bank, Dealer2] ``` -Run the above flow on the Dealer1 node. This will create the agent1, buyer1 and buyer2 accounts on the Dealer1 node and share this account info with BCCI, Bank, and Dealer2 node respecticely. -Then let's go to the Dealer2 node and create buyer3 account: +Then let's go to the Dealer2 interactive node shell and create buyer3 account: ``` flow start CreateAndShareAccountFlow accountName: buyer3, partyToShareAccountInfoToList: [Bank, Dealer1] ``` -Run the below query to confirm if accounts are created on Dealer1 node. Also run the above query on Bank and BCCI node to confirm if account info is shared with these nodes. +Run the below query to confirm if accounts are created on Dealer1 node. Also run the below query on Bank and BCCI's interactive node shell to confirm if account info is shared with these nodes. run vaultQuery contractStateType : com.r3.corda.lib.accounts.contracts.states.AccountInfo - - ### Step 2 +Run the below command on the Bank's interactive node shell, which will issue 20 USD to buyer1 account. ``` start IssueCashFlow accountName : buyer1 , currency : USD , amount : 10 start IssueCashFlow accountName : buyer3 , currency : USD , amount : 20 start IssueCashFlow accountName : buyer2 , currency : USD , amount : 50 ``` -Run the above command on the Bank node, which will issue 20 USD to buyer1 account. ### Step 3 ``` flow start QuerybyAccount whoAmI: buyer1 ``` -You can check balance of buyer1 account at Dealer1's node -[Option] You can also run the below command to confirm if 20 USD fungible tokens are stored at Dealer1's node. The current holder field in the output will be an [AnonymousParty](https://docs.corda.net/docs/corda-os/4.4/api-identity.html#party) which specifies an account. +You can check balance of buyer1 account at Dealer1's interactive node shell. +[Option] You can also run the below command to confirm if 20 USD fungible tokens are stored at Dealer1's node. The current holder field in the output will be an [AnonymousParty](https://docs.r3.com/en/platform/corda/4.9/community/api-identity.html) which specifies an account. ``` run vaultQuery contractStateType : com.r3.corda.lib.tokens.contracts.states.FungibleToken ``` @@ -65,25 +73,27 @@ run vaultQuery contractStateType : com.r3.corda.lib.tokens.contracts.states.Fung ### Step 4 +Run the below flow on BCCI's node. BCCI node will create base token type for the T20 Ticket for the match MumbaiIndians Vs RajasthanRoyals. The ticket ID returned from this flow will be needed in the next steps. + start CreateT20CricketTicketTokenFlow ticketTeam : MumbaiIndiansVsRajasthanRoyals -Run the above flow on BCCI's node. BCCI node will create base token type for the T20 Ticket for the match MumbaiIndians Vs RajasthanRoyals. The ticket ID returned from this flow will be needed in the next steps. -You can see your ticket state generated via vault query at the BCCI'd node: +You can see your ticket state generated via vault query at the BCCI's node: run vaultQuery contractStateType : com.t20worldcup.states.T20CricketTicket ### Step 5 +Run the below flow on BCCI's node to issue a non-fungible token based off the token type which we created in Step5. You will need to replace the `` with the uuid returned from step 6. This token will be issued by the BCCI node to agent1 account on Dealer1 node. + start IssueNonFungibleTicketFlow tokenId : , dealerAccountName : agent1 -Run the above flow on BCCI's node to issue a non fungible token based off the token type which we created in Step5. You will need to replace the `` with the uuid returned from step 6. This token will be issued by the BCCI node to agent1 account on Dealer1 node. Switching to the Dealer1's node, you can run the following code to confirm if the token has been issued to the dealer1 account. ``` flow start QuerybyAccount whoAmI: agent1 ``` -You can also look for the acutal state that is recoreded by: +You can also look for the actual state that is recorded by: run vaultQuery contractStateType : com.r3.corda.lib.tokens.contracts.states.NonFungibleToken Note that, the current holder it will be a key representing the account. @@ -97,7 +107,7 @@ flow start DVPAccountsOnSameNode tokenId: , buyerAccountName This is the DVP flow where the buyer(buyer1 account on Dealer1 node) account will pay cash to seller account(agent1 account on Dealer1 node), and the seller account will transfer the ticket token to the buyer. Again, replace the `` with the uuid generated in step 6. ### Step 7 -Now lets continue the flow logic to intiate an ticket sale between buyer1 and buyer3. Go to Dealer2 node and run the following code: +Now let's continue the flow logic to initiate a ticket sale between buyer1 and buyer3. Go to Dealer2 node and run the following code: ``` flow start DVPAccountsHostedOnDifferentNodes tokenId: , buyerAccountName: buyer3, sellerAccountName: buyer1, costOfTicket: 10, currency: USD @@ -130,30 +140,32 @@ For someone who is looking into how to only transfer tokens from one account to ### Step 1 +Run the below flow on the Dealer1 node. This will create the agent1, buyer1 and buyer2 accounts on the Dealer1 node and share this account info with BCCI, Bank, and Dealer2 node respectively. + ``` flow start CreateAndShareAccountFlow accountName: agent1, partyToShareAccountInfoToList: [BCCI, Dealer2] flow start CreateAndShareAccountFlow accountName: buyer1, partyToShareAccountInfoToList: [Bank, Dealer2] flow start CreateAndShareAccountFlow accountName: buyer2, partyToShareAccountInfoToList: [Bank, Dealer2] ``` -Run the above flow on the Dealer1 node. This will create the agent1, buyer1 and buyer2 accounts on the Dealer1 node and share this account info with BCCI, Bank, and Dealer2 node respecticely. Then let's go to the Dealer2 node and create buyer3 account: ``` flow start CreateAndShareAccountFlow accountName: buyer3, partyToShareAccountInfoToList: [Bank, Dealer1] ``` -Run the below query to confirm if accounts are created on Dealer1 node. Also run the above query on Bank and BCCI node to confirm if account info is shared with these nodes. +Run the below query to confirm if accounts are created on Dealer1 node. Also run the below query on Bank and BCCI node to confirm if account info is shared with these nodes. run vaultQuery contractStateType : com.r3.corda.lib.accounts.contracts.states.AccountInfo ### Step 2 +Run the below command on the Bank node, which will issue 77 USD to buyer1 account. + ``` start IssueCashFlow accountName : buyer1 , currency : USD , amount : 77 ``` -Run the above command on the Bank node, which will issue 77 USD to buyer1 account. ### Step 3 ``` diff --git a/Accounts/worldcupticketbooking/build.gradle b/Accounts/worldcupticketbooking/build.gradle index 482c3164..e567053f 100644 --- a/Accounts/worldcupticketbooking/build.gradle +++ b/Accounts/worldcupticketbooking/build.gradle @@ -36,8 +36,8 @@ buildscript { repositories { mavenLocal() mavenCentral() - jcenter() - maven { url 'https://software.r3.com/artifactory/corda-releases' } + + maven { url 'https://download.corda.net/maven/corda-releases' } // maven { url 'http://software.r3.com/artifactory/corda-lib-dev' } maven { url 'http://software.r3.com/artifactory/corda-lib' } } @@ -57,12 +57,12 @@ allprojects { repositories { mavenLocal() - jcenter() + mavenCentral() - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } // Can be removed post-release - used to get nightly snapshot build. - maven { url 'https://software.r3.com/artifactory/corda-lib' } - maven { url 'https://software.r3.com/artifactory/corda-lib-dev' } + maven { url 'https://download.corda.net/maven/corda-lib' } + maven { url 'https://download.corda.net/maven/corda-lib-dev' } // maven { url 'https://jitpack.io' } maven { url "https://repo.gradle.org/gradle/libs-releases-local" } } @@ -107,6 +107,7 @@ dependencies { cordaCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" cordaCompile "org.apache.logging.log4j:log4j-web:${log4j_version}" cordaCompile "org.slf4j:jul-to-slf4j:$slf4j_version" + cordaDriver "net.corda:corda-shell:4.10" //accounts cordapp "$accounts_release_group:accounts-contracts:$accounts_release_version" diff --git a/Accounts/worldcupticketbooking/clients/build.gradle b/Accounts/worldcupticketbooking/clients/build.gradle index bfed0e1f..c6be5398 100644 --- a/Accounts/worldcupticketbooking/clients/build.gradle +++ b/Accounts/worldcupticketbooking/clients/build.gradle @@ -8,6 +8,12 @@ sourceSets { } } +configurations { + all { + exclude group: 'ch.qos.logback', module: 'logback-classic' + } +} + dependencies { // Corda dependencies. compile "$corda_release_group:corda-rpc:$corda_release_version" diff --git a/Accounts/worldcupticketbooking/repositories.gradle b/Accounts/worldcupticketbooking/repositories.gradle index e4688fa4..072b616b 100644 --- a/Accounts/worldcupticketbooking/repositories.gradle +++ b/Accounts/worldcupticketbooking/repositories.gradle @@ -1,9 +1,9 @@ repositories { mavenLocal() mavenCentral() - jcenter() + maven { url 'https://jitpack.io' } - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } maven { url 'https://repo.gradle.org/gradle/libs-releases' } maven { url 'http://software.r3.com/artifactory/corda-lib-dev' } maven { url 'http://software.r3.com/artifactory/corda-lib' } diff --git a/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/CreateT20CricketTicketTokenFlow.java b/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/CreateT20CricketTicketTokenFlow.java index fd119752..f75f0d25 100644 --- a/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/CreateT20CricketTicketTokenFlow.java +++ b/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/CreateT20CricketTicketTokenFlow.java @@ -11,6 +11,7 @@ import net.corda.core.flows.StartableByRPC; import net.corda.core.identity.Party; import net.corda.core.transactions.SignedTransaction; +import net.corda.core.identity.CordaX500Name; /** * This flow should be run by BCCI node. BCCI node will take care of issuing the base token type for the Ipl ticket. The token type will be craeted on the BCCI node @@ -31,13 +32,8 @@ public CreateT20CricketTicketTokenFlow(String ticketTeam) { @Suspendable public String call() throws FlowException { // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flow or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); //create token type by passing in the name of the ipl match. specify the maintainer as BCCI UniqueIdentifier id = new UniqueIdentifier(); diff --git a/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/DVPAccountsHostedOnDifferentNodes.java b/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/DVPAccountsHostedOnDifferentNodes.java index cb862e8d..39243ab4 100644 --- a/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/DVPAccountsHostedOnDifferentNodes.java +++ b/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/DVPAccountsHostedOnDifferentNodes.java @@ -229,13 +229,7 @@ public Void call() throws FlowException { TokenPointer tokenPointer = evolvableTokenType.toPointer(evolvableTokenType.getClass()); // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flow or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + Party notary = stateAndRef.getState().getNotary(); TransactionBuilder transactionBuilder = new TransactionBuilder(notary); diff --git a/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/DVPAccountsOnSameNode.java b/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/DVPAccountsOnSameNode.java index 977cb472..e71721e7 100644 --- a/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/DVPAccountsOnSameNode.java +++ b/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/DVPAccountsOnSameNode.java @@ -105,13 +105,7 @@ public String call() throws FlowException { TokenPointer tokenPointer = evolvableTokenType.toPointer(evolvableTokenType.getClass()); // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flow or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + Party notary = stateAndRef.getState().getNotary(); //create a transactionBuilder TransactionBuilder transactionBuilder = new TransactionBuilder(notary); diff --git a/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/MoveTokensBetweenAccounts.java b/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/MoveTokensBetweenAccounts.java index b2daf738..c2f0ffb2 100644 --- a/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/MoveTokensBetweenAccounts.java +++ b/Accounts/worldcupticketbooking/workflows/src/main/java/com/t20worldcup/flows/MoveTokensBetweenAccounts.java @@ -19,6 +19,7 @@ import net.corda.core.flows.*; import net.corda.core.identity.AbstractParty; import net.corda.core.identity.AnonymousParty; +import net.corda.core.identity.CordaX500Name; import net.corda.core.identity.Party; import net.corda.core.node.services.vault.QueryCriteria; import net.corda.core.transactions.SignedTransaction; @@ -88,8 +89,9 @@ public String call() throws FlowException { Pair>, List> inputsAndOutputs = tokenSelection.generateMove(Arrays.asList(partyAndAmount), buyerAccount, new TokenQueryBy(), getRunId().getUuid()); - Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); - + // Obtain a reference to a notary we wish to use. + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); TransactionBuilder transactionBuilder = new TransactionBuilder(notary); MoveTokensUtilitiesKt.addMoveTokens(transactionBuilder, inputsAndOutputs.getFirst(), inputsAndOutputs.getSecond()); diff --git a/Advanced/auction-cordapp/build.gradle b/Advanced/auction-cordapp/build.gradle index a78a991d..4d87e6dc 100644 --- a/Advanced/auction-cordapp/build.gradle +++ b/Advanced/auction-cordapp/build.gradle @@ -20,8 +20,9 @@ buildscript { repositories { mavenLocal() mavenCentral() - jcenter() - maven { url 'https://software.r3.com/artifactory/corda' } + + maven { url 'https://download.corda.net/maven/corda-dependencies' } + maven { url 'https://download.corda.net/maven/corda-releases' } } dependencies { @@ -37,9 +38,10 @@ allprojects { repositories { mavenLocal() - jcenter() + mavenCentral() - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } + maven { url 'https://download.corda.net/maven/corda-releases' } maven { url 'https://jitpack.io' } maven { url 'https://repo.gradle.org/gradle/libs-releases' } } @@ -87,6 +89,9 @@ dependencies { cordaCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" cordaCompile "org.apache.logging.log4j:log4j-web:${log4j_version}" cordaCompile "org.slf4j:jul-to-slf4j:$slf4j_version" + + cordaDriver "net.corda:corda-shell:4.10" + } task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { diff --git a/Advanced/auction-cordapp/client/build.gradle b/Advanced/auction-cordapp/client/build.gradle index e9184696..e94a0e39 100644 --- a/Advanced/auction-cordapp/client/build.gradle +++ b/Advanced/auction-cordapp/client/build.gradle @@ -1,5 +1,11 @@ apply plugin: 'org.springframework.boot' +configurations { + all { + exclude group: 'ch.qos.logback', module: 'logback-classic' + } +} + dependencies { // Corda dependencies. compile "$corda_release_group:corda-rpc:$corda_release_version" diff --git a/Advanced/auction-cordapp/contracts/build.gradle b/Advanced/auction-cordapp/contracts/build.gradle index 6d9813f8..d35b4df3 100644 --- a/Advanced/auction-cordapp/contracts/build.gradle +++ b/Advanced/auction-cordapp/contracts/build.gradle @@ -23,7 +23,7 @@ dependencies { // Corda dependencies. cordaCompile "$corda_core_release_group:corda-core:$corda_core_release_version" - compileOnly "$corda_release_group:corda-testserver-impl:$corda_release_version" + cordaRuntime "$corda_release_group:corda:$corda_release_version" cordaRuntime "$corda_release_group:corda-testserver:$corda_release_version" diff --git a/Advanced/auction-cordapp/workflows/src/main/java/net/corda/samples/auction/flows/AuctionDvPFlow.java b/Advanced/auction-cordapp/workflows/src/main/java/net/corda/samples/auction/flows/AuctionDvPFlow.java index da3b9a06..e4321c63 100644 --- a/Advanced/auction-cordapp/workflows/src/main/java/net/corda/samples/auction/flows/AuctionDvPFlow.java +++ b/Advanced/auction-cordapp/workflows/src/main/java/net/corda/samples/auction/flows/AuctionDvPFlow.java @@ -79,13 +79,8 @@ public SignedTransaction call() throws FlowException { .withNewOwner(auctionState.getWinner()); // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = auctionStateAndRef.getState().getNotary(); // Create the transaction builder. TransactionBuilder transactionBuilder = new TransactionBuilder(notary); diff --git a/Advanced/auction-cordapp/workflows/src/main/java/net/corda/samples/auction/flows/CreateAssetFlow.java b/Advanced/auction-cordapp/workflows/src/main/java/net/corda/samples/auction/flows/CreateAssetFlow.java index 2d66e502..dc95df45 100644 --- a/Advanced/auction-cordapp/workflows/src/main/java/net/corda/samples/auction/flows/CreateAssetFlow.java +++ b/Advanced/auction-cordapp/workflows/src/main/java/net/corda/samples/auction/flows/CreateAssetFlow.java @@ -8,6 +8,7 @@ import net.corda.core.transactions.TransactionBuilder; import net.corda.samples.auction.contracts.AssetContract; import net.corda.samples.auction.states.Asset; +import net.corda.core.identity.CordaX500Name; import java.util.Arrays; import java.util.Collections; @@ -42,13 +43,8 @@ public CreateAssetFlow(String title, String description, String imageURL) { @Suspendable public SignedTransaction call() throws FlowException { // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // Create the output states Asset output = new Asset(new UniqueIdentifier(), title, description, imageURL, diff --git a/Advanced/auction-cordapp/workflows/src/main/java/net/corda/samples/auction/flows/CreateAuctionFlow.java b/Advanced/auction-cordapp/workflows/src/main/java/net/corda/samples/auction/flows/CreateAuctionFlow.java index e78675c0..b9b1ccd8 100644 --- a/Advanced/auction-cordapp/workflows/src/main/java/net/corda/samples/auction/flows/CreateAuctionFlow.java +++ b/Advanced/auction-cordapp/workflows/src/main/java/net/corda/samples/auction/flows/CreateAuctionFlow.java @@ -7,12 +7,14 @@ import net.corda.core.contracts.LinearState; import net.corda.core.contracts.UniqueIdentifier; import net.corda.core.flows.*; +import net.corda.core.identity.CordaX500Name; 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 net.corda.samples.auction.contracts.AuctionContract; import net.corda.samples.auction.states.AuctionState; +import net.corda.core.identity.CordaX500Name; import java.time.LocalDateTime; import java.time.ZoneId; @@ -56,13 +58,8 @@ public ProgressTracker getProgressTracker() { @Override public SignedTransaction call() throws FlowException { // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flow or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); Party auctioneer = getOurIdentity(); diff --git a/Advanced/auction-cordapp/workflows/src/test/java/net/corda/samples/auction/FlowTests.java b/Advanced/auction-cordapp/workflows/src/test/java/net/corda/samples/auction/FlowTests.java index 50814f39..58b2a115 100644 --- a/Advanced/auction-cordapp/workflows/src/test/java/net/corda/samples/auction/FlowTests.java +++ b/Advanced/auction-cordapp/workflows/src/test/java/net/corda/samples/auction/FlowTests.java @@ -3,16 +3,14 @@ import com.google.common.collect.ImmutableList; import net.corda.core.concurrent.CordaFuture; import net.corda.core.contracts.Amount; +import net.corda.core.identity.CordaX500Name; import net.corda.core.node.NetworkParameters; import net.corda.core.transactions.SignedTransaction; import net.corda.samples.auction.flows.CreateAssetFlow; import net.corda.samples.auction.flows.CreateAuctionFlow; import net.corda.samples.auction.states.Asset; import net.corda.samples.auction.states.AuctionState; -import net.corda.testing.node.MockNetwork; -import net.corda.testing.node.MockNetworkParameters; -import net.corda.testing.node.StartedMockNode; -import net.corda.testing.node.TestCordapp; +import net.corda.testing.node.*; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -39,7 +37,8 @@ public void setup() { ) ).withNetworkParameters(new NetworkParameters(4, Collections.emptyList(), 10485760, 10485760 * 50, Instant.now(), 1, - Collections.emptyMap())) + Collections.emptyMap()) + ).withNotarySpecs(ImmutableList.of(new MockNetworkNotarySpec(CordaX500Name.parse("O=Notary,L=London,C=GB")))) ); a = network.createPartyNode(null); b = network.createPartyNode(null); diff --git a/Advanced/constants.properties b/Advanced/constants.properties index 9fad7a37..adcdb361 100644 --- a/Advanced/constants.properties +++ b/Advanced/constants.properties @@ -1,12 +1,12 @@ cordaReleaseGroup=net.corda cordaCoreReleaseGroup=net.corda -cordaVersion=4.8 -cordaCoreVersion=4.8 +cordaVersion=4.10 +cordaCoreVersion=4.10 gradlePluginsVersion=5.0.12 kotlinVersion=1.2.71 junitVersion=4.12 quasarVersion=0.7.10 -log4jVersion =2.11.2 -platformVersion=10 +log4jVersion =2.17.1 +platformVersion=12 slf4jVersion=1.7.25 nettyVersion=4.1.22.Final diff --git a/Advanced/duediligence-cordapp/build.gradle b/Advanced/duediligence-cordapp/build.gradle index 3c34d04e..ef682822 100644 --- a/Advanced/duediligence-cordapp/build.gradle +++ b/Advanced/duediligence-cordapp/build.gradle @@ -22,8 +22,8 @@ buildscript {//properties that you need to build the project repositories { mavenLocal() mavenCentral() - jcenter() - maven { url 'https://software.r3.com/artifactory/corda-releases' } + + maven { url 'https://download.corda.net/maven/corda-releases' } } dependencies { @@ -40,9 +40,9 @@ allprojects {//Properties that you need to compile your project (The application repositories { mavenLocal() - jcenter() + mavenCentral() - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } maven { url 'https://jitpack.io' } } @@ -83,6 +83,8 @@ dependencies { cordaCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" cordaCompile "org.apache.logging.log4j:log4j-web:${log4j_version}" cordaCompile "org.slf4j:jul-to-slf4j:$slf4j_version" + cordaDriver "net.corda:corda-shell:4.10" + } diff --git a/Advanced/duediligence-cordapp/clients/build.gradle b/Advanced/duediligence-cordapp/clients/build.gradle index ff114932..0585ba30 100644 --- a/Advanced/duediligence-cordapp/clients/build.gradle +++ b/Advanced/duediligence-cordapp/clients/build.gradle @@ -8,6 +8,12 @@ sourceSets { } } +configurations { + all { + exclude group: 'ch.qos.logback', module: 'logback-classic' + } +} + dependencies { // Corda dependencies. compile "$corda_release_group:corda-rpc:$corda_release_version" diff --git a/Advanced/duediligence-cordapp/repositories.gradle b/Advanced/duediligence-cordapp/repositories.gradle index 206b9c68..8be7b630 100644 --- a/Advanced/duediligence-cordapp/repositories.gradle +++ b/Advanced/duediligence-cordapp/repositories.gradle @@ -1,8 +1,8 @@ repositories { mavenLocal() mavenCentral() - jcenter() + maven { url 'https://jitpack.io' } - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } maven { url 'https://repo.gradle.org/gradle/libs-releases' } } diff --git a/Advanced/duediligence-cordapp/workflows/src/main/java/net/corda/samples/duediligence/flows/RequestToValidateCorporateRecords.java b/Advanced/duediligence-cordapp/workflows/src/main/java/net/corda/samples/duediligence/flows/RequestToValidateCorporateRecords.java index dd297df4..c8b20d09 100644 --- a/Advanced/duediligence-cordapp/workflows/src/main/java/net/corda/samples/duediligence/flows/RequestToValidateCorporateRecords.java +++ b/Advanced/duediligence-cordapp/workflows/src/main/java/net/corda/samples/duediligence/flows/RequestToValidateCorporateRecords.java @@ -8,6 +8,7 @@ import net.corda.core.transactions.TransactionBuilder; import net.corda.samples.duediligence.contracts.CorporateRecordsContract; import net.corda.samples.duediligence.states.CorporateRecordsAuditRequest; +import net.corda.core.identity.CordaX500Name; import java.util.Arrays; import java.util.List; @@ -33,7 +34,8 @@ public RequestToValidateCorporateRecordsInitiator(Party validater, int numberOfF @Override public String call() throws FlowException { //notary - Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); //Initiate Corporate Records validation CorporateRecordsAuditRequest cr = new CorporateRecordsAuditRequest(getOurIdentity(),this.validater,this.numberOfFiles); diff --git a/Advanced/duediligence-cordapp/workflows/src/test/java/net/corda/samples/duediligence/FlowTests.java b/Advanced/duediligence-cordapp/workflows/src/test/java/net/corda/samples/duediligence/FlowTests.java index 80b7ba7f..ae0438d4 100644 --- a/Advanced/duediligence-cordapp/workflows/src/test/java/net/corda/samples/duediligence/FlowTests.java +++ b/Advanced/duediligence-cordapp/workflows/src/test/java/net/corda/samples/duediligence/FlowTests.java @@ -4,14 +4,12 @@ import net.corda.core.contracts.ContractState; import net.corda.core.contracts.StateAndRef; import net.corda.core.contracts.UniqueIdentifier; +import net.corda.core.identity.CordaX500Name; import net.corda.core.node.services.Vault; import net.corda.core.node.services.vault.QueryCriteria; import net.corda.samples.duediligence.flows.RequestToValidateCorporateRecords; import net.corda.samples.duediligence.states.CorporateRecordsAuditRequest; -import net.corda.testing.node.MockNetwork; -import net.corda.testing.node.MockNetworkParameters; -import net.corda.testing.node.StartedMockNode; -import net.corda.testing.node.TestCordapp; +import net.corda.testing.node.*; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -20,7 +18,7 @@ import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -import static org.jgroups.util.Util.assertEquals; +import static org.junit.Assert.assertEquals; public class FlowTests { private MockNetwork network; @@ -31,7 +29,8 @@ public class FlowTests { public void setup() { network = new MockNetwork(new MockNetworkParameters().withCordappsForAllNodes(ImmutableList.of( TestCordapp.findCordapp("net.corda.samples.duediligence.contracts"), - TestCordapp.findCordapp("net.corda.samples.duediligence.flows")))); + TestCordapp.findCordapp("net.corda.samples.duediligence.flows"))) + .withNotarySpecs(ImmutableList.of(new MockNetworkNotarySpec(CordaX500Name.parse("O=Notary,L=London,C=GB"))))); a = network.createPartyNode(null); b = network.createPartyNode(null); network.runNetwork(); diff --git a/Advanced/negotiation-cordapp/build.gradle b/Advanced/negotiation-cordapp/build.gradle index ad92a9bd..d98cff3d 100644 --- a/Advanced/negotiation-cordapp/build.gradle +++ b/Advanced/negotiation-cordapp/build.gradle @@ -20,17 +20,17 @@ buildscript { } repositories { - jcenter() + mavenLocal() mavenCentral() - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } maven { url 'http://software.r3.com/artifactory/corda-lib' } maven { url 'http://software.r3.com/artifactory/corda-lib-dev' } - maven { url 'https://software.r3.com/artifactory/corda-releases' } + maven { url 'https://download.corda.net/maven/corda-releases' } // Corda dependencies for the patched Quasar version - maven { url "https://software.r3.com/artifactory/corda-dependencies" } // access to the patched Quasar version + maven { url "https://download.corda.net/maven/corda-dependencies" } // access to the patched Quasar version } dependencies { @@ -47,12 +47,12 @@ allprojects { repositories { mavenLocal() - jcenter() + mavenCentral() - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } // Can be removed post-release - used to get nightly snapshot build. - maven { url 'https://software.r3.com/artifactory/corda-lib' } - maven { url 'https://software.r3.com/artifactory/corda-lib-dev' } + maven { url 'https://download.corda.net/maven/corda-lib' } + maven { url 'https://download.corda.net/maven/corda-lib-dev' } maven { url 'https://jitpack.io' } maven { url "https://repo.gradle.org/gradle/libs-releases-local" } } @@ -94,6 +94,8 @@ dependencies { cordaCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" cordaCompile "org.apache.logging.log4j:log4j-web:${log4j_version}" cordaCompile "org.slf4j:jul-to-slf4j:$slf4j_version" + cordaDriver "net.corda:corda-shell:4.10" + } cordapp { @@ -111,6 +113,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { nodeDefaults { cordapp project(':contracts') + cordapp project(':workflows') runSchemaMigration = true } diff --git a/Advanced/negotiation-cordapp/repositories.gradle b/Advanced/negotiation-cordapp/repositories.gradle index 206b9c68..9797c0ea 100644 --- a/Advanced/negotiation-cordapp/repositories.gradle +++ b/Advanced/negotiation-cordapp/repositories.gradle @@ -1,8 +1,7 @@ repositories { mavenLocal() mavenCentral() - jcenter() maven { url 'https://jitpack.io' } - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } maven { url 'https://repo.gradle.org/gradle/libs-releases' } } diff --git a/Advanced/negotiation-cordapp/workflows/src/main/java/net/corda/samples/negotiation/flows/ProposalFlow.java b/Advanced/negotiation-cordapp/workflows/src/main/java/net/corda/samples/negotiation/flows/ProposalFlow.java index 8cefad5b..45def7ee 100644 --- a/Advanced/negotiation-cordapp/workflows/src/main/java/net/corda/samples/negotiation/flows/ProposalFlow.java +++ b/Advanced/negotiation-cordapp/workflows/src/main/java/net/corda/samples/negotiation/flows/ProposalFlow.java @@ -15,6 +15,7 @@ import java.security.PublicKey; import java.util.List; +import net.corda.core.identity.CordaX500Name; public class ProposalFlow { @InitiatingFlow @@ -51,13 +52,8 @@ public UniqueIdentifier call() throws FlowException { //Building the transaction // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flow or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); TransactionBuilder txBuilder = new TransactionBuilder(notary) .addOutputState(output, ProposalAndTradeContract.ID) diff --git a/Advanced/negotiation-cordapp/workflows/src/test/java/net/corda/samples/negotiation/flows/FlowTestBase.java b/Advanced/negotiation-cordapp/workflows/src/test/java/net/corda/samples/negotiation/flows/FlowTestBase.java index 55b905a4..d6e2fd85 100644 --- a/Advanced/negotiation-cordapp/workflows/src/test/java/net/corda/samples/negotiation/flows/FlowTestBase.java +++ b/Advanced/negotiation-cordapp/workflows/src/test/java/net/corda/samples/negotiation/flows/FlowTestBase.java @@ -2,14 +2,14 @@ import com.google.common.collect.ImmutableList; import net.corda.core.contracts.UniqueIdentifier; +import net.corda.core.identity.CordaX500Name; import net.corda.core.identity.Party; -import net.corda.testing.node.MockNetwork; -import net.corda.testing.node.MockNetworkParameters; -import net.corda.testing.node.StartedMockNode; -import net.corda.testing.node.TestCordapp; +import net.corda.testing.driver.VerifierType; +import net.corda.testing.node.*; import org.junit.After; import org.junit.Before; +import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -21,11 +21,11 @@ abstract class FlowTestBase { @Before public void setup() { - network = new MockNetwork(new MockNetworkParameters(ImmutableList.of( - TestCordapp.findCordapp("net.corda.samples.negotiation.flows"), - TestCordapp.findCordapp("net.corda.samples.negotiation.contracts") - ) - )); + network = new MockNetwork(new MockNetworkParameters( + ImmutableList.of( + TestCordapp.findCordapp("net.corda.samples.negotiation.flows"), + TestCordapp.findCordapp("net.corda.samples.negotiation.contracts")) + ).withNotarySpecs(ImmutableList.of(new MockNetworkNotarySpec(CordaX500Name.parse("O=Notary,L=London,C=GB"))))); a = network.createPartyNode(null); b = network.createPartyNode(null); diff --git a/Advanced/obligation-cordapp/README.md b/Advanced/obligation-cordapp/README.md index 87830236..952c7f9a 100644 --- a/Advanced/obligation-cordapp/README.md +++ b/Advanced/obligation-cordapp/README.md @@ -1,6 +1,6 @@ # Obligation Cordap -This Cordapp is the complete implementation of our signature IOU (I-owe-you) demonstration. +This CorDapp is the complete implementation of our signature IOU (I-owe-you) demonstration. ## Concepts @@ -9,12 +9,12 @@ An IOU is someone who has cash that is paying it back to someone they owe it to. ### Flows -The first flows are the ones that issue the original cash and assets. You can find that the cash flow at `SelfIssueCashFlow.java` and the IOU issurance in `IOUIssueFlow.java`. +The first flows are the ones that issue the original cash and assets. You can find that the cash flow at `SelfIssueCashFlow.java` and the IOU issuance in `IOUIssueFlow.java`. The next flow is the one that transfers ownership of that asset over to another party. That can be found in `IOUTransferFlow.java`. -Finally, once we have the ability to transfer assets, we just need to settle up. That functiionality can be found here in `IOUSettleFlow.java` +Finally, once we have the ability to transfer assets, we just need to settle up. That functionality can be found here in `IOUSettleFlow.java` diff --git a/Advanced/obligation-cordapp/build.gradle b/Advanced/obligation-cordapp/build.gradle index 9d873ac6..15bd2c09 100644 --- a/Advanced/obligation-cordapp/build.gradle +++ b/Advanced/obligation-cordapp/build.gradle @@ -22,8 +22,8 @@ buildscript { repositories { mavenLocal() mavenCentral() - jcenter() - maven { url 'https://software.r3.com/artifactory/corda-releases' } + + maven { url 'https://download.corda.net/maven/corda-releases' } } dependencies { @@ -41,9 +41,8 @@ allprojects { repositories { mavenLocal() - jcenter() mavenCentral() - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } maven { url 'https://jitpack.io' } } @@ -92,6 +91,8 @@ dependencies { cordaCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" cordaCompile "org.apache.logging.log4j:log4j-web:${log4j_version}" cordaCompile "org.slf4j:jul-to-slf4j:$slf4j_version" + cordaDriver "net.corda:corda-shell:4.10" + } cordapp { diff --git a/Advanced/obligation-cordapp/clients/build.gradle b/Advanced/obligation-cordapp/clients/build.gradle index bab14a2f..6bf3c08f 100644 --- a/Advanced/obligation-cordapp/clients/build.gradle +++ b/Advanced/obligation-cordapp/clients/build.gradle @@ -1,6 +1,6 @@ repositories { mavenLocal() - jcenter() + mavenCentral() maven { url 'https://jitpack.io' } maven { url 'https://ci-artifactory.corda.r3cev.com/artifactory/corda-releases' } @@ -26,6 +26,12 @@ dependencyManagement { } } +configurations { + all { + exclude group: 'ch.qos.logback', module: 'logback-classic' + } +} + dependencies { // CorDapp dependencies. compile project(":contracts") diff --git a/Advanced/obligation-cordapp/contracts/build.gradle b/Advanced/obligation-cordapp/contracts/build.gradle index 71bf133b..ae474abf 100644 --- a/Advanced/obligation-cordapp/contracts/build.gradle +++ b/Advanced/obligation-cordapp/contracts/build.gradle @@ -33,7 +33,6 @@ dependencies { cordaRuntime "$corda_release_group:corda:$corda_release_version" cordaCompile "$corda_release_group:corda-finance-contracts:$corda_release_version" cordaCompile "$corda_release_group:corda-finance-workflows:$corda_release_version" - compileOnly "$corda_release_group:corda-testserver-impl:$corda_release_version" testCompile "$corda_release_group:corda-node-driver:$corda_release_version" cordapp "$corda_release_group:corda-finance-contracts:$corda_release_version" cordapp "$corda_release_group:corda-finance-workflows:$corda_release_version" diff --git a/Advanced/obligation-cordapp/repositories.gradle b/Advanced/obligation-cordapp/repositories.gradle index 206b9c68..8be7b630 100644 --- a/Advanced/obligation-cordapp/repositories.gradle +++ b/Advanced/obligation-cordapp/repositories.gradle @@ -1,8 +1,8 @@ repositories { mavenLocal() mavenCentral() - jcenter() + maven { url 'https://jitpack.io' } - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } maven { url 'https://repo.gradle.org/gradle/libs-releases' } } diff --git a/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/IOUIssueFlow.java b/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/IOUIssueFlow.java index f068e2ed..9a608cf3 100644 --- a/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/IOUIssueFlow.java +++ b/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/IOUIssueFlow.java @@ -18,6 +18,7 @@ import net.corda.samples.obligation.contracts.IOUContract; import net.corda.samples.obligation.states.IOUState; import static net.corda.samples.obligation.contracts.IOUContract.Commands.*; +import net.corda.core.identity.CordaX500Name; /** * This is the flows which handles issuance of new IOUs on the ledger. @@ -39,14 +40,8 @@ public InitiatorFlow(IOUState state) { @Override public SignedTransaction call() throws FlowException { // Step 1. Get a reference to the notary service on our network and our key pair. - - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // Step 2. Create a new issue command. // Remember that a command is a CommandData object and a list of CompositeKeys diff --git a/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/IOUSettleFlow.java b/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/IOUSettleFlow.java index 0cf47b60..714a0d3e 100644 --- a/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/IOUSettleFlow.java +++ b/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/IOUSettleFlow.java @@ -68,13 +68,7 @@ public SignedTransaction call() throws FlowException { // Step 3. Create a transaction builder. // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + Party notary = inputStateAndRefToSettle.getState().getNotary(); TransactionBuilder tb = new TransactionBuilder(notary); diff --git a/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/IOUTransferFlow.java b/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/IOUTransferFlow.java index c29906f0..4186aabb 100644 --- a/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/IOUTransferFlow.java +++ b/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/IOUTransferFlow.java @@ -66,13 +66,7 @@ public SignedTransaction call() throws FlowException { // Here we get a reference to the default notary and instantiate a transaction builder. // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + Party notary = inputStateAndRefToTransfer.getState().getNotary(); TransactionBuilder tb = new TransactionBuilder(notary); diff --git a/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/SelfIssueCashFlow.java b/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/SelfIssueCashFlow.java index 4e5d69cb..2f0094dc 100644 --- a/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/SelfIssueCashFlow.java +++ b/Advanced/obligation-cordapp/workflows/src/main/java/net/corda/samples/obligation/flows/SelfIssueCashFlow.java @@ -9,6 +9,7 @@ import net.corda.finance.contracts.asset.Cash; import net.corda.finance.flows.CashIssueFlow; import java.util.Currency; +import net.corda.core.identity.CordaX500Name; @InitiatingFlow @StartableByRPC @@ -26,13 +27,8 @@ public Cash.State call() throws FlowException { OpaqueBytes issueRef = OpaqueBytes.of("1".getBytes()); // Obtain a reference to a notary we wish to use. - /** METHOD 1: Take first notary on network, WARNING: use for test, non-prod environments, and single-notary networks only!* - * METHOD 2: Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred) - * - * * - For production you always want to use Method 2 as it guarantees the expected notary is returned. - */ - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); // METHOD 1 - // final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); // METHOD 2 + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); /** Create the cash issuance transaction. */ SignedTransaction cashIssueTransaction = subFlow(new CashIssueFlow(amount, issueRef, notary)).getStx(); diff --git a/Advanced/secretsanta-cordapp/build.gradle b/Advanced/secretsanta-cordapp/build.gradle index d67642c8..622a2636 100644 --- a/Advanced/secretsanta-cordapp/build.gradle +++ b/Advanced/secretsanta-cordapp/build.gradle @@ -28,11 +28,10 @@ buildscript { //properties that you need to build the project repositories { mavenLocal() mavenCentral() - jcenter() maven { url 'https://jitpack.io' } maven { url 'https://repo.gradle.org/gradle/libs-releases' } maven { url 'http://software.r3.com/artifactory/corda-lib' } - maven { url 'https://software.r3.com/artifactory/corda-releases' } + maven { url 'https://download.corda.net/maven/corda-releases' } } dependencies { @@ -53,10 +52,10 @@ allprojects {//Properties that you need to compile your project (The application repositories { mavenLocal() - jcenter() + mavenCentral() maven { url 'https://jitpack.io' } - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } } tasks.withType(JavaCompile) { @@ -106,6 +105,8 @@ dependencies { cordaCompile "org.slf4j:jul-to-slf4j:$slf4j_version" cordaCompile "org.apache.logging.log4j:log4j-web:${log4j_version}" cordaCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" + cordaDriver "net.corda:corda-shell:4.10" + } //Task to deploy the nodes in order to bootstrap a network diff --git a/Advanced/secretsanta-cordapp/repositories.gradle b/Advanced/secretsanta-cordapp/repositories.gradle index 2874c2ab..7adba3a3 100644 --- a/Advanced/secretsanta-cordapp/repositories.gradle +++ b/Advanced/secretsanta-cordapp/repositories.gradle @@ -1,7 +1,7 @@ repositories { mavenLocal() mavenCentral() - jcenter() + maven { url 'https://jitpack.io' } maven { url 'https://ci-artifactory.corda.r3cev.com/artifactory/corda' } maven { url 'https://repo.gradle.org/gradle/libs-releases' } diff --git a/Advanced/secretsanta-cordapp/workflows/src/main/java/net/corda/samples/secretsanta/flows/CreateSantaSessionFlow.java b/Advanced/secretsanta-cordapp/workflows/src/main/java/net/corda/samples/secretsanta/flows/CreateSantaSessionFlow.java index 0065f0e8..7b9635d5 100644 --- a/Advanced/secretsanta-cordapp/workflows/src/main/java/net/corda/samples/secretsanta/flows/CreateSantaSessionFlow.java +++ b/Advanced/secretsanta-cordapp/workflows/src/main/java/net/corda/samples/secretsanta/flows/CreateSantaSessionFlow.java @@ -14,6 +14,7 @@ import static java.util.Collections.singletonList; import java.util.*; +import net.corda.core.identity.CordaX500Name; /** @@ -65,7 +66,8 @@ public ProgressTracker getProgressTracker() { public SignedTransaction call() throws FlowException { // run an issuance transaction for a new secret santa game progressTracker.setCurrentStep(CREATING); - Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); Party issuer = getOurIdentity(); SantaSessionState newSantaState = new SantaSessionState(playerNames, playerEmails, issuer, owner); diff --git a/Advanced/secretsanta-cordapp/workflows/src/test/java/net/corda/samples/secretsanta/CheckAssignedSantaFlowTests.java b/Advanced/secretsanta-cordapp/workflows/src/test/java/net/corda/samples/secretsanta/CheckAssignedSantaFlowTests.java index f59aa598..8102b6e6 100644 --- a/Advanced/secretsanta-cordapp/workflows/src/test/java/net/corda/samples/secretsanta/CheckAssignedSantaFlowTests.java +++ b/Advanced/secretsanta-cordapp/workflows/src/test/java/net/corda/samples/secretsanta/CheckAssignedSantaFlowTests.java @@ -1,6 +1,7 @@ package net.corda.samples.secretsanta; import com.google.common.collect.ImmutableList; +import net.corda.core.identity.CordaX500Name; import net.corda.samples.secretsanta.flows.CheckAssignedSantaFlow; import net.corda.samples.secretsanta.flows.CreateSantaSessionFlow; import net.corda.samples.secretsanta.states.SantaSessionState; @@ -8,10 +9,7 @@ import net.corda.core.contracts.UniqueIdentifier; import net.corda.core.node.NetworkParameters; import net.corda.core.transactions.SignedTransaction; -import net.corda.testing.node.MockNetwork; -import net.corda.testing.node.MockNetworkParameters; -import net.corda.testing.node.StartedMockNode; -import net.corda.testing.node.TestCordapp; +import net.corda.testing.node.*; import org.junit.After; import org.junit.Before; @@ -20,7 +18,7 @@ import java.time.Instant; import java.util.*; -import static org.jgroups.util.Util.assertEquals; +import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; public class CheckAssignedSantaFlowTests { @@ -39,6 +37,7 @@ public void setup() { network = new MockNetwork(new MockNetworkParameters().withCordappsForAllNodes(ImmutableList.of( TestCordapp.findCordapp("net.corda.samples.secretsanta.contracts"), TestCordapp.findCordapp("net.corda.samples.secretsanta.flows"))).withNetworkParameters(testNetworkParameters) + .withNotarySpecs(ImmutableList.of(new MockNetworkNotarySpec(CordaX500Name.parse("O=Notary,L=London,C=GB")))) ); santa = network.createPartyNode(null); diff --git a/Advanced/secretsanta-cordapp/workflows/src/test/java/net/corda/samples/secretsanta/CreateSantaSessionFlowTests.java b/Advanced/secretsanta-cordapp/workflows/src/test/java/net/corda/samples/secretsanta/CreateSantaSessionFlowTests.java index 1b22d6f8..b617bca2 100644 --- a/Advanced/secretsanta-cordapp/workflows/src/test/java/net/corda/samples/secretsanta/CreateSantaSessionFlowTests.java +++ b/Advanced/secretsanta-cordapp/workflows/src/test/java/net/corda/samples/secretsanta/CreateSantaSessionFlowTests.java @@ -1,6 +1,7 @@ package net.corda.samples.secretsanta; import com.google.common.collect.ImmutableList; +import net.corda.core.identity.CordaX500Name; import net.corda.samples.secretsanta.contracts.SantaSessionContract; import net.corda.samples.secretsanta.flows.CreateSantaSessionFlow; import net.corda.samples.secretsanta.states.SantaSessionState; @@ -9,10 +10,7 @@ import net.corda.core.contracts.TransactionState; import net.corda.core.node.NetworkParameters; import net.corda.core.transactions.SignedTransaction; -import net.corda.testing.node.MockNetwork; -import net.corda.testing.node.MockNetworkParameters; -import net.corda.testing.node.StartedMockNode; -import net.corda.testing.node.TestCordapp; +import net.corda.testing.node.*; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -22,8 +20,8 @@ import java.util.Arrays; import java.util.LinkedHashMap; -import static org.jgroups.util.Util.assertEquals; -import static org.jgroups.util.Util.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertNull; public class CreateSantaSessionFlowTests { @@ -43,6 +41,7 @@ public void setup() { network = new MockNetwork(new MockNetworkParameters().withCordappsForAllNodes(ImmutableList.of( TestCordapp.findCordapp("net.corda.samples.secretsanta.contracts"), TestCordapp.findCordapp("net.corda.samples.secretsanta.flows"))).withNetworkParameters(testNetworkParameters) + .withNotarySpecs(ImmutableList.of(new MockNetworkNotarySpec(CordaX500Name.parse("O=Notary,L=London,C=GB")))) ); santa = network.createPartyNode(null); diff --git a/Advanced/snakesandladders-cordapp/README.md b/Advanced/snakesandladders-cordapp/README.md index ae80630b..2e5f5b9a 100644 --- a/Advanced/snakesandladders-cordapp/README.md +++ b/Advanced/snakesandladders-cordapp/README.md @@ -2,13 +2,13 @@ This sample implements a simple Snakes And Ladder Game on Corda. -Its a simple game which has a board with numbers from 1 to 100. Each player starts at 1. -Players takes turn to roll a dice and move as many places as they rolled. If a player lands on a number -with a ladder thay climb up using the ladder or if they land in a number with a snake they move down on the board. +It's a simple game which has a board with numbers from 1 to 100. Each player starts at 1. +Players take turn to roll a dice and move as many places as they rolled. If a player lands on a number +with a ladder they climb up using the ladder or if they land in a number with a snake they move down on the board. The player who reach 100 first wins. -The cordapp runs a network having 4 nodes, -1. Classis Games +The CorDapp runs a network having 4 nodes, +1. Classic Games 2. Mega Games 3. Oracle 4. Notary diff --git a/Advanced/snakesandladders-cordapp/build.gradle b/Advanced/snakesandladders-cordapp/build.gradle index 04dde1ae..f30e7f56 100644 --- a/Advanced/snakesandladders-cordapp/build.gradle +++ b/Advanced/snakesandladders-cordapp/build.gradle @@ -28,8 +28,8 @@ buildscript { repositories { mavenLocal() mavenCentral() - jcenter() - maven { url 'https://software.r3.com/artifactory/corda-releases' } + + maven { url 'https://download.corda.net/maven/corda-releases' } } dependencies { @@ -46,12 +46,12 @@ allprojects { repositories { mavenLocal() - jcenter() + mavenCentral() - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } maven { url 'https://jitpack.io' } //SDK lib - maven { url 'https://software.r3.com/artifactory/corda-lib' } + maven { url 'https://download.corda.net/maven/corda-lib' } //Gradle Plugins maven { url 'https://repo.gradle.org/gradle/libs-releases' } } @@ -98,6 +98,8 @@ dependencies { cordaCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" cordaCompile "org.apache.logging.log4j:log4j-web:${log4j_version}" cordaCompile "org.slf4j:jul-to-slf4j:$slf4j_version" + cordaDriver "net.corda:corda-shell:4.10" + //accounts cordapp "$accounts_release_group:accounts-contracts:$accounts_release_version" diff --git a/Advanced/snakesandladders-cordapp/client/build.gradle b/Advanced/snakesandladders-cordapp/client/build.gradle index 79ce3545..82103fec 100644 --- a/Advanced/snakesandladders-cordapp/client/build.gradle +++ b/Advanced/snakesandladders-cordapp/client/build.gradle @@ -1,5 +1,11 @@ apply plugin: 'org.springframework.boot' +configurations { + all { + exclude group: 'ch.qos.logback', module: 'logback-classic' + } +} + dependencies { // Corda dependencies. compile "$corda_release_group:corda-rpc:$corda_release_version" diff --git a/Advanced/snakesandladders-cordapp/repositories.gradle b/Advanced/snakesandladders-cordapp/repositories.gradle index 206b9c68..8be7b630 100644 --- a/Advanced/snakesandladders-cordapp/repositories.gradle +++ b/Advanced/snakesandladders-cordapp/repositories.gradle @@ -1,8 +1,8 @@ repositories { mavenLocal() mavenCentral() - jcenter() + maven { url 'https://jitpack.io' } - maven { url 'https://software.r3.com/artifactory/corda' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } maven { url 'https://repo.gradle.org/gradle/libs-releases' } } diff --git a/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/CreateAndShareAccountFlow.java b/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/CreateAndShareAccountFlow.java index 008c605b..17c1cb96 100644 --- a/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/CreateAndShareAccountFlow.java +++ b/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/CreateAndShareAccountFlow.java @@ -14,6 +14,7 @@ import java.util.List; import java.util.stream.Collectors; +import net.corda.core.identity.CordaX500Name; @StartableByRPC @InitiatingFlow @@ -33,7 +34,9 @@ public String call() throws FlowException { StateAndRef accountInfoStateAndRef = (StateAndRef) subFlow(new CreateAccount(accountName)); - final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); + Party oracle = getServiceHub().getNetworkMapCache() .getNodeByLegalName(CordaX500Name.parse("O=Oracle,L=Mumbai,C=IN")).getLegalIdentities().get(0); diff --git a/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/CreateBoardConfig.java b/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/CreateBoardConfig.java index 705a716c..8af2de27 100644 --- a/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/CreateBoardConfig.java +++ b/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/CreateBoardConfig.java @@ -17,6 +17,7 @@ import java.security.SignatureException; import java.util.*; +import net.corda.core.identity.CordaX500Name; public class CreateBoardConfig { private CreateBoardConfig() {} @@ -36,7 +37,9 @@ public Initiator(String player1, String player2) { @Override @Suspendable public SignedTransaction call() throws FlowException { - Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); + AccountService accountService = getServiceHub().cordaService(KeyManagementBackedAccountService.class); List> p1accountInfo = accountService.accountInfo(player1); diff --git a/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/CreateGameFlow.java b/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/CreateGameFlow.java index ae6845b5..fb664384 100644 --- a/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/CreateGameFlow.java +++ b/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/CreateGameFlow.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.List; import java.util.UUID; +import net.corda.core.identity.CordaX500Name; public class CreateGameFlow { @@ -43,7 +44,9 @@ public Initiator(String player1, String player2) { @Override @Suspendable public String call() throws FlowException { - Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); + AccountService accountService = getServiceHub().cordaService(KeyManagementBackedAccountService.class); List> p1accountInfo = accountService.accountInfo(player1); diff --git a/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/PlayerMoveFlow.java b/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/PlayerMoveFlow.java index 19642828..4712a094 100644 --- a/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/PlayerMoveFlow.java +++ b/Advanced/snakesandladders-cordapp/workflows/src/main/java/net/corda/samples/snl/flows/PlayerMoveFlow.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; +import net.corda.core.identity.CordaX500Name; public class PlayerMoveFlow { @@ -52,7 +53,9 @@ public Initiator(String player, String linearId, int diceRolled) { @Override @Suspendable public SignedTransaction call() throws FlowException { - Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0); + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); + AccountService accountService = getServiceHub().cordaService(KeyManagementBackedAccountService.class); //Get current player account info diff --git a/Advanced/snakesandladders-cordapp/workflows/src/test/java/net/corda/samples/snl/flows/FlowTests.java b/Advanced/snakesandladders-cordapp/workflows/src/test/java/net/corda/samples/snl/flows/FlowTests.java index c047e9f6..7f141371 100644 --- a/Advanced/snakesandladders-cordapp/workflows/src/test/java/net/corda/samples/snl/flows/FlowTests.java +++ b/Advanced/snakesandladders-cordapp/workflows/src/test/java/net/corda/samples/snl/flows/FlowTests.java @@ -3,13 +3,11 @@ import com.google.common.collect.ImmutableList; import com.r3.corda.lib.accounts.workflows.flows.CreateAccount; import net.corda.core.concurrent.CordaFuture; +import net.corda.core.identity.CordaX500Name; import net.corda.core.node.NetworkParameters; import net.corda.core.transactions.SignedTransaction; import net.corda.samples.snl.states.BoardConfig; -import net.corda.testing.node.MockNetwork; -import net.corda.testing.node.MockNetworkParameters; -import net.corda.testing.node.StartedMockNode; -import net.corda.testing.node.TestCordapp; +import net.corda.testing.node.*; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -36,7 +34,9 @@ public void setup() { TestCordapp.findCordapp("com.r3.corda.lib.ci")) ).withNetworkParameters(new NetworkParameters(4, Collections.emptyList(), 10485760, 10485760 * 50, Instant.now(), 1, - Collections.emptyMap())) + Collections.emptyMap()) + ) + .withNotarySpecs(ImmutableList.of(new MockNetworkNotarySpec(CordaX500Name.parse("O=Notary,L=London,C=GB")))) ); a = network.createPartyNode(null); b = network.createPartyNode(null); diff --git a/Advanced/syndicated-lending/.ci/Jenkinsfile b/Advanced/syndicated-lending/.ci/Jenkinsfile new file mode 100644 index 00000000..7421cafe --- /dev/null +++ b/Advanced/syndicated-lending/.ci/Jenkinsfile @@ -0,0 +1,37 @@ +#!groovy +/** + * Jenkins pipeline to build the java CorDapp template + */ + +/** + * Kill already started job. + * Assume new commit takes precedence and results from previousunfinished builds are not required. + * This feature doesn't play well with disableConcurrentBuilds() option + */ +@Library('corda-shared-build-pipeline-steps') +import static com.r3.build.BuildControl.killAllExistingBuildsForJob +killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger()) + +pipeline { + agent { + label 'eight-cores' + } + options { + ansiColor('xterm') + timestamps() + timeout(3*60) // 3 hours + buildDiscarder(logRotator(daysToKeepStr: '7', artifactDaysToKeepStr: '7')) + } + stages { + stage('Build') { + steps { + sh './gradlew --no-daemon -s clean build test deployNodes' + } + } + } + post { + cleanup { + deleteDir() + } + } +} diff --git a/Advanced/syndicated-lending/.gitignore b/Advanced/syndicated-lending/.gitignore new file mode 100644 index 00000000..0d75547d --- /dev/null +++ b/Advanced/syndicated-lending/.gitignore @@ -0,0 +1,78 @@ +# Eclipse, ctags, Mac metadata, log files +.classpath +.project +tags +.DS_Store +*.log +*.log.gz +*.orig + +.gradle + +# General build files +**/build/* +!docs/build/* + +lib/dokka.jar + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio + +*.iml + +## Directory-based project format: +#.idea + +# if you remove the above rule, at least ignore the following: + +# Specific files to avoid churn +.idea/*.xml +.idea/copyright +.idea/jsLibraryMappings.xml + +# User-specific stuff: +.idea/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/dataSources.ids +.idea/dataSources.xml +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml + +# Gradle: +.idea/libraries + +# Mongo Explorer plugin: +.idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ +/workflows/out/ +/contracts/out/ +clients/out/ +*/bin/* + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties + +# docs related +docs/virtualenv/ + +# if you use the installQuasar task +lib diff --git a/Advanced/syndicated-lending/.settings/org.eclipse.jdt.core.prefs b/Advanced/syndicated-lending/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..ac86f90c --- /dev/null +++ b/Advanced/syndicated-lending/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1 @@ +org.eclipse.jdt.core.compiler.codegen.methodParameters=generate \ No newline at end of file diff --git a/Advanced/syndicated-lending/FlowDiagram.pptx b/Advanced/syndicated-lending/FlowDiagram.pptx new file mode 100644 index 00000000..c011cc9e Binary files /dev/null and b/Advanced/syndicated-lending/FlowDiagram.pptx differ diff --git a/Advanced/syndicated-lending/LICENCE b/Advanced/syndicated-lending/LICENCE new file mode 100644 index 00000000..3ff572d1 --- /dev/null +++ b/Advanced/syndicated-lending/LICENCE @@ -0,0 +1,13 @@ + Copyright 2016, R3 Limited. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Advanced/syndicated-lending/README.md b/Advanced/syndicated-lending/README.md new file mode 100644 index 00000000..77b8b6c9 --- /dev/null +++ b/Advanced/syndicated-lending/README.md @@ -0,0 +1,102 @@ +

+ Corda +

+ +# Syndicated Lending Sample Cordapp + +This is a sample Cordapp which demonstrate a high level Syndicated Lending scenario on a Corda network. + +Syndicated lending comprises of multiple banks coming together to service the loan requirement of a borrower. +Generally a lead bank is appointed who coordinated the process to forming a syndicate with other participating banks +and agreeing on loan terms. + +# Pre-Requisites + +See https://docs.corda.net/getting-set-up.html. + +# Usage + +## Running the CorDapp + +Open a terminal and go to the project root directory and type: (to deploy the nodes using bootstrapper) +``` +./gradlew clean deployNodes +``` +Then type: (to run the nodes) +``` +./build/nodes/runnodes +``` + +## Interacting with the CorDapp + +PeterCo (as a borrower) starts the `SubmitProjectProposalFlow` in order to submit the project details to a group of +lenders and request for funds. + +Go to PeterCo's terminal and run the below command + +``` +start SubmitProjectProposalFlow lenders: [BankOfAshu, BankOfSneha], projectDescription: "Overseas Expansion", projectCost: 10000000, loanAmount: 8000000 +``` + +Validate the project details are created and shared with the lenders successfully by running the vaultQuery command in each +lender's terminal and borrower's terminal. + +``` +run vaultQuery contractStateType: net.corda.samples.lending.states.ProjectState +``` + +Once the lenders have verified the project details and done their due deligence, they could submit bids for loan. + +Goto BankOfAshu's terminal and run the below command. The project-id can be found using the vaultQuery command shown earlier. + +``` +start SubmitLoanBidFlow borrower: PeterCo, loanAmount: 8000000, tenure: 5, rateofInterest: 4.0, transactionFees: 20000, projectIdentifier: +``` + +Validate the loanBid is submitted successfully by running the vaultQuery command below: + +``` +run vaultQuery contractStateType: net.corda.samples.lending.states.LoanBidState +``` + +Now the borrower can inspect the loan terms and approve the loan bid, to start the syndication process. + +Go to PeterCo's terminal and run the below command. The loanbid-identifier can be found using the vaultQuery command used earlier. + +``` +start ApproveLoanBidFlow bidIdentifier: +``` + +One the loan bid has been approved by the borrower, the lender can start the process of creating the syndicate by +acting as the lead bank and approach participating bank for funds. + +Goto BankOfAshu's terminal and run the below command. + +``` +start CreateSyndicateFlow participantBanks: [BankOfSneha, BankOfTom], projectIdentifier: , loanDetailIdentifier: +``` + +Verify the syndicate is created using the below command: + +``` +run vaultQuery contractStateType: net.corda.samples.lending.states.SyndicateState +``` + +On receiving the syndicate creation request, participating banks could verify the project and loan terms and submit +bids for the amount of fund they wish to lend by using the below flow in BankOfSneha or BankOfTom node. + +``` +start SyndicateBidFlow$Initiator syndicateIdentifier: , bidAmount: +``` + +Verify the syndicate bid is successfully created using the below command: + +``` +run vaultQuery contractStateType: net.corda.samples.lending.states.SyndicateBidState +``` + +The lead bank on receiving bids from participating banks could approve the bid using the below flow command. + +``` +start ApproveSyndicateBidFlow bidIdentifier: +``` \ No newline at end of file diff --git a/Advanced/syndicated-lending/TRADEMARK b/Advanced/syndicated-lending/TRADEMARK new file mode 100644 index 00000000..d2e056b5 --- /dev/null +++ b/Advanced/syndicated-lending/TRADEMARK @@ -0,0 +1,4 @@ +Corda and the Corda logo are trademarks of R3CEV LLC and its affiliates. All rights reserved. + +For R3CEV LLC's trademark and logo usage information, please consult our Trademark Usage Policy at +https://www.r3.com/trademark-policy/. \ No newline at end of file diff --git a/Advanced/syndicated-lending/build.gradle b/Advanced/syndicated-lending/build.gradle new file mode 100644 index 00000000..68ca4762 --- /dev/null +++ b/Advanced/syndicated-lending/build.gradle @@ -0,0 +1,156 @@ +buildscript {//properties that you need to build the project + Properties constants = new Properties() + file("$projectDir/./constants.properties").withInputStream { constants.load(it) } + + ext { + corda_release_group = constants.getProperty("cordaReleaseGroup") + corda_core_release_group = constants.getProperty("cordaCoreReleaseGroup") + corda_release_version = constants.getProperty("cordaVersion") + corda_core_release_version = constants.getProperty("cordaCoreVersion") + corda_gradle_plugins_version = constants.getProperty("gradlePluginsVersion") + kotlin_version = constants.getProperty("kotlinVersion") + junit_version = constants.getProperty("junitVersion") + quasar_version = constants.getProperty("quasarVersion") + log4j_version = constants.getProperty("log4jVersion") + slf4j_version = constants.getProperty("slf4jVersion") + corda_platform_version = constants.getProperty("platformVersion").toInteger() + //springboot + spring_boot_version = '2.0.2.RELEASE' + spring_boot_gradle_plugin_version = '2.0.2.RELEASE' + } + + repositories { + mavenLocal() + mavenCentral() + + maven { url 'https://download.corda.net/maven/corda-dependencies' } + maven { url 'https://download.corda.net/maven/corda-releases' } + } + + dependencies { + classpath "net.corda.plugins:cordapp:$corda_gradle_plugins_version" + classpath "net.corda.plugins:cordformation:$corda_gradle_plugins_version" + classpath "net.corda.plugins:quasar-utils:$corda_gradle_plugins_version" + classpath "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_gradle_plugin_version" + } +} + +allprojects {//Properties that you need to compile your project (The application) + apply from: "${rootProject.projectDir}/repositories.gradle" + apply plugin: 'java' + + repositories { + mavenLocal() + + mavenCentral() + maven { url 'https://download.corda.net/maven/corda-dependencies' } + maven { url 'https://download.corda.net/maven/corda-releases' } + maven { url 'https://jitpack.io' } + } + + tasks.withType(JavaCompile) { + options.compilerArgs << "-parameters" // Required by Corda's serialisation framework. + } + + jar { + // This makes the JAR's SHA-256 hash repeatable. + preserveFileTimestamps = false + reproducibleFileOrder = true + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + } +} + +apply plugin: 'net.corda.plugins.cordapp' +apply plugin: 'net.corda.plugins.cordformation' +apply plugin: 'net.corda.plugins.quasar-utils' + +sourceSets { + main { + resources { + srcDir rootProject.file("config/dev") + } + } +} +//Module dependencis +dependencies { + // Corda dependencies. + cordaCompile "$corda_core_release_group:corda-core:$corda_core_release_version" + cordaCompile "$corda_release_group:corda-node-api:$corda_release_version" + cordaRuntime "$corda_release_group:corda:$corda_release_version" + + // CorDapp dependencies. + cordapp project(":workflows") + cordapp project(":contracts") + + cordaCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" + cordaCompile "org.apache.logging.log4j:log4j-web:${log4j_version}" + cordaCompile "org.slf4j:jul-to-slf4j:$slf4j_version" + cordaDriver "net.corda:corda-shell:4.10" + +} + + +//Task to deploy the nodes in order to bootstrap a network +task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { + + /* This property will load the CorDapps to each of the node by default, including the Notary. You can find them + * in the cordapps folder of the node at build/nodes/Notary/cordapps. However, the notary doesn't really understand + * the notion of cordapps. In production, Notary does not need cordapps as well. This is just a short cut to load + * the Corda network bootstrapper. + */ + nodeDefaults { + projectCordapp { + deploy = false + } + cordapp project(':contracts') + cordapp project(':workflows') + runSchemaMigration = true //This configuration is for any CorDapps with custom schema, We will leave this as true to avoid + //problems for developers who are not familiar with Corda. If you are not using custom schemas, you can change + //it to false for quicker project compiling time. + } + node { + name "O=Notary,L=London,C=GB" + notary = [validating : false] + p2pPort 10002 + rpcSettings { + address("localhost:10003") + adminAddress("localhost:10043") + } + } + node { + name "O=PeterCo,L=London,C=GB" + p2pPort 10005 + rpcSettings { + address("localhost:10006") + adminAddress("localhost:10046") + } + rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]] + } + node { + name "O=BankOfAshu,L=New York,C=US" + p2pPort 10008 + rpcSettings { + address("localhost:10009") + adminAddress("localhost:10049") + } + rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]] + } + node { + name "O=BankOfSneha,L=New York,C=US" + p2pPort 10011 + rpcSettings { + address("localhost:10012") + adminAddress("localhost:10052") + } + rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]] + } + node { + name "O=BankOfTom,L=New York,C=US" + p2pPort 10014 + rpcSettings { + address("localhost:10016") + adminAddress("localhost:10056") + } + rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]] + } +} diff --git a/Advanced/syndicated-lending/config/dev/log4j2.xml b/Advanced/syndicated-lending/config/dev/log4j2.xml new file mode 100644 index 00000000..34ba4d45 --- /dev/null +++ b/Advanced/syndicated-lending/config/dev/log4j2.xml @@ -0,0 +1,59 @@ + + + + + logs + node-${hostName} + ${log-path}/archive + + + + + + + + + %highlight{%level{length=1} %d{HH:mm:ss} %T %c{1}.%M - %msg%n}{INFO=white,WARN=red,FATAL=bright red blink} + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Advanced/syndicated-lending/config/test/log4j2.xml b/Advanced/syndicated-lending/config/test/log4j2.xml new file mode 100644 index 00000000..cd9926ca --- /dev/null +++ b/Advanced/syndicated-lending/config/test/log4j2.xml @@ -0,0 +1,20 @@ + + + + + + + [%-5level] %d{HH:mm:ss.SSS} [%t] %c{1}.%M - %msg%n + > + + + + + + + + + + + + diff --git a/Advanced/syndicated-lending/constants.properties b/Advanced/syndicated-lending/constants.properties new file mode 100644 index 00000000..adedb0f3 --- /dev/null +++ b/Advanced/syndicated-lending/constants.properties @@ -0,0 +1,12 @@ +cordaReleaseGroup=net.corda +cordaCoreReleaseGroup=net.corda +cordaVersion=4.8.5 +cordaCoreVersion=4.8.5 +gradlePluginsVersion=5.0.12 +kotlinVersion=1.2.71 +junitVersion=4.12 +quasarVersion=0.7.10 +log4jVersion =2.16.0 +platformVersion=10 +slf4jVersion=1.7.25 +nettyVersion=4.1.22.Final diff --git a/Advanced/syndicated-lending/contracts/build.gradle b/Advanced/syndicated-lending/contracts/build.gradle new file mode 100644 index 00000000..9f2664fb --- /dev/null +++ b/Advanced/syndicated-lending/contracts/build.gradle @@ -0,0 +1,35 @@ +apply plugin: 'net.corda.plugins.cordapp' +apply plugin: 'net.corda.plugins.cordformation' + +cordapp { + targetPlatformVersion corda_platform_version + minimumPlatformVersion corda_platform_version + contract { + name "Lending Contracts" + vendor "Corda Open Source" + licence "Apache License, Version 2.0" + versionId 1 + } +} + +sourceSets { + main{ + java { + srcDir 'src/main/java' + java.outputDir = file('bin/main') + } + } + test{ + java{ + srcDir 'src/test/java' + java.outputDir = file('bin/test') + } + } +} + +dependencies { + // Corda dependencies. + cordaCompile "$corda_core_release_group:corda-core:$corda_core_release_version" + cordaRuntime "$corda_release_group:corda:$corda_release_version" + testCompile "$corda_release_group:corda-node-driver:$corda_release_version" +} \ No newline at end of file diff --git a/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/contracts/LoanBidContract.java b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/contracts/LoanBidContract.java new file mode 100644 index 00000000..047caa6c --- /dev/null +++ b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/contracts/LoanBidContract.java @@ -0,0 +1,42 @@ +package net.corda.samples.lending.contracts; + + +import net.corda.core.contracts.CommandData; +import net.corda.core.contracts.Contract; +import net.corda.core.transactions.LedgerTransaction; +import org.jetbrains.annotations.NotNull; + +import static net.corda.core.contracts.ContractsDSL.requireThat; + +public class LoanBidContract implements Contract { + + // This is used to identify our contract when building a transaction. + public static final String ID = "net.corda.samples.lending.contracts.LoanBidContract"; + + @Override + public void verify(@NotNull LedgerTransaction tx) throws IllegalArgumentException { + // Contract Validation Logic Goes Here + final CommandData commandData = tx.getCommands().get(0).getValue(); + + if (commandData instanceof Commands.Submit) { + requireThat(require -> { + /* At here, the loan bid proposal from the competing banks is verified. + These contract rules make sure that each loan bid for project is valid. */ + return null; + }); + }else if (commandData instanceof Commands.Approve) { + requireThat(require -> { + /* At here, the loan bid is verified for approval process. These contract rules make + sure that all the conditions are met for the borrower to approve the sole loan bid for its + project. */ + return null; + }); + } + } + + // Used to indicate the transaction's intent. + public interface Commands extends CommandData { + class Submit implements ProjectContract.Commands {} + class Approve implements ProjectContract.Commands {} + } +} diff --git a/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/contracts/ProjectContract.java b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/contracts/ProjectContract.java new file mode 100644 index 00000000..3189f63e --- /dev/null +++ b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/contracts/ProjectContract.java @@ -0,0 +1,40 @@ +package net.corda.samples.lending.contracts; + +import net.corda.core.contracts.CommandData; +import net.corda.core.contracts.Contract; +import net.corda.core.transactions.LedgerTransaction; +import org.jetbrains.annotations.NotNull; + +import static net.corda.core.contracts.ContractsDSL.requireThat; + +// ************ +// * Contract * +// ************ +public class ProjectContract implements Contract { + + // This is used to identify our contract when building a transaction. + public static final String ID = "net.corda.samples.lending.contracts.ProjectContract"; + + + // A transaction is valid if the verify() function of the contract of all the transaction's input and output states + // does not throw an exception. + @Override + public void verify(@NotNull LedgerTransaction tx) throws IllegalArgumentException { + // Contract Validation Logic Goes Here + final CommandData commandData = tx.getCommands().get(0).getValue(); + + if (commandData instanceof Commands.ProposeProject) { + requireThat(require -> { + /*At here, you can structure the rules for creating a project proposal + * this verify method makes sure that all proposed projects from the borrower company + * are sound, so that banks are not going to waste any time on unqualified project proposals*/ + return null; + }); + } + } + + // Used to indicate the transaction's intent. + public interface Commands extends CommandData { + class ProposeProject implements Commands {} + } +} \ No newline at end of file diff --git a/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/contracts/SyndicateBidContract.java b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/contracts/SyndicateBidContract.java new file mode 100644 index 00000000..bd3738c2 --- /dev/null +++ b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/contracts/SyndicateBidContract.java @@ -0,0 +1,39 @@ +package net.corda.samples.lending.contracts; + +import net.corda.core.contracts.CommandData; +import net.corda.core.contracts.Contract; +import net.corda.core.transactions.LedgerTransaction; +import org.jetbrains.annotations.NotNull; + +import static net.corda.core.contracts.ContractsDSL.requireThat; + +public class SyndicateBidContract implements Contract { + + // This is used to identify our contract when building a transaction. + public static final String ID = "net.corda.samples.lending.contracts.SyndicateBidContract"; + + @Override + public void verify(@NotNull LedgerTransaction tx) throws IllegalArgumentException { + // Contract Validation Logic Goes Here + final CommandData commandData = tx.getCommands().get(0).getValue(); + + if (commandData instanceof Commands.Submit) { + requireThat(require -> { + /* At here, the syndication bid proposal from the syndication participating banks is verified. + These contract rules make sure that each bid for syndicated loan is valid. */ + return null; + }); + }else if (commandData instanceof Commands.Approve) { + requireThat(require -> { + /* At here, the syndicated bid is verified for approval process. These contract rules make + sure that all the conditions are met for the lead bank to approve the each syndicated bid. */ + return null; + }); + } + } + + public interface Commands extends CommandData { + class Submit implements Commands {} + class Approve implements Commands {} + } +} diff --git a/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/contracts/SyndicateContract.java b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/contracts/SyndicateContract.java new file mode 100644 index 00000000..d2c15f9c --- /dev/null +++ b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/contracts/SyndicateContract.java @@ -0,0 +1,38 @@ +package net.corda.samples.lending.contracts; + +import net.corda.core.contracts.CommandData; +import net.corda.core.contracts.Contract; +import net.corda.core.contracts.StateAndRef; +import net.corda.core.transactions.LedgerTransaction; +import net.corda.samples.lending.states.LoanBidState; +import net.corda.samples.lending.states.SyndicateState; +import org.jetbrains.annotations.NotNull; + +import static net.corda.core.contracts.ContractsDSL.requireThat; + +public class SyndicateContract implements Contract { + + // This is used to identify our contract when building a transaction. + public static final String ID = "net.corda.samples.lending.contracts.SyndicateContract"; + + + // A transaction is valid if the verify() function of the contract of all the transaction's input and output states + // does not throw an exception. + @Override + public void verify(@NotNull LedgerTransaction tx) throws IllegalArgumentException { + // Contract Validation Logic Goes Here + final CommandData commandData = tx.getCommands().get(0).getValue(); + + if (commandData instanceof Commands.Create) { + requireThat(require -> { + /*Here writes the rules for the lead bank's creating the syndication.*/ + + return null; + }); + } + } + + public interface Commands extends CommandData { + class Create implements Commands {} + } +} diff --git a/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/states/LoanBidState.java b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/states/LoanBidState.java new file mode 100644 index 00000000..7be802bc --- /dev/null +++ b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/states/LoanBidState.java @@ -0,0 +1,82 @@ +package net.corda.samples.lending.states; + +import net.corda.core.contracts.*; +import net.corda.core.identity.AbstractParty; +import net.corda.core.identity.Party; +import net.corda.samples.lending.contracts.LoanBidContract; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.List; + +@BelongsToContract(LoanBidContract.class) +public class LoanBidState implements LinearState { + + private StaticPointer projectDetails; + private UniqueIdentifier uniqueIdentifier; + private Party lender; + private Party borrower; + private int loanAmount; + private int tenure; + private double rateofInterest; + private int transactionFees; + private String status; + + public LoanBidState(StaticPointer projectDetails, UniqueIdentifier uniqueIdentifier, + Party lender, Party borrower, int loanAmount, int tenure, + double rateofInterest, int transactionFees, String status) { + this.projectDetails = projectDetails; + this.uniqueIdentifier = uniqueIdentifier; + this.lender = lender; + this.borrower = borrower; + this.loanAmount = loanAmount; + this.tenure = tenure; + this.rateofInterest = rateofInterest; + this.transactionFees = transactionFees; + this.status = status; + } + + public StaticPointer getProjectDetails() { + return projectDetails; + } + + public Party getLender() { + return lender; + } + + public Party getBorrower() { + return borrower; + } + + public int getLoanAmount() { + return loanAmount; + } + + public int getTenure() { + return tenure; + } + + public double getRateofInterest() { + return rateofInterest; + } + + public int getTransactionFees() { + return transactionFees; + } + + public String getStatus() { + return status; + } + + @NotNull + @Override + public List getParticipants() { + return Arrays.asList(lender, borrower); + } + + @NotNull + @Override + public UniqueIdentifier getLinearId() { + return uniqueIdentifier; + } +} diff --git a/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/states/ProjectState.java b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/states/ProjectState.java new file mode 100644 index 00000000..a4240e05 --- /dev/null +++ b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/states/ProjectState.java @@ -0,0 +1,77 @@ +package net.corda.samples.lending.states; + +import net.corda.core.contracts.BelongsToContract; +import net.corda.core.contracts.LinearState; +import net.corda.core.contracts.UniqueIdentifier; +import net.corda.core.identity.AbstractParty; +import net.corda.core.identity.Party; +import net.corda.samples.lending.contracts.ProjectContract; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +// ********* +// * ProposalState * +// ********* +@BelongsToContract(ProjectContract.class) +public class ProjectState implements LinearState { + + //private variables + private UniqueIdentifier uniqueIdentifier; + private String projectDescription; + private Party borrower; + private int projectCost; + private int loanAmount; + private List lenders; + + /* Constructor of your Corda state */ + + public ProjectState(UniqueIdentifier uniqueIdentifier, String projectDescription, Party borrower, + int projectCost, int loanAmount, List lenders) { + this.uniqueIdentifier = uniqueIdentifier; + this.projectDescription = projectDescription; + this.borrower = borrower; + this.projectCost = projectCost; + this.loanAmount = loanAmount; + this.lenders = lenders; + } + + // getters + + public String getProjectDescription() { + return projectDescription; + } + + public Party getBorrower() { + return borrower; + } + + public int getProjectCost() { + return projectCost; + } + + public int getLoanAmount() { + return loanAmount; + } + + public List getBidders() { + return lenders; + } + + /* This method will indicate who are the participants when + * this state is used in a transaction. */ + @Override + public List getParticipants() { + List particiants = new ArrayList<>(); + particiants.add(borrower); + particiants.addAll(lenders); + return particiants; + } + + @NotNull + @Override + public UniqueIdentifier getLinearId() { + return uniqueIdentifier; + } +} \ No newline at end of file diff --git a/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/states/SyndicateBidState.java b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/states/SyndicateBidState.java new file mode 100644 index 00000000..204289ba --- /dev/null +++ b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/states/SyndicateBidState.java @@ -0,0 +1,66 @@ +package net.corda.samples.lending.states; + +import net.corda.core.contracts.BelongsToContract; +import net.corda.core.contracts.LinearPointer; +import net.corda.core.contracts.LinearState; +import net.corda.core.contracts.UniqueIdentifier; +import net.corda.core.identity.AbstractParty; +import net.corda.core.identity.Party; +import net.corda.samples.lending.contracts.SyndicateBidContract; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.List; + +@BelongsToContract(SyndicateBidContract.class) +public class SyndicateBidState implements LinearState { + + private UniqueIdentifier uniqueIdentifier; + private LinearPointer syndicateState; + private int bidAmount; + private Party leadBank; + private Party participatBank; + private String status; + + public SyndicateBidState(UniqueIdentifier uniqueIdentifier, LinearPointer syndicateState, int bidAmount, + Party leadBank, Party participatBank, String status) { + this.uniqueIdentifier = uniqueIdentifier; + this.syndicateState = syndicateState; + this.bidAmount = bidAmount; + this.leadBank = leadBank; + this.participatBank = participatBank; + this.status = status; + } + + public LinearPointer getSyndicateState() { + return syndicateState; + } + + public int getBidAmount() { + return bidAmount; + } + + public Party getLeadBank() { + return leadBank; + } + + public Party getParticipatBank() { + return participatBank; + } + + public String getStatus() { + return status; + } + + @NotNull + @Override + public List getParticipants() { + return Arrays.asList(participatBank, leadBank); + } + + @NotNull + @Override + public UniqueIdentifier getLinearId() { + return uniqueIdentifier; + } +} diff --git a/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/states/SyndicateState.java b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/states/SyndicateState.java new file mode 100644 index 00000000..0787b300 --- /dev/null +++ b/Advanced/syndicated-lending/contracts/src/main/java/net/corda/samples/lending/states/SyndicateState.java @@ -0,0 +1,62 @@ +package net.corda.samples.lending.states; + +import net.corda.core.contracts.*; +import net.corda.core.identity.AbstractParty; +import net.corda.core.identity.Party; +import net.corda.samples.lending.contracts.SyndicateContract; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +@BelongsToContract(SyndicateContract.class) +public class SyndicateState implements LinearState { + + private UniqueIdentifier uniqueIdentifier; + private Party leadBank; + private List participantBanks; + private LinearPointer projectDetails; + private LinearPointer loanDetails; + + public SyndicateState(UniqueIdentifier uniqueIdentifier, Party leadBank, List participantBanks, + LinearPointer projectDetails, + LinearPointer loanDetails) { + this.uniqueIdentifier = uniqueIdentifier; + this.leadBank = leadBank; + this.participantBanks = participantBanks; + this.projectDetails = projectDetails; + this.loanDetails = loanDetails; + } + + public Party getLeadBank() { + return leadBank; + } + + public List getParticipantBanks() { + return participantBanks; + } + + public LinearPointer getProjectDetails() { + return projectDetails; + } + + public LinearPointer getLoanDetails() { + return loanDetails; + } + + + @NotNull + @Override + public List getParticipants() { + List particiants = new ArrayList<>(); + particiants.add(leadBank); + particiants.addAll(participantBanks); + return particiants; + } + + @NotNull + @Override + public UniqueIdentifier getLinearId() { + return uniqueIdentifier; + } +} diff --git a/Advanced/syndicated-lending/contracts/src/test/java/net/corda/samples/lending/contracts/ContractTests.java b/Advanced/syndicated-lending/contracts/src/test/java/net/corda/samples/lending/contracts/ContractTests.java new file mode 100644 index 00000000..04ad1485 --- /dev/null +++ b/Advanced/syndicated-lending/contracts/src/test/java/net/corda/samples/lending/contracts/ContractTests.java @@ -0,0 +1,18 @@ +package net.corda.samples.lending.contracts; + +import net.corda.core.identity.CordaX500Name; +import net.corda.testing.core.TestIdentity; +import net.corda.testing.node.MockServices; + +import java.util.Arrays; + +import static net.corda.testing.node.NodeTestUtils.ledger; + + +public class ContractTests { + private final MockServices ledgerServices = new MockServices(Arrays.asList("net.corda.samples.lending")); + TestIdentity alice = new TestIdentity(new CordaX500Name("Alice", "TestLand", "US")); + TestIdentity bob = new TestIdentity(new CordaX500Name("Alice", "TestLand", "US")); + + +} \ No newline at end of file diff --git a/Advanced/syndicated-lending/contracts/src/test/java/net/corda/samples/lending/contracts/StateTests.java b/Advanced/syndicated-lending/contracts/src/test/java/net/corda/samples/lending/contracts/StateTests.java new file mode 100644 index 00000000..e886d011 --- /dev/null +++ b/Advanced/syndicated-lending/contracts/src/test/java/net/corda/samples/lending/contracts/StateTests.java @@ -0,0 +1,8 @@ +package net.corda.samples.lending.contracts; + +import net.corda.samples.lending.states.ProjectState; +import org.junit.Test; + +public class StateTests { + +} \ No newline at end of file diff --git a/Advanced/syndicated-lending/gradle.properties b/Advanced/syndicated-lending/gradle.properties new file mode 100644 index 00000000..60bb519a --- /dev/null +++ b/Advanced/syndicated-lending/gradle.properties @@ -0,0 +1,3 @@ +name=Test +group=net.corda.samples.lending +version=0.1 \ No newline at end of file diff --git a/Advanced/syndicated-lending/gradle/wrapper/gradle-wrapper.jar b/Advanced/syndicated-lending/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..99340b4a Binary files /dev/null and b/Advanced/syndicated-lending/gradle/wrapper/gradle-wrapper.jar differ diff --git a/Advanced/syndicated-lending/gradle/wrapper/gradle-wrapper.properties b/Advanced/syndicated-lending/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..0188225a --- /dev/null +++ b/Advanced/syndicated-lending/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +#Fri Aug 25 12:50:39 BST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip + diff --git a/Advanced/syndicated-lending/gradlew b/Advanced/syndicated-lending/gradlew new file mode 100755 index 00000000..cccdd3d5 --- /dev/null +++ b/Advanced/syndicated-lending/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/Advanced/syndicated-lending/gradlew.bat b/Advanced/syndicated-lending/gradlew.bat new file mode 100644 index 00000000..f9553162 --- /dev/null +++ b/Advanced/syndicated-lending/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Advanced/syndicated-lending/repositories.gradle b/Advanced/syndicated-lending/repositories.gradle new file mode 100644 index 00000000..8be7b630 --- /dev/null +++ b/Advanced/syndicated-lending/repositories.gradle @@ -0,0 +1,8 @@ +repositories { + mavenLocal() + mavenCentral() + + maven { url 'https://jitpack.io' } + maven { url 'https://download.corda.net/maven/corda-dependencies' } + maven { url 'https://repo.gradle.org/gradle/libs-releases' } +} diff --git a/Advanced/syndicated-lending/settings.gradle b/Advanced/syndicated-lending/settings.gradle new file mode 100644 index 00000000..b4446eaf --- /dev/null +++ b/Advanced/syndicated-lending/settings.gradle @@ -0,0 +1,2 @@ +include 'workflows' +include 'contracts' \ No newline at end of file diff --git a/Advanced/syndicated-lending/workflows/build.gradle b/Advanced/syndicated-lending/workflows/build.gradle new file mode 100644 index 00000000..8a229424 --- /dev/null +++ b/Advanced/syndicated-lending/workflows/build.gradle @@ -0,0 +1,64 @@ +apply plugin: 'net.corda.plugins.cordapp' +apply plugin: 'net.corda.plugins.cordformation' +apply plugin: 'net.corda.plugins.quasar-utils' + +cordapp { + targetPlatformVersion corda_platform_version + minimumPlatformVersion corda_platform_version + workflow { + name "Lending Flows" + vendor "Corda Open Source" + licence "Apache License, Version 2.0" + versionId 1 + } +} + +sourceSets { + main { + java { + srcDir 'src/main/java' + java.outputDir = file('bin/main') + } + resources { + srcDir rootProject.file("config/dev") + } + } + test { + java { + srcDir 'src/test/java' + java.outputDir = file('bin/main') + } + resources { + srcDir rootProject.file("config/test") + } + } + integrationTest { + java { + compileClasspath += main.output + test.output + runtimeClasspath += main.output + test.output + srcDir file('src/integrationTest/java') + } + } +} + +configurations { + integrationTestCompile.extendsFrom testCompile + integrationTestRuntime.extendsFrom testRuntime +} + +dependencies { + testCompile "junit:junit:$junit_version" + + // Corda dependencies. + cordaCompile "$corda_core_release_group:corda-core:$corda_core_release_version" + cordaRuntime "$corda_release_group:corda:$corda_release_version" + testCompile "$corda_release_group:corda-node-driver:$corda_release_version" + + // CorDapp dependencies. + cordapp project(":contracts") +} + +task integrationTest(type: Test, dependsOn: []) { + testClassesDirs = sourceSets.integrationTest.output.classesDirs + classpath = sourceSets.integrationTest.runtimeClasspath +} \ No newline at end of file diff --git a/Advanced/syndicated-lending/workflows/src/integrationTest/java/net/corda/samples/lending/DriverBasedTest.java b/Advanced/syndicated-lending/workflows/src/integrationTest/java/net/corda/samples/lending/DriverBasedTest.java new file mode 100644 index 00000000..85ec790f --- /dev/null +++ b/Advanced/syndicated-lending/workflows/src/integrationTest/java/net/corda/samples/lending/DriverBasedTest.java @@ -0,0 +1,48 @@ +package net.corda.samples.lending; + +import com.google.common.collect.ImmutableList; +import net.corda.core.concurrent.CordaFuture; +import net.corda.core.identity.CordaX500Name; +import net.corda.testing.core.TestIdentity; +import net.corda.testing.driver.DriverParameters; +import net.corda.testing.driver.NodeHandle; +import net.corda.testing.driver.NodeParameters; +import org.junit.Test; + +import java.util.List; + +import static net.corda.testing.driver.Driver.driver; +import static org.junit.Assert.assertEquals; + +public class DriverBasedTest { + private final TestIdentity bankA = new TestIdentity(new CordaX500Name("BankA", "", "GB")); + private final TestIdentity bankB = new TestIdentity(new CordaX500Name("BankB", "", "US")); + + @Test + public void nodeTest() { + driver(new DriverParameters().withIsDebug(true).withStartNodesInProcess(true), dsl -> { + // Start a pair of nodes and wait for them both to be ready. + List> handleFutures = ImmutableList.of( + dsl.startNode(new NodeParameters().withProvidedName(bankA.getName())), + dsl.startNode(new NodeParameters().withProvidedName(bankB.getName())) + ); + + try { + NodeHandle partyAHandle = handleFutures.get(0).get(); + NodeHandle partyBHandle = handleFutures.get(1).get(); + + // From each node, make an RPC call to retrieve another node's name from the network map, to verify that the + // nodes have started and can communicate. + + // This is a very basic test: in practice tests would be starting flows, and verifying the states in the vault + // and other important metrics to ensure that your CorDapp is working as intended. + assertEquals(partyAHandle.getRpc().wellKnownPartyFromX500Name(bankB.getName()).getName(), bankB.getName()); + assertEquals(partyBHandle.getRpc().wellKnownPartyFromX500Name(bankA.getName()).getName(), bankA.getName()); + } catch (Exception e) { + throw new RuntimeException("Caught exception during test: ", e); + } + + return null; + }); + } +} \ No newline at end of file diff --git a/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/ApproveLoanBidFlow.java b/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/ApproveLoanBidFlow.java new file mode 100644 index 00000000..776a85c6 --- /dev/null +++ b/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/ApproveLoanBidFlow.java @@ -0,0 +1,112 @@ +package net.corda.samples.lending.flows; + +import co.paralleluniverse.fibers.Suspendable; +import net.corda.core.contracts.StateAndRef; +import net.corda.core.contracts.StaticPointer; +import net.corda.core.contracts.UniqueIdentifier; +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.samples.lending.contracts.LoanBidContract; +import net.corda.samples.lending.states.LoanBidState; +import net.corda.samples.lending.states.ProjectState; + +import java.util.Arrays; +import java.util.List; + +public class ApproveLoanBidFlow { + + @InitiatingFlow + @StartableByRPC + public static class Initiator extends FlowLogic { + + private UniqueIdentifier bidIdentifier; + + //public constructor + public Initiator(UniqueIdentifier bidIdentifier) { + this.bidIdentifier = bidIdentifier; + } + + @Override + @Suspendable + public SignedTransaction call() throws FlowException { + + List> loanBidStateAndRefs = getServiceHub().getVaultService() + .queryBy(LoanBidState.class).getStates(); + + StateAndRef inputStateAndRef = loanBidStateAndRefs.stream().filter(loanBidStateAndRef -> { + LoanBidState loanBidState = loanBidStateAndRef.getState().getData(); + return loanBidState.getLinearId().equals(bidIdentifier); + }).findAny().orElseThrow(() -> new IllegalArgumentException("Loan Bid Not Found")); + + LoanBidState inputState = inputStateAndRef.getState().getData(); + + final LoanBidState output = new LoanBidState( + new StaticPointer<>(inputStateAndRef.getRef(), ProjectState.class), + inputState.getLinearId(), inputState.getLender(), inputState.getBorrower(), + inputState.getLoanAmount(), inputState.getTenure(), inputState.getRateofInterest(), + inputState.getTransactionFees(), "APPROVED" + ); + + Party notary = inputStateAndRef.getState().getNotary(); + + // Step 3. Create a new TransactionBuilder object. + final TransactionBuilder builder = new TransactionBuilder(notary); + + // Step 4. Add the inputs and outputs, as well as a command to the transaction builder. + builder.addInputState(inputStateAndRef); + builder.addOutputState(output); + builder.addCommand(new LoanBidContract.Commands.Approve(), Arrays.asList(inputState.getBorrower().getOwningKey(),inputState.getLender().getOwningKey())); + + // Step 5. Verify and sign it with our KeyPair. + builder.verify(getServiceHub()); + final SignedTransaction ptx = getServiceHub().signInitialTransaction(builder); + + FlowSession cpSession = initiateFlow(inputState.getLender()); + + //step 6: collect signatures + SignedTransaction stx = subFlow(new CollectSignaturesFlow(ptx, Arrays.asList(cpSession))); + + + // Step 7. Assuming no exceptions, we can now finalise the transaction + return subFlow(new FinalityFlow(stx, Arrays.asList(cpSession))); + } + } + + @InitiatedBy(Initiator.class) + public static class Responder extends FlowLogic { + //private variable + private FlowSession counterpartySession; + + //Constructor + public Responder(FlowSession counterpartySession) { + this.counterpartySession = counterpartySession; + } + + @Suspendable + @Override + public Void call() throws FlowException { + SignedTransaction signedTransaction = subFlow(new SignTransactionFlow(counterpartySession) { + @Suspendable + @Override + protected void checkTransaction(SignedTransaction stx) throws FlowException { + /* + * SignTransactionFlow will automatically verify the transaction and its signatures before signing it. + * However, just because a transaction is contractually valid doesn’t mean we necessarily want to sign. + * What if we don’t want to deal with the counterparty in question, or the value is too high, + * or we’re not happy with the transaction’s structure? checkTransaction + * allows us to define these additional checks. If any of these conditions are not met, + * we will not sign the transaction - even if the transaction and its signatures are contractually valid. + * ---------- + * For this hello-world cordapp, we will not implement any aditional checks. + * */ + } + }); + //Stored the transaction into data base. + subFlow(new ReceiveFinalityFlow(counterpartySession, signedTransaction.getId())); + return null; + } + } + +} diff --git a/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/ApproveSyndicateBidFlow.java b/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/ApproveSyndicateBidFlow.java new file mode 100644 index 00000000..b1702d49 --- /dev/null +++ b/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/ApproveSyndicateBidFlow.java @@ -0,0 +1,113 @@ +package net.corda.samples.lending.flows; + +import co.paralleluniverse.fibers.Suspendable; +import net.corda.core.contracts.StateAndRef; +import net.corda.core.contracts.UniqueIdentifier; +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.samples.lending.contracts.SyndicateBidContract; +import net.corda.samples.lending.states.SyndicateBidState; + +import java.util.Arrays; +import java.util.List; + +public class ApproveSyndicateBidFlow { + + @InitiatingFlow + @StartableByRPC + public static class Initiator extends FlowLogic { + private UniqueIdentifier bidIdentifier; + + //public constructor + public Initiator(UniqueIdentifier bidIdentifier) { + this.bidIdentifier = bidIdentifier; + } + + @Override + @Suspendable + public SignedTransaction call() throws FlowException { + + // Fetch Project + List> syndicateBidStateAndRefs = getServiceHub().getVaultService() + .queryBy(SyndicateBidState.class).getStates(); + + StateAndRef syndicateBidStateAndRef = syndicateBidStateAndRefs.stream().filter(synStateAndRef -> { + SyndicateBidState syndicateBidState = synStateAndRef.getState().getData(); + return syndicateBidState.getLinearId().equals(bidIdentifier); + }).findAny().orElseThrow(() -> new IllegalArgumentException("Syndicate Bid Not Found")); + + SyndicateBidState inputState = syndicateBidStateAndRef.getState().getData(); + + SyndicateBidState outputState = new SyndicateBidState( + inputState.getLinearId(), + inputState.getSyndicateState(), + inputState.getBidAmount(), + inputState.getLeadBank(), + inputState.getParticipatBank(), + "APPROVED" + ); + + Party notary = syndicateBidStateAndRef.getState().getNotary(); + + + // Step 3. Create a new TransactionBuilder object. + final TransactionBuilder builder = new TransactionBuilder(notary); + + // Step 4. Add the input and output state, as well as a command to the transaction builder. + builder.addInputState(syndicateBidStateAndRef); + builder.addOutputState(outputState); + builder.addCommand(new SyndicateBidContract.Commands.Submit(), + Arrays.asList(getOurIdentity().getOwningKey(),inputState.getParticipatBank().getOwningKey())); + + // Step 5. Verify and sign it with our KeyPair. + builder.verify(getServiceHub()); + final SignedTransaction ptx = getServiceHub().signInitialTransaction(builder); + + FlowSession cpSession = initiateFlow(inputState.getParticipatBank()); + + //step 6: collect signatures + SignedTransaction stx = subFlow(new CollectSignaturesFlow(ptx, Arrays.asList(cpSession))); + + // Step 7. Assuming no exceptions, we can now finalise the transaction + return subFlow(new FinalityFlow(stx, Arrays.asList(cpSession))); + } + } + + @InitiatedBy(Initiator.class) + public static class Responder extends FlowLogic { + //private variable + private FlowSession counterpartySession; + + //Constructor + public Responder(FlowSession counterpartySession) { + this.counterpartySession = counterpartySession; + } + + @Suspendable + @Override + public Void call() throws FlowException { + SignedTransaction signedTransaction = subFlow(new SignTransactionFlow(counterpartySession) { + @Suspendable + @Override + protected void checkTransaction(SignedTransaction stx) throws FlowException { + /* + * SignTransactionFlow will automatically verify the transaction and its signatures before signing it. + * However, just because a transaction is contractually valid doesn’t mean we necessarily want to sign. + * What if we don’t want to deal with the counterparty in question, or the value is too high, + * or we’re not happy with the transaction’s structure? checkTransaction + * allows us to define these additional checks. If any of these conditions are not met, + * we will not sign the transaction - even if the transaction and its signatures are contractually valid. + * ---------- + * For this hello-world cordapp, we will not implement any aditional checks. + * */ + } + }); + //Stored the transaction into data base. + subFlow(new ReceiveFinalityFlow(counterpartySession, signedTransaction.getId())); + return null; + } + } + +} diff --git a/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/CreateSyndicateFlow.java b/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/CreateSyndicateFlow.java new file mode 100644 index 00000000..bdf1c264 --- /dev/null +++ b/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/CreateSyndicateFlow.java @@ -0,0 +1,116 @@ +package net.corda.samples.lending.flows; + +import co.paralleluniverse.fibers.Suspendable; +import net.corda.core.contracts.LinearPointer; +import net.corda.core.contracts.StateAndRef; +import net.corda.core.contracts.StaticPointer; +import net.corda.core.contracts.UniqueIdentifier; +import net.corda.core.flows.*; +import net.corda.core.identity.CordaX500Name; +import net.corda.core.identity.Party; +import net.corda.core.node.StatesToRecord; +import net.corda.core.node.services.Vault; +import net.corda.core.transactions.SignedTransaction; +import net.corda.core.transactions.TransactionBuilder; +import net.corda.samples.lending.contracts.SyndicateContract; +import net.corda.samples.lending.states.LoanBidState; +import net.corda.samples.lending.states.ProjectState; +import net.corda.samples.lending.states.SyndicateState; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class CreateSyndicateFlow { + + @InitiatingFlow + @StartableByRPC + public static class Initiator extends FlowLogic { + + private Party leadBank; + private List participantBanks; + private UniqueIdentifier projectIdentifier; + private UniqueIdentifier loanDetailIdentifier; + + //public constructor + public Initiator(List participantBanks, UniqueIdentifier projectIdentifier, UniqueIdentifier loanDetailIdentifier) { + this.participantBanks = participantBanks; + this.projectIdentifier = projectIdentifier; + this.loanDetailIdentifier = loanDetailIdentifier; + } + + @Override + @Suspendable + public SignedTransaction call() throws FlowException { + + // Step 1. Get a reference to the notary service on our network and our key pair. + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); + + + this.leadBank = getOurIdentity(); + + // Fetch Project + List> projectStateAndRefs = getServiceHub().getVaultService() + .queryBy(ProjectState.class).getStates(); + + StateAndRef projectDetailStateAndRef = projectStateAndRefs.stream().filter(projectStateAndRef -> { + ProjectState projectState = projectStateAndRef.getState().getData(); + return projectState.getLinearId().equals(projectIdentifier); + }).findAny().orElseThrow(() -> new IllegalArgumentException("Project Not Found")); + + // Fetch Loan + List> loanBidStateAndRefs = getServiceHub().getVaultService() + .queryBy(LoanBidState.class).getStates(); + + StateAndRef loanStateAndRef = loanBidStateAndRefs.stream().filter(loanBidStateAndRef -> { + LoanBidState loanBidState = loanBidStateAndRef.getState().getData(); + return loanBidState.getLinearId().equals(loanDetailIdentifier); + }).findAny().orElseThrow(() -> new IllegalArgumentException("Loan Details Not Found")); + + SyndicateState syndicateState = new SyndicateState( + new UniqueIdentifier(), leadBank, participantBanks, + new LinearPointer<>(projectIdentifier, ProjectState.class), + new LinearPointer<>(loanDetailIdentifier, LoanBidState.class) + //Collections.emptyList() + ); + + + // Step 3. Create a new TransactionBuilder object. + final TransactionBuilder builder = new TransactionBuilder(notary); + + // Step 4. Add the project as an output state, as well as a command to the transaction builder. + builder.addOutputState(syndicateState); + builder.addCommand(new SyndicateContract.Commands.Create(), Arrays.asList(syndicateState.getLeadBank().getOwningKey())); + + // Step 5. Verify and sign it with our KeyPair. + builder.verify(getServiceHub()); + final SignedTransaction ptx = getServiceHub().signInitialTransaction(builder); + + List cpSesions = participantBanks.stream().map(this::initiateFlow).collect(Collectors.toList()); + + // Step 7. Assuming no exceptions, we can now finalise the transaction + return subFlow(new FinalityFlow(ptx, cpSesions)); + } + } + + @InitiatedBy(Initiator.class) + public static class Responder extends FlowLogic { + //private variable + private FlowSession counterpartySession; + + //Constructor + public Responder(FlowSession counterpartySession) { + this.counterpartySession = counterpartySession; + } + + @Suspendable + @Override + public Void call() throws FlowException { + //Stored the transaction into data base. + subFlow(new ReceiveFinalityFlow(counterpartySession, null, StatesToRecord.ALL_VISIBLE)); + return null; + } + } + +} diff --git a/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/SubmitLoanBidFlow.java b/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/SubmitLoanBidFlow.java new file mode 100644 index 00000000..fe2f9980 --- /dev/null +++ b/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/SubmitLoanBidFlow.java @@ -0,0 +1,108 @@ +package net.corda.samples.lending.flows; + +import co.paralleluniverse.fibers.Suspendable; +import net.corda.core.contracts.StateAndRef; +import net.corda.core.contracts.StatePointer; +import net.corda.core.contracts.StaticPointer; +import net.corda.core.contracts.UniqueIdentifier; +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.samples.lending.contracts.LoanBidContract; +import net.corda.samples.lending.contracts.ProjectContract; +import net.corda.samples.lending.states.LoanBidState; +import net.corda.samples.lending.states.ProjectState; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class SubmitLoanBidFlow { + + @InitiatingFlow + @StartableByRPC + public static class Initiator extends FlowLogic{ + + private Party borrower; + private Party lender; + private int loanAmount; + private int tenure; + private double rateofInterest; + private int transactionFees; + private UniqueIdentifier projectIdentifier; + + //public constructor + public Initiator(Party borrower, int loanAmount, int tenure, double rateofInterest, int transactionFees, + UniqueIdentifier projectIdentifier) { + this.borrower = borrower; + this.loanAmount = loanAmount; + this.tenure = tenure; + this.rateofInterest = rateofInterest; + this.transactionFees = transactionFees; + this.projectIdentifier = projectIdentifier; + } + + @Override + @Suspendable + public SignedTransaction call() throws FlowException { + this.lender = getOurIdentity(); + + + List> projectStateAndRefs = getServiceHub().getVaultService() + .queryBy(ProjectState.class).getStates(); + + StateAndRef inputStateAndRef = projectStateAndRefs.stream().filter(projectStateAndRef -> { + ProjectState projectState = projectStateAndRef.getState().getData(); + return projectState.getLinearId().equals(projectIdentifier); + }).findAny().orElseThrow(() -> new IllegalArgumentException("Project Not Found")); + + Party notary = inputStateAndRef.getState().getNotary(); + + final LoanBidState output = new LoanBidState( + new StaticPointer<>(inputStateAndRef.getRef(), ProjectState.class), + new UniqueIdentifier(), + lender, borrower, + loanAmount, tenure, rateofInterest, transactionFees, + "SUBMITTED" + ); + + // Step 3. Create a new TransactionBuilder object. + final TransactionBuilder builder = new TransactionBuilder(notary); + + // Step 4. Add the project as an output state, as well as a command to the transaction builder. + builder.addOutputState(output); + builder.addCommand(new LoanBidContract.Commands.Submit(), Arrays.asList(lender.getOwningKey())); + + // Step 5. Verify and sign it with our KeyPair. + builder.verify(getServiceHub()); + final SignedTransaction ptx = getServiceHub().signInitialTransaction(builder); + + FlowSession cpSession = initiateFlow(borrower); + + // Step 7. Assuming no exceptions, we can now finalise the transaction + return subFlow(new FinalityFlow(ptx, Arrays.asList(cpSession))); + } + } + + @InitiatedBy(Initiator.class) + public static class Responder extends FlowLogic{ + //private variable + private FlowSession counterpartySession; + + //Constructor + public Responder(FlowSession counterpartySession) { + this.counterpartySession = counterpartySession; + } + + @Suspendable + @Override + public Void call() throws FlowException { + + //Stored the transaction into data base. + subFlow(new ReceiveFinalityFlow(counterpartySession)); + return null; + } + } + +} diff --git a/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/SubmitProjectProposalFlow.java b/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/SubmitProjectProposalFlow.java new file mode 100644 index 00000000..036f7f18 --- /dev/null +++ b/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/SubmitProjectProposalFlow.java @@ -0,0 +1,90 @@ +package net.corda.samples.lending.flows; + +import co.paralleluniverse.fibers.Suspendable; +import net.corda.core.contracts.UniqueIdentifier; +import net.corda.core.flows.*; +import net.corda.core.identity.CordaX500Name; +import net.corda.core.identity.Party; +import net.corda.core.transactions.SignedTransaction; +import net.corda.core.transactions.TransactionBuilder; +import net.corda.samples.lending.contracts.ProjectContract; +import net.corda.samples.lending.states.ProjectState; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class SubmitProjectProposalFlow { + + @InitiatingFlow + @StartableByRPC + public static class Initiator extends FlowLogic{ + + private Party borrower; + private List lenders; + private String projectDescription; + private int projectCost; + private int loanAmount; + + //public constructor + public Initiator(List lenders, String projectDescription, int projectCost, int loanAmount) { + this.lenders = lenders; + this.projectDescription = projectDescription; + this.projectCost = projectCost; + this.loanAmount = loanAmount; + } + + @Override + @Suspendable + public SignedTransaction call() throws FlowException { + this.borrower = getOurIdentity(); + + // Step 1. Get a reference to the notary service on our network and our key pair. + /** Explicit selection of notary by CordaX500Name - argument can by coded in flows or parsed from config (Preferred)*/ + final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB")); + + + //Compose the State that carries the Hello World message + final ProjectState output = new ProjectState(new UniqueIdentifier(), projectDescription, borrower, + projectCost, loanAmount, lenders); + + // Step 3. Create a new TransactionBuilder object. + final TransactionBuilder builder = new TransactionBuilder(notary); + + // Step 4. Add the project as an output state, as well as a command to the transaction builder. + builder.addOutputState(output); + builder.addCommand(new ProjectContract.Commands.ProposeProject(), Collections.singletonList(borrower.getOwningKey())); + + // Step 5. Verify and sign it with our KeyPair. + builder.verify(getServiceHub()); + final SignedTransaction ptx = getServiceHub().signInitialTransaction(builder); + + List cpSesions = lenders.stream().map(this::initiateFlow).collect(Collectors.toList()); + + // Step 7. Assuming no exceptions, we can now finalise the transaction + return subFlow(new FinalityFlow(ptx, cpSesions)); + } + } + + @InitiatedBy(Initiator.class) + public static class Responder extends FlowLogic{ + //private variable + private FlowSession counterpartySession; + + //Constructor + public Responder(FlowSession counterpartySession) { + this.counterpartySession = counterpartySession; + } + + @Suspendable + @Override + public Void call() throws FlowException { + + //Stored the transaction into data base. + subFlow(new ReceiveFinalityFlow(counterpartySession)); + return null; + } + } + +} diff --git a/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/SubmitSyndicateBidFlow.java b/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/SubmitSyndicateBidFlow.java new file mode 100644 index 00000000..b1740ec6 --- /dev/null +++ b/Advanced/syndicated-lending/workflows/src/main/java/net/corda/samples/lending/flows/SubmitSyndicateBidFlow.java @@ -0,0 +1,97 @@ +package net.corda.samples.lending.flows; + +import co.paralleluniverse.fibers.Suspendable; +import net.corda.core.contracts.LinearPointer; +import net.corda.core.contracts.StateAndRef; +import net.corda.core.contracts.UniqueIdentifier; +import net.corda.core.flows.*; +import net.corda.core.identity.CordaX500Name; +import net.corda.core.identity.Party; +import net.corda.core.transactions.SignedTransaction; +import net.corda.core.transactions.TransactionBuilder; +import net.corda.samples.lending.contracts.SyndicateBidContract; +import net.corda.samples.lending.states.SyndicateBidState; +import net.corda.samples.lending.states.SyndicateState; + +import java.util.Arrays; +import java.util.List; + +public class SubmitSyndicateBidFlow { + + @InitiatingFlow + @StartableByRPC + public static class Initiator extends FlowLogic { + private UniqueIdentifier syndicateIdentifier; + private int bidAmount; + + //public constructor + public Initiator(UniqueIdentifier syndicateIdentifier, int bidAmount) { + this.syndicateIdentifier = syndicateIdentifier; + this.bidAmount = bidAmount; + } + + @Override + @Suspendable + public SignedTransaction call() throws FlowException { + + // Fetch Project + List> syndicateStateAndRefs = getServiceHub().getVaultService() + .queryBy(SyndicateState.class).getStates(); + + StateAndRef syndicateStateAndRef = syndicateStateAndRefs.stream().filter(synStateAndRef -> { + SyndicateState syndicateState = synStateAndRef.getState().getData(); + return syndicateState.getLinearId().equals(syndicateIdentifier); + }).findAny().orElseThrow(() -> new IllegalArgumentException("Syndicate Not Found")); + + SyndicateState syndicateState = syndicateStateAndRef.getState().getData(); + + SyndicateBidState syndicateBidState = new SyndicateBidState( + new UniqueIdentifier(), + new LinearPointer<>(syndicateIdentifier, SyndicateState.class), + bidAmount, + syndicateState.getLeadBank(), + getOurIdentity(), + "SUBMITTED" + ); + + Party notary = syndicateStateAndRef.getState().getNotary(); + + // Step 3. Create a new TransactionBuilder object. + final TransactionBuilder builder = new TransactionBuilder(notary); + + // Step 4. Add the project as an output state, as well as a command to the transaction builder. + builder.addOutputState(syndicateBidState); + builder.addCommand(new SyndicateBidContract.Commands.Submit(), Arrays.asList(getOurIdentity().getOwningKey())); + + // Step 5. Verify and sign it with our KeyPair. + builder.verify(getServiceHub()); + final SignedTransaction ptx = getServiceHub().signInitialTransaction(builder); + + FlowSession cpSession = initiateFlow(syndicateState.getLeadBank()); + + // Step 7. Assuming no exceptions, we can now finalise the transaction + return subFlow(new FinalityFlow(ptx, Arrays.asList(cpSession))); + } + } + + @InitiatedBy(Initiator.class) + public static class Responder extends FlowLogic { + //private variable + private FlowSession counterpartySession; + + //Constructor + public Responder(FlowSession counterpartySession) { + this.counterpartySession = counterpartySession; + } + + @Suspendable + @Override + public Void call() throws FlowException { + + //Stored the transaction into data base. + subFlow(new ReceiveFinalityFlow(counterpartySession)); + return null; + } + } + +} diff --git a/Advanced/syndicated-lending/workflows/src/test/java/net/corda/samples/lending/AllInOneTester.java b/Advanced/syndicated-lending/workflows/src/test/java/net/corda/samples/lending/AllInOneTester.java new file mode 100644 index 00000000..bfe225ec --- /dev/null +++ b/Advanced/syndicated-lending/workflows/src/test/java/net/corda/samples/lending/AllInOneTester.java @@ -0,0 +1,113 @@ +package net.corda.samples.lending; + +import com.google.common.collect.ImmutableList; +import net.corda.core.contracts.UniqueIdentifier; +import net.corda.core.identity.CordaX500Name; +import net.corda.core.identity.Party; +import net.corda.core.node.NetworkParameters; +import net.corda.core.node.services.Vault; +import net.corda.core.node.services.vault.QueryCriteria; +import net.corda.core.transactions.SignedTransaction; +import net.corda.samples.lending.flows.*; +import net.corda.samples.lending.states.LoanBidState; +import net.corda.samples.lending.states.ProjectState; +import net.corda.samples.lending.states.SyndicateBidState; +import net.corda.samples.lending.states.SyndicateState; +import net.corda.testing.node.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.concurrent.Future; + +import static org.junit.Assert.assertEquals; + +public class AllInOneTester { + + private MockNetwork network; + private StartedMockNode bankA; + private StartedMockNode bankB; + private StartedMockNode bankC; + private StartedMockNode borrower; + private NetworkParameters testNetworkParameters = + new NetworkParameters(4, Arrays.asList(), 10485760, (10485760 * 5), Instant.now(),1, new LinkedHashMap<>()); + @Before + public void setup() { + network = new MockNetwork(new MockNetworkParameters().withCordappsForAllNodes(ImmutableList.of( + TestCordapp.findCordapp("net.corda.samples.lending.contracts"), + TestCordapp.findCordapp("net.corda.samples.lending.flows"))) + .withNotarySpecs(ImmutableList.of(new MockNetworkNotarySpec(CordaX500Name.parse("O=Notary,L=London,C=GB")))) + .withNetworkParameters(testNetworkParameters)); + borrower = network.createPartyNode(null); + bankA = network.createPartyNode(null); + bankB = network.createPartyNode(null); + bankC = network.createPartyNode(null); + network.runNetwork(); + } + + @After + public void tearDown() { + network.stopNodes(); + } + + @Test + public void AllBusinessLogicFlowTests() { + //Create the project + List lenders = new ArrayList(); + lenders.add(bankA.getInfo().getLegalIdentities().get(0)); + lenders.add(bankB.getInfo().getLegalIdentities().get(0)); + SubmitProjectProposalFlow.Initiator createProjectFlow = new SubmitProjectProposalFlow.Initiator(lenders, "oversea expansion", 100, 10); + Future future = borrower.startFlow(createProjectFlow); + network.runNetwork(); + + //successful query means the state is stored at node b's vault. Flow went through. + QueryCriteria inputCriteria = new QueryCriteria.VaultQueryCriteria().withStatus(Vault.StateStatus.UNCONSUMED); + ProjectState project = bankA.getServices().getVaultService().queryBy(ProjectState.class,inputCriteria).getStates().get(0).getState().getData(); + + //place loan bid + UniqueIdentifier projectID = project.getLinearId(); + SubmitLoanBidFlow.Initiator submitLoanBidFlow = new SubmitLoanBidFlow.Initiator(borrower.getInfo().getLegalIdentities().get(0), 7, 5, 4.0, 1, projectID); + Future future2 = bankA.startFlow(submitLoanBidFlow); + network.runNetwork(); + LoanBidState loanBid = borrower.getServices().getVaultService().queryBy(LoanBidState.class,inputCriteria).getStates().get(0).getState().getData(); + + //Borrower approves the loan bid. pick the winning bank + UniqueIdentifier loanBidId = loanBid.getLinearId(); + ApproveLoanBidFlow.Initiator approveLoanBidFlow = new ApproveLoanBidFlow.Initiator(loanBidId); + Future future3 = borrower.startFlow(approveLoanBidFlow); + network.runNetwork(); + LoanBidState loanBidApproved = bankA.getServices().getVaultService().queryBy(LoanBidState.class,inputCriteria).getStates().get(0).getState().getData(); + assertEquals("APPROVED", loanBidApproved.getStatus()); + + //lead bank create Syndication + UniqueIdentifier approveLoanBidID = loanBidApproved.getLinearId(); + List participatingBanks = new ArrayList(); + participatingBanks.add(bankB.getInfo().getLegalIdentities().get(0)); + participatingBanks.add(bankC.getInfo().getLegalIdentities().get(0)); + CreateSyndicateFlow.Initiator createSyndication = new CreateSyndicateFlow.Initiator(participatingBanks, projectID, approveLoanBidID); + Future future4 = bankA.startFlow(createSyndication); + network.runNetwork(); + SyndicateState syndication = bankA.getServices().getVaultService().queryBy(SyndicateState.class,inputCriteria).getStates().get(0).getState().getData(); + + //participating bank submit syndication bid + UniqueIdentifier syndicationID = syndication.getLinearId(); + SubmitSyndicateBidFlow.Initiator submitSyndicationBid = new SubmitSyndicateBidFlow.Initiator(syndicationID,2); + Future future5 = bankB.startFlow(submitSyndicationBid); + network.runNetwork(); + SyndicateBidState syndicatedBid = bankA.getServices().getVaultService().queryBy(SyndicateBidState.class,inputCriteria).getStates().get(0).getState().getData(); + + //Lead bank approves syndication bid + UniqueIdentifier syndicationBidId = syndicatedBid.getLinearId(); + ApproveSyndicateBidFlow.Initiator approveSyndicationBid = new ApproveSyndicateBidFlow.Initiator(syndicationBidId); + Future future6 = bankA.startFlow(approveSyndicationBid); + network.runNetwork(); + SyndicateBidState syndicatedBidApproved = bankA.getServices().getVaultService().queryBy(SyndicateBidState.class,inputCriteria).getStates().get(0).getState().getData(); + assertEquals("APPROVED", syndicatedBidApproved.getStatus()); + + } +} diff --git a/Advanced/syndicated-lending/workflows/src/test/java/net/corda/samples/lending/FlowTests.java b/Advanced/syndicated-lending/workflows/src/test/java/net/corda/samples/lending/FlowTests.java new file mode 100644 index 00000000..2f2ab817 --- /dev/null +++ b/Advanced/syndicated-lending/workflows/src/test/java/net/corda/samples/lending/FlowTests.java @@ -0,0 +1,104 @@ +package net.corda.samples.lending; + +import com.google.common.collect.ImmutableList; +import net.corda.core.concurrent.CordaFuture; +import net.corda.core.identity.CordaX500Name; +import net.corda.core.transactions.SignedTransaction; +import net.corda.samples.lending.flows.ApproveLoanBidFlow; +import net.corda.samples.lending.flows.SubmitLoanBidFlow; +import net.corda.samples.lending.flows.SubmitProjectProposalFlow; +import net.corda.samples.lending.states.LoanBidState; +import net.corda.samples.lending.states.ProjectState; +import net.corda.testing.node.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.*; + +public class FlowTests { + private MockNetwork network; + private StartedMockNode a; + private StartedMockNode b; + private StartedMockNode c; + private StartedMockNode d; + + @Before + public void setup() { + network = new MockNetwork(new MockNetworkParameters().withCordappsForAllNodes(ImmutableList.of( + TestCordapp.findCordapp("net.corda.samples.lending.contracts"), + TestCordapp.findCordapp("net.corda.samples.lending.flows"))) + .withNotarySpecs(ImmutableList.of(new MockNetworkNotarySpec(CordaX500Name.parse("O=Notary,L=London,C=GB"))))); + a = network.createPartyNode(null); + b = network.createPartyNode(null); + c = network.createPartyNode(null); + d = network.createPartyNode(null); + network.runNetwork(); + } + + @After + public void tearDown() { + network.stopNodes(); + } + + private ProjectState createProject() throws Exception{ + SubmitProjectProposalFlow.Initiator flow = new SubmitProjectProposalFlow.Initiator( + Arrays.asList( + b.getInfo().getLegalIdentities().get(0), + c.getInfo().getLegalIdentities().get(0)), + "Test Project", 10000000, 8000000); + CordaFuture future = a.startFlow(flow); + network.runNetwork(); + SignedTransaction transaction = future.get(); + ProjectState projectState = (ProjectState) transaction.getTx().getOutput(0); + return projectState; + } + + private LoanBidState submitLoanBid(ProjectState projectState) throws Exception{ + SubmitLoanBidFlow.Initiator flow = new SubmitLoanBidFlow.Initiator( + projectState.getBorrower(), + 8000000, 5, 8, 20000, + projectState.getLinearId() + ); + CordaFuture future = b.startFlow(flow); + network.runNetwork(); + SignedTransaction transaction = future.get(); + LoanBidState loanBidState = (LoanBidState) transaction.getTx().getOutput(0); + return loanBidState; + } + + private LoanBidState approveLoanBid(LoanBidState loanBidState) throws Exception{ + ApproveLoanBidFlow.Initiator flow = new ApproveLoanBidFlow.Initiator(loanBidState.getLinearId()); + CordaFuture future = a.startFlow(flow); + network.runNetwork(); + SignedTransaction transaction = future.get(); + LoanBidState loanBidStateUpdated = (LoanBidState) transaction.getTx().getOutput(0); + return loanBidStateUpdated; + } + + @Test + public void testSubmitProjectProposalFlow() throws Exception{ + ProjectState projectState = createProject(); + assertNotNull(projectState); + } + + @Test + public void testSubmitLoanBidFlow() throws Exception{ + ProjectState projectState = createProject(); + LoanBidState loanBidState = submitLoanBid(projectState); + assertNotNull(loanBidState); + } + + @Test + public void testApproveLoanBidFlow() throws Exception{ + ProjectState projectState = createProject(); + LoanBidState loanBidState = submitLoanBid(projectState); + LoanBidState loanBidStateApproved = approveLoanBid(loanBidState); + assertNotNull(loanBidStateApproved); + assertEquals("APPROVED", loanBidStateApproved.getStatus()); + } + + +} diff --git a/Basic/constants.properties b/Basic/constants.properties index 6a01932e..eb9e0ed4 100644 --- a/Basic/constants.properties +++ b/Basic/constants.properties @@ -1,12 +1,12 @@ cordaReleaseGroup=net.corda cordaCoreReleaseGroup=net.corda -cordaVersion=4.8 -cordaCoreVersion=4.8 +cordaVersion=4.10 +cordaCoreVersion=4.10 gradlePluginsVersion=5.0.12 kotlinVersion=1.2.71 junitVersion=4.12 quasarVersion=0.7.10 -log4jVersion =2.11.2 -platformVersion=9 +log4jVersion =2.17.1 +platformVersion=10 slf4jVersion=1.7.25 nettyVersion=4.1.22.Final diff --git a/Basic/cordapp-example/.idea/jarRepositories.xml b/Basic/cordapp-example/.idea/jarRepositories.xml index 580d46d3..554006bf 100644 --- a/Basic/cordapp-example/.idea/jarRepositories.xml +++ b/Basic/cordapp-example/.idea/jarRepositories.xml @@ -26,11 +26,6 @@