Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/delegation signatures #171

Merged
merged 5 commits into from
Jul 7, 2021
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
4 changes: 2 additions & 2 deletions .env
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
AETERNITY_TAG=node-v6.0.0_indaex-v1.0.6
SOPHIA_COMPILER_TAG=v6.0.0
AETERNITY_TAG=node-v6.1.0_indaex-v1.0.8
SOPHIA_COMPILER_TAG=v6.0.2
NGINX_TAG=1.13.8
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ public void testStatus(TestContext context) {
t -> {
StatusResult statusResult = this.aeternityServiceNative.indaex.blockingGetStatus();
_logger.info(statusResult.toString());
context.assertEquals("6.0.0", statusResult.getNodeVersion());
context.assertEquals("1.0.6", statusResult.getMdwVersion());
context.assertEquals("6.1.0", statusResult.getNodeVersion());
context.assertEquals("1.0.8", statusResult.getMdwVersion());
});
}
}
26 changes: 26 additions & 0 deletions src/main/java/com/kryptokrauts/aeternity/sdk/constants/AENS.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.kryptokrauts.aeternity.sdk.constants;

import com.kryptokrauts.aeternity.sdk.util.EncodingUtils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -93,6 +95,20 @@ static BigInteger getBlockTimeout(String domain) {
}
}

/**
* returns the initial nameFee which is required to claim the name
*
* @param name the name to claim
* @return the initial nameFee which is required to claim the name
*/
static BigInteger getInitialNameFee(String name) {
int length = name.split("\\.")[0].length();
if (length >= 31) {
return SMALLEST_FEE;
}
return INITIAL_NAME_LENGTH_FEE_MAP.get(length);
}

