Skip to content

Commit 46685bb

Browse files
authored
Merge pull request #72 from unicitynetwork/issue-71
#71 Add network id to unicity id minting
2 parents 91f400e + d9c12e2 commit 46685bb

6 files changed

Lines changed: 129 additions & 33 deletions

File tree

Lines changed: 70 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,75 @@
11
package org.unicitylabs.sdk.api;
22

3+
import com.fasterxml.jackson.annotation.JsonCreator;
4+
import com.fasterxml.jackson.annotation.JsonValue;
5+
36
/**
4-
* Status codes for certification.
7+
* Status codes for certification. Known statuses are exposed as singleton
8+
* constants; any other value returned by the aggregator is accepted and
9+
* preserved as a custom status instead of being rejected.
510
*/
6-
public enum CertificationStatus {
11+
public final class CertificationStatus {
12+
713
/**
814
* The certification request was accepted and stored.
915
*/
10-
SUCCESS("SUCCESS"),
16+
public static final CertificationStatus SUCCESS = new CertificationStatus("SUCCESS");
1117

1218
/**
1319
* The certification request failed because the state ID does not match the expected format.
1420
*/
15-
STATE_ID_MISMATCH("STATE_ID_MISMATCH"),
21+
public static final CertificationStatus STATE_ID_MISMATCH =
22+
new CertificationStatus("STATE_ID_MISMATCH");
1623
/**
1724
* The certification request failed because the signature verification failed.
1825
*/
19-
SIGNATURE_VERIFICATION_FAILED("SIGNATURE_VERIFICATION_FAILED"),
26+
public static final CertificationStatus SIGNATURE_VERIFICATION_FAILED =
27+
new CertificationStatus("SIGNATURE_VERIFICATION_FAILED");
2028
/**
2129
* The certification request failed because signature has invalid format.
2230
*/
23-
INVALID_SIGNATURE_FORMAT("INVALID_SIGNATURE_FORMAT"),
31+
public static final CertificationStatus INVALID_SIGNATURE_FORMAT =
32+
new CertificationStatus("INVALID_SIGNATURE_FORMAT");
2433
/**
2534
* The certification request failed because the public key has invalid format.
2635
*/
27-
INVALID_PUBLIC_KEY_FORMAT("INVALID_PUBLIC_KEY_FORMAT"),
36+
public static final CertificationStatus INVALID_PUBLIC_KEY_FORMAT =
37+
new CertificationStatus("INVALID_PUBLIC_KEY_FORMAT");
2838
/**
2939
* The certification request failed because the source state hash has invalid format.
3040
*/
31-
INVALID_SOURCE_STATE_HASH_FORMAT("INVALID_SOURCE_STATE_HASH_FORMAT"),
41+
public static final CertificationStatus INVALID_SOURCE_STATE_HASH_FORMAT =
42+
new CertificationStatus("INVALID_SOURCE_STATE_HASH_FORMAT");
3243
/**
3344
* The certification request failed because the transaction hash has invalid format.
3445
*/
35-
INVALID_TRANSACTION_HASH_FORMAT("INVALID_TRANSACTION_HASH_FORMAT"),
46+
public static final CertificationStatus INVALID_TRANSACTION_HASH_FORMAT =
47+
new CertificationStatus("INVALID_TRANSACTION_HASH_FORMAT");
3648
/**
3749
* The certification request failed because the algorithm is not supported.
3850
*/
39-
UNSUPPORTED_ALGORITHM("UNSUPPORTED_ALGORITHM"),
51+
public static final CertificationStatus UNSUPPORTED_ALGORITHM =
52+
new CertificationStatus("UNSUPPORTED_ALGORITHM");
4053
/**
4154
* The certification request failed because request was sent to invalid shard.
4255
*/
43-
INVALID_SHARD("INVALID_SHARD");
56+
public static final CertificationStatus INVALID_SHARD = new CertificationStatus("INVALID_SHARD");
57+
58+
private static final CertificationStatus[] VALUES = {
59+
SUCCESS,
60+
STATE_ID_MISMATCH,
61+
SIGNATURE_VERIFICATION_FAILED,
62+
INVALID_SIGNATURE_FORMAT,
63+
INVALID_PUBLIC_KEY_FORMAT,
64+
INVALID_SOURCE_STATE_HASH_FORMAT,
65+
INVALID_TRANSACTION_HASH_FORMAT,
66+
UNSUPPORTED_ALGORITHM,
67+
INVALID_SHARD
68+
};
4469

4570
private final String value;
4671

47-
CertificationStatus(String value) {
72+
private CertificationStatus(String value) {
4873
this.value = value;
4974
}
5075

@@ -53,22 +78,50 @@ public enum CertificationStatus {
5378
*
5479
* @return string value
5580
*/
81+
@JsonValue
5682
public String getValue() {
57-
return value;
83+
return this.value;
5884
}
5985

6086
/**
61-
* Create status from string value.
87+
* Resolve a status from its string value. Returns the registered singleton
88+
* for known statuses; constructs a new instance for any other (custom) value
89+
* returned by the aggregator.
6290
*
6391
* @param value string value
6492
* @return status
6593
*/
94+
@JsonCreator
6695
public static CertificationStatus fromString(String value) {
67-
for (CertificationStatus status : CertificationStatus.values()) {
96+
if (value == null) {
97+
throw new IllegalArgumentException("Status value must not be null");
98+
}
99+
for (CertificationStatus status : CertificationStatus.VALUES) {
68100
if (status.value.equalsIgnoreCase(value)) {
69101
return status;
70102
}
71103
}
72-
throw new IllegalArgumentException("Unknown status: " + value);
104+
return new CertificationStatus(value);
105+
}
106+
107+
@Override
108+
public boolean equals(Object o) {
109+
if (this == o) {
110+
return true;
111+
}
112+
if (!(o instanceof CertificationStatus)) {
113+
return false;
114+
}
115+
return this.value.equals(((CertificationStatus) o).value);
116+
}
117+
118+
@Override
119+
public int hashCode() {
120+
return this.value.hashCode();
121+
}
122+
123+
@Override
124+
public String toString() {
125+
return this.value;
73126
}
74-
}
127+
}

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ public static VerificationResult<VerificationStatus> verify(
4040
) {
4141
List<VerificationResult<?>> results = new ArrayList<>();
4242

43+
if (!genesis.getNetworkId().equals(trustBase.getNetworkId())) {
44+
results.add(new VerificationResult<>("MintNetworkMatchesTrustBaseRule",
45+
VerificationStatus.FAIL));
46+
return new VerificationResult<>(
47+
"CertifiedUnicityIdMintTransactionVerificationRule",
48+
VerificationStatus.FAIL,
49+
"Mint network does not match trust base.",
50+
results
51+
);
52+
}
53+
results.add(new VerificationResult<>("MintNetworkMatchesTrustBaseRule",
54+
VerificationStatus.OK));
55+
4356
if (issuerPublicKey != null) {
4457
EncodedPredicate expectedLockScript = EncodedPredicate.fromPredicate(
4558
SignaturePredicate.create(issuerPublicKey));

src/main/java/org/unicitylabs/sdk/unicityid/CertifiedUnicityIdMintTransaction.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.unicitylabs.sdk.unicityid;
22

33
import org.unicitylabs.sdk.api.InclusionProof;
4+
import org.unicitylabs.sdk.api.NetworkId;
45
import org.unicitylabs.sdk.api.bft.RootTrustBase;
56
import org.unicitylabs.sdk.crypto.hash.DataHash;
67
import org.unicitylabs.sdk.predicate.EncodedPredicate;
@@ -49,6 +50,15 @@ public EncodedPredicate getRecipient() {
4950
return this.transaction.getRecipient();
5051
}
5152

53+
/**
54+
* Returns the network identifier.
55+
*
56+
* @return network identifier
57+
*/
58+
public NetworkId getNetworkId() {
59+
return this.transaction.getNetworkId();
60+
}
61+
5262
@Override
5363
public DataHash getSourceStateHash() {
5464
return this.transaction.getSourceStateHash();

src/main/java/org/unicitylabs/sdk/unicityid/UnicityId.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
import org.unicitylabs.sdk.crypto.hash.HashAlgorithm;
66
import org.unicitylabs.sdk.serializer.cbor.CborDeserializer;
77
import org.unicitylabs.sdk.serializer.cbor.CborSerializer;
8-
import org.unicitylabs.sdk.transaction.TokenId;
8+
import org.unicitylabs.sdk.transaction.TokenSalt;
99

1010
import java.util.List;
1111
import java.util.Objects;
1212

1313
/**
1414
* Human-readable identifier for a unicity token. The pair (domain, name) is hashed deterministically
15-
* to derive the corresponding {@link TokenId}.
15+
* to derive the corresponding {@link TokenSalt}.
1616
*/
1717
public final class UnicityId {
1818

@@ -85,12 +85,12 @@ public byte[] toCbor() {
8585
}
8686

8787
/**
88-
* Derive the token id from this unicity id by hashing the tagged ("NAMETAG_", domain, name)
88+
* Derive the token salt from this unicity id by hashing the tagged ("NAMETAG_", domain, name)
8989
* tuple with SHA-256.
9090
*
91-
* @return derived token id
91+
* @return derived token salt
9292
*/
93-
public TokenId toTokenId() {
93+
public TokenSalt toTokenSalt() {
9494
DataHash hash = new DataHasher(HashAlgorithm.SHA256)
9595
.update(
9696
CborSerializer.encodeArray(
@@ -100,7 +100,7 @@ public TokenId toTokenId() {
100100
)
101101
)
102102
.digest();
103-
return new TokenId(hash.getData());
103+
return TokenSalt.fromBytes(hash.getData());
104104
}
105105

106106
@Override

src/main/java/org/unicitylabs/sdk/unicityid/UnicityIdMintTransaction.java

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.unicitylabs.sdk.unicityid;
22

33
import org.unicitylabs.sdk.api.InclusionProof;
4+
import org.unicitylabs.sdk.api.NetworkId;
45
import org.unicitylabs.sdk.api.bft.RootTrustBase;
56
import org.unicitylabs.sdk.crypto.hash.DataHash;
67
import org.unicitylabs.sdk.crypto.hash.DataHasher;
@@ -31,6 +32,7 @@ public final class UnicityIdMintTransaction implements Transaction {
3132

3233
private final MintTransactionState sourceStateHash;
3334
private final EncodedPredicate lockScript;
35+
private final NetworkId networkId;
3436
private final EncodedPredicate recipient;
3537
private final TokenId tokenId;
3638
private final TokenType tokenType;
@@ -40,6 +42,7 @@ public final class UnicityIdMintTransaction implements Transaction {
4042
private UnicityIdMintTransaction(
4143
MintTransactionState sourceStateHash,
4244
EncodedPredicate lockScript,
45+
NetworkId networkId,
4346
EncodedPredicate recipient,
4447
TokenId tokenId,
4548
TokenType tokenType,
@@ -48,6 +51,7 @@ private UnicityIdMintTransaction(
4851
) {
4952
this.sourceStateHash = sourceStateHash;
5053
this.lockScript = lockScript;
54+
this.networkId = networkId;
5155
this.recipient = recipient;
5256
this.tokenId = tokenId;
5357
this.tokenType = tokenType;
@@ -79,6 +83,15 @@ public EncodedPredicate getRecipient() {
7983
return this.recipient;
8084
}
8185

86+
/**
87+
* Get the network identifier.
88+
*
89+
* @return network identifier
90+
*/
91+
public NetworkId getNetworkId() {
92+
return this.networkId;
93+
}
94+
8295
/**
8396
* Get the token id derived from the unicity id.
8497
*
@@ -129,6 +142,7 @@ public byte[] getStateMask() {
129142
* Create a unicity id mint transaction. The token id is derived from the unicity id; the lock
130143
* script is supplied by the caller.
131144
*
145+
* @param networkId network identifier
132146
* @param lockScript lock script predicate (the predicate that must be unlocked to spend this
133147
* transaction)
134148
* @param recipient recipient predicate
@@ -139,23 +153,26 @@ public byte[] getStateMask() {
139153
* @return mint transaction
140154
*/
141155
public static UnicityIdMintTransaction create(
156+
NetworkId networkId,
142157
SignaturePredicate lockScript,
143158
Predicate recipient,
144159
UnicityId unicityId,
145160
TokenType tokenType,
146161
SignaturePredicate targetPredicate
147162
) {
163+
Objects.requireNonNull(networkId, "Network ID must not be null");
148164
Objects.requireNonNull(lockScript, "lockScript cannot be null");
149165
Objects.requireNonNull(recipient, "recipient cannot be null");
150166
Objects.requireNonNull(unicityId, "unicityId cannot be null");
151167
Objects.requireNonNull(tokenType, "tokenType cannot be null");
152168
Objects.requireNonNull(targetPredicate, "targetPredicate cannot be null");
153169

154-
TokenId tokenId = unicityId.toTokenId();
170+
TokenId tokenId = TokenId.fromSalt(networkId, unicityId.toTokenSalt());
155171

156172
return new UnicityIdMintTransaction(
157173
MintTransactionState.create(tokenId),
158174
EncodedPredicate.fromPredicate(lockScript),
175+
networkId,
159176
EncodedPredicate.fromPredicate(recipient),
160177
tokenId,
161178
tokenType,
@@ -179,22 +196,23 @@ public static UnicityIdMintTransaction fromCbor(byte[] bytes) {
179196
if (tag.getTag() != UnicityIdMintTransaction.CBOR_TAG) {
180197
throw new CborSerializationException(String.format("Invalid CBOR tag: %s", tag.getTag()));
181198
}
182-
List<byte[]> data = CborDeserializer.decodeArray(tag.getData(), 6);
199+
List<byte[]> data = CborDeserializer.decodeArray(tag.getData(), 7);
183200

184201
int version = CborDeserializer.decodeUnsignedInteger(data.get(0)).asInt();
185202
if (version != UnicityIdMintTransaction.VERSION) {
186203
throw new CborSerializationException(String.format("Unsupported version: %s", version));
187204
}
188205

189206
return UnicityIdMintTransaction.create(
207+
NetworkId.fromId(CborDeserializer.decodeUnsignedInteger(data.get(1)).asShort()),
190208
SignaturePredicate.fromPredicate(
191-
EncodedPredicate.fromCbor(data.get(1))
209+
EncodedPredicate.fromCbor(data.get(2))
192210
),
193-
EncodedPredicate.fromCbor(data.get(2)),
194-
UnicityId.fromCbor(data.get(3)),
195-
TokenType.fromCbor(data.get(4)),
211+
EncodedPredicate.fromCbor(data.get(3)),
212+
UnicityId.fromCbor(data.get(4)),
213+
TokenType.fromCbor(data.get(5)),
196214
SignaturePredicate.fromPredicate(
197-
EncodedPredicate.fromCbor(data.get(5))
215+
EncodedPredicate.fromCbor(data.get(6))
198216
)
199217
);
200218
}
@@ -222,6 +240,7 @@ public byte[] toCbor() {
222240
UnicityIdMintTransaction.CBOR_TAG,
223241
CborSerializer.encodeArray(
224242
CborSerializer.encodeUnsignedInteger(UnicityIdMintTransaction.VERSION),
243+
CborSerializer.encodeUnsignedInteger(this.networkId.getId()),
225244
this.lockScript.toCbor(),
226245
this.recipient.toCbor(),
227246
this.unicityId.toCbor(),
@@ -252,9 +271,9 @@ public CertifiedUnicityIdMintTransaction toCertifiedTransaction(
252271
@Override
253272
public String toString() {
254273
return String.format(
255-
"UnicityIdMintTransaction{lockScript=%s, recipient=%s, tokenId=%s, tokenType=%s, unicityId=%s, targetPredicate=%s}",
256-
this.lockScript, this.recipient, this.tokenId, this.tokenType, this.unicityId,
257-
this.targetPredicate
274+
"UnicityIdMintTransaction{networkId=%s, lockScript=%s, recipient=%s, tokenId=%s, tokenType=%s, unicityId=%s, targetPredicate=%s}",
275+
this.networkId, this.lockScript, this.recipient, this.tokenId, this.tokenType,
276+
this.unicityId, this.targetPredicate
258277
);
259278
}
260279
}

src/test/java/org/unicitylabs/sdk/common/CommonTestFlow.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public void testUnicityIdMintFlow() throws Exception {
8585

8686
UnicityId unicityId = new UnicityId("testuser", "unicity-labs/test");
8787
UnicityIdMintTransaction unicityIdMintTransaction = UnicityIdMintTransaction.create(
88+
this.trustBase.getNetworkId(),
8889
SignaturePredicate.fromSigningService(unicityIdSigningService),
8990
targetPredicate,
9091
unicityId,

0 commit comments

Comments
 (0)