Skip to content

Commit 381dede

Browse files
committed
#73 Fix issues brought up in pull request
1 parent 0d3799b commit 381dede

8 files changed

Lines changed: 140 additions & 52 deletions

File tree

src/main/java/org/unicitylabs/sdk/api/NetworkId.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,17 @@ private NetworkId(short id) {
2323
}
2424

2525
/**
26-
* Resolve a NetworkId from its numeric identifier. Returns the registered
27-
* singleton for known ids; constructs a new (unnamed) instance for any
28-
* other 16-bit value.
26+
* Resolve a NetworkId from its raw 16-bit identifier. Returns the registered singleton for
27+
* known ids; constructs a new (unnamed) instance for any other value.
2928
*
30-
* @param id numeric network identifier
29+
* @param id raw 16-bit network identifier
3130
* @return NetworkId for the given identifier
3231
*/
3332
public static NetworkId fromId(short id) {
34-
if (id <= 0) {
35-
throw new IllegalArgumentException(
36-
"Network identifier out of allowed 16-bit unsigned range: " + id + ".");
33+
if (id == 0) {
34+
throw new IllegalArgumentException("Network identifier cannot be zero.");
3735
}
36+
3837
if (id == MAINNET.id) {
3938
return MAINNET;
4039
}

src/main/java/org/unicitylabs/sdk/api/bft/RootTrustBase.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,12 @@ public class RootTrustBase {
5454
String.format("Unsupported RootTrustBase version: %s", version));
5555
}
5656

57+
Objects.requireNonNull(rootNodes, "rootNodes cannot be null");
58+
5759
Map<String, NodeInfo> nodes = new LinkedHashMap<>();
5860
Set<String> signingKeys = new HashSet<>();
5961
for (NodeInfo node : rootNodes) {
62+
Objects.requireNonNull(node, "Trust base node cannot be null");
6063
if (nodes.putIfAbsent(node.getNodeId(), node) != null) {
6164
throw new IllegalArgumentException(
6265
String.format("Duplicate trust base node id: %s", node.getNodeId()));
@@ -250,6 +253,8 @@ public static class NodeInfo {
250253
@JsonProperty("sigKey") byte[] signingKey,
251254
@JsonProperty("stake") long stakedAmount
252255
) {
256+
Objects.requireNonNull(nodeId, "Node id cannot be null");
257+
Objects.requireNonNull(signingKey, "Node signing key cannot be null");
253258
if (stakedAmount <= 0) {
254259
throw new IllegalArgumentException("Each trust base root node must have positive stake.");
255260
}

src/main/java/org/unicitylabs/sdk/api/jsonrpc/JsonRpcHttpTransport.java

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.nio.charset.StandardCharsets;
1111
import java.util.List;
1212
import java.util.Map;
13+
import java.util.Objects;
1314
import java.util.UUID;
1415
import java.util.concurrent.CompletableFuture;
1516

@@ -23,6 +24,11 @@ public class JsonRpcHttpTransport {
2324

2425
private static final MediaType MEDIA_TYPE_JSON = MediaType.get("application/json; charset=utf-8");
2526

27+
private static final OkHttpClient DEFAULT_HTTP_CLIENT = new OkHttpClient.Builder()
28+
.followRedirects(false)
29+
.followSslRedirects(false)
30+
.build();
31+
2632
private final String url;
2733
private final int maxResponseBytes;
2834
private final OkHttpClient httpClient;
@@ -43,12 +49,32 @@ public JsonRpcHttpTransport(String url) {
4349
* @param maxResponseBytes maximum response body size in bytes
4450
*/
4551
public JsonRpcHttpTransport(String url, int maxResponseBytes) {
46-
this.url = url;
52+
this(url, JsonRpcHttpTransport.DEFAULT_HTTP_CLIENT, maxResponseBytes);
53+
}
54+
55+
/**
56+
* JSON-RPC HTTP service constructor with a caller-supplied HTTP client, to share a single
57+
* connection and thread pool across transports.
58+
*
59+
* @param url service URL
60+
* @param httpClient OkHttp client to use
61+
*/
62+
public JsonRpcHttpTransport(String url, OkHttpClient httpClient) {
63+
this(url, httpClient, JsonRpcHttpTransport.DEFAULT_MAX_RESPONSE_BYTES);
64+
}
65+
66+
/**
67+
* JSON-RPC HTTP service constructor with a caller-supplied HTTP client, to share a single
68+
* connection and thread pool across transports.
69+
*
70+
* @param url service URL
71+
* @param httpClient OkHttp client to use
72+
* @param maxResponseBytes maximum response body size in bytes
73+
*/
74+
public JsonRpcHttpTransport(String url, OkHttpClient httpClient, int maxResponseBytes) {
75+
this.url = Objects.requireNonNull(url, "url cannot be null");
76+
this.httpClient = Objects.requireNonNull(httpClient, "httpClient cannot be null");
4777
this.maxResponseBytes = maxResponseBytes;
48-
this.httpClient = new OkHttpClient.Builder()
49-
.followRedirects(false)
50-
.followSslRedirects(false)
51-
.build();
5278
}
5379

5480
/**
@@ -80,6 +106,10 @@ public <T> CompletableFuture<T> request(
80106
Class<T> resultType,
81107
Map<String, List<String>> headers
82108
) {
109+
Objects.requireNonNull(method, "method cannot be null");
110+
Objects.requireNonNull(resultType, "resultType cannot be null");
111+
Objects.requireNonNull(headers, "headers cannot be null");
112+
83113
CompletableFuture<T> future = new CompletableFuture<>();
84114

85115
try {

src/main/java/org/unicitylabs/sdk/payment/SplitAllocationProof.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Arrays;
2020
import java.util.Collections;
2121
import java.util.List;
22+
import java.util.Objects;
2223

2324
/**
2425
* Split allocation inclusion proof for one output asset: the explicit-depth inclusion proof of a
@@ -58,6 +59,12 @@ public int getLength() {
5859
* @throws IllegalArgumentException if the key is not present in the tree
5960
*/
6061
public static SplitAllocationProof create(SparseMerkleSumTreeRootNode root, byte[] key) {
62+
Objects.requireNonNull(root, "root cannot be null");
63+
Objects.requireNonNull(key, "key cannot be null");
64+
if (key.length != 32) {
65+
throw new IllegalArgumentException("Key must be 32 bytes long.");
66+
}
67+
6168
BigInteger keyPath = BitString.fromBytesReversedLSB(key).toBigInteger();
6269
List<Sibling> siblings = new ArrayList<>();
6370

@@ -111,7 +118,7 @@ public static SplitAllocationProof fromCbor(byte[] bytes) {
111118
for (byte[] entry : entries) {
112119
List<byte[]> fields = CborDeserializer.decodeArray(entry, 3);
113120

114-
int depth = CborDeserializer.decodeUnsignedInteger(fields.get(0)).asInt();
121+
int depth = CborDeserializer.decodeUnsignedInteger(fields.get(0)).asListSize();
115122
if (depth > SplitAllocationProof.MAX_DEPTH) {
116123
throw new CborSerializationException("Sibling depth must be in the range [0, 255].");
117124
}

src/main/java/org/unicitylabs/sdk/payment/SplitMintJustification.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ public static byte[] calculateLeafData(
7575
TokenId tokenId,
7676
byte[] data
7777
) {
78+
Objects.requireNonNull(token, "token cannot be null");
79+
Objects.requireNonNull(recipient, "recipient cannot be null");
80+
Objects.requireNonNull(salt, "salt cannot be null");
81+
Objects.requireNonNull(tokenId, "tokenId cannot be null");
82+
7883
return new DataHasher(HashAlgorithm.SHA256)
7984
.update(
8085
CborSerializer.encodeArray(

src/main/java/org/unicitylabs/sdk/serializer/cbor/CborDeserializer.java

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ public static <T> T decodeNullable(byte[] data, Function<byte[], T> decoder) {
4545
* @param data bytes
4646
* @return unsigned number
4747
*/
48-
public static CborNumber decodeUnsignedInteger(byte[] data) {
48+
public static CborUnsignedLong decodeUnsignedInteger(byte[] data) {
4949
CborReader reader = new CborReader(data);
50-
CborNumber value = reader.readLength(CborMajorType.UNSIGNED_INTEGER);
50+
CborUnsignedLong value = reader.readLength(CborMajorType.UNSIGNED_INTEGER);
5151
reader.assertExhausted();
5252

5353
return value;
@@ -61,7 +61,7 @@ public static CborNumber decodeUnsignedInteger(byte[] data) {
6161
*/
6262
public static byte[] decodeByteString(byte[] data) {
6363
CborReader reader = new CborReader(data);
64-
byte[] result = reader.read(reader.readLength(CborMajorType.BYTE_STRING).asInt());
64+
byte[] result = reader.read(reader.readLength(CborMajorType.BYTE_STRING).asListSize());
6565
reader.assertExhausted();
6666

6767
return result;
@@ -108,7 +108,7 @@ public static BigInteger decodeBigInteger(byte[] data, Integer maxByteLength) {
108108
*/
109109
public static String decodeTextString(byte[] data) {
110110
CborReader reader = new CborReader(data);
111-
byte[] bytes = reader.read(reader.readLength(CborMajorType.TEXT_STRING).asInt());
111+
byte[] bytes = reader.read(reader.readLength(CborMajorType.TEXT_STRING).asListSize());
112112
reader.assertExhausted();
113113

114114
return new String(bytes);
@@ -122,7 +122,7 @@ public static String decodeTextString(byte[] data) {
122122
*/
123123
public static List<byte[]> decodeArray(byte[] data) {
124124
CborReader reader = new CborReader(data);
125-
int length = reader.readLength(CborMajorType.ARRAY).asInt();
125+
int length = reader.readLength(CborMajorType.ARRAY).asListSize();
126126

127127
ArrayList<byte[]> result = new ArrayList<>();
128128
for (int i = 0; i < length; i++) {
@@ -160,7 +160,7 @@ public static List<byte[]> decodeArray(byte[] data, long expectedLength) {
160160
*/
161161
public static Set<CborMap.Entry> decodeMap(byte[] data) {
162162
CborReader reader = new CborReader(data);
163-
int length = reader.readLength(CborMajorType.MAP).asInt();
163+
int length = reader.readLength(CborMajorType.MAP).asListSize();
164164

165165
Set<Entry> result = new LinkedHashSet<>();
166166
Entry previous = null;
@@ -258,7 +258,7 @@ public byte[] read(int length) {
258258
}
259259
}
260260

261-
public CborNumber readLength(CborMajorType majorType) {
261+
public CborUnsignedLong readLength(CborMajorType majorType) {
262262
byte initialByte = this.readByte();
263263

264264
CborMajorType parsedMajorType = CborMajorType.fromType(
@@ -271,7 +271,7 @@ public CborNumber readLength(CborMajorType majorType) {
271271
byte additionalInformation = (byte) (initialByte
272272
& CborDeserializer.ADDITIONAL_INFORMATION_MASK);
273273
if (Byte.compareUnsigned(additionalInformation, (byte) 24) < 0) {
274-
return new CborNumber(additionalInformation);
274+
return new CborUnsignedLong(additionalInformation);
275275
}
276276

277277
switch (majorType) {
@@ -307,7 +307,7 @@ public CborNumber readLength(CborMajorType majorType) {
307307
length, Long.toUnsignedString(t)));
308308
}
309309

310-
return new CborNumber(t);
310+
return new CborUnsignedLong(t);
311311
}
312312

313313
public byte[] readRawCbor() {
@@ -323,19 +323,19 @@ public byte[] readRawCbor() {
323323

324324
CborMajorType majorType = CborMajorType.fromType(
325325
this.data[this.position] & CborDeserializer.MAJOR_TYPE_MASK);
326-
CborNumber length = this.readLength(majorType);
326+
CborUnsignedLong length = this.readLength(majorType);
327327
switch (majorType) {
328328
case BYTE_STRING:
329329
case TEXT_STRING:
330-
this.read(length.asInt());
330+
this.read(length.asListSize());
331331
break;
332332
case ARRAY:
333333
// asInt bounds each count and every header consumes input, so the counter cannot
334334
// overflow; undersupplied counts fail with premature end of data as items are read.
335-
remaining += length.asInt();
335+
remaining += length.asListSize();
336336
break;
337337
case MAP:
338-
remaining += length.asInt() * 2L;
338+
remaining += length.asListSize() * 2L;
339339
break;
340340
case TAG:
341341
remaining += 1;
@@ -384,59 +384,82 @@ public byte[] getData() {
384384
/**
385385
* CBOR number implementation.
386386
*/
387-
public static class CborNumber {
387+
public static class CborUnsignedLong {
388388

389389
private final long value;
390390

391-
private CborNumber(long value) {
391+
private CborUnsignedLong(long value) {
392392
this.value = value;
393393
}
394394

395395
/**
396-
* Get number as long.
396+
* Get the raw unsigned value as a {@code long}. Values at or above {@code 2^63} are returned
397+
* as a negative long with the same bit pattern; use {@link Long#compareUnsigned} to compare
398+
* them.
397399
*
398-
* @return number
400+
* @return value
399401
*/
400402
public long asLong() {
401403
return this.value;
402404
}
403405

404406
/**
405-
* Get number as int, throw error if does not fit.
407+
* Get the value as an unsigned 32-bit integer, throwing if it exceeds {@code 0xFFFFFFFF}.
408+
* Values above {@link Integer#MAX_VALUE} are returned with the same bit pattern (a negative
409+
* {@code int}); mask with {@code & 0xFFFFFFFFL} to recover the unsigned value.
406410
*
407-
* @return number
411+
* @return value
408412
*/
409413
public int asInt() {
410-
if (Long.compareUnsigned(this.value, Integer.MAX_VALUE) > 0) {
414+
if (Long.compareUnsigned(this.value, 0xFFFFFFFFL) > 0) {
411415
throw new CborSerializationException("Value too large");
412416
}
413417
return (int) this.value;
414418
}
415419

416420
/**
417-
* Get number as byte, throw error if does not fit.
421+
* Get the value as an unsigned 16-bit integer, throwing if it exceeds {@code 0xFFFF}. Values
422+
* above {@link Short#MAX_VALUE} are returned with the same bit pattern (a negative
423+
* {@code short}); mask with {@code & 0xFFFF} to recover the unsigned value.
418424
*
419-
* @return number
425+
* @return value
426+
*/
427+
public short asShort() {
428+
if (Long.compareUnsigned(this.value, 0xFFFFL) > 0) {
429+
throw new CborSerializationException("Value too large");
430+
}
431+
432+
return (short) this.value;
433+
}
434+
435+
/**
436+
* Get the value as an unsigned 8-bit integer, throwing if it exceeds {@code 0xFF}. Values
437+
* above {@link Byte#MAX_VALUE} are returned with the same bit pattern (a negative
438+
* {@code byte}); mask with {@code & 0xFF} to recover the unsigned value.
439+
*
440+
* @return value
420441
*/
421442
public byte asByte() {
422-
if (Long.compareUnsigned(this.value, Byte.MAX_VALUE) > 0) {
443+
if (Long.compareUnsigned(this.value, 0xFFL) > 0) {
423444
throw new CborSerializationException("Value too large");
424445
}
425446

426447
return (byte) this.value;
427448
}
428449

429450
/**
430-
* Get number as short, throw error if does not fit.
451+
* Get the value as a non-negative {@code int} bounded to {@link Integer#MAX_VALUE}, suitable
452+
* for a collection size, byte-string length or index. Throws if the value would not fit in a
453+
* valid Java array size.
431454
*
432-
* @return number
455+
* @return value
433456
*/
434-
public short asShort() {
435-
if (Long.compareUnsigned(this.value, Short.MAX_VALUE) > 0) {
457+
public int asListSize() {
458+
if (Long.compareUnsigned(this.value, Integer.MAX_VALUE) > 0) {
436459
throw new CborSerializationException("Value too large");
437460
}
438461

439-
return (short) this.value;
462+
return (int) this.value;
440463
}
441464
}
442465
}

src/main/java/org/unicitylabs/sdk/transaction/verification/TokenIssuanceVerifierService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import java.util.HashMap;
1010
import java.util.Map;
11+
import java.util.Objects;
1112

1213
/**
1314
* Registry that dispatches token verification to the right {@link TokenIssuanceVerifier} based on
@@ -46,6 +47,7 @@ public TokenIssuanceVerifierService(boolean rejectUnregisteredTypes) {
4647
* @throws IllegalArgumentException if a policy is already registered for the token type
4748
*/
4849
public TokenIssuanceVerifierService register(TokenIssuanceVerifier verifier) {
50+
Objects.requireNonNull(verifier, "verifier cannot be null");
4951
String key = HexConverter.encode(verifier.getTokenType().getBytes());
5052
if (this.verifiers.containsKey(key)) {
5153
throw new IllegalArgumentException(String.format(

0 commit comments

Comments
 (0)