/**
* returns the nameFee which is required for the next claim based on the current nameFee <br>
* the next nameFee is 5% higher than the current nameFee
Expand All @@ -109,4 +125,14 @@ static BigInteger getNextNameFee(BigInteger currentNameFee) {
.setScale(2, RoundingMode.HALF_UP)
.toBigInteger();
}

/**
* @param name the AENS name (e.g. kryptokrauts.chain)
* @return the nameId for a given name
*/
static String getNameId(String name) {
return EncodingUtils.encodeCheck(
EncodingUtils.hash(name.toLowerCase().getBytes(StandardCharsets.UTF_8)),
ApiIdentifiers.NAME);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.common.collect.ImmutableMap;
import com.kryptokrauts.aeternity.generated.ApiClient;
import com.kryptokrauts.aeternity.sdk.constants.BaseConstants;
import com.kryptokrauts.aeternity.sdk.constants.Network;
import com.kryptokrauts.aeternity.sdk.constants.VirtualMachine;
import com.kryptokrauts.aeternity.sdk.domain.secret.KeyPair;
import com.kryptokrauts.aeternity.sdk.exception.InvalidParameterException;
Expand Down Expand Up @@ -51,13 +52,23 @@ public class ServiceConfiguration {

@Default @Nonnull protected String indaexBaseUrl = BaseConstants.DEFAULT_TESTNET_INDAEX_URL;

@Getter @Default protected Network network = Network.TESTNET;

@Getter @Default @Nonnull protected VirtualMachine targetVM = VirtualMachine.FATE;

private KeyPair keyPair;

/** the vertx instance */
protected Vertx vertx;

public KeyPair getKeyPair() {
if (keyPair == null) {
throw new InvalidParameterException(
"Service call was initiated which needs the keyPair but none is set in ServiceConfiguration.keyPair - check parameters");
}
return keyPair;
}

/** @return apiClient initalized with default or given values of vertx and baseURL */
public ApiClient getApiClient() {
if (vertx == null) {
Expand Down Expand Up @@ -113,12 +124,4 @@ public com.kryptokrauts.indaex.generated.ApiClient getIndaexApiClient() {
throw new RuntimeException(
"Cannot instantiate ApiClient due to missing params vertx and or indaexBaseUrl");
}

public KeyPair getKeyPair() {
if (keyPair == null) {
throw new InvalidParameterException(
"Service call was initiated which needs the baseKeyPair but none is set in ServiceConfiguration.baseKeyPair - check parameters");
}
return keyPair;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.kryptokrauts.aeternity.sdk.service.aeternity;

import com.kryptokrauts.aeternity.sdk.constants.BaseConstants;
import com.kryptokrauts.aeternity.sdk.constants.Network;
import com.kryptokrauts.aeternity.sdk.service.ServiceConfiguration;
import lombok.Builder.Default;
import lombok.Getter;
Expand All @@ -15,8 +14,6 @@ public class AeternityServiceConfiguration extends ServiceConfiguration {

@Default private boolean debugDryRun = false;

@Default private Network network = Network.TESTNET;

@Default private long minimalGasPrice = BaseConstants.MINIMAL_GAS_PRICE;

@Default private boolean waitForTxIncludedInBlockEnabled = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.kryptokrauts.aeternity.sdk.service.delegation;

import java.math.BigInteger;

public interface DelegationService {

/**
* creates a delegation signature over "network id + account address + contract address"
* (concatenated as byte arrays)
*
* @param contractId the address of the contract (ct_...)
* @return the delegation signature that allows a contract to perform a preclaim for an AENS name
* on behalf of the configured keypair
*/
String createAensDelegationSignature(String contractId);

/**
* creates a delegation signature over "network id + account address + name hash + contract
* address" (concatenated as byte arrays)
*
* @param contractId the address of the contract (ct_...)
* @param name the AENS name (e.g. kryptokrauts.chain)
* @return the delegation signature that allows a contract to perform AENS related actions for a
* specific name on behalf of the configured keypair
*/
String createAensDelegationSignature(String contractId, String name);

/**
* creates a delegation signature over "network id + account address + contract" (concatenated as
* byte arrays)
*
* @param contractId the address of the contract (ct_...)
* @return the delegation signature that allows a contract to create and extend an oracle on
* behalf of the configured keypair
*/
String createOracleDelegationSignature(String contractId);

/**
* creates a delegation signature over "network id + oracle query id + contract address"
* (concatenated as byte arrays)
*
* @param contractId the address of the contract (ct_...)
* @param queryId the query id (oq_...)
* @return the delegation signature that allows a contract to respond to a specific query on
* behalf of the configured (oracle) keypair
*/
String createOracleDelegationSignature(String contractId, String queryId);

/**
* for claiming names with contracts it is required to provide the commitmentHash for an aens name
*
* @param name the AENS name to claim
* @param salt the salt used in the pre-claim transaction
* @return the hash that needs to be wrapped in the `Hash` object (generated via
* contraect-maven-plugin)
*/
String getAensCommitmentHash(String name, BigInteger salt);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.kryptokrauts.aeternity.sdk.service.delegation;

import com.kryptokrauts.aeternity.sdk.service.AbstractServiceFactory;
import com.kryptokrauts.aeternity.sdk.service.ServiceConfiguration;
import com.kryptokrauts.aeternity.sdk.service.delegation.impl.DelegationServiceImpl;

public class DelegationServiceFactory
extends AbstractServiceFactory<DelegationService, ServiceConfiguration> {

@Override
public DelegationService getService() {
return getService(ServiceConfiguration.configure().compile());
}

@Override
protected DelegationService getServiceWithConfig(ServiceConfiguration config) {
return new DelegationServiceImpl(config);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.kryptokrauts.aeternity.sdk.service.delegation.impl;

import com.kryptokrauts.aeternity.sdk.constants.AENS;
import com.kryptokrauts.aeternity.sdk.exception.AException;
import com.kryptokrauts.aeternity.sdk.service.ServiceConfiguration;
import com.kryptokrauts.aeternity.sdk.service.delegation.DelegationService;
import com.kryptokrauts.aeternity.sdk.util.ByteUtils;
import com.kryptokrauts.aeternity.sdk.util.EncodingUtils;
import com.kryptokrauts.aeternity.sdk.util.SigningUtil;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import javax.annotation.Nonnull;
import lombok.RequiredArgsConstructor;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.util.encoders.Hex;

@RequiredArgsConstructor
public class DelegationServiceImpl implements DelegationService {

@Nonnull private ServiceConfiguration config;

@Override
public String createAensDelegationSignature(String contractId) {
byte[] payload =
ByteUtils.concatenate(
EncodingUtils.decodeCheckWithIdentifier(this.config.getKeyPair().getAddress()),
EncodingUtils.decodeCheckWithIdentifier(contractId));
return signPayloadWithNetworkId(payload);
}

@Override
public String createAensDelegationSignature(String contractId, String name) {
byte[] payload =
ByteUtils.concatenate(
EncodingUtils.decodeCheckWithIdentifier(this.config.getKeyPair().getAddress()),
EncodingUtils.decodeCheckWithIdentifier(AENS.getNameId(name)),
EncodingUtils.decodeCheckWithIdentifier(contractId));
return signPayloadWithNetworkId(payload);
}

@Override
public String createOracleDelegationSignature(String contractId) {
byte[] payload =
ByteUtils.concatenate(
EncodingUtils.decodeCheckWithIdentifier(this.config.getKeyPair().getAddress()),
EncodingUtils.decodeCheckWithIdentifier(contractId));
return signPayloadWithNetworkId(payload);
}

@Override
public String createOracleDelegationSignature(String contractId, String queryId) {
byte[] payload =
ByteUtils.concatenate(
EncodingUtils.decodeCheckWithIdentifier(queryId),
EncodingUtils.decodeCheckWithIdentifier(contractId));
return signPayloadWithNetworkId(payload);
}

@Override
public String getAensCommitmentHash(String name, BigInteger salt) {
return Hex.toHexString(
EncodingUtils.decodeCheckWithIdentifier(EncodingUtils.generateCommitmentHash(name, salt)));
}

private String signPayloadWithNetworkId(byte[] payload) {
try {
byte[] signature =
SigningUtil.sign(
ByteUtils.concatenate(
this.config.getNetwork().getId().getBytes(StandardCharsets.UTF_8), payload),
this.config.getKeyPair().getEncodedPrivateKey());
return Hex.toHexString(signature);
} catch (CryptoException e) {
throw new AException(String.format("Error during signing: %s", e.getMessage()), e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ Single<PostTransactionResult> asyncPostTransaction(
* sign an unsigned transaction with the given private key. method uses an additional prefix and
* must be used to sign inner transactions of PayingForTx
*
* @param transactionModel of the inner tx to be signed
* @param model of the inner tx to be signed
* @param privateKey the encoded private key to sign the transaction
* @return signed and encoded transaction
* @throws TransactionCreateException if an error occurs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ public String signTransaction(final String unsignedTx, final String privateKey)
}
}

@Override
public String signPayingForInnerTransaction(
final AbstractTransactionModel<?> model, final String privateKey)
throws TransactionCreateException {
Expand Down Expand Up @@ -290,7 +291,7 @@ public String toString() {

private TransactionCreateException createException(Exception e) {
return new TransactionCreateException(
String.format("Technical error creating exception: ", e.getMessage()), e);
String.format("Technical error creating exception: %s", e.getMessage()), e);
}

private Tx createGeneratedTxObject(String signedTx) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public Function<GenericTx, NameClaimTransactionModel> getApiToModelFunction() {
@Override
public void validateInput() {
ValidationUtil.checkNamespace(this.name);
BigInteger minimumNameFee = AENS.INITIAL_NAME_LENGTH_FEE_MAP.get(this.getNameLength());
BigInteger minimumNameFee = AENS.getInitialNameFee(this.name);
ValidationUtil.checkParameters(
validate -> this.getNameFee().compareTo(minimumNameFee) != -1,
this.nameFee,
Expand All @@ -88,18 +88,9 @@ public BigInteger getNameFee() {
if (this.nameFee == null && this.name != null) {
log.info(
"nameFee not provided. using the initial required fee for the length of the given name.");
int nameLength = this.getNameLength();
if (nameLength >= 31) {
this.nameFee = AENS.SMALLEST_FEE;
} else {
this.nameFee = AENS.INITIAL_NAME_LENGTH_FEE_MAP.get(nameLength);
}
this.nameFee = AENS.getInitialNameFee(name);
log.info("initial name fee for the domain '{}' is: {}", this.name, this.nameFee);
}
return this.nameFee;
}

private Integer getNameLength() {
return this.name.split("\\.")[0].length();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,8 @@ public static String generateCommitmentHash(final String name, final BigInteger
return encodeCheck(
hash(
ByteUtils.concatenate(
name.getBytes(StandardCharsets.UTF_8), ByteUtils.leftPad(32, salt.toByteArray()))),
name.toLowerCase().getBytes(StandardCharsets.UTF_8),
ByteUtils.leftPad(32, salt.toByteArray()))),
ApiIdentifiers.COMMITMENT);
}

Expand Down