Skip to content

Commit 8d34b20

Browse files
mastersingh24Gerrit Code Review
authored andcommitted
Merge "[FAB-13912] Implement new interfaces"
2 parents bd1c269 + 1662390 commit 8d34b20

File tree

17 files changed

+792
-37
lines changed

17 files changed

+792
-37
lines changed

fabric-chaincode-integration-test/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
dependencies {
22
compile project(':fabric-chaincode-docker')
33
testCompile 'org.testcontainers:testcontainers:1.10.3'
4-
testCompile 'org.hyperledger.fabric-sdk-java:fabric-sdk-java:1.3.0'
4+
testCompile 'org.hyperledger.fabric-sdk-java:fabric-sdk-java:1.4.1'
55
compile project(':fabric-chaincode-shim')
66
}
77

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

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@
1212
import org.hyperledger.fabric.sdk.exception.*;
1313
import org.hyperledger.fabric.sdk.security.CryptoSuite;
1414
import org.hyperledger.fabric.shim.Chaincode;
15-
import org.junit.AfterClass;
16-
import org.junit.BeforeClass;
17-
import org.junit.ClassRule;
18-
import org.junit.Test;
15+
import org.junit.*;
1916
import org.testcontainers.containers.DockerComposeContainer;
2017

2118
import java.io.File;
@@ -331,6 +328,63 @@ private void executeAndValidateQueryOnAccount(HFClient client, Channel channel,
331328
);
332329
}
333330

331+
@Test
332+
@Ignore
333+
public void testSimpelChaincodeFirstNetworkNewPM() throws IllegalAccessException, InvocationTargetException, InvalidArgumentException, InstantiationException, NoSuchMethodException, CryptoException, ClassNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, IOException, TransactionException, ProposalException, ChaincodeEndorsementPolicyParseException, ChaincodeCollectionConfigurationException {
334+
final CryptoSuite crypto = CryptoSuite.Factory.getCryptoSuite();
335+
336+
// Create client and set default crypto suite
337+
System.out.println("Creating client");
338+
final HFClient client = HFClient.createNewInstance();
339+
client.setCryptoSuite(crypto);
340+
341+
client.setUserContext(Utils.getAdminUserOrg1TLS());
342+
343+
Channel myChannel = Utils.getMyChannelFirstNetwork(client);
344+
345+
System.out.println("Installing chaincode SimpleChaincode, packaged as gzip stream");
346+
InstallProposalRequest installProposalRequest = generateSimpleChaincodeInstallRequestNewPM(client);
347+
Utils.sendInstallProposals(client, installProposalRequest, myChannel.getPeers().stream().filter(peer -> peer.getName().contains("org1")).collect(Collectors.toList()));
348+
349+
client.setUserContext(Utils.getAdminUserOrg2TLS());
350+
installProposalRequest = generateSimpleChaincodeInstallRequestNewPM(client);
351+
Utils.sendInstallProposals(client, installProposalRequest, myChannel.getPeers().stream().filter(peer -> peer.getName().contains("org2")).collect(Collectors.toList()));
352+
353+
InstantiateProposalRequest instantiateProposal = generateSimpleChaincodeInstantiateRequestNewPM(client);
354+
Utils.sendInstantiateProposal("SimpleChaincodeNewPM", instantiateProposal, myChannel, myChannel.getPeers().stream().filter(peer -> peer.getName().contains("peer0.org2")).collect(Collectors.toList()), myChannel.getOrderers());
355+
356+
runTransferNewPM(client, myChannel);
357+
}
358+
359+
void runTransferNewPM(HFClient client, Channel channel) throws
360+
NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, IOException, ProposalException, InvalidArgumentException {
361+
client.setUserContext(Utils.getUser1Org1TLS());
362+
TransactionProposalRequest proposal = generateSimpleChaincodeInvokeRequestNewPM(client, "a", "b", "10");
363+
Utils.sendTransactionProposalInvoke(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().contains("peer0.org1")).collect(Collectors.toList()), channel.getOrderers());
364+
365+
executeAndValidateQueryOnAccountNewPM(client, channel, "a", "peer0.org1", "90");
366+
executeAndValidateQueryOnAccountNewPM(client, channel, "b", "peer0.org1", "210");
367+
executeAndValidateQueryOnAccountNewPM(client, channel, "a", "peer0.org2", "90");
368+
executeAndValidateQueryOnAccountNewPM(client, channel, "b", "peer0.org2", "210");
369+
}
370+
371+
private void executeAndValidateQueryOnAccountNewPM(HFClient client, Channel channel, String keyAccount, String
372+
peerName, String expectedAmount) throws ProposalException, InvalidArgumentException {
373+
TransactionProposalRequest proposal = generateSimpleChaincodeQueryRequestNewPM(client, keyAccount);
374+
Utils.sendTransactionProposalQuery(
375+
proposal,
376+
channel,
377+
channel.getPeers()
378+
.stream()
379+
.filter(peer -> peer.getName().contains(peerName))
380+
.collect(Collectors.toList()),
381+
Matchers.is(Chaincode.Response.Status.SUCCESS.getCode()),
382+
Matchers.anything(),
383+
Matchers.is(ByteString.copyFrom(expectedAmount, StandardCharsets.UTF_8))
384+
);
385+
}
386+
387+
334388

