Skip to content

Commit 5d2bee4

Browse files
authored
Merge pull request #161 from jt-nti/187-message-size-2.2
[FABCJ-187] Add max inbound msg size configuration
2 parents b2095bb + dd4332a commit 5d2bee4

File tree

9 files changed

+111
-32
lines changed

9 files changed

+111
-32
lines changed

fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/src/main/java/org/hyperledger/fabric/example/AllAPI.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
import org.hyperledger.fabric.contract.Context;
77
import org.hyperledger.fabric.contract.ContractInterface;
88
import org.hyperledger.fabric.contract.annotation.*;
9-
10-
9+
import org.hyperledger.fabric.metrics.Metrics;
10+
import org.hyperledger.fabric.metrics.MetricsProvider;
1111
import org.hyperledger.fabric.shim.ledger.*;
1212
import org.hyperledger.fabric.shim.*;
1313
import java.util.*;
@@ -95,5 +95,12 @@ public String getByRangePaged(Context ctx, String start, String end, int pageSiz
9595
System.out.println("getByRangePaged<<");
9696
return newbookmark;
9797
}
98+
99+
@Transaction()
100+
public String getMetricsProviderName(Context ctx){
101+
final MetricsProvider provider = Metrics.getProvider();
102+
final String name = provider.getClass().getName();
103+
return name;
104+
}
98105

99106
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
MAX_INBOUND_MESSAGE_SIZE=4000
2+
CHAINCODE_METRICS_ENABLED=true
3+
TP_CORE_POOL_SIZE=4
4+
TP_MAX_POOL_SIZE=4
5+
TP_QUEUE_SIZE=4000
6+

fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/SACCIntegrationTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ public void TestQuery(){
7575
System.out.println(text);
7676
assertThat(text, containsString("key130"));
7777

78+
text = invoke(new String[]{"getMetricsProviderName"});
79+
System.out.println(text);
80+
assertThat(text, containsString("org.hyperledger.fabric.metrics.impl.DefaultProvider"));
7881
}
7982

