Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 70 additions & 17 deletions src/main/java/org/unicitylabs/sdk/api/CertificationStatus.java
Original file line number Diff line number Diff line change
@@ -1,50 +1,75 @@
package org.unicitylabs.sdk.api;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;

/**
* Status codes for certification.
* Status codes for certification. Known statuses are exposed as singleton
* constants; any other value returned by the aggregator is accepted and
* preserved as a custom status instead of being rejected.
*/
public enum CertificationStatus {
public final class CertificationStatus {

/**
* The certification request was accepted and stored.
*/
SUCCESS("SUCCESS"),
public static final CertificationStatus SUCCESS = new CertificationStatus("SUCCESS");

/**
* The certification request failed because the state ID does not match the expected format.
*/
STATE_ID_MISMATCH("STATE_ID_MISMATCH"),
public static final CertificationStatus STATE_ID_MISMATCH =
new CertificationStatus("STATE_ID_MISMATCH");
/**
* The certification request failed because the signature verification failed.
*/
SIGNATURE_VERIFICATION_FAILED("SIGNATURE_VERIFICATION_FAILED"),
public static final CertificationStatus SIGNATURE_VERIFICATION_FAILED =
new CertificationStatus("SIGNATURE_VERIFICATION_FAILED");
/**
* The certification request failed because signature has invalid format.
*/
INVALID_SIGNATURE_FORMAT("INVALID_SIGNATURE_FORMAT"),
public static final CertificationStatus INVALID_SIGNATURE_FORMAT =
new CertificationStatus("INVALID_SIGNATURE_FORMAT");
/**
* The certification request failed because the public key has invalid format.
*/
INVALID_PUBLIC_KEY_FORMAT("INVALID_PUBLIC_KEY_FORMAT"),
public static final CertificationStatus INVALID_PUBLIC_KEY_FORMAT =
new CertificationStatus("INVALID_PUBLIC_KEY_FORMAT");
/**
* The certification request failed because the source state hash has invalid format.
*/
INVALID_SOURCE_STATE_HASH_FORMAT("INVALID_SOURCE_STATE_HASH_FORMAT"),
public static final CertificationStatus INVALID_SOURCE_STATE_HASH_FORMAT =
new CertificationStatus("INVALID_SOURCE_STATE_HASH_FORMAT");
/**
* The certification request failed because the transaction hash has invalid format.
*/
INVALID_TRANSACTION_HASH_FORMAT("INVALID_TRANSACTION_HASH_FORMAT"),
public static final CertificationStatus INVALID_TRANSACTION_HASH_FORMAT =
new CertificationStatus("INVALID_TRANSACTION_HASH_FORMAT");
/**
* The certification request failed because the algorithm is not supported.
*/
UNSUPPORTED_ALGORITHM("UNSUPPORTED_ALGORITHM"),
public static final CertificationStatus UNSUPPORTED_ALGORITHM =
new CertificationStatus("UNSUPPORTED_ALGORITHM");
/**
* The certification request failed because request was sent to invalid shard.
*/
INVALID_SHARD("INVALID_SHARD");
public static final CertificationStatus INVALID_SHARD = new CertificationStatus("INVALID_SHARD");

private static final CertificationStatus[] VALUES = {
SUCCESS,
STATE_ID_MISMATCH,
SIGNATURE_VERIFICATION_FAILED,
INVALID_SIGNATURE_FORMAT,
INVALID_PUBLIC_KEY_FORMAT,
INVALID_SOURCE_STATE_HASH_FORMAT,
INVALID_TRANSACTION_HASH_FORMAT,
UNSUPPORTED_ALGORITHM,
INVALID_SHARD
};

private final String value;

CertificationStatus(String value) {
private CertificationStatus(String value) {
this.value = value;
}

Expand All @@ -53,22 +78,50 @@ public enum CertificationStatus {
*
* @return string value
*/
@JsonValue
public String getValue() {
return value;
return this.value;
}

/**
* Create status from string value.
* Resolve a status from its string value. Returns the registered singleton
* for known statuses; constructs a new instance for any other (custom) value
* returned by the aggregator.
*
* @param value string value
* @return status
*/
@JsonCreator
public static CertificationStatus fromString(String value) {
for (CertificationStatus status : CertificationStatus.values()) {
if (value == null) {
throw new IllegalArgumentException("Status value must not be null");
}
for (CertificationStatus status : CertificationStatus.VALUES) {
if (status.value.equalsIgnoreCase(value)) {
return status;
}
}
throw new IllegalArgumentException("Unknown status: " + value);
return new CertificationStatus(value);
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof CertificationStatus)) {
return false;
}
return this.value.equals(((CertificationStatus) o).value);
}

@Override
public int hashCode() {
return this.value.hashCode();
}
Comment thread
martti007 marked this conversation as resolved.

@Override
public String toString() {
return this.value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ public static VerificationResult<VerificationStatus> verify(
) {
List<VerificationResult<?>> results = new ArrayList<>();

if (!genesis.getNetworkId().equals(trustBase.getNetworkId())) {
results.add(new VerificationResult<>("MintNetworkMatchesTrustBaseRule",
VerificationStatus.FAIL));
return new VerificationResult<>(
"CertifiedUnicityIdMintTransactionVerificationRule",
VerificationStatus.FAIL,
"Mint network does not match trust base.",
results
);
}
results.add(new VerificationResult<>("MintNetworkMatchesTrustBaseRule",
VerificationStatus.OK));
Comment thread
martti007 marked this conversation as resolved.

if (issuerPublicKey != null) {
EncodedPredicate expectedLockScript = EncodedPredicate.fromPredicate(
SignaturePredicate.create(issuerPublicKey));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.unicitylabs.sdk.unicityid;

import org.unicitylabs.sdk.api.InclusionProof;
import org.unicitylabs.sdk.api.NetworkId;
import org.unicitylabs.sdk.api.bft.RootTrustBase;
import org.unicitylabs.sdk.crypto.hash.DataHash;
import org.unicitylabs.sdk.predicate.EncodedPredicate;
Expand Down Expand Up @@ -49,6 +50,15 @@ public EncodedPredicate getRecipient() {
return this.transaction.getRecipient();
}

/**
* Returns the network identifier.
*
* @return network identifier
*/
public NetworkId getNetworkId() {
return this.transaction.getNetworkId();
}

@Override
public DataHash getSourceStateHash() {
return this.transaction.getSourceStateHash();
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/org/unicitylabs/sdk/unicityid/UnicityId.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
import org.unicitylabs.sdk.crypto.hash.HashAlgorithm;
import org.unicitylabs.sdk.serializer.cbor.CborDeserializer;
import org.unicitylabs.sdk.serializer.cbor.CborSerializer;
import org.unicitylabs.sdk.transaction.TokenId;
import org.unicitylabs.sdk.transaction.TokenSalt;

import java.util.List;
import java.util.Objects;

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

Expand Down Expand Up @@ -85,12 +85,12 @@ public byte[] toCbor() {
}

/**
* Derive the token id from this unicity id by hashing the tagged ("NAMETAG_", domain, name)
* Derive the token salt from this unicity id by hashing the tagged ("NAMETAG_", domain, name)
* tuple with SHA-256.
*
* @return derived token id
* @return derived token salt
*/
public TokenId toTokenId() {
public TokenSalt toTokenSalt() {
DataHash hash = new DataHasher(HashAlgorithm.SHA256)
.update(
CborSerializer.encodeArray(
Expand All @@ -100,7 +100,7 @@ public TokenId toTokenId() {
)
)
.digest();
return new TokenId(hash.getData());
return TokenSalt.fromBytes(hash.getData());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.unicitylabs.sdk.unicityid;

import org.unicitylabs.sdk.api.InclusionProof;
import org.unicitylabs.sdk.api.NetworkId;
import org.unicitylabs.sdk.api.bft.RootTrustBase;
import org.unicitylabs.sdk.crypto.hash.DataHash;
import org.unicitylabs.sdk.crypto.hash.DataHasher;
Expand Down Expand Up @@ -31,6 +32,7 @@ public final class UnicityIdMintTransaction implements Transaction {

private final MintTransactionState sourceStateHash;
private final EncodedPredicate lockScript;
private final NetworkId networkId;
private final EncodedPredicate recipient;
private final TokenId tokenId;
private final TokenType tokenType;
Expand All @@ -40,6 +42,7 @@ public final class UnicityIdMintTransaction implements Transaction {
private UnicityIdMintTransaction(
MintTransactionState sourceStateHash,
EncodedPredicate lockScript,
NetworkId networkId,
EncodedPredicate recipient,
TokenId tokenId,
TokenType tokenType,
Expand All @@ -48,6 +51,7 @@ private UnicityIdMintTransaction(
) {
this.sourceStateHash = sourceStateHash;
this.lockScript = lockScript;
this.networkId = networkId;
this.recipient = recipient;
this.tokenId = tokenId;
this.tokenType = tokenType;
Expand Down Expand Up @@ -79,6 +83,15 @@ public EncodedPredicate getRecipient() {
return this.recipient;
}

/**
* Get the network identifier.
*
* @return network identifier
*/
public NetworkId getNetworkId() {
return this.networkId;
}

/**
* Get the token id derived from the unicity id.
*
Expand Down Expand Up @@ -129,6 +142,7 @@ public byte[] getStateMask() {
* Create a unicity id mint transaction. The token id is derived from the unicity id; the lock
* script is supplied by the caller.
*
* @param networkId network identifier
* @param lockScript lock script predicate (the predicate that must be unlocked to spend this
* transaction)
* @param recipient recipient predicate
Expand All @@ -139,23 +153,26 @@ public byte[] getStateMask() {
* @return mint transaction
*/
public static UnicityIdMintTransaction create(
NetworkId networkId,
SignaturePredicate lockScript,
Predicate recipient,
UnicityId unicityId,
TokenType tokenType,
SignaturePredicate targetPredicate
) {
Objects.requireNonNull(networkId, "Network ID must not be null");
Objects.requireNonNull(lockScript, "lockScript cannot be null");
Objects.requireNonNull(recipient, "recipient cannot be null");
Objects.requireNonNull(unicityId, "unicityId cannot be null");
Objects.requireNonNull(tokenType, "tokenType cannot be null");
Objects.requireNonNull(targetPredicate, "targetPredicate cannot be null");

TokenId tokenId = unicityId.toTokenId();
TokenId tokenId = TokenId.fromSalt(networkId, unicityId.toTokenSalt());

return new UnicityIdMintTransaction(
MintTransactionState.create(tokenId),
EncodedPredicate.fromPredicate(lockScript),
networkId,
EncodedPredicate.fromPredicate(recipient),
tokenId,
tokenType,
Expand All @@ -179,22 +196,23 @@ public static UnicityIdMintTransaction fromCbor(byte[] bytes) {
if (tag.getTag() != UnicityIdMintTransaction.CBOR_TAG) {
throw new CborSerializationException(String.format("Invalid CBOR tag: %s", tag.getTag()));
}
List<byte[]> data = CborDeserializer.decodeArray(tag.getData(), 6);
List<byte[]> data = CborDeserializer.decodeArray(tag.getData(), 7);

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

return UnicityIdMintTransaction.create(
NetworkId.fromId(CborDeserializer.decodeUnsignedInteger(data.get(1)).asShort()),
SignaturePredicate.fromPredicate(
EncodedPredicate.fromCbor(data.get(1))
EncodedPredicate.fromCbor(data.get(2))
),
EncodedPredicate.fromCbor(data.get(2)),
UnicityId.fromCbor(data.get(3)),
TokenType.fromCbor(data.get(4)),
EncodedPredicate.fromCbor(data.get(3)),
UnicityId.fromCbor(data.get(4)),
TokenType.fromCbor(data.get(5)),
SignaturePredicate.fromPredicate(
EncodedPredicate.fromCbor(data.get(5))
EncodedPredicate.fromCbor(data.get(6))
)
);
}
Expand Down Expand Up @@ -222,6 +240,7 @@ public byte[] toCbor() {
UnicityIdMintTransaction.CBOR_TAG,
CborSerializer.encodeArray(
CborSerializer.encodeUnsignedInteger(UnicityIdMintTransaction.VERSION),
CborSerializer.encodeUnsignedInteger(this.networkId.getId()),
this.lockScript.toCbor(),
this.recipient.toCbor(),
this.unicityId.toCbor(),
Expand Down Expand Up @@ -252,9 +271,9 @@ public CertifiedUnicityIdMintTransaction toCertifiedTransaction(
@Override
public String toString() {
return String.format(
"UnicityIdMintTransaction{lockScript=%s, recipient=%s, tokenId=%s, tokenType=%s, unicityId=%s, targetPredicate=%s}",
this.lockScript, this.recipient, this.tokenId, this.tokenType, this.unicityId,
this.targetPredicate
"UnicityIdMintTransaction{networkId=%s, lockScript=%s, recipient=%s, tokenId=%s, tokenType=%s, unicityId=%s, targetPredicate=%s}",
this.networkId, this.lockScript, this.recipient, this.tokenId, this.tokenType,
this.unicityId, this.targetPredicate
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public void testUnicityIdMintFlow() throws Exception {

UnicityId unicityId = new UnicityId("testuser", "unicity-labs/test");
UnicityIdMintTransaction unicityIdMintTransaction = UnicityIdMintTransaction.create(
this.trustBase.getNetworkId(),
SignaturePredicate.fromSigningService(unicityIdSigningService),
targetPredicate,
unicityId,
Expand Down
Loading