Skip to content

Commit

Permalink
Account Transaction : Configure Baker and Delegation (#150)
Browse files Browse the repository at this point in the history
Co-authored-by: parv <[email protected]>
Co-authored-by: Parv Sharma <[email protected]>
  • Loading branch information
3 people authored Jan 25, 2023
1 parent f743e59 commit 85f2089
Show file tree
Hide file tree
Showing 37 changed files with 1,732 additions and 189 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
- Added support for Transfer To Encrypted wallet.
- Added support for Encrypted Transfer.
- Added support for Encrypted Transfer with Memo.
- Added support for Configuring a baker.
- Added support for Configuring the account as a Delegator.

## 4.0.0
- Support for Protocol 5.
Expand Down
113 changes: 113 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,12 @@ Make an encrypted transfer.
- Encrypted Transfer with memo:
Make an encrypted transfer with memo.

- Configure Baker:
Configures an account as a baker.

- Configure Delegation:
Configure the account as a delegator

## Exceptions and general error handling

- `TransactionCreationException`
Expand Down Expand Up @@ -1130,6 +1136,113 @@ The following example demonstrates how to make an encrypted transfer with memo.
```


### Configure Baker
The following example demonstrates how to construct a "configureBaker" transaction, which is used to add, remove or update a baker.

#### Configure baker
```java
try{
AccountAddress accountAddress = AccountAddress.from("48x2Uo8xCMMxwGuSQnwbqjzKtVqK5MaUud4vG7QEUgDmYkV85e");

TransactionSigner signer = TransactionSigner.from(
SignerEntry.from(Index.from(0), Index.from(0),
firstSecretKey),
SignerEntry.from(Index.from(0), Index.from(1),
secondSecretKey));

ConfigureBakerPayload configureBakerPayload = ConfigureBakerPayload.builder()
.capital(CCDAmount.fromMicro("14000000000"))
.restakeEarnings(true)
.openForDelegation(0)
.keysWithProofs(ConfigureBakerKeysPayload.getNewConfigureBakerKeysPayload(accountAddress))
.transactionFeeCommission(UInt32.from(10000))
.bakingRewardCommission(UInt32.from(10000))
.finalizationRewardCommission(UInt32.from(100000))
.build();


ConfigureBakerTransaction transaction = TransactionFactory.newConfigureBaker()
.sender(accountAddress)
.nonce(AccountNonce.from(nonceValue))
.expiry(Expiry.from(expiry))
.signer(signer)
.payload(configureBakerPayload)
.build();
client.sendTransaction(transaction);
} catch (TransactionRejectionException e) {
// Handle the rejected transaction, here we simply log it.
Transaction rejectedTransaction = e.getTransaction();
Hash rejectedTransactionHash = rejectedTransaction.getHash();
String rejectedTransactionHashHex = rejectedTransactionHash.asHex();
Log.err("Transaction " + rejectedTransactionHashHex + " was rejected");
}
```
#### Remove baker
```java
try{
AccountAddress accountAddress = AccountAddress.from("48x2Uo8xCMMxwGuSQnwbqjzKtVqK5MaUud4vG7QEUgDmYkV85e");

TransactionSigner signer = TransactionSigner.from(
SignerEntry.from(Index.from(0), Index.from(0),
firstSecretKey),
SignerEntry.from(Index.from(0), Index.from(1),
secondSecretKey));

ConfigureBakerTransaction transaction = TransactionFactory.newRemoveBaker()
.sender(accountAddress)
.nonce(AccountNonce.from(nonceValue))
.expiry(Expiry.from(expiry))
.signer(signer)
.build();
client.sendTransaction(transaction);
} catch (TransactionRejectionException e) {
// Handle the rejected transaction, here we simply log it.
Transaction rejectedTransaction = e.getTransaction();
Hash rejectedTransactionHash = rejectedTransaction.getHash();
String rejectedTransactionHashHex = rejectedTransactionHash.asHex();
Log.err("Transaction " + rejectedTransactionHashHex + " was rejected");
}
```

### Configure Delegation
The following example demonstrates how to construct a "configureDelegation" transaction, which is used to configure a delegator.

```java
try{
AccountAddress accountAddress = AccountAddress.from("48x2Uo8xCMMxwGuSQnwbqjzKtVqK5MaUud4vG7QEUgDmYkV85e");

TransactionSigner signer = TransactionSigner.from(
SignerEntry.from(Index.from(0), Index.from(0),
firstSecretKey),
SignerEntry.from(Index.from(0), Index.from(1),
secondSecretKey));

ConfigureDelegationPayload payload = ConfigureDelegationPayload.builder()
.capital(CCDAmount.fromMicro("500000"))
.restakeEarnings(true)
.delegationTarget(DelegationTarget.builder()
.type(DelegationTarget.DelegationType.PASSIVE)
.build())
.build();


ConfigureDelegationTransaction transaction = TransactionFactory.newConfigureDelegation()
.sender(accountAddress)
.nonce(AccountNonce.from(nonceValue))
.expiry(Expiry.from(expiry))
.signer(signer)
.payload(payload)
.build();
client.sendTransaction(transaction);
} catch (TransactionRejectionException e) {
// Handle the rejected transaction, here we simply log it.
Transaction rejectedTransaction = e.getTransaction();
Hash rejectedTransactionHash = rejectedTransaction.getHash();
String rejectedTransactionHashHex = rejectedTransactionHash.asHex();
Log.err("Transaction " + rejectedTransactionHashHex + " was rejected");
}
```

# Custom Signing
By default the java library supports ED25519 signing via the native binding [ED25519SecretKey](./concordium-sdk/src/main/java/com/concordium/sdk/crypto/ed25519/ED25519SecretKey.java).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ public class CryptoJniNative {
/**
* Creates a transfer from the encrypted amount to a public account payload, using the provided input string.
*
*
* @param input The input string to use for creating the transfer.
* @return The transfer data as a JSON string.
*/
Expand All @@ -56,5 +55,20 @@ public class CryptoJniNative {
*/
public static native String generateEncryptedTransfer(String input);

/**
* Generates baker keys.
*
* @return The baker keys data as a JSON string.
*/

public static native String generateBakerKeys();

/**
* Generates a configure baker keys payload, using the provided input string.
*
* @param input The input string to use for generating the configure baker keys payload.
* @return The configure baker keys data as a JSON string.
*/
public static native String generateConfigureBakerKeysPayload(String input);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.concordium.sdk.crypto.bakertransactions;

import com.concordium.sdk.crypto.CryptoJniNative;
import com.concordium.sdk.crypto.CryptoJniResultCode;
import com.concordium.sdk.crypto.NativeResolver;
import com.concordium.sdk.exceptions.CryptoJniException;
import com.concordium.sdk.serializing.JsonMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.val;

public final class BakerKeys {
//static block to load native library
static {
NativeResolver.loadLib();
}

//Method to create baker keys
public static BakerKeysJniOutput createBakerKeys() {

BakerKeysResult result = null;
try {
//Invoking native method to generate baker keys
val jsonStr = CryptoJniNative.generateBakerKeys();
result = JsonMapper.INSTANCE.readValue(jsonStr, BakerKeysResult.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
if (!result.isok()) {
throw CryptoJniException.from(
result.getErr().orElse(CryptoJniResultCode.ERROR_UNKNOWN_RESULT_CODE));
}

return result.getOk().orElseThrow(
() -> CryptoJniException.from(CryptoJniResultCode.ERROR_UNKNOWN_RESULT_CODE));

}

}


Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.concordium.sdk.crypto.bakertransactions;

import lombok.Builder;
import lombok.Data;
import lombok.extern.jackson.Jacksonized;

@Jacksonized
@Builder
@Data
public class BakerKeysJniOutput {
/**
* New public key for participating in the election lottery.
*/
private final String electionVerifyKey;
/**
* New public key for verifying this baker's signatures.
*/
private final String signatureVerifyKey;
/**
* New public key for verifying this baker's signature on finalization records.
*/
private final String aggregationVerifyKey;
/**
* A secret key used by a baker to sign blocks.
*/
private final String signatureSignKey;
/**
* A private key for participating in the election lottery.
*/
private final String electionPrivateKey;
/**
* A secret key used by bakers and finalizers to sign finalization records.
*/
private final String aggregationSignKey;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.concordium.sdk.crypto.bakertransactions;

import com.concordium.sdk.crypto.CryptoJniResultCode;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.Optional;

/**
* Class that holds the result of generating baker keys payload
*/
@Data
public class BakerKeysResult {
/**
* An optional `BakerKeysJniOutput` object, containing the output of the generate baker keys function.
*/
@JsonProperty("Ok")
private final Optional<BakerKeysJniOutput> ok;

/**
* An optional `CryptoJniResultCode` object, containing an error code if the generate baker keys function failed.
*/
@JsonProperty("Err")
private final Optional<CryptoJniResultCode> err;

@JsonCreator
BakerKeysResult(
@JsonProperty("Ok") BakerKeysJniOutput ok,
@JsonProperty("Err") CryptoJniResultCode err
) {
this.ok = Optional.ofNullable(ok);
this.err = Optional.ofNullable(err);
}

/**
* Returns a boolean indicating whether the `ok` field is present (i.e. whether the baker key was successfully generated).
*
* @return a boolean indicating whether the `ok` field is present.
*/
public boolean isok() {
return ok.isPresent();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.concordium.sdk.crypto.bakertransactions;

import com.concordium.sdk.crypto.CryptoJniNative;
import com.concordium.sdk.crypto.CryptoJniResultCode;
import com.concordium.sdk.crypto.NativeResolver;
import com.concordium.sdk.exceptions.CryptoJniException;
import com.concordium.sdk.serializing.JsonMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.val;

public final class ConfigureBakerKeys {
//static block to load native library
static {
NativeResolver.loadLib();
}

// Method to generate the payload for configuring baker keys
public static ConfigureBakerKeysJniOutput generateConfigureBakerKeysPayload(ConfigureBakerKeysJniInput jniInput) {

ConfigureBakerKeysResult result = null;
try {
val inputJsonString = JsonMapper.INSTANCE.writeValueAsString(jniInput);
//Invoking native method to generate configure baker keys payload
val jsonStr = CryptoJniNative.generateConfigureBakerKeysPayload(inputJsonString);
result = JsonMapper.INSTANCE.readValue(jsonStr, ConfigureBakerKeysResult.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}

if (!result.isok()) {
throw CryptoJniException.from(
result.getErr().orElse(CryptoJniResultCode.ERROR_UNKNOWN_RESULT_CODE));
}

// return the ok field of the result object
return result.getOk().orElseThrow(
() -> CryptoJniException.from(CryptoJniResultCode.ERROR_UNKNOWN_RESULT_CODE));

}

}


Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.concordium.sdk.crypto.bakertransactions;

import com.concordium.sdk.transactions.AccountAddress;
import lombok.Builder;
import lombok.Data;

/**
* Configure the account as a baker. Only valid for protocol version 4 and up.
*/
@Data
@Builder
public class ConfigureBakerKeysJniInput {
/**
* The address of the account that will be configured as a baker
*/
private final AccountAddress sender;
/**
* The baker keys that will be configured for the account
*/
private final BakerKeysJniOutput keys;
}
Loading

0 comments on commit 85f2089

Please sign in to comment.