Skip to content

Commit

Permalink
Chaincode-as-a-service main bootstrap method
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
mbwhite authored and jt-nti committed Dec 2, 2021
1 parent d596ec8 commit f9ada8f
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 204 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.hyperledger.fabric.shim.ChaincodeBase;
import org.hyperledger.fabric.shim.ChaincodeServer;
import org.hyperledger.fabric.shim.ChaincodeStub;
import org.hyperledger.fabric.shim.NettyChaincodeServer;
import org.hyperledger.fabric.shim.ResponseUtils;
import org.hyperledger.fabric.traces.Traces;

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

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

logger.info(() -> "Got routing:" + txFn.getRouting());
Expand Down Expand Up @@ -159,7 +161,7 @@ TxFunction getRouting(final InvocationRequest request) {
*
* @param args
*/
public static void main(final String[] args) {
public static void main(final String[] args) throws Exception {

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

// commence routing, once this has returned the chaincode and contract api is
// 'open for chaining'
cfc.startRouting();

// check if this should be running in client or server mode
if (cfc.isServer()) {
logger.info("Starting chaincode as server");
ChaincodeServer chaincodeServer = new NettyChaincodeServer(cfc,
cfc.getChaincodeServerConfig());
chaincodeServer.start();
} else {
logger.info("Starting chaincode as client");
cfc.startRouting();
}
}

protected TypeRegistry getTypeRegistry() {
Expand All @@ -190,14 +198,15 @@ protected RoutingRegistry getRoutingRegistry() {
*
* @param chaincodeServer
*/
public void startRouterWithChaincodeServer(final ChaincodeServer chaincodeServer) throws IOException, InterruptedException {
public void startRouterWithChaincodeServer(final ChaincodeServer chaincodeServer)
throws IOException, InterruptedException {
findAllContracts();
logger.fine(getRoutingRegistry().toString());

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

logger.info("Starting ChaincodeServer");
chaincodeServer.start();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Security;
Expand Down Expand Up @@ -51,8 +53,11 @@
* Abstract implementation of {@link Chaincode}.
*
* <p>
* All chaincode implementations must extend the abstract class <code>ChaincodeBase</code>.
* 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.
* All chaincode implementations must extend the abstract class
* <code>ChaincodeBase</code>. 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.
*
* @see org.hyperledger.fabric.contract
*/
Expand Down Expand Up @@ -96,17 +101,23 @@ public abstract class ChaincodeBase implements Chaincode {
private boolean tlsEnabled = false;
private String tlsClientKeyPath;
private String tlsClientCertPath;
private String tlsClientKeyFile;
private String tlsClientCertFile;
private String tlsClientRootCertPath;

private String id;
private String localMspId = "";
private String chaincodeServerAddress = "";

private static final String CHAINCODE_SERVER_ADDRESS = "CHAINCODE_SERVER_ADDRESS";
private static final String CORE_CHAINCODE_ID_NAME = "CORE_CHAINCODE_ID_NAME";
private static final String CORE_PEER_ADDRESS = "CORE_PEER_ADDRESS";
private static final String CORE_PEER_TLS_ENABLED = "CORE_PEER_TLS_ENABLED";
private static final String CORE_PEER_TLS_ROOTCERT_FILE = "CORE_PEER_TLS_ROOTCERT_FILE";
private static final String ENV_TLS_CLIENT_KEY_PATH = "CORE_TLS_CLIENT_KEY_PATH";
private static final String ENV_TLS_CLIENT_CERT_PATH = "CORE_TLS_CLIENT_CERT_PATH";
private static final String ENV_TLS_CLIENT_KEY_FILE = "CORE_TLS_CLIENT_KEY_FILE";
private static final String ENV_TLS_CLIENT_CERT_FILE = "CORE_TLS_CLIENT_CERT_FILE";
private static final String CORE_PEER_LOCALMSPID = "CORE_PEER_LOCALMSPID";
private static final String MAX_INBOUND_MESSAGE_SIZE = "MAX_INBOUND_MESSAGE_SIZE";
private Properties props;
Expand All @@ -120,8 +131,10 @@ private int getMaxInboundMessageSize() {
if (this.props == null) {
throw new IllegalStateException("Chaincode config not available");
}
final int maxMsgSize = Integer.parseInt(this.props.getProperty(MAX_INBOUND_MESSAGE_SIZE, DEFAULT_MAX_INBOUND_MESSAGE_SIZE));
final String msgSizeInfo = String.format("Maximum Inbound Message Size [%s] = %d", MAX_INBOUND_MESSAGE_SIZE, maxMsgSize);
final int maxMsgSize = Integer
.parseInt(this.props.getProperty(MAX_INBOUND_MESSAGE_SIZE, DEFAULT_MAX_INBOUND_MESSAGE_SIZE));
final String msgSizeInfo = String.format("Maximum Inbound Message Size [%s] = %d", MAX_INBOUND_MESSAGE_SIZE,
maxMsgSize);
LOGGER.info(msgSizeInfo);
return maxMsgSize;
}
Expand Down Expand Up @@ -165,7 +178,6 @@ protected final void connectToPeer() throws IOException {

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


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

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

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

/**
* connect external chaincode to peer for chat.
*
* @param requestObserver reqeust from peer
* @return itm - The InnvocationTask Manager handles the message level communication with the peer.
* @return itm - The InnvocationTask Manager handles the message level
* communication with the peer.
* @throws IOException validation fields exception
*/
protected StreamObserver<ChaincodeShim.ChaincodeMessage> connectToPeer(final StreamObserver<ChaincodeMessage> requestObserver) throws IOException {
protected StreamObserver<ChaincodeShim.ChaincodeMessage> connectToPeer(
final StreamObserver<ChaincodeMessage> requestObserver) throws IOException {
validateOptions();
if (requestObserver == null) {
throw new IOException("StreamObserver 'requestObserver' for chat with peer can't be null");
Expand Down Expand Up @@ -254,7 +271,8 @@ public void onNext(final ChaincodeMessage chaincodeMessage) {

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

chaincodeSupportClient.shutdown(itm);
}
Expand Down Expand Up @@ -310,33 +328,60 @@ private Level mapLevel(final String level) {

if (level != null) {
switch (level.toUpperCase().trim()) {
case "CRITICAL":
case "ERROR":
return Level.SEVERE;
case "WARNING":
case "WARN":
return Level.WARNING;
case "INFO":
return Level.INFO;
case "NOTICE":
return Level.CONFIG;
case "DEBUG":
return Level.FINEST;
default:
break;
case "CRITICAL":
case "ERROR":
return Level.SEVERE;
case "WARNING":
case "WARN":
return Level.WARNING;
case "INFO":
return Level.INFO;
case "NOTICE":
return Level.CONFIG;
case "DEBUG":
return Level.FINEST;
default:
break;
}
}
return Level.INFO;
}


private SocketAddress parseHostPort(final String hostAddrStr) {
String[] hostArr = hostAddrStr.split(":");
String h;
int p;

if (hostArr.length == 2) {
p = Integer.valueOf(hostArr[1].trim());
h = hostArr[0].trim();
} else {
final String msg = String.format(
"peer address argument should be in host:port format, current %s in wrong", hostAddrStr);
LOGGER.severe(msg);
throw new IllegalArgumentException(msg);
}
return new InetSocketAddress(h, p);
}

/**
* Use the CHAINCODE_SERVER_ADDRESS as the key to swap mode.
*
* @return true if this should be run as `chaincode-as-a-service`
*/
public boolean isServer() {
return !chaincodeServerAddress.isEmpty();
}

/**
* Validate init parameters from env chaincode base.
*/
public void validateOptions() {
if (this.id == null || this.id.isEmpty()) {
throw new IllegalArgumentException(
format("The chaincode id must be specified using either the -i or --i command line options or the %s environment variable.",
CORE_CHAINCODE_ID_NAME));
throw new IllegalArgumentException(format(
"The chaincode id must be specified using either the -i or --i command line options or the %s environment variable.",
CORE_CHAINCODE_ID_NAME));
}
if (this.tlsEnabled) {
if (tlsClientCertPath == null) {
Expand Down Expand Up @@ -390,10 +435,7 @@ protected final void processCommandLineOptions(final String[] args) {
LOGGER.info("<<<<<<<<<<<<<CommandLine options>>>>>>>>>>>>");
LOGGER.info("CORE_CHAINCODE_ID_NAME: " + this.id);
LOGGER.info("CORE_PEER_ADDRESS: " + this.host + ":" + this.port);
LOGGER.info("CORE_PEER_TLS_ENABLED: " + this.tlsEnabled);
LOGGER.info("CORE_PEER_TLS_ROOTCERT_FILE: " + this.tlsClientRootCertPath);
LOGGER.info("CORE_TLS_CLIENT_KEY_PATH: " + this.tlsClientKeyPath);
LOGGER.info("CORE_TLS_CLIENT_CERT_PATH: " + this.tlsClientCertPath);

}

/**
Expand All @@ -417,6 +459,10 @@ public final void processEnvironmentOptions() {
}
}

if (System.getenv().containsKey(CHAINCODE_SERVER_ADDRESS)) {
this.chaincodeServerAddress = System.getenv(CHAINCODE_SERVER_ADDRESS);
}

if (System.getenv().containsKey(CORE_PEER_LOCALMSPID)) {
this.localMspId = System.getenv(CORE_PEER_LOCALMSPID);
}
Expand All @@ -426,6 +472,9 @@ public final void processEnvironmentOptions() {
this.tlsClientRootCertPath = System.getenv(CORE_PEER_TLS_ROOTCERT_FILE);
this.tlsClientKeyPath = System.getenv(ENV_TLS_CLIENT_KEY_PATH);
this.tlsClientCertPath = System.getenv(ENV_TLS_CLIENT_CERT_PATH);

this.tlsClientKeyFile = System.getenv(ENV_TLS_CLIENT_KEY_FILE);
this.tlsClientCertFile = System.getenv(ENV_TLS_CLIENT_CERT_FILE);
}

LOGGER.info("<<<<<<<<<<<<<Environment options>>>>>>>>>>>>");
Expand All @@ -435,7 +484,10 @@ public final void processEnvironmentOptions() {
LOGGER.info("CORE_PEER_TLS_ROOTCERT_FILE: " + this.tlsClientRootCertPath);
LOGGER.info("CORE_TLS_CLIENT_KEY_PATH: " + this.tlsClientKeyPath);
LOGGER.info("CORE_TLS_CLIENT_CERT_PATH: " + this.tlsClientCertPath);
LOGGER.info("CORE_TLS_CLIENT_KEY_FILE: " + this.tlsClientKeyFile);
LOGGER.info("CORE_TLS_CLIENT_CERT_FILE: " + this.tlsClientCertFile);
LOGGER.info("CORE_PEER_LOCALMSPID: " + this.localMspId);
LOGGER.info("CHAINCODE_SERVER_ADDRESS: " + this.chaincodeServerAddress);
LOGGER.info("LOGLEVEL: " + this.logLevel);
}

Expand Down Expand Up @@ -473,6 +525,26 @@ public Properties getChaincodeConfig() {
return this.props;
}

/**
* The properties for starting as chaincode-as-a-service.
*
* @return ChaincodeServerProperties populated
*/
public final ChaincodeServerProperties getChaincodeServerConfig() {
ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();

chaincodeServerProperties.setServerAddress(parseHostPort(chaincodeServerAddress));

if (tlsEnabled) {

// set values on the server properties
chaincodeServerProperties.setTlsEnabled(true);
chaincodeServerProperties.setKeyFile(this.tlsClientCertFile);
chaincodeServerProperties.setKeyCertChainFile(this.tlsClientCertFile);
}
return chaincodeServerProperties;
}

/**
* create NettyChannel for host:port with tls if tlsEnabled.
*
Expand Down Expand Up @@ -584,6 +656,7 @@ final String getTlsClientRootCertPath() {

/**
* Chaincode name / Chaincode id.
*
* @return string
*/
String getId() {
Expand Down
Loading

0 comments on commit f9ada8f

Please sign in to comment.