335389
static public InstallProposalRequest generateNoBuildInstallRequest(HFClient client, String name, boolean useSrcPrefix) throws IOException, InvalidArgumentException {
336390
return Utils.generateInstallRequest(client, name, "1.0", "src/test/resources/NoBuildCC", useSrcPrefix);
@@ -387,5 +441,23 @@ static public TransactionProposalRequest generateSimpleChaincodeQueryRequest(HFC
387441
return Utils.generateTransactionRequest(client, "SimpleChaincode", "1.0", "query", key);
388442
}
389443

444+
private InstallProposalRequest generateSimpleChaincodeInstallRequestNewPM(HFClient client) throws
445+
IOException, InvalidArgumentException {
446+
return Utils.generateInstallRequest(client, "SimpleChaincodeNewPM", "1.0", "../fabric-chaincode-newprogrammingmodel");
447+
}
448+
449+
static public InstantiateProposalRequest generateSimpleChaincodeInstantiateRequestNewPM(HFClient client) throws
450+
InvalidArgumentException, IOException, ChaincodeEndorsementPolicyParseException, ChaincodeCollectionConfigurationException {
451+
return Utils.generateInstantiateRequest(client,"SimpleChaincodeNewPM","1.0","src/test/resources/chaincodeendorsementpolicy_2orgs.yaml","src/test/resources/collection_config.yaml","simplechaincode:init", "a", "100", "b", "200");
452+
}
453+
454+
static public TransactionProposalRequest generateSimpleChaincodeInvokeRequestNewPM(HFClient client, String
455+
from, String to, String amount) {
456+
return Utils.generateTransactionRequest(client, "SimpleChaincodeNewPM", "1.0", "simplechaincode:invoke", from, to, amount);
457+
}
458+
459+
static public TransactionProposalRequest generateSimpleChaincodeQueryRequestNewPM(HFClient client, String key) {
460+
return Utils.generateTransactionRequest(client, "SimpleChaincodeNewPM", "1.0", "simplechaincode:query", key);
461+
}
390462

391463
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ static public TransactionProposalRequest generateTransactionRequest(HFClient cli
298298

299299
proposalRequest.setChaincodeID(chaincodeID);
300300
proposalRequest.setFcn(function);
301-
proposalRequest.setProposalWaitTime(TimeUnit.SECONDS.toMillis(60));
301+
proposalRequest.setProposalWaitTime(TimeUnit.SECONDS.toMillis(120));
302302
proposalRequest.setArgs(args);
303303

304304
return proposalRequest;
@@ -319,7 +319,7 @@ static public void sendInstallProposals(HFClient client, InstallProposalRequest
319319

320320
static public void sendInstantiateProposal(String chaincode, InstantiateProposalRequest proposal, Channel channel, Collection<Peer> peers, Collection<Orderer> orderers) throws ProposalException, InvalidArgumentException {
321321
// Sending proposal
322-
System.out.println("Sending instantiate to peers: " + String.join(", ", peers.stream().map(p -> p.getName()).collect(Collectors.toList())));
322+
System.out.println("Sending instantiate proposal " + proposal.getFcn() + "(" + String.join(",", proposal.getArgs()) + ")" + " to peers: " + String.join(", ", peers.stream().map(p -> p.getName()).collect(Collectors.toList())));
323323
Collection<ProposalResponse> instantiationResponces = channel.sendInstantiationProposal(proposal, peers);
324324
if (instantiationResponces == null || instantiationResponces.isEmpty()) {
325325
System.out.println("We have a problem, no responses to instantiate request");

fabric-chaincode-shim/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ dependencies {
1717
compile 'io.swagger.core.v3:swagger-annotations:2.0.0'
1818
compile 'org.bouncycastle:bcpkix-jdk15on:1.60'
1919
compile 'org.bouncycastle:bcprov-jdk15on:1.60'
20+
compile 'org.reflections:reflections:0.9.11'
21+
compile group: 'cglib', name: 'cglib', version: '3.2.10'
2022
}
2123

2224
sourceSets {
@@ -74,6 +76,7 @@ jacocoTestCoverageVerification {
7476
rule {
7577
element = 'CLASS'
7678
includes = ['org.hyperledger.fabric.shim.helper.Channel',
79+
'org.hyperledger.fabric.contract.ContractRouter',
7780
'org.hyperledger.fabric.shim.impl.Handler']
7881
limit {
7982
minimum = 0.79

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

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,16 @@
66

77
package org.hyperledger.fabric.contract;
88

9+
import org.hyperledger.fabric.contract.execution.ExecutionFactory;
910
import org.hyperledger.fabric.contract.execution.ExecutionService;
11+
import org.hyperledger.fabric.contract.execution.InvocationRequest;
1012
import org.hyperledger.fabric.contract.routing.ContractScanner;
13+
import org.hyperledger.fabric.contract.routing.Routing;
14+
import org.hyperledger.fabric.contract.routing.TransactionType;
15+
import org.hyperledger.fabric.contract.routing.impl.ContractScannerImpl;
1116
import org.hyperledger.fabric.shim.ChaincodeBase;
1217
import org.hyperledger.fabric.shim.ChaincodeStub;
18+
import org.hyperledger.fabric.shim.ResponseUtils;
1319

1420
/**
1521
* Router class routes Init/Invoke requests to contracts.
@@ -21,29 +27,57 @@ public class ContractRouter extends ChaincodeBase {
2127
private ExecutionService executor;
2228

2329
public ContractRouter() {
30+
scanner = new ContractScannerImpl();
31+
executor = ExecutionFactory.getInstance().createExecutionService();
2432
}
2533

26-
public void findAllContracts() {
27-
34+
void findAllContracts() {
35+
try {
36+
scanner.findAndSetContracts();
37+
} catch (Exception e) {
38+
throw new IllegalStateException(e);
39+
}
2840
}
2941

30-
public void startRouting(String[] args) {
42+
void startRouting(String[] args) {
3143
start(args);
3244
}
3345

3446
@Override
3547
public Response init(ChaincodeStub stub) {
36-
return newErrorResponse();
48+
InvocationRequest request = ExecutionFactory.getInstance().createRequest(stub);
49+
Routing routing = getRouting(request);
50+
if (routing != null) {
51+
if (routing.getType() == TransactionType.INIT || routing.getType() == TransactionType.DEFAULT) {
52+
return executor.executeRequest(routing, request, stub);
53+
}
54+
}
55+
return ResponseUtils.newErrorResponse("Can't find @Init method " + request.getMethod() + " in namespace " + request.getNamespace() + " and no default method as well");
3756
}
3857

3958
@Override
4059
public Response invoke(ChaincodeStub stub) {
41-
return newErrorResponse();
60+
InvocationRequest request = ExecutionFactory.getInstance().createRequest(stub);
61+
Routing routing = getRouting(request);
62+
if (routing != null) {
63+
if (routing.getType() == TransactionType.INVOKE || routing.getType() == TransactionType.QUERY || routing.getType() == TransactionType.DEFAULT) {
64+
return executor.executeRequest(routing, request, stub);
65+
}
66+
}
67+
return ResponseUtils.newErrorResponse("Can't find @Transaction method " + request.getMethod() + " in namespace " + request.getNamespace() + " and no default method as well");
4268
}
4369

4470
public static void main(String[] args) {
4571
ContractRouter cfc = new ContractRouter();
4672
cfc.findAllContracts();
4773
cfc.startRouting(args);
4874
}
75+
76+
Routing getRouting(InvocationRequest request) {
77+
Routing routing = scanner.getRouting(request);
78+
if (routing == null) {
79+
routing = scanner.getDefaultRouting(request);
80+
}
81+
return routing;
82+
}
4983
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
Copyright IBM Corp., DTCC All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package org.hyperledger.fabric.contract.execution;
8+
9+
import org.hyperledger.fabric.contract.Context;
10+
import org.hyperledger.fabric.contract.execution.impl.ContractExecutionService;
11+
import org.hyperledger.fabric.contract.execution.impl.ContractInvocationRequest;
12+
import org.hyperledger.fabric.shim.ChaincodeStub;
13+
14+
public class ExecutionFactory {
15+
private static ExecutionFactory rf;
16+
private static ExecutionService es;
17+
18+
public static ExecutionFactory getInstance() {
19+
if (rf == null) {
20+
rf = new ExecutionFactory();
21+
}
22+
return rf;
23+
}
24+
25+
public InvocationRequest createRequest(ChaincodeStub context) {
26+
return new ContractInvocationRequest(context);
27+
}
28+
29+
public ExecutionService createExecutionService() {
30+
if (es == null) {
31+
es = new ContractExecutionService();
32+
}
33+
return es;
34+
}
35+
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88

99
import org.hyperledger.fabric.contract.routing.Routing;
1010
import org.hyperledger.fabric.shim.Chaincode;
11+
import org.hyperledger.fabric.shim.ChaincodeStub;
1112

1213
/**
1314
* Service that executes {@link InvocationRequest} (wrapped INit/Invoke + extra data) using routing information {@link Routing}
1415
*/
1516
public interface ExecutionService {
1617

17-
Chaincode.Response executeRequest(Routing rd, InvocationRequest req);
18+
Chaincode.Response executeRequest(Routing rd, InvocationRequest req, ChaincodeStub stub);
1819
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
Copyright IBM Corp., DTCC All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package org.hyperledger.fabric.contract.execution.impl;
8+
9+
import net.sf.cglib.proxy.Enhancer;
10+
import net.sf.cglib.proxy.MethodInterceptor;
11+
import net.sf.cglib.proxy.MethodProxy;
12+
import org.apache.commons.logging.Log;
13+
import org.apache.commons.logging.LogFactory;
14+
import org.hyperledger.fabric.contract.Context;
15+
import org.hyperledger.fabric.contract.ContractInterface;
16+
import org.hyperledger.fabric.contract.annotation.Init;
17+
import org.hyperledger.fabric.contract.annotation.Transaction;
18+
import org.hyperledger.fabric.contract.execution.ExecutionService;
19+
import org.hyperledger.fabric.contract.execution.InvocationRequest;
20+
import org.hyperledger.fabric.contract.routing.Routing;
21+
import org.hyperledger.fabric.shim.Chaincode;
22+
import org.hyperledger.fabric.shim.ChaincodeStub;
23+
import org.hyperledger.fabric.shim.ResponseUtils;
24+
25+
import java.lang.reflect.InvocationTargetException;
26+
import java.lang.reflect.Method;
27+
import java.nio.charset.StandardCharsets;
28+
import java.util.ArrayList;
29+
import java.util.HashMap;
30+
import java.util.List;
31+
import java.util.Map;
32+
33+
public class ContractExecutionService implements ExecutionService {
34+
35+
private static Log logger = LogFactory.getLog(ContractExecutionService.class);
36+
37+
Map<String, Object> proxies = new HashMap<>();
38+
Map<String, ProxyMethodInterceptor> methodInterceptors = new HashMap<>();
39+
40+
@Override
41+
public Chaincode.Response executeRequest(Routing rd, InvocationRequest req, ChaincodeStub stub) {
42+
final ContractInterface contractObject = rd.getContractObject();
43+
final Class<?> contractClass = rd.getContractClass();
44+
if (!proxies.containsKey(req.getNamespace())) {
45+
ProxyMethodInterceptor interceptor = createMethodInterceptorForContract(contractClass, contractObject);
46+
methodInterceptors.put(req.getNamespace(), interceptor);
47+
proxies.put(req.getNamespace(), createProxyForContract(contractClass, interceptor));
48+
}
49+
50+
Object proxyObject = proxies.get(req.getNamespace());
51+
ProxyMethodInterceptor interceptor = methodInterceptors.get(req.getNamespace());
52+
interceptor.setContextForThread(stub);
53+
final List<Object> args = convertArgs(req.getArgs(), rd.getMethod().getParameterTypes());
54+
55+
Chaincode.Response response;
56+
try {
57+
response = (Chaincode.Response)rd.getMethod().invoke(proxyObject, args.toArray());
58+
} catch (IllegalAccessException|InvocationTargetException e) {
59+
logger.warn("Error during contract method invocation", e);
60+
response = ResponseUtils.newErrorResponse(e);
61+
}
62+
return response;
63+
}
64+
65+
private List<Object> convertArgs(List<byte[]> stubArgs, Class<?>[] methodParameterTypes) {
66+
List<Object> args = new ArrayList<>();
67+
for (int i = 0; i < methodParameterTypes.length; i++) {
68+
Class<?> param = methodParameterTypes[i];
69+
if (param.isArray()) {
70+
args.add(stubArgs.get(i));
71+
} else {
72+
args.add(new String(stubArgs.get(i), StandardCharsets.UTF_8));
73+
}
74+
}
75+
return args;
76+
}
77+
78+
private Object createProxyForContract(Class<?> contractClass, ProxyMethodInterceptor interceptor) {
79+
Enhancer enhancer = new Enhancer();
80+
enhancer.setSuperclass(contractClass);
81+
enhancer.setCallback(interceptor);
82+
return enhancer.create();
83+
}
84+
85+
private ProxyMethodInterceptor createMethodInterceptorForContract(final Class<?> contractClass, final ContractInterface contractObject) {
86+
return new ProxyMethodInterceptor(contractClass, contractObject);
87+
}
88+
89+
private static class ProxyMethodInterceptor implements MethodInterceptor {
90+
Class<?> contractClass;
91+
ContractInterface contractObject;
92+
ThreadLocal<Context> context = new ThreadLocal<>();
93+
public ProxyMethodInterceptor(Class<?> contractClass, ContractInterface contractObject) {
94+
this.contractClass = contractClass;
95+
this.contractObject = contractObject;
96+
}
97+
98+
public void setContextForThread(ChaincodeStub stub) {
99+
context.set(contractObject.createContext(stub));
100+
}
101+
102+
@Override
103+
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
104+
throws Throwable {
105+
if (method.getName().equals("getContext")) {
106+
return context.get();
107+
} else if (method.getDeclaringClass() != Object.class && method.getDeclaringClass() != ContractInterface.class &&
108+
(method.getAnnotation(Init.class) != null || method.getAnnotation(Transaction.class) != null)) {
109+
contractObject.beforeTransaction();
110+
Object result = proxy.invokeSuper(obj, args);
111+
contractObject.afterTransaction();
112+
return result;
113+
} else {
114+
return proxy.invokeSuper(obj, args);
115+
}
116+
}
117+
118+
}
119+
120+
}

0 commit comments

Comments
 (0)