Skip to content

Commit f9ada8f

Browse files
mbwhitejt-nti
authored andcommitted
Chaincode-as-a-service main bootstrap method
Included the main bootstrap method into the codebase to assist in getting the chaincode as a service up and running. Signed-off-by: Matthew B White <[email protected]>
1 parent d596ec8 commit f9ada8f

File tree

7 files changed

+246
-204
lines changed

7 files changed

+246
-204
lines changed

fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.hyperledger.fabric.shim.ChaincodeBase;
2828
import org.hyperledger.fabric.shim.ChaincodeServer;
2929
import org.hyperledger.fabric.shim.ChaincodeStub;
30+
import org.hyperledger.fabric.shim.NettyChaincodeServer;
3031
import org.hyperledger.fabric.shim.ResponseUtils;
3132
import org.hyperledger.fabric.traces.Traces;
3233

@@ -114,7 +115,8 @@ private Response processRequest(final ChaincodeStub stub) {
114115

115116
// based on the routing information the serializer can be found
116117
// TRANSACTION target as this on the 'inbound' to invoke a tx
117-
final SerializerInterface si = serializers.getSerializer(txFn.getRouting().getSerializerName(), Serializer.TARGET.TRANSACTION);
118+
final SerializerInterface si = serializers.getSerializer(txFn.getRouting().getSerializerName(),
119+
Serializer.TARGET.TRANSACTION);
118120
final ExecutionService executor = ExecutionFactory.getInstance().createExecutionService(si);
119121

120122
logger.info(() -> "Got routing:" + txFn.getRouting());
@@ -159,7 +161,7 @@ TxFunction getRouting(final InvocationRequest request) {
159161
*
160162
* @param args
161163
*/
162-
public static void main(final String[] args) {
164+
public static void main(final String[] args) throws Exception {
163165

164166
final ContractRouter cfc = new ContractRouter(args);
165167
cfc.findAllContracts();
@@ -171,10 +173,16 @@ public static void main(final String[] args) {
171173
MetadataBuilder.initialize(cfc.getRoutingRegistry(), cfc.getTypeRegistry());
172174
logger.info(() -> "Metadata follows:" + MetadataBuilder.debugString());
173175

174-
// commence routing, once this has returned the chaincode and contract api is
175-
// 'open for chaining'
176-
cfc.startRouting();
177-
176+
// check if this should be running in client or server mode
177+
if (cfc.isServer()) {
178+
logger.info("Starting chaincode as server");
179+
ChaincodeServer chaincodeServer = new NettyChaincodeServer(cfc,
180+
cfc.getChaincodeServerConfig());
181+
chaincodeServer.start();
182+
} else {
183+
logger.info("Starting chaincode as client");
184+
cfc.startRouting();
185+
}
178186
}
179187

180188
protected TypeRegistry getTypeRegistry() {
@@ -190,14 +198,15 @@ protected RoutingRegistry getRoutingRegistry() {
190198
*
191199
* @param chaincodeServer
192200
*/
193-
public void startRouterWithChaincodeServer(final ChaincodeServer chaincodeServer) throws IOException, InterruptedException {
201+
public void startRouterWithChaincodeServer(final ChaincodeServer chaincodeServer)
202+
throws IOException, InterruptedException {
194203
findAllContracts();
195204
logger.fine(getRoutingRegistry().toString());
196205

197206
MetadataBuilder.initialize(getRoutingRegistry(), getTypeRegistry());
198207
logger.info(() -> "Metadata follows:" + MetadataBuilder.debugString());
199208

200-
logger.info("Starting ChaincodeServer");
201209
chaincodeServer.start();
202210
}
211+
203212
}

fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java

Lines changed: 103 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import java.io.File;
1414
import java.io.IOException;
1515
import java.io.InputStream;
16+
import java.net.InetSocketAddress;
17+
import java.net.SocketAddress;
1618
import java.nio.file.Files;
1719
import java.nio.file.Paths;
1820
import java.security.Security;
@@ -51,8 +53,11 @@
5153
* Abstract implementation of {@link Chaincode}.
5254
*
5355
* <p>
54-
* All chaincode implementations must extend the abstract class <code>ChaincodeBase</code>.
55-
* It is possible to implement chaincode by extending <code>ChaincodeBase</code> directly however new projects should implement {@link org.hyperledger.fabric.contract.ContractInterface} and use the contract programming model instead.
56+
* All chaincode implementations must extend the abstract class
57+
* <code>ChaincodeBase</code>. It is possible to implement chaincode by
58+
* extending <code>ChaincodeBase</code> directly however new projects should
59+
* implement {@link org.hyperledger.fabric.contract.ContractInterface} and use
60+
* the contract programming model instead.
5661
*
5762
* @see org.hyperledger.fabric.contract
5863
*/
@@ -96,17 +101,23 @@ public abstract class ChaincodeBase implements Chaincode {
96101
private boolean tlsEnabled = false;
97102
private String tlsClientKeyPath;
98103
private String tlsClientCertPath;
104+
private String tlsClientKeyFile;
105+
private String tlsClientCertFile;
99106
private String tlsClientRootCertPath;
100107

101108
private String id;
102109
private String localMspId = "";
110+
private String chaincodeServerAddress = "";
103111

112+
private static final String CHAINCODE_SERVER_ADDRESS = "CHAINCODE_SERVER_ADDRESS";
104113
private static final String CORE_CHAINCODE_ID_NAME = "CORE_CHAINCODE_ID_NAME";
105114
private static final String CORE_PEER_ADDRESS = "CORE_PEER_ADDRESS";
106115
private static final String CORE_PEER_TLS_ENABLED = "CORE_PEER_TLS_ENABLED";
107116
private static final String CORE_PEER_TLS_ROOTCERT_FILE = "CORE_PEER_TLS_ROOTCERT_FILE";
108117
private static final String ENV_TLS_CLIENT_KEY_PATH = "CORE_TLS_CLIENT_KEY_PATH";
109118
private static final String ENV_TLS_CLIENT_CERT_PATH = "CORE_TLS_CLIENT_CERT_PATH";
119+
private static final String ENV_TLS_CLIENT_KEY_FILE = "CORE_TLS_CLIENT_KEY_FILE";
120+
private static final String ENV_TLS_CLIENT_CERT_FILE = "CORE_TLS_CLIENT_CERT_FILE";
110121
private static final String CORE_PEER_LOCALMSPID = "CORE_PEER_LOCALMSPID";
111122
private static final String MAX_INBOUND_MESSAGE_SIZE = "MAX_INBOUND_MESSAGE_SIZE";
112123
private Properties props;
@@ -120,8 +131,10 @@ private int getMaxInboundMessageSize() {
120131
if (this.props == null) {
121132
throw new IllegalStateException("Chaincode config not available");
122133
}
123-
final int maxMsgSize = Integer.parseInt(this.props.getProperty(MAX_INBOUND_MESSAGE_SIZE, DEFAULT_MAX_INBOUND_MESSAGE_SIZE));
124-
final String msgSizeInfo = String.format("Maximum Inbound Message Size [%s] = %d", MAX_INBOUND_MESSAGE_SIZE, maxMsgSize);
134+
final int maxMsgSize = Integer
135+
.parseInt(this.props.getProperty(MAX_INBOUND_MESSAGE_SIZE, DEFAULT_MAX_INBOUND_MESSAGE_SIZE));
136+
final String msgSizeInfo = String.format("Maximum Inbound Message Size [%s] = %d", MAX_INBOUND_MESSAGE_SIZE,
137+
maxMsgSize);
125138
LOGGER.info(msgSizeInfo);
126139
return maxMsgSize;
127140
}
@@ -165,7 +178,6 @@ protected final void connectToPeer() throws IOException {
165178

166179
final InvocationTaskManager itm = InvocationTaskManager.getManager(this, chaincodeId);
167180

168-
169181
// This is a critical method - it is the one time that a
170182
// protobuf service is invoked. The single 'register' call
171183
// is made, and two streams are created.
@@ -200,7 +212,9 @@ public void onNext(final ChaincodeMessage chaincodeMessage) {
200212

201213
@Override
202214
public void onError(final Throwable t) {
203-
LOGGER.severe(() -> "An error occured on the chaincode stream. Shutting down the chaincode stream." + Logging.formatError(t));
215+
LOGGER.severe(
216+
() -> "An error occured on the chaincode stream. Shutting down the chaincode stream."
217+
+ Logging.formatError(t));
204218

205219
chaincodeSupportClient.shutdown(itm);
206220
}
@@ -220,11 +234,14 @@ public void onCompleted() {
220234

221235
/**
222236
* connect external chaincode to peer for chat.
237+
*
223238
* @param requestObserver reqeust from peer
224-
* @return itm - The InnvocationTask Manager handles the message level communication with the peer.
239+
* @return itm - The InnvocationTask Manager handles the message level
240+
* communication with the peer.
225241
* @throws IOException validation fields exception
226242
*/
227-
protected StreamObserver<ChaincodeShim.ChaincodeMessage> connectToPeer(final StreamObserver<ChaincodeMessage> requestObserver) throws IOException {
243+
protected StreamObserver<ChaincodeShim.ChaincodeMessage> connectToPeer(
244+
final StreamObserver<ChaincodeMessage> requestObserver) throws IOException {
228245
validateOptions();
229246
if (requestObserver == null) {
230247
throw new IOException("StreamObserver 'requestObserver' for chat with peer can't be null");
@@ -254,7 +271,8 @@ public void onNext(final ChaincodeMessage chaincodeMessage) {
254271

255272
@Override
256273
public void onError(final Throwable t) {
257-
LOGGER.severe(() -> "An error occured on the chaincode stream. Shutting down the chaincode stream." + Logging.formatError(t));
274+
LOGGER.severe(() -> "An error occured on the chaincode stream. Shutting down the chaincode stream."
275+
+ Logging.formatError(t));
258276

259277
chaincodeSupportClient.shutdown(itm);
260278
}
@@ -310,33 +328,60 @@ private Level mapLevel(final String level) {
310328

311329
if (level != null) {
312330
switch (level.toUpperCase().trim()) {
313-
case "CRITICAL":
314-
case "ERROR":
315-
return Level.SEVERE;
316-
case "WARNING":
317-
case "WARN":
318-
return Level.WARNING;
319-
case "INFO":
320-
return Level.INFO;
321-
case "NOTICE":
322-
return Level.CONFIG;
323-
case "DEBUG":
324-
return Level.FINEST;
325-
default:
326-
break;
331+
case "CRITICAL":
332+
case "ERROR":
333+
return Level.SEVERE;
334+
case "WARNING":
335+
case "WARN":
336+
return Level.WARNING;
337+
case "INFO":
338+
return Level.INFO;
339+
case "NOTICE":
340+
return Level.CONFIG;
341+
case "DEBUG":
342+
return Level.FINEST;
343+
default:
344+
break;
327345
}
328346
}
329347
return Level.INFO;
330348
}
331349

350+
351+
private SocketAddress parseHostPort(final String hostAddrStr) {
352+
String[] hostArr = hostAddrStr.split(":");
353+
String h;
354+
int p;
355+
356+
if (hostArr.length == 2) {
357+
p = Integer.valueOf(hostArr[1].trim());
358+
h = hostArr[0].trim();
359+
} else {
360+
final String msg = String.format(
361+
"peer address argument should be in host:port format, current %s in wrong", hostAddrStr);
362+
LOGGER.severe(msg);
363+
throw new IllegalArgumentException(msg);
364+
}
365+
return new InetSocketAddress(h, p);
366+
}
367+
368+
/**
369+
* Use the CHAINCODE_SERVER_ADDRESS as the key to swap mode.
370+
*
371+
* @return true if this should be run as `chaincode-as-a-service`
372+
*/
373+
public boolean isServer() {
374+
return !chaincodeServerAddress.isEmpty();
375+
}
376+
332377
/**
333378
* Validate init parameters from env chaincode base.
334379
*/
335380
public void validateOptions() {
336381
if (this.id == null || this.id.isEmpty()) {
337-
throw new IllegalArgumentException(
338-
format("The chaincode id must be specified using either the -i or --i command line options or the %s environment variable.",
339-
CORE_CHAINCODE_ID_NAME));
382+
throw new IllegalArgumentException(format(
383+
"The chaincode id must be specified using either the -i or --i command line options or the %s environment variable.",
384+
CORE_CHAINCODE_ID_NAME));
340385
}
341386
if (this.tlsEnabled) {
342387
if (tlsClientCertPath == null) {
@@ -390,10 +435,7 @@ protected final void processCommandLineOptions(final String[] args) {
390435
LOGGER.info("<<<<<<<<<<<<<CommandLine options>>>>>>>>>>>>");
391436
LOGGER.info("CORE_CHAINCODE_ID_NAME: " + this.id);
392437
LOGGER.info("CORE_PEER_ADDRESS: " + this.host + ":" + this.port);
393-
LOGGER.info("CORE_PEER_TLS_ENABLED: " + this.tlsEnabled);
394-
LOGGER.info("CORE_PEER_TLS_ROOTCERT_FILE: " + this.tlsClientRootCertPath);
395-
LOGGER.info("CORE_TLS_CLIENT_KEY_PATH: " + this.tlsClientKeyPath);
396-
LOGGER.info("CORE_TLS_CLIENT_CERT_PATH: " + this.tlsClientCertPath);
438+
397439
}
398440

399441
/**
@@ -417,6 +459,10 @@ public final void processEnvironmentOptions() {
417459
}
418460
}
419461

462+
if (System.getenv().containsKey(CHAINCODE_SERVER_ADDRESS)) {
463+
this.chaincodeServerAddress = System.getenv(CHAINCODE_SERVER_ADDRESS);
464+
}
465+
420466
if (System.getenv().containsKey(CORE_PEER_LOCALMSPID)) {
421467
this.localMspId = System.getenv(CORE_PEER_LOCALMSPID);
422468
}
@@ -426,6 +472,9 @@ public final void processEnvironmentOptions() {
426472
this.tlsClientRootCertPath = System.getenv(CORE_PEER_TLS_ROOTCERT_FILE);
427473
this.tlsClientKeyPath = System.getenv(ENV_TLS_CLIENT_KEY_PATH);
428474
this.tlsClientCertPath = System.getenv(ENV_TLS_CLIENT_CERT_PATH);
475+
476+
this.tlsClientKeyFile = System.getenv(ENV_TLS_CLIENT_KEY_FILE);
477+
this.tlsClientCertFile = System.getenv(ENV_TLS_CLIENT_CERT_FILE);
429478
}
430479

431480
LOGGER.info("<<<<<<<<<<<<<Environment options>>>>>>>>>>>>");
@@ -435,7 +484,10 @@ public final void processEnvironmentOptions() {
435484
LOGGER.info("CORE_PEER_TLS_ROOTCERT_FILE: " + this.tlsClientRootCertPath);
436485
LOGGER.info("CORE_TLS_CLIENT_KEY_PATH: " + this.tlsClientKeyPath);
437486
LOGGER.info("CORE_TLS_CLIENT_CERT_PATH: " + this.tlsClientCertPath);
487+
LOGGER.info("CORE_TLS_CLIENT_KEY_FILE: " + this.tlsClientKeyFile);
488+
LOGGER.info("CORE_TLS_CLIENT_CERT_FILE: " + this.tlsClientCertFile);
438489
LOGGER.info("CORE_PEER_LOCALMSPID: " + this.localMspId);
490+
LOGGER.info("CHAINCODE_SERVER_ADDRESS: " + this.chaincodeServerAddress);
439491
LOGGER.info("LOGLEVEL: " + this.logLevel);
440492
}
441493

@@ -473,6 +525,26 @@ public Properties getChaincodeConfig() {
473525
return this.props;
474526
}
475527

528+
/**
529+
* The properties for starting as chaincode-as-a-service.
530+
*
531+
* @return ChaincodeServerProperties populated
532+
*/
533+
public final ChaincodeServerProperties getChaincodeServerConfig() {
534+
ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
535+
536+
chaincodeServerProperties.setServerAddress(parseHostPort(chaincodeServerAddress));
537+
538+
if (tlsEnabled) {
539+
540+
// set values on the server properties
541+
chaincodeServerProperties.setTlsEnabled(true);
542+
chaincodeServerProperties.setKeyFile(this.tlsClientCertFile);
543+
chaincodeServerProperties.setKeyCertChainFile(this.tlsClientCertFile);
544+
}
545+
return chaincodeServerProperties;
546+
}
547+
476548
/**
477549
* create NettyChannel for host:port with tls if tlsEnabled.
478550
*
@@ -584,6 +656,7 @@ final String getTlsClientRootCertPath() {
584656

585657
/**
586658
* Chaincode name / Chaincode id.
659+
*
587660
* @return string
588661
*/
589662
String getId() {

0 commit comments

Comments
 (0)