Skip to content

Commit 79c8eb7

Browse files
committed
example cordapp revamp
1 parent f4720b9 commit 79c8eb7

File tree

78 files changed

+1063
-1679
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+1063
-1679
lines changed

Basic/cordapp-example/clients/src/main/resources/application.properties renamed to Basic/cordapp-example-new/README.md

File renamed without changes.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.template;
2+
3+
import net.corda.client.rpc.CordaRPCClient;
4+
import net.corda.client.rpc.CordaRPCConnection;
5+
import net.corda.core.identity.CordaX500Name;
6+
import net.corda.core.messaging.CordaRPCOps;
7+
import net.corda.core.node.NodeInfo;
8+
import net.corda.core.utilities.NetworkHostAndPort;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
12+
import java.util.List;
13+
14+
import static net.corda.core.utilities.NetworkHostAndPort.parse;
15+
16+
/**
17+
* Connects to a Corda node via RPC and performs RPC operations on the node.
18+
*
19+
* The RPC connection is configured using command line arguments.
20+
*/
21+
public class Client {
22+
private static final Logger logger = LoggerFactory.getLogger(Client.class);
23+
24+
public static void main(String[] args) {
25+
// Create an RPC connection to the node.
26+
if (args.length != 3) throw new IllegalArgumentException("Usage: Client <node address> <rpc username> <rpc password>");
27+
final NetworkHostAndPort nodeAddress = parse(args[0]);
28+
final String rpcUsername = args[1];
29+
final String rpcPassword = args[2];
30+
final CordaRPCClient client = new CordaRPCClient(nodeAddress);
31+
final CordaRPCConnection clientConnection = client.start(rpcUsername, rpcPassword);
32+
final CordaRPCOps proxy = clientConnection.getProxy();
33+
34+
// Interact with the node.
35+
// Example #1, here we print the nodes on the network.
36+
final List<NodeInfo> nodes = proxy.networkMapSnapshot();
37+
System.out.println("\n-- Here is the networkMap snapshot --");
38+
logger.info("{}", nodes);
39+
40+
// Example #2, here we print the PartyA's node info
41+
CordaX500Name name = proxy.nodeInfo().getLegalIdentities().get(0).getName();//nodeInfo().legalIdentities.first().name
42+
System.out.println("\n-- Here is the node info of the node that the client connected to --");
43+
logger.info("{}", name);
44+
45+
//Close the client connection
46+
clientConnection.close();
47+
48+
}
49+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.template.webserver;
2+
3+
import net.corda.core.messaging.CordaRPCOps;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.RequestMapping;
8+
import org.springframework.web.bind.annotation.RestController;
9+
10+
/**
11+
* Define your API endpoints here.
12+
*/
13+
@RestController
14+
@RequestMapping("/") // The paths for HTTP requests are relative to this base path.
15+
public class Controller {
16+
private final CordaRPCOps proxy;
17+
private final static Logger logger = LoggerFactory.getLogger(Controller.class);
18+
19+
public Controller(NodeRPCConnection rpc) {
20+
this.proxy = rpc.proxy;
21+
}
22+
23+
@GetMapping(value = "/templateendpoint", produces = "text/plain")
24+
private String templateendpoint() {
25+
return "Define an endpoint here.";
26+
}
27+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.template.webserver;
2+
3+
import net.corda.client.rpc.CordaRPCClient;
4+
import net.corda.client.rpc.CordaRPCConnection;
5+
import net.corda.core.messaging.CordaRPCOps;
6+
import net.corda.core.utilities.NetworkHostAndPort;
7+
import org.springframework.beans.factory.annotation.Value;
8+
import org.springframework.stereotype.Component;
9+
10+
import javax.annotation.PostConstruct;
11+
import javax.annotation.PreDestroy;
12+
13+
/**
14+
* Wraps an RPC connection to a Corda node.
15+
*
16+
* The RPC connection is configured using command line arguments.
17+
*/
18+
@Component
19+
public class NodeRPCConnection implements AutoCloseable {
20+
// The host of the node we are connecting to.
21+
@Value("${config.rpc.host}")
22+
private String host;
23+
// The RPC port of the node we are connecting to.
24+
@Value("${config.rpc.username}")
25+
private String username;
26+
// The username for logging into the RPC client.
27+
@Value("${config.rpc.password}")
28+
private String password;
29+
// The password for logging into the RPC client.
30+
@Value("${config.rpc.port}")
31+
private int rpcPort;
32+
33+
private CordaRPCConnection rpcConnection;
34+
CordaRPCOps proxy;
35+
36+
@PostConstruct
37+
public void initialiseNodeRPCConnection() {
38+
NetworkHostAndPort rpcAddress = new NetworkHostAndPort(host, rpcPort);
39+
CordaRPCClient rpcClient = new CordaRPCClient(rpcAddress);
40+
rpcConnection = rpcClient.start(username, password);
41+
proxy = rpcConnection.getProxy();
42+
}
43+
44+
@PreDestroy
45+
public void close() {
46+
rpcConnection.notifyServerAndClose();
47+
}
48+
}

Basic/cordapp-example/clients/src/main/java/com/example/server/Server.java renamed to Basic/cordapp-example-new/clients/src/main/java/net/corda/samples/example/webserver/Starter.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
1-
package com.example.server;
1+
package com.template.webserver;
22

33
import org.springframework.boot.Banner;
44
import org.springframework.boot.SpringApplication;
5-
import org.springframework.boot.WebApplicationType;
65
import org.springframework.boot.autoconfigure.SpringBootApplication;
76

7+
import static org.springframework.boot.WebApplicationType.SERVLET;
8+
89
/**
910
* Our Spring Boot application.
1011
*/
1112
@SpringBootApplication
12-
public class Server {
13+
public class Starter {
1314
/**
1415
* Starts our Spring Boot application.
1516
*/
1617
public static void main(String[] args) {
17-
SpringApplication app = new SpringApplication(Server.class);
18+
SpringApplication app = new SpringApplication(Starter.class);
1819
app.setBannerMode(Banner.Mode.OFF);
19-
app.setWebApplicationType(WebApplicationType.SERVLET);
20+
app.setWebApplicationType(SERVLET);
2021
app.run(args);
2122
}
22-
}
23+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.template.contracts;
2+
3+
import com.template.states.TemplateState;
4+
import net.corda.core.contracts.CommandData;
5+
import net.corda.core.contracts.CommandWithParties;
6+
import net.corda.core.contracts.Contract;
7+
import net.corda.core.transactions.LedgerTransaction;
8+
9+
import static net.corda.core.contracts.ContractsDSL.requireSingleCommand;
10+
import static net.corda.core.contracts.ContractsDSL.requireThat;
11+
import java.util.List;
12+
13+
// ************
14+
// * Contract *
15+
// ************
16+
public class TemplateContract implements Contract {
17+
// This is used to identify our contract when building a transaction.
18+
public static final String ID = "com.template.contracts.TemplateContract";
19+
20+
// A transaction is valid if the verify() function of the contract of all the transaction's input and output states
21+
// does not throw an exception.
22+
@Override
23+
public void verify(LedgerTransaction tx) {
24+
25+
/* We can use the requireSingleCommand function to extract command data from transaction.
26+
* However, it is possible to have multiple commands in a signle transaction.*/
27+
final CommandWithParties<Commands> command = requireSingleCommand(tx.getCommands(), Commands.class);
28+
final Commands commandData = command.getValue();
29+
30+
if (commandData.equals(new Commands.Send())) {
31+
//Retrieve the output state of the transaction
32+
TemplateState output = tx.outputsOfType(TemplateState.class).get(0);
33+
34+
//Using Corda DSL function requireThat to replicate conditions-checks
35+
requireThat(require -> {
36+
require.using("No inputs should be consumed when sending the Hello-World message.", tx.getInputStates().size() == 0);
37+
require.using("The message must be Hello-World", output.getMsg().equals("Hello-World"));
38+
return null;
39+
});
40+
}
41+
}
42+
43+
// Used to indicate the transaction's intent.
44+
public interface Commands extends CommandData {
45+
//In our hello-world app, We will only have one command.
46+
class Send implements Commands {}
47+
}
48+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.template.states;
2+
3+
import com.template.contracts.TemplateContract;
4+
import net.corda.core.contracts.BelongsToContract;
5+
import net.corda.core.contracts.ContractState;
6+
import net.corda.core.identity.AbstractParty;
7+
import net.corda.core.identity.Party;
8+
9+
import java.util.Arrays;
10+
import java.util.List;
11+
12+
// *********
13+
// * State *
14+
// *********
15+
@BelongsToContract(TemplateContract.class)
16+
public class TemplateState implements ContractState {
17+
18+
//private variables
19+
private String msg;
20+
private Party sender;
21+
private Party receiver;
22+
23+
/* Constructor of your Corda state */
24+
public TemplateState(String msg, Party sender, Party receiver) {
25+
this.msg = msg;
26+
this.sender = sender;
27+
this.receiver = receiver;
28+
}
29+
30+
//getters
31+
public String getMsg() { return msg; }
32+
public Party getSender() { return sender; }
33+
public Party getReceiver() { return receiver; }
34+
35+
/* This method will indicate who are the participants and required signers when
36+
* this state is used in a transaction. */
37+
@Override
38+
public List<AbstractParty> getParticipants() {
39+
return Arrays.asList(sender,receiver);
40+
}
41+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.template.contracts;
2+
3+
import net.corda.testing.node.MockServices;
4+
import org.junit.Test;
5+
6+
public class ContractTests {
7+
private final MockServices ledgerServices = new MockServices();
8+
9+
@Test
10+
public void dummyTest() {
11+
12+
}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.template.contracts;
2+
3+
import net.corda.testing.node.MockServices;
4+
import org.junit.Test;
5+
6+
public class StateTests {
7+
private final MockServices ledgerServices = new MockServices();
8+
9+
@Test
10+
public void dummyTest() {
11+
12+
}
13+
}

Basic/cordapp-example/workflows-java/src/integrationTest/java/com/example/DriverBasedTests.java renamed to Basic/cordapp-example-new/workflows/src/integrationTest/java/net/corda/samples/example/DriverBasedTest.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.example;
1+
package com.template;
22

33
import com.google.common.collect.ImmutableList;
44
import net.corda.core.concurrent.CordaFuture;
@@ -14,16 +14,14 @@
1414
import static net.corda.testing.driver.Driver.driver;
1515
import static org.junit.Assert.assertEquals;
1616

17-
public class DriverBasedTests {
17+
public class DriverBasedTest {
1818
private final TestIdentity bankA = new TestIdentity(new CordaX500Name("BankA", "", "GB"));
1919
private final TestIdentity bankB = new TestIdentity(new CordaX500Name("BankB", "", "US"));
2020

2121
@Test
2222
public void nodeTest() {
2323
driver(new DriverParameters().withIsDebug(true).withStartNodesInProcess(true), dsl -> {
24-
25-
// This starts three nodes simultaneously with startNode, which returns a future that completes when the node
26-
// has completed startup. Then these are all resolved with getOrThrow which returns the NodeHandle list.
24+
// Start a pair of nodes and wait for them both to be ready.
2725
List<CordaFuture<NodeHandle>> handleFutures = ImmutableList.of(
2826
dsl.startNode(new NodeParameters().withProvidedName(bankA.getName())),
2927
dsl.startNode(new NodeParameters().withProvidedName(bankB.getName()))
@@ -33,17 +31,18 @@ public void nodeTest() {
3331
NodeHandle partyAHandle = handleFutures.get(0).get();
3432
NodeHandle partyBHandle = handleFutures.get(1).get();
3533

36-
// This test will call via the RPC proxy to find a party of another node to verify that the nodes have
37-
// started and can communicate. This is a very basic test, in practice tests would be starting flows,
38-
// and verifying the states in the vault and other important metrics to ensure that your CorDapp is working
39-
// as intended.
34+
// From each node, make an RPC call to retrieve another node's name from the network map, to verify that the
35+
// nodes have started and can communicate.
36+
37+
// This is a very basic test: in practice tests would be starting flows, and verifying the states in the vault
38+
// and other important metrics to ensure that your CorDapp is working as intended.
4039
assertEquals(partyAHandle.getRpc().wellKnownPartyFromX500Name(bankB.getName()).getName(), bankB.getName());
4140
assertEquals(partyBHandle.getRpc().wellKnownPartyFromX500Name(bankA.getName()).getName(), bankA.getName());
4241
} catch (Exception e) {
43-
throw new RuntimeException("Caught exception during test", e);
42+
throw new RuntimeException("Caught exception during test: ", e);
4443
}
4544

4645
return null;
4746
});
4847
}
49-
}
48+
}

0 commit comments

Comments
 (0)