Skip to content

Commit ff9e936

Browse files
authored
Merge pull request #226 from millefoglie/fix/serializers
Fix transaction serializer usage
2 parents 5388349 + d13d307 commit ff9e936

File tree

4 files changed

+98
-54
lines changed

4 files changed

+98
-54
lines changed

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

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

77
package org.hyperledger.fabric.contract;
88

9-
import java.io.IOException;
10-
import java.util.Properties;
11-
import java.util.logging.Logger;
12-
139
import org.hyperledger.fabric.Logging;
14-
import org.hyperledger.fabric.contract.annotation.Serializer;
1510
import org.hyperledger.fabric.contract.execution.ExecutionFactory;
1611
import org.hyperledger.fabric.contract.execution.ExecutionService;
1712
import org.hyperledger.fabric.contract.execution.InvocationRequest;
18-
import org.hyperledger.fabric.contract.execution.SerializerInterface;
1913
import org.hyperledger.fabric.contract.metadata.MetadataBuilder;
2014
import org.hyperledger.fabric.contract.routing.ContractDefinition;
2115
import org.hyperledger.fabric.contract.routing.RoutingRegistry;
@@ -31,6 +25,10 @@
3125
import org.hyperledger.fabric.shim.ResponseUtils;
3226
import org.hyperledger.fabric.traces.Traces;
3327

28+
import java.io.IOException;
29+
import java.util.Properties;
30+
import java.util.logging.Logger;
31+
3432
/**
3533
* Router class routes Init/Invoke requests to contracts. Implements
3634
* {@link org.hyperledger.fabric.shim.Chaincode} interface.
@@ -46,6 +44,7 @@ public final class ContractRouter extends ChaincodeBase {
4644
// Store instances of SerializerInterfaces - identified by the contract
4745
// annotation (default is JSON)
4846
private final SerializerRegistryImpl serializers;
47+
private final ExecutionService executor;
4948

5049
/**
5150
* Take the arguments from the cli, and initiate processing of cli options and
@@ -79,6 +78,7 @@ public ContractRouter(final String[] args) {
7978
throw new RuntimeException(cre);
8079
}
8180

81+
executor = ExecutionFactory.getInstance().createExecutionService(serializers);
8282
}
8383

8484
/**
@@ -112,13 +112,6 @@ private Response processRequest(final ChaincodeStub stub) {
112112
logger.info(() -> "Got the invoke request for:" + stub.getFunction() + " " + stub.getParameters());
113113
final InvocationRequest request = ExecutionFactory.getInstance().createRequest(stub);
114114
final TxFunction txFn = getRouting(request);
115-
116-
// based on the routing information the serializer can be found
117-
// TRANSACTION target as this on the 'inbound' to invoke a tx
118-
final SerializerInterface si = serializers.getSerializer(txFn.getRouting().getSerializerName(),
119-
Serializer.TARGET.TRANSACTION);
120-
final ExecutionService executor = ExecutionFactory.getInstance().createExecutionService(si);
121-
122115
logger.info(() -> "Got routing:" + txFn.getRouting());
123116
return executor.executeRequest(txFn, request, stub);
124117
} else {

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88

99
import org.hyperledger.fabric.contract.execution.impl.ContractExecutionService;
1010
import org.hyperledger.fabric.contract.execution.impl.ContractInvocationRequest;
11+
import org.hyperledger.fabric.contract.routing.impl.SerializerRegistryImpl;
1112
import org.hyperledger.fabric.shim.ChaincodeStub;
1213

1314
public class ExecutionFactory {
1415
private static ExecutionFactory rf;
15-
private static ExecutionService es;
1616

1717
/**
1818
* @return ExecutionFactory
@@ -36,10 +36,7 @@ public InvocationRequest createRequest(final ChaincodeStub context) {
3636
* @param serializers Instance of the serializer
3737
* @return Execution Service
3838
*/
39-
public ExecutionService createExecutionService(final SerializerInterface serializers) {
40-
if (es == null) {
41-
es = new ContractExecutionService(serializers);
42-
}
43-
return es;
39+
public ExecutionService createExecutionService(final SerializerRegistryImpl serializers) {
40+
return new ContractExecutionService(serializers);
4441
}
4542
}

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

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,38 @@
66

77
package org.hyperledger.fabric.contract.execution.impl;
88

9-
import java.lang.reflect.InvocationTargetException;
10-
import java.util.ArrayList;
11-
import java.util.HashMap;
12-
import java.util.List;
13-
import java.util.Map;
14-
import java.util.logging.Logger;
15-
16-
import org.hyperledger.fabric.contract.Context;
9+
import org.hyperledger.fabric.contract.Context;
1710
import org.hyperledger.fabric.contract.ContractInterface;
1811
import org.hyperledger.fabric.contract.ContractRuntimeException;
12+
import org.hyperledger.fabric.contract.annotation.Serializer;
1913
import org.hyperledger.fabric.contract.execution.ExecutionService;
2014
import org.hyperledger.fabric.contract.execution.InvocationRequest;
2115
import org.hyperledger.fabric.contract.execution.SerializerInterface;
2216
import org.hyperledger.fabric.contract.metadata.TypeSchema;
2317
import org.hyperledger.fabric.contract.routing.ParameterDefinition;
2418
import org.hyperledger.fabric.contract.routing.TxFunction;
19+
import org.hyperledger.fabric.contract.routing.impl.SerializerRegistryImpl;
2520
import org.hyperledger.fabric.shim.Chaincode;
2621
import org.hyperledger.fabric.shim.ChaincodeException;
2722
import org.hyperledger.fabric.shim.ChaincodeStub;
2823
import org.hyperledger.fabric.shim.ResponseUtils;
2924

