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

feat: allow usage of custom keypair in stateful convenience methods #231

Merged
merged 1 commit into from
Feb 1, 2022
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
12 changes: 11 additions & 1 deletion docker/accounts_test.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
{
"ak_twR4h7dEcUtc2iSEDv8kB7UFJJDGiEDQCXr85C3fYF8FdVdyo": 100000000000001000000000000000000
"ak_twR4h7dEcUtc2iSEDv8kB7UFJJDGiEDQCXr85C3fYF8FdVdyo": 100000000000001000000000000000000,
"ak_fUq2NesPXcYZ1CcqBcGC3StpdnQw3iVxMA3YSeCNAwfN4myQk": 100000000000000000000000000000000,
"ak_tWZrf8ehmY7CyB1JAoBmWJEeThwWnDpU4NadUdzxVSbzDgKjP": 100000000000000000000000000000000,
"ak_FHZrEbRmanKUe9ECPXVNTLLpRP2SeQCLCT6Vnvs9JuVu78J7V": 100000000000000000000000000000000,
"ak_RYkcTuYcyxQ6fWZsL2G3Kj3K5WCRUEXsi76bPUNkEsoHc52Wp": 100000000000000000000000000000000,
"ak_2VvB4fFu7BQHaSuW5EkQ7GCaM5qiA5BsFUHjJ7dYpAaBoeFCZi": 100000000000000000000000000000000,
"ak_286tvbfP6xe4GY9sEbuN2ftx1LpavQwFVcPor9H4GxBtq5fXws": 100000000000000000000000000000000,
"ak_f9bmi44rdvUGKDsTLp3vMCMLMvvqsMQVWyc3XDAYECmCXEbzy": 100000000000000000000000000000000,
"ak_23p6pT7bajYMJRbnJ5BsbFUuYGX2PBoZAiiYcsrRHZ1BUY2zSF": 100000000000000000000000000000000,
"ak_gLYH5tAexTCvvQA6NpXksrkPJKCkLnB9MTDFTVCBuHNDJ3uZv": 100000000000000000000000000000000,
"ak_zPoY7cSHy2wBKFsdWJGXM7LnSjVt6cn1TWBDdRBUMC7Tur2NQ": 100000000000000000000000000000000
}
6 changes: 6 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## NEXT (unreleased)

