Skip to content
This repository was archived by the owner on Apr 22, 2025. It is now read-only.

Commit 3b32367

Browse files
FGJ-86: Allow client to specify transaction ID (#57)
- Add Channel.newTransactionContext() to allow transaction IDs to be generated prior to sending proposals. - Add TransactionRequest.setTransactionContext() to allow pre-generated transactions IDs to be used. - Up-front validation of user context on TransactionRequest to avoid numerous checks further through the submit flow. Signed-off-by: Mark S. Lewis <mark_lewis@uk.ibm.com>
1 parent 9da9a07 commit 3b32367

File tree

11 files changed

+208
-114
lines changed

11 files changed

+208
-114
lines changed

pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@
7070
</reporting>
7171

7272
<dependencies>
73+
<dependency>
74+
<groupId>org.mockito</groupId>
75+
<artifactId>mockito-core</artifactId>
76+
<version>3.3.3</version>
77+
<scope>test</scope>
78+
</dependency>
7379
<dependency>
7480
<groupId>junit</groupId>
7581
<artifactId>junit</artifactId>

src/main/java/org/hyperledger/fabric/sdk/Channel.java

Lines changed: 49 additions & 40 deletions
Large diffs are not rendered by default.

src/main/java/org/hyperledger/fabric/sdk/HFClient.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -684,13 +684,15 @@ public QueryByChaincodeRequest newQueryProposalRequest() {
684684
*
685685
* @param userContext
686686
* @return the old user context. Maybe null if never set!
687-
* @throws InvalidArgumentException
687+
* @throws IllegalStateException if no crypto suite has been set.
688+
* @throws NullPointerException if the user context is null.
689+
* @throws IllegalArgumentException if the user context is not valid.
688690
*/
689691

690-
public User setUserContext(User userContext) throws InvalidArgumentException {
692+
public User setUserContext(User userContext) {
691693

692694
if (null == cryptoSuite) {
693-
throw new InvalidArgumentException("No cryptoSuite has been set.");
695+
throw new IllegalStateException("No cryptoSuite has been set.");
694696
}
695697
userContextCheck(userContext);
696698

src/main/java/org/hyperledger/fabric/sdk/TransactionProposalRequest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ public class TransactionProposalRequest extends TransactionRequest {
2525

2626
public static TransactionProposalRequest newInstance(User userContext) {
2727
return new TransactionProposalRequest(userContext);
28-
2928
}
3029

3130
public void setChaincodeLanguage(Type chaincodeLanguage) {

src/main/java/org/hyperledger/fabric/sdk/TransactionRequest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
import java.util.Arrays;
1919
import java.util.HashMap;
2020
import java.util.Map;
21+
import java.util.Optional;
2122

2223
import org.hyperledger.fabric.protos.peer.Chaincode;
2324
import org.hyperledger.fabric.sdk.helper.Config;
25+
import org.hyperledger.fabric.sdk.transaction.TransactionContext;
2426

2527
/**
2628
* A base transaction request common for InstallProposalRequest,trRequest, and QueryRequest.
@@ -63,6 +65,8 @@ public void setChaincodeName(String chaincodeName) {
6365
protected Map<String, byte[]> transientMap;
6466
protected ChaincodeCollectionConfiguration chaincodeCollectionConfiguration = null;
6567

68+
private TransactionContext transactionContext;
69+
6670
/**
6771
* The user context to use on this request.
6872
*
@@ -79,7 +83,26 @@ User getUserContext() {
7983
* @param userContext The user context for this request used for signing.
8084
*/
8185
public void setUserContext(User userContext) {
86+
User.userContextCheck(userContext);
8287
this.userContext = userContext;
88+
this.transactionContext = null;
89+
}
90+
91+
/**
92+
* Get the transaction context to be used when submitting this transaction request, if one has been set.
93+
* @return A transaction context.
94+
*/
95+
public Optional<TransactionContext> getTransactionContext() {
96+
return Optional.ofNullable(transactionContext);
97+
}
98+
99+
/**
100+
* Get the transaction context to be used when submitting this transaction request.
101+
* @param transactionContext A transaction ID.
102+
*/
103+
public void setTransactionContext(final TransactionContext transactionContext) {
104+
userContext = transactionContext.getUser();
105+
this.transactionContext = transactionContext;
83106
}
84107

85108
/**
@@ -345,6 +368,7 @@ public void setProposalWaitTime(long proposalWaitTime) {
345368
}
346369

347370
protected TransactionRequest(User userContext) {
371+
User.userContextCheck(userContext);
348372
this.userContext = userContext;
349373
}
350374

src/main/java/org/hyperledger/fabric/sdk/User.java

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
import java.util.Set;
1818

19-
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
2019
import org.hyperledger.fabric.sdk.helper.Utils;
2120
import org.hyperledger.fabric.sdk.identity.X509Enrollment;
2221

@@ -70,33 +69,31 @@ public interface User {
7069
*/
7170
String getMspId();
7271

73-
static void userContextCheck(User userContext) throws InvalidArgumentException {
74-
72+
static void userContextCheck(User userContext) {
7573
if (userContext == null) {
76-
throw new InvalidArgumentException("UserContext is null");
74+
throw new NullPointerException("UserContext is null");
7775
}
76+
7877
final String userName = userContext.getName();
7978
if (Utils.isNullOrEmpty(userName)) {
80-
throw new InvalidArgumentException("UserContext user's name missing.");
79+
throw new IllegalArgumentException("UserContext user's name missing.");
8180
}
8281

8382
Enrollment enrollment = userContext.getEnrollment();
8483
if (enrollment == null) {
85-
throw new InvalidArgumentException(format("UserContext for user %s has no enrollment set.", userName));
84+
throw new IllegalArgumentException(format("UserContext for user %s has no enrollment set.", userName));
8685
}
8786
if (enrollment instanceof X509Enrollment) {
8887
if (Utils.isNullOrEmpty(enrollment.getCert())) {
89-
throw new InvalidArgumentException(format("UserContext for user %s enrollment missing user certificate.", userName));
88+
throw new IllegalArgumentException(format("UserContext for user %s enrollment missing user certificate.", userName));
9089
}
9190
if (null == enrollment.getKey()) {
92-
throw new InvalidArgumentException(format("UserContext for user %s has Enrollment missing signing key", userName));
91+
throw new IllegalArgumentException(format("UserContext for user %s has Enrollment missing signing key", userName));
9392
}
9493
}
9594

9695
if (Utils.isNullOrEmpty(userContext.getMspId())) {
97-
throw new InvalidArgumentException(format("UserContext for user %s has user's MSPID missing.", userName));
96+
throw new IllegalArgumentException(format("UserContext for user %s has user's MSPID missing.", userName));
9897
}
99-
10098
}
101-
10299
}

src/test/java/org/hyperledger/fabric/sdk/ChannelTest.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import java.util.concurrent.LinkedBlockingQueue;
3636
import java.util.concurrent.TimeUnit;
3737

38-
3938
import com.google.protobuf.ByteString;
4039
import io.grpc.Status;
4140
import io.grpc.StatusRuntimeException;
@@ -961,7 +960,8 @@ public void testProposalBuilderWithOutMetaInf() throws Exception {
961960
installProposalBuilder.chaincodeVersion("1");
962961

963962
Channel channel = hfclient.newChannel("testProposalBuilderWithOutMetaInf");
964-
TransactionContext transactionContext = new TransactionContext(channel, getMockUser("rick", "rickORG"), CryptoSuite.Factory.getCryptoSuite());
963+
User user = getMockUser("rick", "rickORG");
964+
TransactionContext transactionContext = new TransactionContext(channel, user, CryptoSuite.Factory.getCryptoSuite());
965965

966966
installProposalBuilder.context(transactionContext);
967967

@@ -1001,7 +1001,8 @@ public void testProposalBuilderWithNoMetaInfDir() throws Exception {
10011001
installProposalBuilder.setChaincodeMetaInfLocation(new File("src/test/fixture/meta-infs/test1/META-INF")); // points into which is not what's expected.
10021002

10031003
Channel channel = hfclient.newChannel("testProposalBuilderWithNoMetaInfDir");
1004-
TransactionContext transactionContext = new TransactionContext(channel, getMockUser("rick", "rickORG"), CryptoSuite.Factory.getCryptoSuite());
1004+
User user = getMockUser("rick", "rickORG");
1005+
TransactionContext transactionContext = new TransactionContext(channel, user, CryptoSuite.Factory.getCryptoSuite());
10051006

10061007
installProposalBuilder.context(transactionContext);
10071008

@@ -1023,7 +1024,8 @@ public void testProposalBuilderWithMetaInfExistsNOT() throws Exception {
10231024
installProposalBuilder.setChaincodeMetaInfLocation(new File("/tmp/fdsjfksfj/fjksfjskd/fjskfjdsk/should never exist")); // points into which is not what's expected.
10241025

10251026
Channel channel = hfclient.newChannel("testProposalBuilderWithMetaInfExistsNOT");
1026-
TransactionContext transactionContext = new TransactionContext(channel, getMockUser("rick", "rickORG"), CryptoSuite.Factory.getCryptoSuite());
1027+
User user = getMockUser("rick", "rickORG");
1028+
TransactionContext transactionContext = new TransactionContext(channel, user, CryptoSuite.Factory.getCryptoSuite());
10271029

10281030
installProposalBuilder.context(transactionContext);
10291031

@@ -1102,7 +1104,8 @@ public void testProposalBuilderWithMetaInfEmpty() throws Exception {
11021104
installProposalBuilder.setChaincodeMetaInfLocation(new File("src/test/fixture/meta-infs/emptyMetaInf")); // points into which is not what's expected.
11031105

11041106
Channel channel = hfclient.newChannel("testProposalBuilderWithMetaInfEmpty");
1105-
TransactionContext transactionContext = new TransactionContext(channel, getMockUser("rick", "rickORG"), CryptoSuite.Factory.getCryptoSuite());
1107+
User user = getMockUser("rick", "rickORG");
1108+
TransactionContext transactionContext = new TransactionContext(channel, user, CryptoSuite.Factory.getCryptoSuite());
11061109

11071110
installProposalBuilder.context(transactionContext);
11081111

src/test/java/org/hyperledger/fabric/sdk/ClientTest.java

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -121,60 +121,55 @@ public void testGoodMockUser() throws Exception {
121121

122122
}
123123

124-
@Test (expected = InvalidArgumentException.class)
124+
@Test (expected = NullPointerException.class)
125125
public void testBadUserContextNull() throws Exception {
126126
HFClient client = HFClient.createNewInstance();
127127
client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
128128

129129
client.setUserContext(null);
130-
131130
}
132131

133-
@Test (expected = InvalidArgumentException.class)
132+
@Test (expected = IllegalArgumentException.class)
134133
public void testBadUserNameNull() throws Exception {
135134
HFClient client = HFClient.createNewInstance();
136135
client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
137136

138137
MockUser mockUser = TestUtils.getMockUser(null, USER_MSP_ID);
139138

140139
client.setUserContext(mockUser);
141-
142140
}
143141

144-
@Test (expected = InvalidArgumentException.class)
142+
@Test (expected = IllegalArgumentException.class)
145143
public void testBadUserNameEmpty() throws Exception {
146144
HFClient client = HFClient.createNewInstance();
147145
client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
148146

149147
MockUser mockUser = TestUtils.getMockUser("", USER_MSP_ID);
150148

151149
client.setUserContext(mockUser);
152-
153150
}
154151

155-
@Test (expected = InvalidArgumentException.class)
152+
@Test (expected = IllegalArgumentException.class)
156153
public void testBadUserMSPIDNull() throws Exception {
157154
HFClient client = HFClient.createNewInstance();
158155
client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
159156

160157
MockUser mockUser = TestUtils.getMockUser(USER_NAME, null);
161158

162159
client.setUserContext(mockUser);
163-
164160
}
165161

166-
@Test (expected = InvalidArgumentException.class)
162+
@Test (expected = IllegalArgumentException.class)
167163
public void testBadUserMSPIDEmpty() throws Exception {
168164
HFClient client = HFClient.createNewInstance();
169165
client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
170166

171167
MockUser mockUser = TestUtils.getMockUser(USER_NAME, "");
172168

173169
client.setUserContext(mockUser);
174-
175170
}
176171

177-
@Test (expected = InvalidArgumentException.class)
172+
@Test (expected = IllegalArgumentException.class)
178173
public void testBadEnrollmentNull() throws Exception {
179174
HFClient client = HFClient.createNewInstance();
180175
client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
@@ -183,35 +178,30 @@ public void testBadEnrollmentNull() throws Exception {
183178
mockUser.setEnrollment(null);
184179

185180
client.setUserContext(mockUser);
186-
187181
}
188182

189-
@Test (expected = InvalidArgumentException.class)
183+
@Test (expected = IllegalArgumentException.class)
190184
public void testBadEnrollmentBadCert() throws Exception {
191185
HFClient client = HFClient.createNewInstance();
192186
client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
193187

194188
MockUser mockUser = TestUtils.getMockUser(USER_NAME, USER_MSP_ID);
195-
196189
Enrollment mockEnrollment = TestUtils.getMockEnrollment(null);
197190
mockUser.setEnrollment(mockEnrollment);
198191

199192
client.setUserContext(mockUser);
200-
201193
}
202194

203-
@Test (expected = InvalidArgumentException.class)
195+
@Test (expected = IllegalArgumentException.class)
204196
public void testBadEnrollmentBadKey() throws Exception {
205197
HFClient client = HFClient.createNewInstance();
206198
client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
207199

208200
MockUser mockUser = TestUtils.getMockUser(USER_NAME, USER_MSP_ID);
209-
210201
Enrollment mockEnrollment = TestUtils.getMockEnrollment(null, "mockCert");
211202
mockUser.setEnrollment(mockEnrollment);
212203

213204
client.setUserContext(mockUser);
214-
215205
}
216206

217207
@Test

src/test/java/org/hyperledger/fabric/sdk/RequestTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.io.InputStream;
2222

2323
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
24+
import org.hyperledger.fabric.sdk.security.CryptoSuite;
25+
import org.hyperledger.fabric.sdk.testutils.TestUtils;
2426
import org.junit.Before;
2527
import org.junit.Rule;
2628
import org.junit.Test;
@@ -40,6 +42,8 @@ public class RequestTest {
4042
@Before
4143
public void setupClient() throws Exception {
4244
hfclient = HFClient.createNewInstance();
45+
hfclient.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
46+
hfclient.setUserContext(TestUtils.getMockUser("user", "mspId"));
4347
mockstream = new ByteArrayInputStream(new byte[0]);
4448

4549
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2020 IBM - All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
15+
package org.hyperledger.fabric.sdk;
16+
17+
import java.util.Optional;
18+
19+
import org.hyperledger.fabric.sdk.testutils.TestUtils;
20+
import org.hyperledger.fabric.sdk.transaction.TransactionContext;
21+
import org.junit.Assert;
22+
import org.junit.Test;
23+
import org.mockito.Mockito;
24+
25+
public class TransactionRequestTest {
26+
@Test(expected = NullPointerException.class)
27+
public void newWithNullUserThrows() {
28+
TransactionRequest request = new TransactionRequest(null);
29+
}
30+
31+
@Test(expected = NullPointerException.class)
32+
public void testSetUserContextWithNullUserThrows() {
33+
User user = TestUtils.getMockUser("user", "mspId");
34+
TransactionRequest request = new TransactionRequest(user);
35+
36+
request.setUserContext(null);
37+
}
38+
39+
@Test
40+
public void testSetTransactionContext() {
41+
User user = TestUtils.getMockUser("user", "mspId");
42+
TransactionRequest request = new TransactionRequest(user);
43+
44+
TransactionContext context = Mockito.mock(TransactionContext.class);
45+
Mockito.when(context.getUser()).thenReturn(user);
46+
47+
request.setTransactionContext(context);
48+
49+
Optional<TransactionContext> actual = request.getTransactionContext();
50+
Assert.assertTrue("Transaction context is present", actual.isPresent());
51+
Assert.assertEquals("Excepted context", context, actual.get());
52+
}
53+
54+
@Test
55+
public void testSetTransactionContextAlsoSetsUserContext() {
56+
User oldUser = TestUtils.getMockUser("oldUser", "mspId");
57+
TransactionRequest request = new TransactionRequest(oldUser);
58+
59+
TransactionContext context = Mockito.mock(TransactionContext.class);
60+
User newUser = TestUtils.getMockUser("newUser", "mspId");
61+
Mockito.when(context.getUser()).thenReturn(newUser);
62+
63+
request.setTransactionContext(context);
64+
65+
Assert.assertEquals(newUser, request.getUserContext());
66+
}
67+
68+
@Test
69+
public void testSetUserContextRemovesTransactionContext() {
70+
User user = TestUtils.getMockUser("user", "mspId");
71+
TransactionRequest request = new TransactionRequest(user);
72+
73+
TransactionContext context = Mockito.mock(TransactionContext.class);
74+
Mockito.when(context.getUser()).thenReturn(user);
75+
request.setTransactionContext(context);
76+
77+
request.setUserContext(user);
78+
79+
Assert.assertFalse(request.getTransactionContext().isPresent());
80+
}
81+
}

0 commit comments

Comments
 (0)