Skip to content

Commit

Permalink
feat: add username transactions (#181)
Browse files Browse the repository at this point in the history
  • Loading branch information
alfonsobries authored Aug 14, 2024
1 parent cf8fa10 commit 07ad144
Show file tree
Hide file tree
Showing 23 changed files with 519 additions and 224 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ public enum CoreTransactionTypes {
VALIDATOR_REGISTRATION(2),
VOTE(3),
MULTI_SIGNATURE_REGISTRATION(4),
IPFS(5),
MULTI_PAYMENT(6),
VALIDATOR_RESIGNATION(7),
HTLC_LOCK(8),
HTLC_CLAIM(9),
HTLC_REFUND(10);
USERNAME_REGISTRATION(8),
USERNAME_RESIGNATION(9);

private final int value;

Expand Down
6 changes: 2 additions & 4 deletions src/main/java/org/arkecosystem/crypto/enums/Fees.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ public enum Fees {
VALIDATOR_REGISTRATION(2_500_000_000L),
VOTE(100_000_000L),
MULTI_SIGNATURE_REGISTRATION(500_000_000L),
IPFS(500_000_000L),
MULTI_PAYMENT(10_000_000L),
VALIDATOR_RESIGNATION(2_500_000_000L),
HTLC_LOCK(10_000_000L),
HTLC_CLAIM(0L),
HTLC_REFUND(0L);
USERNAME_REGISTRATION(2_500_000_000L),
USERNAME_RESIGNATION(2_500_000_000L);

private final Long value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import org.arkecosystem.crypto.transactions.types.SecondSignatureRegistration;
import org.arkecosystem.crypto.transactions.types.Transaction;
import org.arkecosystem.crypto.transactions.types.Transfer;
import org.arkecosystem.crypto.transactions.types.UsernameRegistration;
import org.arkecosystem.crypto.transactions.types.UsernameResignation;
import org.arkecosystem.crypto.transactions.types.ValidatorRegistration;
import org.arkecosystem.crypto.transactions.types.ValidatorResignation;
import org.arkecosystem.crypto.transactions.types.Vote;
Expand Down Expand Up @@ -42,6 +44,10 @@ public Deserializer(String serialized) {
coreTransactionTypes.put(CoreTransactionTypes.MULTI_PAYMENT.getValue(), new MultiPayment());
coreTransactionTypes.put(
CoreTransactionTypes.VALIDATOR_RESIGNATION.getValue(), new ValidatorResignation());
coreTransactionTypes.put(
CoreTransactionTypes.USERNAME_RESIGNATION.getValue(), new UsernameResignation());
coreTransactionTypes.put(
CoreTransactionTypes.USERNAME_REGISTRATION.getValue(), new UsernameRegistration());

transactionGroups.put(TransactionTypeGroup.CORE.getValue(), coreTransactionTypes);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class TransactionAsset {
public HashMap<String, Object> customAsset = new HashMap<>();
public long amount = 0L;
public String validatorPublicKey;
public String username;

public static class Signature {
public String publicKey;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.arkecosystem.crypto.transactions.builder;

import org.arkecosystem.crypto.enums.Fees;
import org.arkecosystem.crypto.transactions.types.Transaction;
import org.arkecosystem.crypto.transactions.types.UsernameRegistration;

public class UsernameRegistrationBuilder
extends AbstractTransactionBuilder<UsernameRegistrationBuilder> {
public UsernameRegistrationBuilder() {
super();
this.transaction.fee = Fees.VALIDATOR_REGISTRATION.getValue();
}

public UsernameRegistrationBuilder usernameAsset(String username) {
this.transaction.asset.username = username;

return this;
}

@Override
public Transaction getTransactionInstance() {
return new UsernameRegistration();
}

@Override
public UsernameRegistrationBuilder instance() {
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.arkecosystem.crypto.transactions.builder;

import org.arkecosystem.crypto.enums.Fees;
import org.arkecosystem.crypto.transactions.types.Transaction;
import org.arkecosystem.crypto.transactions.types.UsernameResignation;

public class UsernameResignationBuilder
extends AbstractTransactionBuilder<UsernameResignationBuilder> {

public UsernameResignationBuilder() {
super();
this.transaction.fee = Fees.USERNAME_RESIGNATION.getValue();
}

@Override
public Transaction getTransactionInstance() {
return new UsernameResignation();
}

@Override
public UsernameResignationBuilder instance() {
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.arkecosystem.crypto.encoding.Hex;
import org.arkecosystem.crypto.identities.PrivateKey;
import org.arkecosystem.crypto.signature.SchnorrSigner;
Expand Down Expand Up @@ -93,7 +91,7 @@ public boolean verify() {
byte[] signature = Hex.decode(this.signature);
byte[] hash = Sha256Hash.hash(Serializer.serialize(this, true, true, false));

return verifier(this.signature).verify(hash, keys, signature);
return verifier().verify(hash, keys, signature);
}

public boolean secondVerify(String secondPublicKey) {
Expand All @@ -102,48 +100,7 @@ public boolean secondVerify(String secondPublicKey) {
byte[] signature = Hex.decode(this.secondSignature);
byte[] hash = Sha256Hash.hash(Serializer.serialize(this, false, true, false));

return verifier(this.secondSignature).verify(hash, keys, signature);
}

public boolean multiVerify(int min, List<String> publicKeys) {
if (publicKeys.isEmpty()) {
throw new RuntimeException("The multi signature asset is invalid.");
}

byte[] hash = Sha256Hash.hash(Serializer.serialize(this, true, true, true));

Set<Integer> publicKeyIndexes = new HashSet<>();
int verifiedSignatures = 0;
boolean verified = false;
for (int i = 0; i < this.signatures.size(); i++) {
String signature = this.signatures.get(i);
int publicKeyIndex = Integer.parseInt(signature.substring(0, 2), 16);

if (!publicKeyIndexes.contains(publicKeyIndex)) {
publicKeyIndexes.add(publicKeyIndex);
} else {
throw new RuntimeException("Duplicate participant in multi signature");
}

String partialSignature = signature.substring(2);
String publicKey = publicKeys.get(publicKeyIndex);

if (verifier(partialSignature)
.verify(
hash,
ECKey.fromPublicOnly(Hex.decode(publicKey)),
Hex.decode(partialSignature))) {
verifiedSignatures++;
}

if (verifiedSignatures == min) {
verified = true;
break;
} else if (signatures.size() - (i + 1 - verifiedSignatures) < min) {
break;
}
}
return verified;
return verifier().verify(hash, keys, signature);
}

public String toJson() {
Expand Down Expand Up @@ -206,7 +163,7 @@ private Signer signer() {
return new SchnorrSigner();
}

private Verifier verifier(String signature) {
private Verifier verifier() {
return new SchnorrVerifier();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.arkecosystem.crypto.transactions.types;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
import org.arkecosystem.crypto.enums.CoreTransactionTypes;
import org.arkecosystem.crypto.enums.TransactionTypeGroup;

public class UsernameRegistration extends Transaction {
@Override
public int getTransactionType() {
return CoreTransactionTypes.USERNAME_REGISTRATION.getValue();
}

@Override
public int getTransactionTypeGroup() {
return TransactionTypeGroup.CORE.getValue();
}

@Override
public HashMap<String, Object> assetToHashMap() {
HashMap<String, Object> asset = new HashMap<>();

asset.put("username", this.asset.username);

return asset;
}

@Override
public byte[] serialize() {
byte[] username = this.asset.username.getBytes();

ByteBuffer buffer = ByteBuffer.allocate(username.length + 1);

buffer.order(ByteOrder.LITTLE_ENDIAN);

buffer.put((byte) username.length);
buffer.put(username);

return buffer.array();
}

@Override
public void deserialize(ByteBuffer buffer) {
int usernameLength = buffer.get() & 0xff;

byte[] username = new byte[usernameLength];
buffer.get(username);

String utf8Username = new String(username);
this.asset.username = utf8Username;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.arkecosystem.crypto.transactions.types;

import java.nio.ByteBuffer;
import java.util.HashMap;
import org.arkecosystem.crypto.enums.CoreTransactionTypes;
import org.arkecosystem.crypto.enums.TransactionTypeGroup;

public class UsernameResignation extends Transaction {
@Override
public int getTransactionType() {
return CoreTransactionTypes.USERNAME_RESIGNATION.getValue();
}

@Override
public int getTransactionTypeGroup() {
return TransactionTypeGroup.CORE.getValue();
}

@Override
public HashMap<String, Object> assetToHashMap() {
return null;
}

@Override
public byte[] serialize() {
return new byte[0];
}

@Override
public void deserialize(ByteBuffer buffer) {}
}
Loading

0 comments on commit 07ad144

Please sign in to comment.