### New features
- [#230](https://github.com/kryptokrauts/aepp-sdk-java/issues/230) allow usage of custom KeyPair in stateful convenience methods (`ContractCreateTx` & `ContractCallTx`)


## [v3.0.1](https://github.com/kryptokrauts/aepp-sdk-java/releases/tag/v3.0.1)

This is a minor release to address potential vulnerabilities in third party dependencies. It's highly recommended to update to this version.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.naming.ConfigurationException;
import org.apache.commons.io.IOUtils;
import org.junit.After;
Expand Down Expand Up @@ -69,6 +70,19 @@ public abstract class BaseTest {

private static final String MDW_BASE_URL = "MDW_BASE_URL";

private static final List<String> testPrivateKeys =
List.of(
"7c6e602a94f30e4ea7edabe4376314f69ba7eaa2f355ecedb339df847b6f0d80575f81ffb0a297b7725dc671da0b1769b1fc5cbe45385c7b5ad1fc2eaf1d609d",
"7fa7934d142c8c1c944e1585ec700f671cbc71fb035dc9e54ee4fb880edfe8d974f58feba752ae0426ecbee3a31414d8e6b3335d64ec416f3e574e106c7e5412",
"1509d7d0e113528528b7ce4bf72c3a027bcc98656e46ceafcfa63e56597ec0d8206ff07f99ea517b7a028da8884fb399a2e3f85792fe418966991ba09b192c91",
"58bd39ded1e3907f0b9c1fbaa4456493519995d524d168e0b04e86400f4aa13937bcec56026494dcf9b19061559255d78deea3281ac649ca307ead34346fa621",
"50458d629ae7109a98e098c51c29ec39c9aea9444526692b1924660b5e2309c7c55aeddd5ebddbd4c6970e91f56e8aaa04eb52a1224c6c783196802e136b9459",
"707881878eacacce4db463de9c7bf858b95c3144d52fafed4a41ffd666597d0393d23cf31fcd12324cd45d4784d08953e8df8283d129f357463e6795b40e88aa",
"9262701814da8149615d025377e2a08b5f10a6d33d1acaf2f5e703e87fe19c83569ecc7803d297fde01758f1bdc9e0c2eb666865284dff8fa39edb2267de70db",
"e15908673cda8a171ea31333538437460d9ca1d8ba2e61c31a9a3d01a8158c398a14cd12266e480f85cc1dc3239ed5cfa99f3d6955082446bebfe961449dc48b",
"6eb127925aa10d6d468630a0ca28ff5e1b8ad00db151fdcc4878362514d6ae865951b78cf5ef047cab42218e0d5a4020ad34821ca043c0f1febd27aaa87d5ed7",
"36595b50bf097cd19423c40ee66b117ed15fc5ec03d8676796bdf32bc8fe367d82517293a0f82362eb4f93d0de77af5724fba64cbcf55542328bc173dbe13d33");

protected static final VirtualMachine targetVM = VirtualMachine.FATE;

protected KeyPairService keyPairService;
Expand All @@ -77,12 +91,15 @@ public abstract class BaseTest {

protected KeyPair keyPair;

protected List<KeyPair> otherKeyPairs;

protected static String paymentSplitterSource,
ethereumSignaturesSource,
chatBotSource,
gaBlindAuthSource,
sophiaTypesSource,
ecdsaAuthSource;
ecdsaAuthSource,
statefulTest;

protected UnitConversionService unitConversionService = new DefaultUnitConversionServiceImpl();

Expand Down Expand Up @@ -110,6 +127,11 @@ public void setupTestEnv(TestContext context) throws ConfigurationException {

keyPair = keyPairService.recoverKeyPair(TestConstants.BENEFICIARY_PRIVATE_KEY);

otherKeyPairs =
testPrivateKeys.stream()
.map(key -> keyPairService.recoverKeyPair(key))
.collect(Collectors.toList());

aeternityService =
new AeternityServiceFactory()
.getService(
Expand Down Expand Up @@ -174,6 +196,7 @@ public static void startup() throws ConfigurationException, IOException {
gaBlindAuthSource = getContractSourceCode("GaBlindAuth.aes");
sophiaTypesSource = getContractSourceCode("SophiaTypes.aes");
ecdsaAuthSource = getContractSourceCode("ECDSAAuth.aes");
statefulTest = getContractSourceCode("StatefulTest.aes");
}

protected BigInteger getNextKeypairNonce() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.kryptokrauts.aeternity.test.integration;

import com.kryptokrauts.aeternity.sdk.domain.secret.KeyPair;
import com.kryptokrauts.aeternity.sdk.service.transaction.domain.ContractTxOptions;
import com.kryptokrauts.aeternity.sdk.service.transaction.domain.ContractTxResult;
import io.vertx.ext.unit.TestContext;
import org.junit.Test;

public class StatefulContractTest extends BaseTest {

@Test
public void testStatefulConvenienceMethodsWithDifferentCallers(TestContext context) {
this.executeTest(
context,
t -> {
ContractTxResult txResult =
aeternityService.transactions.blockingContractCreate(statefulTest);
_logger.info("Deployment result with default keypair: {}", txResult);
String contractIdDefaultKeyPair = txResult.getCallResult().getContractId();

Object lastCaller =
aeternityService.transactions.blockingReadOnlyContractCall(
contractIdDefaultKeyPair, "get_last_caller", statefulTest);
// expecting latest caller (contract creator) to be default keypair address
context.assertEquals(aeternityService.keyPairAddress, lastCaller);

KeyPair otherKeyPair = otherKeyPairs.get(0);
txResult =
aeternityService.transactions.blockingStatefulContractCall(
contractIdDefaultKeyPair,
"remember_caller",
statefulTest,
ContractTxOptions.builder().customKeyPair(otherKeyPair).build());
_logger.info("Call result with other keypair: {}", txResult);
lastCaller =
aeternityService.transactions.blockingReadOnlyContractCall(
contractIdDefaultKeyPair, "get_last_caller", statefulTest);
// expecting latest caller to be address of other keypair
context.assertEquals(otherKeyPair.getAddress(), lastCaller);

txResult =
aeternityService.transactions.blockingContractCreate(
statefulTest, ContractTxOptions.builder().customKeyPair(otherKeyPair).build());
_logger.info("Deployment result with other keypair: {}", txResult);
String contractIdOtherKeyPair = txResult.getCallResult().getContractId();

lastCaller =
aeternityService.transactions.blockingReadOnlyContractCall(
contractIdOtherKeyPair, "get_last_caller", statefulTest);
// expecting latest caller (contract creator) to be default keypair address
context.assertEquals(otherKeyPair.getAddress(), lastCaller);

txResult =
aeternityService.transactions.blockingStatefulContractCall(
contractIdOtherKeyPair, "remember_caller", statefulTest);
_logger.info("Call result with default keypair: {}", txResult);
lastCaller =
aeternityService.transactions.blockingReadOnlyContractCall(
contractIdOtherKeyPair, "get_last_caller", statefulTest);
// expecting latest caller to be address of default keypair
context.assertEquals(aeternityService.keyPairAddress, lastCaller);
});
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kryptokrauts.aeternity.sdk.service.transaction.domain;

import com.kryptokrauts.aeternity.sdk.domain.secret.KeyPair;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -38,4 +39,13 @@ public class ContractTxOptions {
* only needed if there are custom includes defined in the contract source
*/
private Map<String, String> filesystem;

/**
* by default the {@link com.kryptokrauts.aeternity.sdk.service.aeternity.impl.AeternityService}
* will use the KeyPair configured in the {@link
* com.kryptokrauts.aeternity.sdk.service.aeternity.AeternityServiceConfiguration}
*
* <p>if a custom KeyPair is provided, it will be used instead
*/
private KeyPair customKeyPair;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.kryptokrauts.aeternity.sdk.constants.SerializationTags;
import com.kryptokrauts.aeternity.sdk.domain.ObjectResultWrapper;
import com.kryptokrauts.aeternity.sdk.domain.StringResultWrapper;
import com.kryptokrauts.aeternity.sdk.domain.secret.KeyPair;
import com.kryptokrauts.aeternity.sdk.domain.sophia.SophiaTypeTransformer;
import com.kryptokrauts.aeternity.sdk.exception.AException;
import com.kryptokrauts.aeternity.sdk.exception.InvalidParameterException;
Expand Down Expand Up @@ -324,6 +325,10 @@ public ContractTxResult blockingContractCreate(String sourceCode, ContractTxOpti
if (sourceCode == null || txOptions == null) {
throw new InvalidParameterException("Arguments must not be null.");
}
KeyPair keyPair =
txOptions.getCustomKeyPair() != null
? txOptions.getCustomKeyPair()
: this.config.getKeyPair();
String entrypoint = "init";
String byteCode =
this.compilerService.blockingCompile(sourceCode, txOptions.getFilesystem()).getResult();
Expand All @@ -339,12 +344,12 @@ public ContractTxResult blockingContractCreate(String sourceCode, ContractTxOpti
nonce =
txOptions.getNonce() != null
? txOptions.getNonce()
: this.accountService.blockingGetNextNonce();
: this.accountService.blockingGetNextNonce(keyPair.getAddress());
ContractCreateTransactionModel contractCreateModel =
new ContractCreateTransactionModel(
byteCode,
callData,
this.config.getKeyPair().getAddress(),
keyPair.getAddress(),
txOptions.getAmount(),
nonce,
txOptions.getGasLimit(),
Expand Down Expand Up @@ -375,7 +380,7 @@ public ContractTxResult blockingContractCreate(String sourceCode, ContractTxOpti
contractCreateModel = contractCreateModel.toBuilder().gasLimit(gasLimitWithMargin).build();
}
PostTransactionResult contractCreatePostTxResult =
this.blockingPostTransaction(contractCreateModel);
this.blockingPostTransaction(contractCreateModel, keyPair.getEncodedPrivateKey());
if (contractCreatePostTxResult == null) {
throw new RuntimeException("Unexpected error: transaction not broadcasted.");
}
Expand Down Expand Up @@ -475,6 +480,10 @@ public ContractTxResult blockingStatefulContractCall(
if (contractId == null || entrypoint == null || sourceCode == null || txOptions == null) {
throw new InvalidParameterException("Arguments must not be null.");
}
KeyPair keyPair =
txOptions.getCustomKeyPair() != null
? txOptions.getCustomKeyPair()
: this.config.getKeyPair();
String calldata =
this.compilerService
.blockingEncodeCalldata(
Expand All @@ -487,12 +496,12 @@ public ContractTxResult blockingStatefulContractCall(
nonce =
txOptions.getNonce() != null
? txOptions.getNonce()
: this.accountService.blockingGetNextNonce();
: this.accountService.blockingGetNextNonce(keyPair.getAddress());
ContractCallTransactionModel contractCallModel =
new ContractCallTransactionModel(
contractId,
calldata,
this.config.getKeyPair().getAddress(),
keyPair.getAddress(),
txOptions.getAmount(),
nonce,
txOptions.getGasLimit(),
Expand Down Expand Up @@ -523,7 +532,7 @@ public ContractTxResult blockingStatefulContractCall(
contractCallModel = contractCallModel.toBuilder().gasLimit(gasLimitWithMargin).build();
}
PostTransactionResult contractCallPostTxResult =
this.blockingPostTransaction(contractCallModel);
this.blockingPostTransaction(contractCallModel, keyPair.getEncodedPrivateKey());
if (contractCallPostTxResult == null) {
throw new RuntimeException("Unexpected error: transaction not broadcasted.");
}
Expand Down
11 changes: 11 additions & 0 deletions src/test/resources/contracts/StatefulTest.aes
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
contract StatefulTest =

record state = { last_caller: address }

stateful entrypoint init() = { last_caller = Call.caller }

stateful entrypoint remember_caller() =
put(state{last_caller=Call.caller})

entrypoint get_last_caller() : address =
state.last_caller