Commit 7b23004f authored by Bruno Bradach's avatar Bruno Bradach
Browse files

Add Corda project

parent ff816591
social-security @ 9314ed04
Subproject commit 9314ed045a3a6dd8292ff22318c1890ff71a4d6d
* 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
import static
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
pipeline {
agent {
label 'eight-cores'
options {
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 {
# Eclipse, ctags, Mac metadata, log files
# General build files
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
## Directory-based project format:
# if you remove the above rule, at least ignore the following:
# Specific files to avoid churn
# User-specific stuff:
# Sensitive or high-churn files:
# Gradle:
# Mongo Explorer plugin:
## File-based project format:
## Plugin-specific files:
# IntelliJ
# mpeltonen/sbt-idea plugin
# JIRA plugin
# Crashlytics plugin (for Android Studio and IntelliJ)
# docs related
# if you use the installQuasar task
java.home=C\:/Program Files/Java/jdk-11.0.12
\ No newline at end of file
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
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
See the License for the specific language governing permissions and
limitations under the License.
\ No newline at end of file
<p align="center">
<img src="" alt="Corda" width="500">
# Social Security CorDapp
Este proyecto contiene la implementación del escenario de seguridad social en Corda. El proyecto fue creado a partir del CordApp Example provisto por Corda.
# Pre-Requisitos
Para mas información sobre las herramientas necesarias para el ambiente de desarrollo ver la documentación de Corda:
# Uso
## Iniciar los nodos
Para compilar el proyecto y generar los nodos se debe ejecutar `gradlew deployNodes` estando en el directorio raíz del proyecto. Luego, para iniciar los nodos se debe ejecutar `runnodes.bat` estando en el directorio `/build/nodes`.
Para más información sobre cómo iniciar los nodos de la blockchain, ver el siguiente tutorial a partir del paso 2:
## Interactuar con los nodos
### Shell
Luego de iniciar los nodos, habrá una interfaz shell para cada uno de ellos. Se puede interactuar con los nodos a través de esta interfaz:
Welcome to the Corda interactive shell.
Useful commands include 'help' to see what is available, and 'bye' to shut down the node.
Tue Nov 06 11:58:13 GMT 2018>>>
Por más información sobre los comandos de la shell ver la siguiente documentación:
En el README raíz del repositorio se muestra cómo registrar una transacción y consultar el ledger desde la consola.
### Spring Boot Web Server
En `clients/src/main/java/com/template/webserver/` se encuentra un servidor Spring que se conecta a un nodo a través de RPC y permite interactuar con los nodos de Corda por HTTP.
Los endpoints están definidos en el controlador `clients/src/main/java/com/template/webserver/`.
#### Iniciar el Web Server
Ejecutar la tarea `runTemplateServer` de Gradle ejecutando `gradlew runTemplateServer` en la consola. El Web Server se iniciará en `localhost:10050` exponiendo los endpoints definidos en el controller.
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
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info">
<Property name="log-path">logs</Property>
<Property name="log-name">node-${hostName}</Property>
<Property name="archive">${log-path}/archive</Property>
<ThresholdFilter level="trace"/>
<Console name="Console-Appender" target="SYSTEM_OUT">
%highlight{%level{length=1} %d{HH:mm:ss} %T %c{1}.%M - %msg%n}{INFO=white,WARN=red,FATAL=bright red blink}
<!-- Will generate up to 10 log files for a given day. During every rollover it will delete
those that are older than 60 days, but keep the most recent 10 GB -->
<RollingFile name="RollingFile-Appender"
<PatternLayout pattern="[%-5level] %d{ISO8601}{GMT+0} [%t] %c{1} - %msg%n"/>
<SizeBasedTriggeringPolicy size="10MB"/>
<DefaultRolloverStrategy min="1" max="10">
<Delete basePath="${archive}" maxDepth="1">
<IfFileName glob="${log-name}*.log.gz"/>
<IfLastModified age="60d">
<IfAccumulatedFileSize exceeds="10 GB"/>
<Root level="info">
<AppenderRef ref="Console-Appender"/>
<AppenderRef ref="RollingFile-Appender"/>
<Logger name="net.corda" level="info" additivity="false">
<AppenderRef ref="Console-Appender"/>
<AppenderRef ref="RollingFile-Appender"/>
buildscript {//properties that you need to build the project
Properties constants = new Properties()
file("$projectDir/./").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()
spring_boot_version = '2.0.2.RELEASE'
spring_boot_gradle_plugin_version = '2.0.2.RELEASE'
repositories {
maven { url '' }
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 {
maven { url '' }
maven { url '' }
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"
//Task to build the jar for ganache.
task ganache {
subprojects {
if ( != "clients") {
dependsOn jar
doLast {
copy {
from "${buildDir}/libs"
into "${rootDir}/build/libs"
//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')
node {
name "O=Notary,L=Rome,C=IT"
notary = [validating : false]
p2pPort 10002
rpcSettings {
node {
name "O=BPSES,L=Madrid,C=ES"
p2pPort 10005
rpcSettings {
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
node {
name "O=BPSFR,L=Paris,C=FR"
p2pPort 10008
rpcSettings {
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
node {
name "O=Gateway,L=Berlin,C=DE"
p2pPort 10011
rpcSettings {
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
apply plugin: 'org.springframework.boot'
sourceSets {
main {
resources {
srcDir rootProject.file("config/dev")
dependencies {
// Corda dependencies.
compile "$corda_release_group:corda-rpc:$corda_release_version"
// CorDapp dependencies.
compile project(":contracts")
compile project(":workflows")
compile("org.springframework.boot:spring-boot-starter-websocket:$spring_boot_version") {
exclude group: "org.springframework.boot", module: "spring-boot-starter-logging"
compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}"
compile "org.apache.logging.log4j:log4j-web:${log4j_version}"
compile "org.slf4j:jul-to-slf4j:$slf4j_version"
springBoot {
mainClassName = "com.template.webserver.Server"
/* The Client is the communication channel between the external and the node. This task will help you immediately
* execute your rpc methods in the main method of the client.kt. You can somewhat see this as a quick test of making
* RPC calls to your nodes.
task runTemplateClient(type: JavaExec, dependsOn: assemble) {
classpath = sourceSets.main.runtimeClasspath
main = 'com.template.Client'
args 'localhost:10006', 'user1', 'test'
/* This task will start the springboot server that connects to your node (via RPC connection). All of the http requests
* are in the Controller file. You can leave the Server.kt and NodeRPCConnection.kt file untouched for your use.
* The RPC port is intentionally set to the Gateway node.
task runTemplateServer(type: JavaExec, dependsOn: assemble) {
classpath = sourceSets.main.runtimeClasspath
main = 'com.template.webserver.Starter'
args '--server.port=10050', '', '--config.rpc.port=10012', '--config.rpc.username=user1', '--config.rpc.password=test'
package com.template;
import net.corda.client.rpc.CordaRPCClient;
import net.corda.client.rpc.CordaRPCConnection;
import net.corda.core.identity.CordaX500Name;
import net.corda.core.messaging.CordaRPCOps;
import net.corda.core.node.NodeInfo;
import net.corda.core.utilities.NetworkHostAndPort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import static net.corda.core.utilities.NetworkHostAndPort.parse;
* Connects to a Corda node via RPC and performs RPC operations on the node.
* The RPC connection is configured using command line arguments.
public class Client {
private static final Logger logger = LoggerFactory.getLogger(Client.class);
public static void main(String[] args) {
// Create an RPC connection to the node.
if (args.length != 3) throw new IllegalArgumentException("Usage: Client <node address> <rpc username> <rpc password>");
final NetworkHostAndPort nodeAddress = parse(args[0]);
final String rpcUsername = args[1];
final String rpcPassword = args[2];
final CordaRPCClient client = new CordaRPCClient(nodeAddress);
final CordaRPCConnection clientConnection = client.start(rpcUsername, rpcPassword);
final CordaRPCOps proxy = clientConnection.getProxy();
// Interact with the node.
// Example #1, here we print the nodes on the network.
final List<NodeInfo> nodes = proxy.networkMapSnapshot();
System.out.println("\n-- Here is the networkMap snapshot --");"{}", nodes);
// Example #2, here we print the PartyA's node info
CordaX500Name name = proxy.nodeInfo().getLegalIdentities().get(0).getName();//nodeInfo().legalIdentities.first().name
System.out.println("\n-- Here is the node info of the node that the client connected to --");"{}", name);
//Close the client connection
\ No newline at end of file
package com.template.webserver;
import com.template.flows.*;
import com.template.schema.SSSchema;
import com.template.states.SSState;
import net.corda.core.contracts.StateAndRef;
import net.corda.core.contracts.StateRef;
import net.corda.core.crypto.SecureHash;
import net.corda.core.flows.FlowLogic;
import net.corda.core.identity.CordaX500Name;
import net.corda.core.identity.Party;
import net.corda.core.messaging.CordaRPCOps;
import net.corda.core.transactions.SignedTransaction;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.json.JsonArray;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.exception.ExceptionUtils;
import static org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace;
import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE;
* Define your API endpoints here.
@RequestMapping("/api/crosschain") // The paths for HTTP requests are relative to this base path.
public class Controller {
private final CordaRPCOps proxy;
private final CordaX500Name me;
private final static Logger logger = LoggerFactory.getLogger(Controller.class);
private final String gatewayPartyString = "O=Gateway,L=Berlin,C=DE";
private final Party gatewayParty;
public Controller(NodeRPCConnection rpc) {
this.proxy = rpc.proxy; = proxy.nodeInfo().getLegalIdentities().get(0).getName();
CordaX500Name gatewayPartyName = CordaX500Name.parse(gatewayPartyString);
this.gatewayParty = proxy.wellKnownPartyFromX500Name(gatewayPartyName);
@PostMapping(value = "/transactions")
private ResponseEntity<String> recordExchange(@RequestBody Event event) throws IllegalArgumentException {
String targetContract = event.getTargetContract();
EventData data = event.getData();
// Create a new state using the parameters given
try {
Class<? extends FlowLogic<SignedTransaction>> flowClass = Utils.getMappedFlow(targetContract);
if (flowClass != null) {
// Start the flow. It blocks and waits for the flow to return.
SignedTransaction result =
return ResponseEntity