Skip to content

Commit b6e911b

Browse files
committed
add heartbeat
1 parent 5c4e4a6 commit b6e911b

File tree

27 files changed

+1172
-35
lines changed

27 files changed

+1172
-35
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: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Heartbeat CorDapp [<img src="../../webIDE.png" height=25 />](https://ide.corda.net/?folder=/home/coder/samples-java/Features/schedulablestate-heartbeat)
2+
3+
This CorDapp is a simple showcase of [scheduled activities](https://docs.corda.net/docs/corda-os/event-scheduling.html#how-to-implement-scheduled-events) (i.e. activities started by a node at a specific time without
4+
direct input from the node owner).
5+
6+
7+
8+
## Concepts
9+
10+
11+
### Flows
12+
13+
A node starts its com.heartbeat by calling the `StartHeartbeatFlow`. This creates a `HeartState` on the ledger. This
14+
`HeartState` has a scheduled activity to start the `HeatbeatFlow` one second later.
15+
16+
When the `HeartbeatFlow` runs one second later, it consumes the existing `HeartState` and creates a new `HeartState`.
17+
The new `HeartState` also has a scheduled activity to start the `HeatbeatFlow` in one second.
18+
19+
In this way, calling the `StartHeartbeatFlow` creates an endless chain of `HeartbeatFlow`s one second apart.
20+
21+
22+
You can find those flows here :
23+
24+
- [StartHeartBeatFlow](./workflows/src/main/java/com/heartbeat/flows/StartHeartbeatFlow.java#L52-L65)
25+
26+
- [HeartbeatFlow](./workflows/src/main/java/com/heartbeat/flows/HeartbeatFlow.java#L53-L70)
27+
28+
29+
30+
## Usage
31+
32+
33+
### Pre-requisites:
34+
35+
See https://docs.corda.net/getting-set-up.html.
36+
37+
38+
### Running the CorDapp
39+
40+
Open a terminal and go to the project root directory and type: (to deploy the nodes using bootstrapper)
41+
```
42+
./gradlew clean deployNodes
43+
```
44+
Then type: (to run the nodes)
45+
```
46+
./build/nodes/runnodes
47+
```
48+
49+
50+
### Interacting with the nodes:
51+
52+
Go to the [CRaSH](https://docs.corda.net/docs/corda-os/shell.html) shell for PartyA, and run the `StartHeatbeatFlow`:
53+
54+
start StartHeartbeatFlow
55+
56+
If you now start monitoring the node's flow activity...
57+
58+
flow watch
59+
60+
...you will see the `Heartbeat` flow running every second until you close the Flow Watch window using `ctrl/cmd + c`:
61+
62+
xxxxxxxx-xxxx-xxxx-xx Heartbeat xxxxxxxxxxxxxxxxxxxx Lub-dub
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: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
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+
}
18+
19+
repositories {
20+
mavenLocal()
21+
mavenCentral()
22+
jcenter()
23+
maven { url 'https://software.r3.com/artifactory/corda-releases' }
24+
}
25+
26+
dependencies {
27+
classpath "net.corda.plugins:cordapp:$corda_gradle_plugins_version"
28+
classpath "net.corda.plugins:cordformation:$corda_gradle_plugins_version"
29+
classpath "net.corda.plugins:quasar-utils:$corda_gradle_plugins_version"
30+
}
31+
}
32+
33+
allprojects {//Properties that you need to compile your project (The application)
34+
apply from: "${rootProject.projectDir}/repositories.gradle"
35+
apply plugin: 'java'
36+
37+
repositories {
38+
mavenLocal()
39+
jcenter()
40+
mavenCentral()
41+
maven { url 'https://software.r3.com/artifactory/corda' }
42+
maven { url 'https://jitpack.io' }
43+
}
44+
45+
tasks.withType(JavaCompile) {
46+
options.compilerArgs << "-parameters" // Required by Corda's serialisation framework.
47+
}
48+
49+
jar {
50+
// This makes the JAR's SHA-256 hash repeatable.
51+
preserveFileTimestamps = false
52+
reproducibleFileOrder = true
53+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
54+
}
55+
}
56+
57+
apply plugin: 'net.corda.plugins.cordapp'
58+
apply plugin: 'net.corda.plugins.cordformation'
59+
apply plugin: 'net.corda.plugins.quasar-utils'
60+
61+
sourceSets {
62+
main {
63+
resources {
64+
srcDir rootProject.file("config/dev")
65+
}
66+
}
67+
}
68+
//Module dependencis
69+
dependencies {
70+
// Corda dependencies.
71+
cordaCompile "$corda_core_release_group:corda-core:$corda_core_release_version"
72+
cordaCompile "$corda_release_group:corda-node-api:$corda_release_version"
73+
cordaRuntime "$corda_release_group:corda:$corda_release_version"
74+
75+
// CorDapp dependencies.
76+
cordapp project(":workflows")
77+
cordapp project(":contracts")
78+
79+
cordaCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}"
80+
cordaCompile "org.apache.logging.log4j:log4j-web:${log4j_version}"
81+
cordaCompile "org.slf4j:jul-to-slf4j:$slf4j_version"
82+
}
83+
84+
85+
//Task to deploy the nodes in order to bootstrap a network
86+
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
87+
88+
/* This property will load the CorDapps to each of the node by default, including the Notary. You can find them
89+
* in the cordapps folder of the node at build/nodes/Notary/cordapps. However, the notary doesn't really understand
90+
* the notion of cordapps. In production, Notary does not need cordapps as well. This is just a short cut to load
91+
* the Corda network bootstrapper.
92+
*/
93+
nodeDefaults {
94+
projectCordapp {
95+
deploy = false
96+
}
97+
cordapp project(':contracts')
98+
cordapp project(':workflows')
99+
runSchemaMigration = true //This configuration is for any CorDapps with custom schema, We will leave this as true to avoid
100+
//problems for developers who are not familiar with Corda. If you are not using custom schemas, you can change
101+
//it to false for quicker project compiling time.
102+
}
103+
node {
104+
name "O=Notary,L=London,C=GB"
105+
notary = [validating : false]
106+
p2pPort 10002
107+
rpcSettings {
108+
address("localhost:10003")
109+
adminAddress("localhost:10043")
110+
}
111+
}
112+
node {
113+
name "O=PartyA,L=London,C=GB"
114+
p2pPort 10005
115+
rpcSettings {
116+
address("localhost:10006")
117+
adminAddress("localhost:10046")
118+
}
119+
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
120+
}
121+
node {
122+
name "O=PartyB,L=New York,C=US"
123+
p2pPort 10008
124+
rpcSettings {
125+
address("localhost:10009")
126+
adminAddress("localhost:10049")
127+
}
128+
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
129+
}
130+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Configuration status="info">
3+
4+
<Properties>
5+
<Property name="log-path">logs</Property>
6+
<Property name="log-name">node-${hostName}</Property>
7+
<Property name="archive">${log-path}/archive</Property>
8+
</Properties>
9+
10+
<ThresholdFilter level="trace"/>
11+
12+
<Appenders>
13+
<Console name="Console-Appender" target="SYSTEM_OUT">
14+
<PatternLayout>
15+
<pattern>
16+
%highlight{%level{length=1} %d{HH:mm:ss} %T %c{1}.%M - %msg%n}{INFO=white,WARN=red,FATAL=bright red blink}
17+
</pattern>>
18+
</PatternLayout>
19+
</Console>
20+
21+
<!-- Will generate up to 10 log files for a given day. During every rollover it will delete
22+
those that are older than 60 days, but keep the most recent 10 GB -->
23+
<RollingFile name="RollingFile-Appender"
24+
fileName="${log-path}/${log-name}.log"
25+
filePattern="${archive}/${log-name}.%d{yyyy-MM-dd}-%i.log.gz">
26+
27+
<PatternLayout pattern="[%-5level] %d{ISO8601}{GMT+0} [%t] %c{1} - %msg%n"/>
28+
29+
<Policies>
30+
<TimeBasedTriggeringPolicy/>
31+
<SizeBasedTriggeringPolicy size="10MB"/>
32+
</Policies>
33+
34+
<DefaultRolloverStrategy min="1" max="10">
35+
<Delete basePath="${archive}" maxDepth="1">
36+
<IfFileName glob="${log-name}*.log.gz"/>
37+
<IfLastModified age="60d">
38+
<IfAny>
39+
<IfAccumulatedFileSize exceeds="10 GB"/>
40+
</IfAny>
41+
</IfLastModified>
42+
</Delete>
43+
</DefaultRolloverStrategy>
44+
45+
</RollingFile>
46+
</Appenders>
47+
48+
<Loggers>
49+
<Root level="info">
50+
<AppenderRef ref="Console-Appender"/>
51+
<AppenderRef ref="RollingFile-Appender"/>
52+
</Root>
53+
<Logger name="net.corda" level="info" additivity="false">
54+
<AppenderRef ref="Console-Appender"/>
55+
<AppenderRef ref="RollingFile-Appender"/>
56+
</Logger>
57+
</Loggers>
58+
59+
</Configuration>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Configuration status="info">
3+
<Appenders>
4+
<Console name="Console-Appender" target="SYSTEM_OUT">
5+
<PatternLayout>
6+
<pattern>
7+
[%-5level] %d{HH:mm:ss.SSS} [%t] %c{1}.%M - %msg%n
8+
</pattern>>
9+
</PatternLayout>
10+
</Console>
11+
</Appenders>
12+
<Loggers>
13+
<Root level="info">
14+
<AppenderRef ref="Console-Appender"/>
15+
</Root>
16+
<Logger name="net.corda" level="info" additivity="false">
17+
<AppenderRef ref="Console-Appender"/>
18+
</Logger>
19+
</Loggers>
20+
</Configuration>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
apply plugin: 'net.corda.plugins.cordapp'
2+
apply plugin: 'net.corda.plugins.cordformation'
3+
4+
cordapp {
5+
targetPlatformVersion corda_platform_version
6+
minimumPlatformVersion corda_platform_version
7+
contract {
8+
name "Heartbeat Contracts"
9+
vendor "Corda Open Source"
10+
licence "Apache License, Version 2.0"
11+
versionId 1
12+
}
13+
}
14+
15+
sourceSets {
16+
main{
17+
java {
18+
srcDir 'src/main/java'
19+
java.outputDir = file('bin/main')
20+
}
21+
}
22+
test{
23+
java{
24+
srcDir 'src/test/java'
25+
java.outputDir = file('bin/test')
26+
}
27+
}
28+
}
29+
30+
dependencies {
31+
// Corda dependencies.
32+
cordaCompile "$corda_core_release_group:corda-core:$corda_core_release_version"
33+
cordaRuntime "$corda_release_group:corda:$corda_release_version"
34+
testCompile "$corda_release_group:corda-node-driver:$corda_release_version"
35+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package net.corda.samples.heartbeat.contracts;
2+
3+
import net.corda.core.contracts.CommandData;
4+
import net.corda.core.contracts.Contract;
5+
import net.corda.core.transactions.LedgerTransaction;
6+
import org.jetbrains.annotations.NotNull;
7+
8+
/**
9+
* A blank contract and command, solely used for building a valid Heartbeat state transaction.
10+
*/
11+
public class HeartContract implements Contract {
12+
public final static String contractID = "net.corda.samples.heartbeat.contracts.HeartContract";
13+
14+
@Override
15+
public void verify(@NotNull LedgerTransaction tx) throws IllegalArgumentException {
16+
// Omitted for the purpose of this sample.
17+
}
18+
19+
public interface Commands extends CommandData {
20+
class Beat implements Commands {}
21+
}
22+
}

0 commit comments

Comments
 (0)