Skip to content

Commit 9e11a02

Browse files
committed
add due-diligence-app
1 parent 814e870 commit 9e11a02

File tree

36 files changed

+1818
-0
lines changed

36 files changed

+1818
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Copyright 2016, R3 Limited.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# due-diligence-cordapp
2+
<p align="center">
3+
<img src="./image.png" alt="Corda">
4+
</p>
5+
6+
## Pre-running the app
7+
8+
Deploying nodes: `./gradlew clean deployNodes`
9+
10+
Starting the nodes: `./build/nodes/runnodes`
11+
12+
Uploading whitelisted Auditors: `./gradlew uploadWhitelists`
13+
14+
15+
16+
## Running the Cordapp
17+
Step #1: At PartyA, file the original Corporate Records auditing process with Auditor(Trusted Auditor)
18+
```
19+
flow start RequestToValidateCorporateRecordsInitiator validater: Trusted Auditor, numberOfFiles: 10
20+
```
21+
22+
Step #2: Go to the Trusted Auditor Node, validate the auditing request(This step symbolize the auditing process by this third party auditor). Put in the linearId which was returned in Step #1.
23+
```
24+
flow start ValidateCorporateRecordsInitiator linearId: <XXXX-XXX-XXXX-XXXXX-XXXXXX>
25+
```
26+
27+
Step #3: Go to PartyA, Do a query to confirm that the request has been validated. You should see the variable `qualification=true`.
28+
29+
```
30+
run vaultQuery contractStateType: net.corda.samples.duediligence.states.CorporateRecordsAuditRequest
31+
```
32+
Then, we will instruct PartyA to share a copy of the auditing result with PartyB: (Again, You would need put in the linearId returned from Step #1). The parameter `trustedAuditorAttachment` is a jar file which records the trusted auditors. If PartyA used an untrusted auditor to accquire the corporate records auditing report. He will be prohibited to share with anyone because it is valueless effort(in this business use case, Of course you can modify the business use cases).
33+
```
34+
flow start ShareAuditingResultInitiator AuditingResultID: <XXXX-XXX-XXXX-XXXXX-XXXXXX>, sendTo: BankB, trustedAuditorAttachment: "8DF3275D80B26B9A45AB022F2FDA4A2ED996449B425F8F2245FA5BCF7D1AC587"
35+
```
36+
This flow will return the LinearId of the copy of auditing report, you would need this in Step #6.
37+
38+
Step #4: Go to PartyB, do a query to confirm the delievery of copy of the Auditing Report.
39+
```
40+
run vaultQuery contractStateType: net.corda.samples.duediligence.states.CopyOfCoporateRecordsAuditRequest
41+
```
42+
As of now, the sharing of the trusted auditing report is done. What left now for both PartyA and PartyB in this use case is to upload the Corporate Records auditing report into a due-diligence list, which they can share with a regulator.(You can again alter this step to suit any other use cases).
43+
44+
45+
Step #5: Go to PartyA, Attach the Corporate Records auditing report into a due-diligence checklist and report to the Regulator. Again, the approvalId is the linearId returned in Step #1.
46+
```
47+
flow start CreateCheckListAndAddApprovalInitiator reportTo: Regulator, approvalId: <XXXX-XXX-XXXX-XXXXX-XXXXXX>
48+
```
49+
Step #6: Go to PartyB, Attach the copy of the Corporate Records auditing report into a due-diligence checklist and report to the Regulator. You would need the linearId that is return from Step #5
50+
```
51+
flow start CreateCheckListAndAddApprovalInitiator reportTo: Regulator, approvalId: <XXXX-XXX-XXXX-XXXXX-XXXXXX-Returned-From-Step #5>
52+
```
53+
Step #7: Go to Regulator, do a query on reported due-diligence checklists. You will be able to see both PartyA and PartyB had filed a due-diligence checklist.
54+
```
55+
run vaultQuery contractStateType: net.corda.samples.duediligence.states.DueDChecklist
56+
57+
```
58+
This use of Distributed technology Corda helped PartyB saved the cost of go through corporate records due-diligence process while still reaching a trusted auditing report.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Corda and the Corda logo are trademarks of R3CEV LLC and its affiliates. All rights reserved.
2+
3+
For R3CEV LLC's trademark and logo usage information, please consult our Trademark Usage Policy at
4+
https://www.r3.com/trademark-policy/.
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
buildscript {//properties that you need to build the project
2+
Properties constants = new Properties()
3+
file("$projectDir/../constants.properties").withInputStream { constants.load(it) }
4+
5+
ext {
6+
corda_release_group = constants.getProperty("cordaReleaseGroup")
7+
corda_core_release_group = constants.getProperty("cordaCoreReleaseGroup")
8+
corda_release_version = constants.getProperty("cordaVersion")
9+
corda_core_release_version = constants.getProperty("cordaCoreVersion")
10+
corda_gradle_plugins_version = constants.getProperty("gradlePluginsVersion")
11+
kotlin_version = constants.getProperty("kotlinVersion")
12+
junit_version = constants.getProperty("junitVersion")
13+
quasar_version = constants.getProperty("quasarVersion")
14+
log4j_version = constants.getProperty("log4jVersion")
15+
slf4j_version = constants.getProperty("slf4jVersion")
16+
corda_platform_version = constants.getProperty("platformVersion").toInteger()
17+
//springboot
18+
spring_boot_version = '2.0.2.RELEASE'
19+
spring_boot_gradle_plugin_version = '2.0.2.RELEASE'
20+
}
21+
22+
repositories {
23+
mavenLocal()
24+
mavenCentral()
25+
jcenter()
26+
maven { url 'https://software.r3.com/artifactory/corda-releases' }
27+
}
28+
29+
dependencies {
30+
classpath "net.corda.plugins:cordapp:$corda_gradle_plugins_version"
31+
classpath "net.corda.plugins:cordformation:$corda_gradle_plugins_version"
32+
classpath "net.corda.plugins:quasar-utils:$corda_gradle_plugins_version"
33+
classpath "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_gradle_plugin_version"
34+
}
35+
}
36+
37+
allprojects {//Properties that you need to compile your project (The application)
38+
apply from: "${rootProject.projectDir}/repositories.gradle"
39+
apply plugin: 'java'
40+
41+
repositories {
42+
mavenLocal()
43+
jcenter()
44+
mavenCentral()
45+
maven { url 'https://software.r3.com/artifactory/corda' }
46+
maven { url 'https://jitpack.io' }
47+
}
48+
49+
tasks.withType(JavaCompile) {
50+
options.compilerArgs << "-parameters" // Required by Corda's serialisation framework.
51+
}
52+
53+
jar {
54+
// This makes the JAR's SHA-256 hash repeatable.
55+
preserveFileTimestamps = false
56+
reproducibleFileOrder = true
57+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
58+
}
59+
}
60+
61+
apply plugin: 'net.corda.plugins.cordapp'
62+
apply plugin: 'net.corda.plugins.cordformation'
63+
apply plugin: 'net.corda.plugins.quasar-utils'
64+
65+
sourceSets {
66+
main {
67+
resources {
68+
srcDir rootProject.file("config/dev")
69+
}
70+
}
71+
}
72+
//Module dependencis
73+
dependencies {
74+
// Corda dependencies.
75+
cordaCompile "$corda_core_release_group:corda-core:$corda_core_release_version"
76+
cordaCompile "$corda_release_group:corda-node-api:$corda_release_version"
77+
cordaRuntime "$corda_release_group:corda:$corda_release_version"
78+
79+
// CorDapp dependencies.
80+
cordapp project(":workflows")
81+
cordapp project(":contracts")
82+
83+
cordaCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}"
84+
cordaCompile "org.apache.logging.log4j:log4j-web:${log4j_version}"
85+
cordaCompile "org.slf4j:jul-to-slf4j:$slf4j_version"
86+
}
87+
88+
89+
//Task to deploy the nodes in order to bootstrap a network
90+
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
91+
92+
/* This property will load the CorDapps to each of the node by default, including the Notary. You can find them
93+
* in the cordapps folder of the node at build/nodes/Notary/cordapps. However, the notary doesn't really understand
94+
* the notion of cordapps. In production, Notary does not need cordapps as well. This is just a short cut to load
95+
* the Corda network bootstrapper.
96+
*/
97+
nodeDefaults {
98+
projectCordapp {
99+
deploy = false
100+
}
101+
cordapp project(':contracts')
102+
cordapp project(':workflows')
103+
runSchemaMigration = true //This configuration is for any CorDapps with custom schema, We will leave this as true to avoid
104+
//problems for developers who are not familiar with Corda. If you are not using custom schemas, you can change
105+
//it to false for quicker project compiling time.
106+
}
107+
node {
108+
name "O=Notary,L=London,C=GB"
109+
notary = [validating : false]
110+
p2pPort 10002
111+
rpcSettings {
112+
address("localhost:10003")
113+
adminAddress("localhost:10043")
114+
}
115+
}
116+
node {
117+
name "O=BankA,L=London,C=GB"
118+
p2pPort 10005
119+
rpcSettings {
120+
address("localhost:10006")
121+
adminAddress("localhost:10046")
122+
}
123+
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
124+
}
125+
node {
126+
name "O=BankB,L=New York,C=US"
127+
p2pPort 10008
128+
rpcSettings {
129+
address("localhost:10009")
130+
adminAddress("localhost:10049")
131+
}
132+
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
133+
}
134+
node {
135+
name "O=Trusted Auditor,L=New York,C=US"
136+
p2pPort 10011
137+
rpcSettings {
138+
address("localhost:10012")
139+
adminAddress("localhost:10052")
140+
}
141+
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
142+
}
143+
node {
144+
name "O=Regulator,L=New York,C=US"
145+
p2pPort 10014
146+
rpcSettings {
147+
address("localhost:10015")
148+
adminAddress("localhost:10055")
149+
}
150+
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
151+
}
152+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
apply plugin: 'org.springframework.boot'
2+
3+
sourceSets {
4+
main {
5+
resources {
6+
srcDir rootProject.file("config/dev")
7+
}
8+
}
9+
}
10+
11+
dependencies {
12+
// Corda dependencies.
13+
compile "$corda_release_group:corda-rpc:$corda_release_version"
14+
15+
// CorDapp dependencies.
16+
compile project(":contracts")
17+
compile project(":workflows")
18+
compile("org.springframework.boot:spring-boot-starter-websocket:$spring_boot_version") {
19+
exclude group: "org.springframework.boot", module: "spring-boot-starter-logging"
20+
}
21+
compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}"
22+
compile "org.apache.logging.log4j:log4j-web:${log4j_version}"
23+
compile "org.slf4j:jul-to-slf4j:$slf4j_version"
24+
}
25+
26+
27+
task uploadWhitelists(type: JavaExec, dependsOn: assemble) {
28+
classpath = sourceSets.main.runtimeClasspath
29+
main = 'net.corda.samples.duediligence.client.Client'
30+
args 'localhost:10006', 'localhost:10009', 'localhost:10012'
31+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package net.corda.samples.duediligence.client;
2+
3+
import com.google.common.base.Charsets;
4+
import net.corda.client.rpc.CordaRPCClient;
5+
import net.corda.client.rpc.CordaRPCConnection;
6+
import net.corda.core.crypto.SecureHash;
7+
import net.corda.core.messaging.CordaRPCOps;
8+
import net.corda.core.utilities.NetworkHostAndPort;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
import net.corda.samples.duediligence.Constants;
12+
13+
import java.io.*;
14+
import java.nio.file.FileAlreadyExistsException;
15+
import java.util.List;
16+
import java.util.jar.JarInputStream;
17+
import java.util.stream.Collectors;
18+
19+
public class Client {
20+
21+
private static class Companion {
22+
static Logger logger = LoggerFactory.getLogger(Client.class);
23+
}
24+
25+
/**
26+
* Uploads the jar of blacklisted counterparties with whom agreements cannot be struck to the node.
27+
*/
28+
public static void main(String[] args) throws IOException {
29+
if (args.length == 0) {
30+
String message = "Usage: uploadBlacklist <node address 1> <node address 2> ...";
31+
throw new IllegalArgumentException(message.toString());
32+
}
33+
34+
for (String arg : args) {
35+
NetworkHostAndPort nodeAddress = NetworkHostAndPort.parse(arg);
36+
CordaRPCConnection rpcConnection = new CordaRPCClient(nodeAddress).start("user1", "test");
37+
CordaRPCOps proxy = rpcConnection.getProxy();
38+
39+
SecureHash attachmentHash = Constants.CORPORATE_JAR_HASH;
40+
41+
// take relative path using substring of constant BLACKLIST_JAR_PATH, check if node contains blacklist already
42+
if (!proxy.attachmentExists(attachmentHash)) {
43+
System.out.println("Working Directory = " +
44+
System.getProperty("user.dir"));
45+
attachmentHash = uploadAttachment(proxy, Constants.CORPORATE_JAR_PATH);
46+
Companion.logger.info("Corporate Auditor List uploaded to node at " + nodeAddress);
47+
} else {
48+
Companion.logger.info("Node already contains Corporate Auditor List, skipping upload at " + nodeAddress);
49+
}
50+
51+
JarInputStream attachmentJar = downloadAttachment(proxy, attachmentHash);
52+
Companion.logger.info("Corporate Auditor List downloaded from node at " + nodeAddress);
53+
54+
checkAttachment(attachmentJar, Constants.CORPORATE_ATTACTMENT_FILE_NAME, Constants.CORPORATE_ATTACHMENT_EXPECTED_CONTENTS);
55+
Companion.logger.info("Attachment contents checked on node at " + nodeAddress);
56+
}
57+
58+
}
59+
60+
/**
61+
* Uploads the attachment at [attachmentPath] to the node.
62+
*/
63+
private static SecureHash uploadAttachment(CordaRPCOps proxy, String attachmentPath) throws FileNotFoundException, FileAlreadyExistsException {
64+
FileInputStream attachmentUploadInputStream = new FileInputStream(new File(attachmentPath));
65+
return proxy.uploadAttachment(attachmentUploadInputStream);
66+
}
67+
68+
/**
69+
* Downloads the attachment with hash [attachmentHash] from the node.
70+
*/
71+
private static JarInputStream downloadAttachment(CordaRPCOps proxy, SecureHash attachmentHash) throws IOException {
72+
InputStream attachmentDownloadInputStream = proxy.openAttachment(attachmentHash);
73+
return new JarInputStream(attachmentDownloadInputStream);
74+
}
75+
76+
/**
77+
* Checks the [expectedFileName] and [expectedContents] of the downloaded [attachmentJar].
78+
*/
79+
private static void checkAttachment(JarInputStream attachmentJar, String expectedFileName, List<String> expectedContents) throws IOException {
80+
String name = attachmentJar.getNextEntry().getName();
81+
while (!name.equals(expectedFileName)) {
82+
name = attachmentJar.getNextEntry().getName();
83+
}
84+
85+
BufferedInputStream bisAttachmentJar = new BufferedInputStream(attachmentJar, (8 * 1024));
86+
InputStreamReader isrAttachmentJar = new InputStreamReader(bisAttachmentJar, Charsets.UTF_8);
87+
BufferedReader brAttachmentJar = new BufferedReader(isrAttachmentJar);
88+
89+
List<String> contents = brAttachmentJar.lines().collect(Collectors.toList());
90+
91+
if (!contents.equals(expectedContents)) {
92+
throw new IllegalArgumentException("Downloaded JAR did not have the expected contents.");
93+
}
94+
95+
}
96+
}

0 commit comments

Comments
 (0)