8083
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ public ContractRouter(final String[] args) {
5555
super.initializeLogging();
5656
super.processEnvironmentOptions();
5757
super.processCommandLineOptions(args);
58+
super.validateOptions();
5859

5960
final Properties props = super.getChaincodeConfig();
6061
Metrics.initialize(props);
6162

62-
super.validateOptions();
6363
logger.fine("ContractRouter<init>");
6464
registry = new RoutingRegistryImpl();
6565
typeRegistry = TypeRegistry.getRegistry();

fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/package-info.java

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,15 @@
1111
* The main metrics that are available are the statistics around the number of
1212
* tasks that are running, and how the thread pool is handling these.
1313
*
14+
* <p>
1415
* Note a 'task' is a message from the Peer to the Chaincode - this message is
1516
* either a new transaction, or a response from a stub API, eg getState(). Query
1617
* apis may return more than one response.
1718
*
18-
* To enable metrics ensure that there is a standard format Java properties file
19-
* called `config.props` in the root of your contract code. For example this
20-
* path
21-
*
22-
* <pre>
23-
* myjava - contract - project / java / src / main / resources / config.props
24-
* </pre>
25-
*
26-
* This should contain the following
27-
*
28-
* <pre>
29-
* CHAINCODE_METRICS_ENABLED=true
30-
* TP_CORE_POOL_SIZE=5
31-
* TP_MAX_POOL_SIZE=5
32-
* TP_QUEUE_SIZE=5000
33-
* </pre>
34-
*
35-
* The metrics enabled flag will turn on default metrics logging. (it's off by
36-
* default) The TP values establish the core thread pool size, max thread
37-
* poolsize, and the number of of tasks that will wait. (5, 5, 5000 are the
38-
* default values, so don't need to be explicitly specified).
39-
*
40-
* If no file is supplied metrics are not enabled, the values shown for the
41-
* thread pool are used.
19+
* <p>
20+
* To enable metrics, add a <code>CHAINCODE_METRICS_ENABLED=true</code> setting
21+
* to the <code>config.props</code> chaincode configuration file.
22+
* See the <a href="../../../../index.html">Overview</a> for details of how to
23+
* configure chaincode.
4224
*/
4325
package org.hyperledger.fabric.metrics;

fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/overview.html

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,29 @@
77
<p>The Fabric programming model is described in the <a href="https://hyperledger-fabric.readthedocs.io/en/release-2.2/developapps/developing_applications.html">Developing Applications</a> chapter of the Hyperledger Fabric documentation.</p>
88

99
<p>All Contracts should implement {@link org.hyperledger.fabric.contract.ContractInterface} interface, in addition to the {@link org.hyperledger.fabric.contract.annotation.Contract} annotation.</p>
10+
11+
<h2>Configuration</h2>
12+
13+
<p>
14+
Some Java chaincode settings are configurable on a per chaincode basis, including the maximum gRPC inbound message size, thread pool settings, and whether to enable chaincode metrics.
15+
The default settings are as follows:
16+
</p>
17+
18+
<pre>
19+
MAX_INBOUND_MESSAGE_SIZE=104857600
20+
CHAINCODE_METRICS_ENABLED=false
21+
TP_CORE_POOL_SIZE=5
22+
TP_MAX_POOL_SIZE=5
23+
TP_QUEUE_SIZE=5000
24+
</pre>
25+
26+
<p>
27+
To override the defaults, a <code>config.props</code> Java properties file must be included in the default, unnamed, package on your contract code's classpath, which will then be loaded when the chaincode starts.
28+
Setting the metrics enabled flag to <code>true</code> will turn on default metrics logging. The <code>TP_</code> values establish the core thread pool size, max thread poolsize, and the number of of tasks that will wait.
29+
</p>
30+
31+
<p>
32+
If you are building your chaincode using Gradle or Maven, create a <code>config.props</code> file in the <code>src/main/resources</code> directory and include the settings you want to override.
33+
</p>
1034
</body>
1135
</html>

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

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
import java.util.logging.Logger;
2424
import java.util.logging.SimpleFormatter;
2525

26-
import com.google.protobuf.InvalidProtocolBufferException;
27-
import com.google.protobuf.util.JsonFormat;
28-
2926
import org.apache.commons.cli.CommandLine;
3027
import org.apache.commons.cli.DefaultParser;
3128
import org.apache.commons.cli.Options;
@@ -38,6 +35,9 @@
3835
import org.hyperledger.fabric.shim.impl.ChaincodeSupportClient;
3936
import org.hyperledger.fabric.shim.impl.InvocationTaskManager;
4037

38+
import com.google.protobuf.InvalidProtocolBufferException;
39+
import com.google.protobuf.util.JsonFormat;
40+
4141
import io.grpc.ManagedChannelBuilder;
4242
import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
4343
import io.grpc.netty.shaded.io.grpc.netty.NegotiationType;
@@ -83,6 +83,11 @@ public abstract class ChaincodeBase implements Chaincode {
8383
*/
8484
public static final int DEFAULT_PORT = 7051;
8585

86+
/**
87+
* Default to 100MB for maximum inbound grpc message size.
88+
*/
89+
public static final String DEFAULT_MAX_INBOUND_MESSAGE_SIZE = "104857600";
90+
8691
private String host = DEFAULT_HOST;
8792
private int port = DEFAULT_PORT;
8893
private boolean tlsEnabled = false;
@@ -100,13 +105,24 @@ public abstract class ChaincodeBase implements Chaincode {
100105
private static final String ENV_TLS_CLIENT_KEY_PATH = "CORE_TLS_CLIENT_KEY_PATH";
101106
private static final String ENV_TLS_CLIENT_CERT_PATH = "CORE_TLS_CLIENT_CERT_PATH";
102107
private static final String CORE_PEER_LOCALMSPID = "CORE_PEER_LOCALMSPID";
108+
private static final String MAX_INBOUND_MESSAGE_SIZE = "MAX_INBOUND_MESSAGE_SIZE";
103109
private Properties props;
104110
private Level logLevel;
105111

106112
static {
107113
Security.addProvider(new BouncyCastleProvider());
108114
}
109115

116+
private int getMaxInboundMessageSize() {
117+
if (this.props == null) {
118+
throw new IllegalStateException("Chaincode config not available");
119+
}
120+
final int maxMsgSize = Integer.parseInt(this.props.getProperty(MAX_INBOUND_MESSAGE_SIZE, DEFAULT_MAX_INBOUND_MESSAGE_SIZE));
121+
final String msgSizeInfo = String.format("Maximum Inbound Message Size [%s] = %d", MAX_INBOUND_MESSAGE_SIZE, maxMsgSize);
122+
LOGGER.info(msgSizeInfo);
123+
return maxMsgSize;
124+
}
125+
110126
/**
111127
* Start chaincode.
112128
*
@@ -115,13 +131,13 @@ public abstract class ChaincodeBase implements Chaincode {
115131

116132
public void start(final String[] args) {
117133
try {
134+
initializeLogging();
118135
processEnvironmentOptions();
119136
processCommandLineOptions(args);
120-
initializeLogging();
137+
validateOptions();
121138

122139
final Properties props = getChaincodeConfig();
123140
Metrics.initialize(props);
124-
validateOptions();
125141
connectToPeer();
126142
} catch (final Exception e) {
127143
LOGGER.severe(() -> "Chaincode could not start" + Logging.formatError(e));
@@ -356,6 +372,8 @@ final ManagedChannelBuilder<?> newChannelBuilder() throws IOException {
356372
final NettyChannelBuilder builder = NettyChannelBuilder.forAddress(host, port);
357373
LOGGER.info("Configuring channel connection to peer.");
358374

375+
builder.maxInboundMessageSize(getMaxInboundMessageSize());
376+
359377
if (tlsEnabled) {
360378
builder.negotiationType(NegotiationType.TLS);
361379
builder.sslContext(createSSLContext());

fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import static org.hamcrest.Matchers.is;
1111
import static org.hamcrest.Matchers.notNullValue;
1212
import static org.hamcrest.Matchers.nullValue;
13+
import static org.hamcrest.core.StringContains.containsString;
1314
import static org.junit.Assert.assertThat;
1415

1516
import java.util.ArrayList;
@@ -30,6 +31,16 @@ public class ContractRouterTest {
3031
@Rule
3132
public ExpectedException thrown = ExpectedException.none();
3233

34+
@Test
35+
public void testCreateFailsWithoutValidOptions() {
36+
thrown.expect(IllegalArgumentException.class);
37+
thrown.expectMessage(containsString(
38+
"The chaincode id must be specified using either the -i or --i command line options or the CORE_CHAINCODE_ID_NAME environment variable."));
39+
40+
@SuppressWarnings("unused")
41+
final ContractRouter r = new ContractRouter(new String[] {});
42+
}
43+
3344
@Test
3445
public void testCreateAndScan() {
3546
final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});

fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,20 @@
66

77
package org.hyperledger.fabric.shim;
88

9+
import static org.hamcrest.Matchers.not;
10+
import static org.hamcrest.core.StringContains.containsString;
911
import static org.junit.Assert.assertArrayEquals;
1012
import static org.junit.Assert.assertEquals;
1113
import static org.junit.Assert.assertFalse;
1214
import static org.junit.Assert.assertNull;
15+
import static org.junit.Assert.assertThat;
1316
import static org.junit.Assert.assertTrue;
1417
import static org.junit.Assert.fail;
1518

1619
import java.nio.charset.Charset;
20+
import java.util.logging.Handler;
1721
import java.util.logging.Level;
22+
import java.util.logging.LogRecord;
1823
import java.util.logging.Logger;
1924

2025
import org.hamcrest.Matchers;
@@ -24,6 +29,8 @@
2429
import org.junit.Test;
2530
import org.junit.contrib.java.lang.system.EnvironmentVariables;
2631
import org.junit.rules.ExpectedException;
32+
import org.mockito.ArgumentCaptor;
33+
import org.mockito.Mockito;
2734

2835
import io.grpc.ManagedChannelBuilder;
2936

@@ -245,6 +252,27 @@ public void testInitializeLogging() {
245252
Logger.getLogger(cb.getClass().getPackage().getName()).getLevel());
246253
}
247254

255+
@Test
256+
public void testStartFailsWithoutValidOptions() {
257+
final String[] args = new String[0];
258+
final ChaincodeBase cb = new EmptyChaincode();
259+
260+
Handler mockHandler = Mockito.mock(Handler.class);
261+
ArgumentCaptor<LogRecord> argumentCaptor = ArgumentCaptor.forClass(LogRecord.class);
262+
Logger logger = Logger.getLogger("org.hyperledger.fabric.shim.ChaincodeBase");
263+
logger.addHandler(mockHandler);
264+
265+
cb.start(args);
266+
267+
Mockito.verify(mockHandler, Mockito.atLeast(1)).publish(argumentCaptor.capture());
268+
LogRecord lr = argumentCaptor.getValue();
269+
String msg = lr.getMessage();
270+
271+
assertThat(msg, not(containsString("java.lang.NullPointerException")));
272+
assertThat(msg, containsString(
273+
"The chaincode id must be specified using either the -i or --i command line options or the CORE_CHAINCODE_ID_NAME environment variable."));
274+
}
275+
248276
public static void setLogLevelForChaincode(final EnvironmentVariables environmentVariables, final ChaincodeBase cb, final String shimLevel,
249277
final String chaincodeLevel) {
250278
environmentVariables.set(ChaincodeBase.CORE_CHAINCODE_LOGGING_SHIM, shimLevel);

0 commit comments

Comments
 (0)