25+
import java.lang.reflect.InvocationTargetException;
26+
import java.util.ArrayList;
27+
import java.util.List;
28+
import java.util.logging.Logger;
29+
3030
public class ContractExecutionService implements ExecutionService {
3131

3232
private static Logger logger = Logger.getLogger(ContractExecutionService.class.getName());
3333

34-
private final SerializerInterface serializer;
35-
private Map<String, Object> proxies = new HashMap<>();
34+
private final SerializerRegistryImpl serializers;
3635

3736
/**
38-
* @param serializer
37+
* @param serializers
3938
*/
40-
public ContractExecutionService(final SerializerInterface serializer) {
41-
this.serializer = serializer;
39+
public ContractExecutionService(final SerializerRegistryImpl serializers) {
40+
this.serializers = serializers;
4241
}
4342

4443
/**
@@ -84,15 +83,15 @@ public Chaincode.Response executeRequest(final TxFunction txFn, final Invocation
8483
}
8584

8685
private byte[] convertReturn(final Object obj, final TxFunction txFn) {
87-
byte[] buffer;
86+
final SerializerInterface serializer = serializers.getSerializer(
87+
txFn.getRouting().getSerializerName(), Serializer.TARGET.TRANSACTION);
8888
final TypeSchema ts = txFn.getReturnSchema();
89-
buffer = serializer.toBuffer(obj, ts);
90-
91-
return buffer;
89+
return serializer.toBuffer(obj, ts);
9290
}
9391

9492
private List<Object> convertArgs(final List<byte[]> stubArgs, final TxFunction txFn) {
95-
93+
final SerializerInterface serializer = serializers.getSerializer(
94+
txFn.getRouting().getSerializerName(), Serializer.TARGET.TRANSACTION);
9695
final List<ParameterDefinition> schemaParams = txFn.getParamsList();
9796
final List<Object> args = new ArrayList<>(stubArgs.size() + 1); // allow for context as the first argument
9897
for (int i = 0; i < schemaParams.size(); i++) {

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

Lines changed: 72 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,37 @@
66

77
package org.hyperledger.fabric.contract.execution;
88

9-
import static org.hamcrest.Matchers.equalTo;
10-
import static org.junit.Assert.assertThat;
11-
import static org.mockito.ArgumentMatchers.any;
12-
import static org.mockito.Mockito.mock;
13-
import static org.mockito.Mockito.spy;
14-
import static org.mockito.Mockito.verify;
15-
import static org.mockito.Mockito.when;
16-
17-
import java.lang.reflect.InvocationTargetException;
18-
import java.util.ArrayList;
19-
9+
import contract.SampleContract;
2010
import org.hyperledger.fabric.contract.ChaincodeStubNaiveImpl;
2111
import org.hyperledger.fabric.contract.Context;
2212
import org.hyperledger.fabric.contract.ContractInterface;
2313
import org.hyperledger.fabric.contract.ContractRuntimeException;
14+
import org.hyperledger.fabric.contract.annotation.Serializer;
2415
import org.hyperledger.fabric.contract.execution.impl.ContractExecutionService;
16+
import org.hyperledger.fabric.contract.metadata.TypeSchema;
17+
import org.hyperledger.fabric.contract.routing.ParameterDefinition;
2518
import org.hyperledger.fabric.contract.routing.TxFunction;
19+
import org.hyperledger.fabric.contract.routing.impl.ParameterDefinitionImpl;
20+
import org.hyperledger.fabric.contract.routing.impl.SerializerRegistryImpl;
2621
import org.hyperledger.fabric.shim.Chaincode.Response;
2722
import org.hyperledger.fabric.shim.ChaincodeStub;
2823
import org.junit.Rule;
2924
import org.junit.Test;
3025
import org.junit.rules.ExpectedException;
3126

32-
import contract.SampleContract;
27+
import java.lang.reflect.InvocationTargetException;
28+
import java.lang.reflect.Method;
29+
import java.lang.reflect.Parameter;
30+
import java.util.ArrayList;
31+
import java.util.Collections;
32+
33+
import static org.hamcrest.Matchers.equalTo;
34+
import static org.junit.Assert.assertThat;
35+
import static org.mockito.ArgumentMatchers.any;
36+
import static org.mockito.Mockito.mock;
37+
import static org.mockito.Mockito.spy;
38+
import static org.mockito.Mockito.verify;
39+
import static org.mockito.Mockito.when;
3340

3441
public class ContractExecutionServiceTest {
3542
@Rule
@@ -39,10 +46,9 @@ public class ContractExecutionServiceTest {
3946
@Test
4047
public void noReturnValue()
4148
throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, SecurityException {
42-
4349
JSONTransactionSerializer jts = new JSONTransactionSerializer();
44-
45-
ContractExecutionService ces = new ContractExecutionService(jts);
50+
SerializerRegistryImpl serializerRegistry = spy(new SerializerRegistryImpl());
51+
ContractExecutionService ces = new ContractExecutionService(serializerRegistry);
4652

4753
ContractInterface contract = spy(new SampleContract());
4854
TxFunction txFn = mock(TxFunction.class);
@@ -55,6 +61,7 @@ public void noReturnValue()
5561
when(req.getArgs()).thenReturn(new ArrayList<byte[]>());
5662
when(routing.getMethod()).thenReturn(SampleContract.class.getMethod("noReturn", new Class<?>[] {Context.class}));
5763
when(routing.getContractInstance()).thenReturn(contract);
64+
when(serializerRegistry.getSerializer(any(), any())).thenReturn(jts);
5865
ces.executeRequest(txFn, req, stub);
5966

6067
verify(contract).beforeTransaction(any());
@@ -65,9 +72,9 @@ public void noReturnValue()
6572
@Test()
6673
public void failureToInvoke()
6774
throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, SecurityException {
68-
6975
JSONTransactionSerializer jts = new JSONTransactionSerializer();
70-
ContractExecutionService ces = new ContractExecutionService(jts);
76+
SerializerRegistryImpl serializerRegistry = spy(new SerializerRegistryImpl());
77+
ContractExecutionService ces = new ContractExecutionService(serializerRegistry);
7178

7279
spy(new SampleContract());
7380
TxFunction txFn = mock(TxFunction.class);
@@ -83,6 +90,7 @@ public void failureToInvoke()
8390

8491
when(routing.getContractInstance()).thenThrow(IllegalAccessException.class);
8592
when(routing.toString()).thenReturn("MockMethodName:MockClassName");
93+
when(serializerRegistry.getSerializer(any(), any())).thenReturn(jts);
8694

8795
thrown.expect(ContractRuntimeException.class);
8896
thrown.expectMessage("Could not execute contract method: MockMethodName:MockClassName");
@@ -91,4 +99,51 @@ public void failureToInvoke()
9199
assertThat(resp.getStatusCode(), equalTo(500));
92100
}
93101

102+
@SuppressWarnings({ "serial" })
103+
@Test()
104+
public void invokeWithDifferentSerializers()
105+
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
106+
JSONTransactionSerializer defaultSerializer = spy(new JSONTransactionSerializer());
107+
SerializerInterface customSerializer = mock(SerializerInterface.class);
108+
SerializerRegistryImpl serializerRegistry = spy(new SerializerRegistryImpl());
109+
ExecutionService executionService = ExecutionFactory.getInstance().createExecutionService(serializerRegistry);
110+
111+
TxFunction txFn = mock(TxFunction.class);
112+
InvocationRequest req = mock(InvocationRequest.class);
113+
TxFunction.Routing routing = mock(TxFunction.Routing.class);
114+
115+
TypeSchema ts = TypeSchema.typeConvert(String.class);
116+
Method method = SampleContract.class.getMethod("t1", Context.class, String.class);
117+
Parameter[] params = method.getParameters();
118+
ParameterDefinition pd = new ParameterDefinitionImpl("arg1", String.class, ts, params[1]);
119+
120+
byte[] arg = "asdf".getBytes();
121+
ChaincodeStub stub = new ChaincodeStubNaiveImpl();
122+
ContractInterface contract = spy(new SampleContract());
123+
124+
when(req.getArgs()).thenReturn(Collections.singletonList(arg));
125+
when(txFn.getRouting()).thenReturn(routing);
126+
when(txFn.getParamsList()).thenReturn(Collections.singletonList(pd));
127+
when(txFn.getReturnSchema()).thenReturn(ts);
128+
when(routing.getMethod()).thenReturn(method);
129+
when(routing.getContractInstance()).thenReturn(contract);
130+
131+
String defaultSerializerName = defaultSerializer.getClass().getCanonicalName();
132+
String customSerializerName = "customSerializer";
133+
134+
// execute transaction with the default serializer
135+
when(routing.getSerializerName()).thenReturn(defaultSerializerName);
136+
when(serializerRegistry.getSerializer(defaultSerializerName, Serializer.TARGET.TRANSACTION))
137+
.thenReturn(defaultSerializer);
138+
executionService.executeRequest(txFn, req, stub);
139+
140+
// execute transaction with the custom serializer
141+
when(routing.getSerializerName()).thenReturn(customSerializerName);
142+
when(serializerRegistry.getSerializer(customSerializerName, Serializer.TARGET.TRANSACTION))
143+
.thenReturn(customSerializer);
144+
executionService.executeRequest(txFn, req, stub);
145+
146+
verify(defaultSerializer).fromBuffer(arg, ts);
147+
verify(customSerializer).fromBuffer(arg, ts);
148+
}
94149
}

0 commit comments

Comments
 (0)