From e02a80fdca2b6591742b7088330649f3b0fbedf2 Mon Sep 17 00:00:00 2001 From: Ben Guidarelli Date: Thu, 17 Nov 2022 12:01:08 -0500 Subject: [PATCH 1/6] Fix incorrect reference to global schema (#427) --- src/main/java/com/algorand/algosdk/transaction/Transaction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/algorand/algosdk/transaction/Transaction.java b/src/main/java/com/algorand/algosdk/transaction/Transaction.java index 9b514de53..518796dd6 100644 --- a/src/main/java/com/algorand/algosdk/transaction/Transaction.java +++ b/src/main/java/com/algorand/algosdk/transaction/Transaction.java @@ -948,7 +948,7 @@ public Transaction( if (foreignAssets != null) this.foreignAssets = foreignAssets; if (globalStateSchema != null) this.globalStateSchema = globalStateSchema; if (applicationId != null) this.applicationId = applicationId; - if (localStateSchema != null) this.localStateSchema = globalStateSchema; + if (localStateSchema != null) this.localStateSchema = localStateSchema; if (clearStateProgram != null) this.clearStateProgram = clearStateProgram; if (extraPages != null) this.extraPages = extraPages; } From b09779719133a58748a91a5761a8d7625589f48f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Nov 2022 17:10:38 -0500 Subject: [PATCH 2/6] REST API: Add KV counts to NodeStatusResponse (#428) --- .../v2/client/model/NodeStatusResponse.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/NodeStatusResponse.java b/src/main/java/com/algorand/algosdk/v2/client/model/NodeStatusResponse.java index 48fc8ef40..220edb6a1 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/NodeStatusResponse.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/NodeStatusResponse.java @@ -27,6 +27,13 @@ public class NodeStatusResponse extends PathResponse { @JsonProperty("catchpoint-processed-accounts") public Long catchpointProcessedAccounts; + /** + * The number of key-values (KVs) from the current catchpoint that have been + * processed so far as part of the catchup + */ + @JsonProperty("catchpoint-processed-kvs") + public Long catchpointProcessedKvs; + /** * The total number of accounts included in the current catchpoint */ @@ -40,6 +47,12 @@ public class NodeStatusResponse extends PathResponse { @JsonProperty("catchpoint-total-blocks") public Long catchpointTotalBlocks; + /** + * The total number of key-values (KVs) included in the current catchpoint + */ + @JsonProperty("catchpoint-total-kvs") + public Long catchpointTotalKvs; + /** * The number of accounts from the current catchpoint that have been verified so * far as part of the catchup @@ -47,6 +60,13 @@ public class NodeStatusResponse extends PathResponse { @JsonProperty("catchpoint-verified-accounts") public Long catchpointVerifiedAccounts; + /** + * The number of key-values (KVs) from the current catchpoint that have been + * verified so far as part of the catchup + */ + @JsonProperty("catchpoint-verified-kvs") + public Long catchpointVerifiedKvs; + /** * CatchupTime in nanoseconds */ @@ -113,9 +133,12 @@ public boolean equals(Object o) { if (!Objects.deepEquals(this.catchpoint, other.catchpoint)) return false; if (!Objects.deepEquals(this.catchpointAcquiredBlocks, other.catchpointAcquiredBlocks)) return false; if (!Objects.deepEquals(this.catchpointProcessedAccounts, other.catchpointProcessedAccounts)) return false; + if (!Objects.deepEquals(this.catchpointProcessedKvs, other.catchpointProcessedKvs)) return false; if (!Objects.deepEquals(this.catchpointTotalAccounts, other.catchpointTotalAccounts)) return false; if (!Objects.deepEquals(this.catchpointTotalBlocks, other.catchpointTotalBlocks)) return false; + if (!Objects.deepEquals(this.catchpointTotalKvs, other.catchpointTotalKvs)) return false; if (!Objects.deepEquals(this.catchpointVerifiedAccounts, other.catchpointVerifiedAccounts)) return false; + if (!Objects.deepEquals(this.catchpointVerifiedKvs, other.catchpointVerifiedKvs)) return false; if (!Objects.deepEquals(this.catchupTime, other.catchupTime)) return false; if (!Objects.deepEquals(this.lastCatchpoint, other.lastCatchpoint)) return false; if (!Objects.deepEquals(this.lastRound, other.lastRound)) return false; From aa01220832a9afc798240ecfc4469d4ffba2dd10 Mon Sep 17 00:00:00 2001 From: Hang Su <87964331+ahangsu@users.noreply.github.com> Date: Wed, 23 Nov 2022 17:45:47 -0500 Subject: [PATCH 3/6] Enhancement: Migrate v1 algod dependencies to v2 in cucumber tests (#425) --- .../algosdk/integration/Applications.java | 57 ++- .../integration/AtomicTxnComposer.java | 2 +- .../algorand/algosdk/integration/Clients.java | 24 -- .../algosdk/integration/Stepdefs.java | 364 +++++------------- .../algosdk/integration/TransientAccount.java | 10 +- 5 files changed, 127 insertions(+), 330 deletions(-) delete mode 100644 src/test/java/com/algorand/algosdk/integration/Clients.java diff --git a/src/test/java/com/algorand/algosdk/integration/Applications.java b/src/test/java/com/algorand/algosdk/integration/Applications.java index c862fcfe6..85d7758ee 100644 --- a/src/test/java/com/algorand/algosdk/integration/Applications.java +++ b/src/test/java/com/algorand/algosdk/integration/Applications.java @@ -15,16 +15,12 @@ import io.cucumber.java.en.Then; import org.apache.commons.lang3.StringUtils; import org.assertj.core.api.Assertions; -import org.assertj.core.util.Lists; -import org.bouncycastle.util.Strings; import org.junit.Assert; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -35,7 +31,6 @@ import static org.assertj.core.api.Assertions.assertThat; public class Applications { - public Clients clients; public Stepdefs base; public TransientAccount transientAccount; @@ -44,9 +39,8 @@ public class Applications { public Long appId = 0L; public List rememberedAppIds = new ArrayList<>(); - public Applications(TransientAccount transientAccount, Clients clients, Stepdefs base) { + public Applications(TransientAccount transientAccount, Stepdefs base) { this.transientAccount = transientAccount; - this.clients = clients; this.base = base; } @@ -58,24 +52,24 @@ public void buildAnApplicationTransactions(String operation, String approvalProg switch (operation) { case "create": builder = Transaction.ApplicationCreateTransactionBuilder() - .approvalProgram(loadTEALProgramFromFile(approvalProgramFile, this.clients.v2Client)) - .clearStateProgram(loadTEALProgramFromFile(clearProgramFile, this.clients.v2Client)) + .approvalProgram(loadTEALProgramFromFile(approvalProgramFile, this.base.aclv2)) + .clearStateProgram(loadTEALProgramFromFile(clearProgramFile, this.base.aclv2)) .globalStateSchema(new StateSchema(globalInts, globalBytes)) .localStateSchema(new StateSchema(localInts, localBytes)) .extraPages(extraPages); break; case "create_optin": builder = Transaction.ApplicationCreateTransactionBuilder() - .approvalProgram(loadTEALProgramFromFile(approvalProgramFile, this.clients.v2Client)) - .clearStateProgram(loadTEALProgramFromFile(clearProgramFile, this.clients.v2Client)) + .approvalProgram(loadTEALProgramFromFile(approvalProgramFile, this.base.aclv2)) + .clearStateProgram(loadTEALProgramFromFile(clearProgramFile, this.base.aclv2)) .globalStateSchema(new StateSchema(globalInts, globalBytes)) .localStateSchema(new StateSchema(localInts, localBytes)) .optIn(true); break; case "update": builder = Transaction.ApplicationUpdateTransactionBuilder() - .approvalProgram(loadTEALProgramFromFile(approvalProgramFile, this.clients.v2Client)) - .clearStateProgram(loadTEALProgramFromFile(clearProgramFile, this.clients.v2Client)); + .approvalProgram(loadTEALProgramFromFile(approvalProgramFile, this.base.aclv2)) + .clearStateProgram(loadTEALProgramFromFile(clearProgramFile, this.base.aclv2)); break; case "call": builder = Transaction.ApplicationCallTransactionBuilder(); @@ -115,7 +109,7 @@ public void buildAnApplicationTransactions(String operation, String approvalProg // Send with transient account, suggested params and current application builder.sender(this.transientAccount.transientAccount.getAddress()); - builder.lookupParams(this.clients.v2Client); + builder.lookupParams(this.base.aclv2); if (this.appId != 0 && !operation.equals("create")) { builder.applicationId(appId); } @@ -128,7 +122,7 @@ public void sendTransactionWithTransientAccountAndCheckForError(String error) th SignedTransaction stx = this.transientAccount.transientAccount.signTransaction(this.transaction); // Submit - Response rPost = clients.v2Client.RawTransaction().rawtxn(Encoder.encodeToMsgPack(stx)).execute(); + Response rPost = base.aclv2.RawTransaction().rawtxn(Encoder.encodeToMsgPack(stx)).execute(); // If an error was expected, make sure it is set correctly. if (StringUtils.isNotEmpty(error)) { @@ -142,18 +136,17 @@ public void sendTransactionWithTransientAccountAndCheckForError(String error) th // And save the txId for later this.txId = rPost.body().txId; + base.txid = this.txId; } @Given("I wait for the transaction to be confirmed.") public void waitForTransactionToBeConfirmed() throws Exception { - Utils.waitForConfirmation(clients.v2Client, txId, 1); + Utils.waitForConfirmation(base.aclv2, base.txid, 1); } - // TODO: Use V2 Pending Transaction endpoint when it is available. - // The initial implementation hacks into the v1 endpoint to manually extract the new data. @Given("I remember the new application ID.") public void rememberTheNewApplicatoinId() throws Exception { - PendingTransactionResponse r = clients.v2Client.PendingTransactionInformation(txId).execute().body(); + PendingTransactionResponse r = base.aclv2.PendingTransactionInformation(txId).execute().body(); this.appId = r.applicationIndex; this.rememberedAppIds.add(this.appId); } @@ -171,12 +164,12 @@ public void fundAppAccount(Integer amount) throws Exception { .sender(sender) .receiver(appAddress) .amount(amount) - .lookupParams(clients.v2Client) + .lookupParams(base.aclv2) .build(); SignedTransaction stx = base.signWithAddress(tx, sender); - Response rPost = clients.v2Client.RawTransaction().rawtxn(Encoder.encodeToMsgPack(stx)).execute(); - Utils.waitForConfirmation(clients.v2Client, rPost.body().txId, 1); + Response rPost = base.aclv2.RawTransaction().rawtxn(Encoder.encodeToMsgPack(stx)).execute(); + Utils.waitForConfirmation(base.aclv2, rPost.body().txId, 1); } @Then("I get the account address for the current application and see that it matches the app id's hash") @@ -198,7 +191,7 @@ public void checkAccountData( String hasKey, String keyValue ) throws Exception { - Response acctResponse = clients.v2Client.AccountInformation(transientAccount.transientAccount.getAddress()).execute(); + Response acctResponse = base.aclv2.AccountInformation(this.transientAccount.transientAccount.getAddress()).execute(); com.algorand.algosdk.v2.client.model.Account acct = acctResponse.body(); @@ -263,9 +256,9 @@ public void checkAccountData( public void contentsOfBoxShouldBe(String fromClient, String encodedBoxName, String boxContents, String errStr) throws Exception { Response boxResp; if (fromClient.equals("algod")) - boxResp = clients.v2Client.GetApplicationBoxByName(this.appId).name(encodedBoxName).execute(); + boxResp = base.aclv2.GetApplicationBoxByName(this.appId).name(encodedBoxName).execute(); else if (fromClient.equals("indexer")) - boxResp = clients.v2IndexerClient.lookupApplicationBoxByIDAndName(this.appId).name(encodedBoxName).execute(); + boxResp = base.v2IndexerClient.lookupApplicationBoxByIDAndName(this.appId).name(encodedBoxName).execute(); else throw new IllegalArgumentException("expecting algod or indexer, got " + fromClient); @@ -297,9 +290,9 @@ private static void assertSetOfByteArraysEqual(Set expected, Set public void checkAppBoxes(String fromClient, String encodedBoxesRaw) throws Exception { Response r; if (fromClient.equals("algod")) - r = clients.v2Client.GetApplicationBoxes(this.appId).execute(); + r = base.aclv2.GetApplicationBoxes(this.appId).execute(); else if (fromClient.equals("indexer")) - r = clients.v2IndexerClient.searchForApplicationBoxes(this.appId).execute(); + r = base.v2IndexerClient.searchForApplicationBoxes(this.appId).execute(); else throw new IllegalArgumentException("expecting algod or indexer, got " + fromClient); @@ -307,7 +300,7 @@ else if (fromClient.equals("indexer")) final Set expectedNames = new HashSet<>(); if (!encodedBoxesRaw.isEmpty()) { - for (String s : Strings.split(encodedBoxesRaw, ':')) { + for (String s : encodedBoxesRaw.split(":")) { expectedNames.add(Encoder.decodeFromBase64(s)); } } @@ -324,9 +317,9 @@ else if (fromClient.equals("indexer")) public void checkAppBoxesNum(String fromClient, Long limit, int expected_num) throws Exception { Response r; if (fromClient.equals("algod")) - r = clients.v2Client.GetApplicationBoxes(this.appId).max(limit).execute(); + r = base.aclv2.GetApplicationBoxes(this.appId).max(limit).execute(); else if (fromClient.equals("indexer")) - r = clients.v2IndexerClient.searchForApplicationBoxes(this.appId).limit(limit).execute(); + r = base.v2IndexerClient.searchForApplicationBoxes(this.appId).limit(limit).execute(); else throw new IllegalArgumentException("expecting algod or indexer, got " + fromClient); @@ -337,10 +330,10 @@ else if (fromClient.equals("indexer")) @Then("according to indexer, with {long} being the parameter that limits results, and {string} being the parameter that sets the next result, the current application should have the following boxes {string}.") public void indexerCheckAppBoxesWithParams(Long limit, String next, String encodedBoxesRaw) throws Exception { - Response r = clients.v2IndexerClient.searchForApplicationBoxes(this.appId).limit(limit).next(next).execute(); + Response r = base.v2IndexerClient.searchForApplicationBoxes(this.appId).limit(limit).next(next).execute(); final Set expectedNames = new HashSet<>(); if (!encodedBoxesRaw.isEmpty()) { - for (String s : Strings.split(encodedBoxesRaw, ':')) { + for (String s : encodedBoxesRaw.split(":")) { expectedNames.add(Encoder.decodeFromBase64(s)); } } diff --git a/src/test/java/com/algorand/algosdk/integration/AtomicTxnComposer.java b/src/test/java/com/algorand/algosdk/integration/AtomicTxnComposer.java index de904500a..fc4cf71be 100644 --- a/src/test/java/com/algorand/algosdk/integration/AtomicTxnComposer.java +++ b/src/test/java/com/algorand/algosdk/integration/AtomicTxnComposer.java @@ -47,7 +47,7 @@ public class AtomicTxnComposer { public AtomicTxnComposer(Stepdefs stepdefs, Applications apps, TransactionSteps steps) { base = stepdefs; applications = apps; - applications.transientAccount.clients.v2Client = base.aclv2; + applications.base.aclv2 = base.aclv2; applications.transientAccount.base = base; transSteps = steps; transSteps.transAcc = apps.transientAccount; diff --git a/src/test/java/com/algorand/algosdk/integration/Clients.java b/src/test/java/com/algorand/algosdk/integration/Clients.java deleted file mode 100644 index 562f9316f..000000000 --- a/src/test/java/com/algorand/algosdk/integration/Clients.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.algorand.algosdk.integration; - -import com.algorand.algosdk.v2.client.common.AlgodClient; -import com.algorand.algosdk.v2.client.common.IndexerClient; -import io.cucumber.java.en.Given; - -import java.util.HashMap; -import java.util.Map; - -public class Clients { - AlgodClient v2Client = null; - - IndexerClient v2IndexerClient = null; - - @Given("an algod v2 client connected to {string} port {int} with token {string}") - public void an_algod_v2_client_connected_to_port_with_token(String host, Integer port, String token) { - v2Client = new AlgodClient(host, port, token); - } - - @Given("an indexer v2 client") - public void indexer_v2_client() { - v2IndexerClient = new IndexerClient("localhost", 59999); - } -} diff --git a/src/test/java/com/algorand/algosdk/integration/Stepdefs.java b/src/test/java/com/algorand/algosdk/integration/Stepdefs.java index c84c1f8bc..2af3ba244 100644 --- a/src/test/java/com/algorand/algosdk/integration/Stepdefs.java +++ b/src/test/java/com/algorand/algosdk/integration/Stepdefs.java @@ -1,10 +1,6 @@ package com.algorand.algosdk.integration; import com.algorand.algosdk.account.Account; -import com.algorand.algosdk.algod.client.AlgodClient; -import com.algorand.algosdk.algod.client.ApiException; -import com.algorand.algosdk.algod.client.api.AlgodApi; -import com.algorand.algosdk.algod.client.model.*; import com.algorand.algosdk.auction.Bid; import com.algorand.algosdk.auction.SignedBid; import com.algorand.algosdk.builder.transaction.TransactionBuilder; @@ -18,11 +14,10 @@ import com.algorand.algosdk.util.AlgoConverter; import com.algorand.algosdk.util.Encoder; import com.algorand.algosdk.util.ResourceUtils; +import com.algorand.algosdk.v2.client.common.AlgodClient; +import com.algorand.algosdk.v2.client.common.IndexerClient; import com.algorand.algosdk.v2.client.common.Response; -import com.algorand.algosdk.v2.client.model.CompileResponse; -import com.algorand.algosdk.v2.client.model.DryrunResponse; -import com.algorand.algosdk.v2.client.model.DryrunRequest; -import com.algorand.algosdk.v2.client.model.DryrunSource; +import com.algorand.algosdk.v2.client.model.*; import com.fasterxml.jackson.core.JsonProcessingException; @@ -36,15 +31,12 @@ import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; import java.util.Arrays; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; import static com.algorand.algosdk.util.ResourceUtils.loadResource; import static org.assertj.core.api.Assertions.assertThat; @@ -55,7 +47,7 @@ public class Stepdefs { public static Integer algodPort = 60000; public static Integer kmdPort = 60001; - TransactionParams params; + TransactionParametersResponse params; SignedTransaction stx; SignedTransaction[] stxs; byte[] stxBytes; @@ -76,19 +68,15 @@ public class Stepdefs { String gen; byte[] note; MultisigAddress msig; - MultisigSignature msigsig; String walletName; String walletPswd; String walletID; - AlgodApi acl; - AlgodClient algodClient; KmdApi kcl; KmdClient kmdClient; com.algorand.algosdk.v2.client.common.AlgodClient aclv2; + IndexerClient v2IndexerClient; String handle; List versions; - NodeStatus status; - NodeStatus statusAfter; List pks; List addresses; BigInteger lastRound; @@ -100,14 +88,12 @@ public class Stepdefs { Bid bid; SignedBid oldBid; SignedBid sbid; - BigInteger paramsFee; ParticipationPublicKey votepk; VRFPublicKey vrfpk; String sprfpk; BigInteger votefst; BigInteger votelst; BigInteger votekd; - String num; /* Assets */ String creator = ""; @@ -115,37 +101,12 @@ public class Stepdefs { String assetName = "testcoin"; String assetUnitName = "coins"; com.algorand.algosdk.transaction.AssetParams expectedParams = null; - AssetParams queriedParams = new AssetParams(); + Asset queriedParams = new Asset(); /* Compile / Dryrun */ Response compileResponse; Response dryrunResponse; - private static class DevModeState { - static final long ACCOUNT_FUNDING_MICROALGOS = 100_000_000; - private Account advanceRounds; - - /** - * randomAmount minimizes the chance `advanceRounds` issues duplicate transactions by randomizing the payment amount. - */ - private long randomAmount() { - return ThreadLocalRandom.current().nextLong(1, (long) (ACCOUNT_FUNDING_MICROALGOS * .01)); - } - - public SignedTransaction selfPay(TransactionParams tp) throws Exception { - Transaction tx = - Transaction.PaymentTransactionBuilder() - .sender(advanceRounds.getAddress()) - .suggestedParams(tp) - .amount(randomAmount()) - .receiver(advanceRounds.getAddress()) - .build(); - return advanceRounds.signTransaction(tx); - } - } - - private final DevModeState dms = new DevModeState(); - protected Address getAddress(int i) { if (addresses == null) { throw new RuntimeException("Addresses not initialized, must use given 'wallet information'"); @@ -166,8 +127,8 @@ protected Address getAddress(int i) { */ protected void getParams() { try { - params = acl.transactionParams(); - lastRound = params.getLastRound(); + params = aclv2.TransactionParams().execute().body(); + lastRound = BigInteger.valueOf(params.lastRound); } catch (Exception e) { throw new RuntimeException(e); } @@ -186,60 +147,6 @@ public SignedTransaction signWithAddress(Transaction tx, Address addr) throws co return acct.signTransaction(tx); } - /** - * advanceRound is a convenience method intended for testing with DevMode networks. - *

- * Since DevMode block generation requires a transaction rather than time passing, test assertions may require advancing rounds. advanceRound issues advanceCount payments to advance rounds. - */ - private void advanceRoundsV1(int advanceCount) { - initializeDevModeAccount(); - for (int i = 0; i < advanceCount; i++) { - try { - acl.rawTransaction(Encoder.encodeToMsgPack(dms.selfPay(acl.transactionParams()))); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } - - /** - * initializeDevModeAccount performs a one-time account initialization per inclusion in a scenario outline. No attempt is made to delete the account. - */ - public void initializeDevModeAccount() { - if (dms.advanceRounds != null) { - return; - } - - try { - getParams(); - dms.advanceRounds = new Account(); - Address sender = getAddress(0); - Transaction tx = - Transaction.PaymentTransactionBuilder() - .sender(sender) - .suggestedParams(acl.transactionParams()) - .amount(DevModeState.ACCOUNT_FUNDING_MICROALGOS) - .receiver(dms.advanceRounds.getAddress()) - .build(); - SignedTransaction st = signWithAddress(tx, sender); - acl.rawTransaction(Encoder.encodeToMsgPack(st)); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Convenience method to export a key and initialize an account to use for signing. - */ - public void exportKeyAndSetAccount(Address addr) throws com.algorand.algosdk.kmd.client.ApiException, NoSuchAlgorithmException { - ExportKeyRequest req = new ExportKeyRequest(); - req.setAddress(addr.toString()); - req.setWalletHandleToken(handle); - req.setWalletPassword(walletPswd); - sk = kcl.exportKey(req).getPrivateKey(); - account = new Account(Arrays.copyOfRange(sk, 0, 32)); - } - @When("I create a wallet") public void createWallet() throws com.algorand.algosdk.kmd.client.ApiException { walletName = "Walletjava"; @@ -256,8 +163,9 @@ public void walletExist() throws com.algorand.algosdk.kmd.client.ApiException{ boolean exists = false; APIV1GETWalletsResponse resp = kcl.listWallets(); for (APIV1Wallet w : resp.getWallets()){ - if (w.getName().equals(walletName)){ + if (w.getName().equals(walletName)) { exists = true; + break; } } assertThat(exists).isTrue(); @@ -314,7 +222,7 @@ public void releaseHandle() throws com.algorand.algosdk.kmd.client.ApiException{ } @Then("the wallet handle should not work") - public void tryHandle() throws com.algorand.algosdk.kmd.client.ApiException{ + public void tryHandle() { RenewWalletHandleTokenRequest req = new RenewWalletHandleTokenRequest(); req.setWalletHandleToken(handle); err = false; @@ -327,7 +235,7 @@ public void tryHandle() throws com.algorand.algosdk.kmd.client.ApiException{ } @Given("payment transaction parameters {int} {int} {int} {string} {string} {string} {int} {string} {string}") - public void transactionParameters(int fee, int fv, int lv, String gh, String to, String close, int amt, String gen, String note) throws GeneralSecurityException, NoSuchAlgorithmException{ + public void transactionParameters(int fee, int fv, int lv, String gh, String to, String close, int amt, String gen, String note) throws GeneralSecurityException { this.fee = BigInteger.valueOf(fee); this.fv = BigInteger.valueOf(fv); this.lv = BigInteger.valueOf(lv); @@ -352,7 +260,7 @@ public void mn_for_sk(String mn) throws GeneralSecurityException{ } @Given("default V2 key registration transaction {string}") - public void default_v2_key_registration_transaction(String type) throws NoSuchAlgorithmException, JsonProcessingException, IOException{ + public void default_v2_key_registration_transaction(String type) { getParams(); votepk=new ParticipationPublicKey(Encoder.decodeFromBase64("9mr13Ri8rFepxN3ghIUrZNui6LqqM5hEzB45Rri5lkU=")); vrfpk = new VRFPublicKey(Encoder.decodeFromBase64("dx717L3uOIIb/jr9OIyls1l5Ei00NFgRa380w7TnPr4=")); @@ -444,8 +352,8 @@ public void equalMsigAddrGolden(String golden){ } @When("I get versions with algod") - public void aclV() throws ApiException{ - versions = acl.getVersion().getVersions(); + public void aclV() throws Exception { + versions = aclv2.GetVersion().execute().body().versions; } @Then("v1 should be in the versions") @@ -453,27 +361,16 @@ public void v1InVersions(){ assertThat(versions).contains("v1"); } + @Then("v2 should be in the versions") + public void v2InVersions(){ + assertThat(versions).contains("v2"); + } + @When("I get versions with kmd") public void kclV() throws com.algorand.algosdk.kmd.client.ApiException{ versions = kcl.getVersion().getVersions(); } - @When("I get the status") - public void status() throws ApiException{ - status = acl.getStatus(); - } - - @When("I get status after this block") - public void statusBlock() throws Exception { - advanceRoundsV1(1); - statusAfter = acl.waitForBlock(status.getLastRound()); - } - - @Then("I can get the block info") - public void block() throws ApiException{ - acl.getBlock(status.getLastRound().add(BigInteger.valueOf(1))); - } - @When("I import the multisig") public void importMsig() throws com.algorand.algosdk.kmd.client.ApiException{ ImportMultisigRequest req = new ImportMultisigRequest(); @@ -564,12 +461,12 @@ public void genKeyKmdRekey() throws com.algorand.algosdk.kmd.client.ApiException Transaction tx = Transaction.PaymentTransactionBuilder() .sender(sender) - .suggestedParams(acl.transactionParams()) + .suggestedParams(params) .amount(100_000_000) .receiver(rekey) .build(); SignedTransaction st = signWithAddress(tx, sender); - acl.rawTransaction(Encoder.encodeToMsgPack(st)); + aclv2.RawTransaction().rawtxn(Encoder.encodeToMsgPack(st)).execute(); } catch (Exception e) { throw new RuntimeException(e); } @@ -615,7 +512,7 @@ public void keyNotInWallet() throws com.algorand.algosdk.kmd.client.ApiException } @When("I generate a key") - public void genKey()throws NoSuchAlgorithmException, GeneralSecurityException{ + public void genKey()throws GeneralSecurityException{ account = new Account(); pk = account.getAddress(); address = pk.toString(); @@ -656,7 +553,7 @@ public void expSkEq() throws com.algorand.algosdk.kmd.client.ApiException { } @Given("a kmd client") - public void kClient() throws FileNotFoundException, IOException, NoSuchAlgorithmException{ + public void kClient() { kmdClient = new KmdClient(); kmdClient.setConnectTimeout(30000); kmdClient.setReadTimeout(30000); @@ -666,26 +563,25 @@ public void kClient() throws FileNotFoundException, IOException, NoSuchAlgorithm kcl = new KmdApi(kmdClient); } - @Given("an algod client") - public void aClient() throws FileNotFoundException, IOException{ - algodClient = new AlgodClient(); - algodClient.setConnectTimeout(30000); - algodClient.setReadTimeout(30000); - algodClient.setWriteTimeout(30000); - algodClient.setApiKey(token); - algodClient.setBasePath("http://localhost:" + algodPort); - acl = new AlgodApi(algodClient); - } - @Given("an algod v2 client") - public void aClientv2() throws FileNotFoundException, IOException{ + public void aClientv2() { aclv2 = new com.algorand.algosdk.v2.client.common.AlgodClient( "http://localhost", algodPort, token ); } + @Given("an algod v2 client connected to {string} port {int} with token {string}") + public void an_algod_v2_client_connected_to_port_with_token(String host, Integer port, String token) { + aclv2 = new AlgodClient(host, port, token); + } + + @Given("an indexer v2 client") + public void indexer_v2_client() { + v2IndexerClient = new IndexerClient("localhost", 59999); + } + @Given("wallet information") - public void walletInfo() throws com.algorand.algosdk.kmd.client.ApiException, NoSuchAlgorithmException{ + public void walletInfo() throws com.algorand.algosdk.kmd.client.ApiException { walletName = "unencrypted-default-wallet"; walletPswd = ""; List wallets = kcl.listWallets().getWallets(); @@ -705,7 +601,7 @@ public void walletInfo() throws com.algorand.algosdk.kmd.client.ApiException, No } @Given("default transaction with parameters {int} {string}") - public void defaultTxn(int amt, String note) throws ApiException, NoSuchAlgorithmException { + public void defaultTxn(int amt, String note) { defaultTxnWithAddress(amt, note, getAddress(0)); } @@ -732,7 +628,7 @@ private void defaultTxnWithAddress(int amt, String note, Address sender) { } @Given("default multisig transaction with parameters {int} {string}") - public void defaultMsigTxn(int amt, String note) throws ApiException, NoSuchAlgorithmException{ + public void defaultMsigTxn(int amt, String note) { getParams(); if (note.equals("none")){ this.note = null; @@ -755,37 +651,13 @@ public void defaultMsigTxn(int amt, String note) throws ApiException, NoSuchAlgo } @When("I send the transaction") - public void sendTxn() throws JsonProcessingException, ApiException{ - txid = acl.rawTransaction(Encoder.encodeToMsgPack(stx)).getTxId(); + public void sendTxn() throws Exception { + txid = aclv2.RawTransaction().rawtxn(Encoder.encodeToMsgPack(stx)).execute().body().txId; } @When("I send the multisig transaction") - public void sendMsigTxn() throws JsonProcessingException, ApiException{ - try{ - acl.rawTransaction(Encoder.encodeToMsgPack(stx)); - } catch(Exception e) { - err = true; - } - } - - // TODO: this needs to be modified/removed when v1 is no longer supported!!! - @Then("the transaction should go through") - public void checkTxn() throws Exception { - String ans = acl.pendingTransactionInformation(txid).getFrom(); - assertThat(this.txn.sender.toString()).isEqualTo(ans); - waitForAlgodTransactionProcessingToComplete(); - String senderFromResponse = acl.transactionInformation(txn.sender.toString(), txid).getFrom(); - assertThat(senderFromResponse).isEqualTo(txn.sender.toString()); - // assertThat(acl.transaction(txid).getFrom()).isEqualTo(senderFromResponse); - } - - /** - * waitForAlgodTransactionProcessingToComplete is a Dev mode helper method that's a rough analog to `acl.waitForBlock(lastRound.add(BigInteger.valueOf(2)));`. - *

- * Since Dev mode produces blocks on a per transaction basis, it's possible algod generates a block _before_ the corresponding SDK call to wait for a block. Without _any_ wait, it's possible the SDK looks for the transaction before algod completes processing. So, the method performs a local sleep to simulate waiting for a block. - */ - private static void waitForAlgodTransactionProcessingToComplete() throws Exception { - Thread.sleep(500); + public void sendMsigTxn() throws Exception { + err = !aclv2.RawTransaction().rawtxn(Encoder.encodeToMsgPack(stx)).execute().isSuccessful(); } @Then("the transaction should not go through") @@ -794,7 +666,7 @@ public void txnFail() { } @When("I sign the transaction with kmd") - public void signKmd() throws JsonProcessingException, com.algorand.algosdk.kmd.client.ApiException, NoSuchAlgorithmException{ + public void signKmd() throws JsonProcessingException, com.algorand.algosdk.kmd.client.ApiException { SignTransactionRequest req = new SignTransactionRequest(); req.setTransaction(Encoder.encodeToMsgPack(txn)); req.setWalletHandleToken(handle); @@ -807,7 +679,7 @@ public void signBothEqual() throws JsonProcessingException { } @When("I sign the multisig transaction with kmd") - public void signMsigKmd() throws JsonProcessingException, com.algorand.algosdk.kmd.client.ApiException, IOException{ + public void signMsigKmd() throws com.algorand.algosdk.kmd.client.ApiException, IOException{ ImportMultisigRequest importReq = new ImportMultisigRequest(); importReq.setMultisigVersion(msig.version); importReq.setThreshold(msig.threshold); @@ -834,42 +706,13 @@ public void signMsigBothEqual() throws JsonProcessingException, com.algorand.alg } @Then("the node should be healthy") - public void nodeHealth() throws ApiException{ - acl.healthCheck(); + public void nodeHealth() throws Exception { + aclv2.HealthCheck().execute(); } @Then("I get the ledger supply") - public void getLedger() throws ApiException{ - acl.getSupply(); - } - - @Then("I get transactions by address and round") - public void txnsByAddrRound() throws ApiException{ - assertThat(acl.transactions(addresses.get(0), BigInteger.valueOf(1), acl.getStatus().getLastRound(), null, null, BigInteger.valueOf(10)).getTransactions()) - .isInstanceOf(List.class); - //Assert.assertTrue(acl.transactions(addresses.get(0), BigInteger.valueOf(1), acl.getStatus().getLastRound(), null, null, BigInteger.valueOf(10)).getTransactions() instanceof List); - } - - @Then("I get pending transactions") - public void pendingTxns() throws ApiException{ - assertThat(acl.getPendingTransactions(BigInteger.valueOf(10)).getTruncatedTxns()) - .isInstanceOf(TransactionList.class); - //Assert.assertTrue(acl.getPendingTransactions(BigInteger.valueOf(10)).getTruncatedTxns() instanceof TransactionList); - } - - @When("I get the suggested params") - public void suggestedParams() throws ApiException{ - paramsFee = acl.transactionParams().getFee(); - } - - @When("I get the suggested fee") - public void suggestedFee() throws ApiException { - fee = acl.suggestedFee().getFee(); - } - - @Then("the fee in the suggested params should equal the suggested fee") - public void checkSuggested() { - assertThat(paramsFee).isEqualTo(fee); + public void getLedger() throws Exception { + aclv2.GetSupply().execute(); } @When("I create a bid") @@ -933,7 +776,7 @@ public void mdkToMn() { } @When("I create the flat fee payment transaction") - public void createPaytxnFlat() throws NoSuchAlgorithmException{ + public void createPaytxnFlat() { txn = Transaction.PaymentTransactionBuilder() .sender(pk) .flatFee(fee) @@ -989,14 +832,9 @@ public void checkMicro(long ma) { assertThat(microalgos).isEqualTo(BigInteger.valueOf(ma)); } - @Then("I get account information") - public void accInfo() throws ApiException { - acl.accountInformation(addresses.get(0)); - } - @Then("I can get account information") - public void newAccInfo() throws ApiException, NoSuchAlgorithmException, com.algorand.algosdk.kmd.client.ApiException { - acl.accountInformation(pk.encodeAsString()); + public void newAccInfo() throws Exception { + aclv2.AccountInformation(pk).execute(); DeleteKeyRequest req = new DeleteKeyRequest(); req.setAddress(pk.encodeAsString()); req.setWalletHandleToken(handle); @@ -1010,7 +848,7 @@ public void asset_test_fixture() { } @Given("default asset creation transaction with total issuance {int}") - public void default_asset_creation_transaction_with_total_issuance(Integer assetTotal) throws NoSuchAlgorithmException, ApiException, InvalidKeySpecException { + public void default_asset_creation_transaction_with_total_issuance(Integer assetTotal) { getParams(); Transaction tx = Transaction.AssetCreateTransactionBuilder() @@ -1033,21 +871,25 @@ public void default_asset_creation_transaction_with_total_issuance(Integer asset } @When("I get the asset info") - public void i_get_the_asset_info() throws ApiException { - this.queriedParams = acl.assetInformation(this.assetID); + public void i_get_the_asset_info() throws Exception { + this.queriedParams = aclv2.GetAssetByID(this.assetID.longValue()).execute().body(); + } + + static private String null_to_empty(String str) { + return str == null ? "" : str; } @Then("the asset info should match the expected asset info") - public void the_asset_info_should_match_the_expected_asset_info() throws JsonProcessingException, NoSuchAlgorithmException { + public void the_asset_info_should_match_the_expected_asset_info() { // Can't use a regular assertj call because 'compareTo' isn't a regular comparator. - assertThat(this.expectedParams.assetManager.compareTo(this.queriedParams.getManagerkey())).isTrue(); - assertThat(this.expectedParams.assetReserve.compareTo(this.queriedParams.getReserveaddr())).isTrue(); - assertThat(this.expectedParams.assetFreeze.compareTo(this.queriedParams.getFreezeaddr())).isTrue(); - assertThat(this.expectedParams.assetClawback.compareTo(this.queriedParams.getClawbackaddr())).isTrue(); + assertThat(this.expectedParams.assetManager.compareTo(null_to_empty(this.queriedParams.params.manager))).isTrue(); + assertThat(this.expectedParams.assetReserve.compareTo(null_to_empty(this.queriedParams.params.reserve))).isTrue(); + assertThat(this.expectedParams.assetFreeze.compareTo(null_to_empty(this.queriedParams.params.freeze))).isTrue(); + assertThat(this.expectedParams.assetClawback.compareTo(null_to_empty(this.queriedParams.params.clawback))).isTrue(); } @When("I create a no-managers asset reconfigure transaction") - public void i_create_a_no_managers_asset_reconfigure_transaction() throws NoSuchAlgorithmException, ApiException, InvalidKeySpecException { + public void i_create_a_no_managers_asset_reconfigure_transaction() { getParams(); Transaction tx = Transaction.AssetConfigureTransactionBuilder() @@ -1063,7 +905,7 @@ public void i_create_a_no_managers_asset_reconfigure_transaction() throws NoSuch } @When("I create an asset destroy transaction") - public void i_create_an_asset_destroy_transaction() throws NoSuchAlgorithmException, ApiException, InvalidKeySpecException { + public void i_create_an_asset_destroy_transaction() { getParams(); Transaction tx = Transaction.AssetDestroyTransactionBuilder() @@ -1077,21 +919,16 @@ public void i_create_an_asset_destroy_transaction() throws NoSuchAlgorithmExcept } @Then("I should be unable to get the asset info") - public void i_should_be_unable_to_get_the_asset_info() { - boolean exists = true; - try { - this.i_get_the_asset_info(); - } catch (ApiException e) { - exists = false; - } - assertThat(exists).isFalse(); + public void i_should_be_unable_to_get_the_asset_info() throws Exception { + this.i_get_the_asset_info(); + assertThat(queriedParams).isNull(); } @When("I create a transaction transferring {int} assets from creator to a second account") - public void i_create_a_transaction_transferring_assets_from_creator_to_a_second_account(Integer int1) throws NoSuchAlgorithmException, ApiException, InvalidKeySpecException { + public void i_create_a_transaction_transferring_assets_from_creator_to_a_second_account(Integer int1) { getParams(); - Transaction tx = Transaction.AssetTransferTransactionBuilder() + this.txn = Transaction.AssetTransferTransactionBuilder() .sender(this.creator) .assetReceiver(getAddress(1)) .assetAmount(int1) @@ -1099,59 +936,58 @@ public void i_create_a_transaction_transferring_assets_from_creator_to_a_second_ .note(this.note) .assetIndex(this.assetID) .build(); - this.txn = tx; this.pk = getAddress(0); } @Then("the creator should have {int} assets remaining") - public void the_creator_should_have_assets_remaining(Integer expectedBal) throws ApiException { - com.algorand.algosdk.algod.client.model.Account accountResp = - this.acl.accountInformation(this.creator); - AssetHolding holding = accountResp.getHolding(this.assetID); - assertThat(holding.getAmount()).isEqualTo(BigInteger.valueOf(expectedBal)); + public void the_creator_should_have_assets_remaining(Integer expectedBal) throws Exception { + AccountAssetResponse holding = aclv2.AccountAssetInformation(new Address(this.creator), this.assetID.longValue()).execute().body(); + assertThat(holding.assetHolding.amount).isEqualTo(BigInteger.valueOf(expectedBal)); } @Then("I update the asset index") - public void i_update_the_asset_index() throws ApiException { - com.algorand.algosdk.algod.client.model.Account accountResp = acl.accountInformation(this.creator); - Set keys = accountResp.getThisassettotal().keySet(); - this.assetID = Collections.max(keys); + public void i_update_the_asset_index() throws Exception { + List assets = aclv2.AccountInformation(new Address(this.creator)).execute().body().createdAssets; + List assetIDs = new ArrayList<>(); + for (Asset a: assets) { + assetIDs.add(BigInteger.valueOf(a.index)); + } + this.assetID = Collections.max(assetIDs); } @When("I send the bogus kmd-signed transaction") public void i_send_the_bogus_kmd_signed_transaction() { try { - txid = acl.rawTransaction(this.stxBytes).getTxId(); - } catch (ApiException e) { + txid = aclv2.RawTransaction().rawtxn(this.stxBytes).execute().body().txId; + } catch (Exception e) { this.err = true; } } @Then("I create a transaction for a second account, signalling asset acceptance") - public void i_create_a_transaction_for_a_second_account_signalling_asset_acceptance() throws ApiException, NoSuchAlgorithmException { + public void i_create_a_transaction_for_a_second_account_signalling_asset_acceptance() { getParams(); - Transaction tx = Transaction.AssetAcceptTransactionBuilder() + this.txn = Transaction.AssetAcceptTransactionBuilder() .acceptingAccount(getAddress(1)) .suggestedParams(this.params) .note(this.note) .assetIndex(this.assetID) .build(); - this.txn = tx; this.pk = getAddress(1); } @Then("I send the kmd-signed transaction") - public void i_send_the_kmd_signed_transaction() throws ApiException { - txid = acl.rawTransaction(this.stxBytes).getTxId(); + public void i_send_the_kmd_signed_transaction() throws Exception { + txid = aclv2.RawTransaction().rawtxn(this.stxBytes).execute().body().txId; } @When("I create a freeze transaction targeting the second account") - public void i_create_a_freeze_transaction_targeting_the_second_account() throws NoSuchAlgorithmException, ApiException, com.algorand.algosdk.kmd.client.ApiException { + public void i_create_a_freeze_transaction_targeting_the_second_account() throws com.algorand.algosdk.kmd.client.ApiException { this.renewHandle(); // to avoid handle expired error getParams(); - Transaction tx = Transaction.AssetFreezeTransactionBuilder() + this.txn = Transaction.AssetFreezeTransactionBuilder() .sender(getAddress(0)) .freezeTarget(getAddress(1)) .freezeState(true) @@ -1159,15 +995,14 @@ public void i_create_a_freeze_transaction_targeting_the_second_account() throws .note(this.note) .suggestedParams(this.params) .build(); - this.txn = tx; this.pk = getAddress(0); } @When("I create a transaction transferring {int} assets from a second account to creator") - public void i_create_a_transaction_transferring_assets_from_a_second_account_to_creator(Integer int1) throws ApiException, NoSuchAlgorithmException { + public void i_create_a_transaction_transferring_assets_from_a_second_account_to_creator(Integer int1) { getParams(); - Transaction tx = Transaction.AssetTransferTransactionBuilder() + this.txn = Transaction.AssetTransferTransactionBuilder() .sender(getAddress(1)) .assetReceiver(this.creator) .assetAmount(int1) @@ -1175,16 +1010,15 @@ public void i_create_a_transaction_transferring_assets_from_a_second_account_to_ .assetIndex(this.assetID) .suggestedParams(this.params) .build(); - this.txn = tx; this.pk = getAddress(1); } @When("I create an un-freeze transaction targeting the second account") - public void i_create_an_un_freeze_transaction_targeting_the_second_account() throws ApiException, NoSuchAlgorithmException, com.algorand.algosdk.kmd.client.ApiException { + public void i_create_an_un_freeze_transaction_targeting_the_second_account() throws com.algorand.algosdk.kmd.client.ApiException { this.renewHandle(); // to avoid handle expired error getParams(); - Transaction tx = Transaction.AssetFreezeTransactionBuilder() + this.txn = Transaction.AssetFreezeTransactionBuilder() .sender(getAddress(0)) .freezeTarget(getAddress(1)) .freezeState(false) @@ -1192,12 +1026,11 @@ public void i_create_an_un_freeze_transaction_targeting_the_second_account() thr .note(this.note) .suggestedParams(this.params) .build(); - this.txn = tx; this.pk = getAddress(0); } @Given("default-frozen asset creation transaction with total issuance {int}") - public void default_frozen_asset_creation_transaction_with_total_issuance(Integer int1) throws ApiException, NoSuchAlgorithmException { + public void default_frozen_asset_creation_transaction_with_total_issuance(Integer int1) throws NoSuchAlgorithmException { getParams(); Transaction tx = Transaction.AssetCreateTransactionBuilder() @@ -1221,10 +1054,10 @@ public void default_frozen_asset_creation_transaction_with_total_issuance(Intege } @When("I create a transaction revoking {int} assets from a second account to creator") - public void i_create_a_transaction_revoking_assets_from_a_second_account_to_creator(Integer int1) throws ApiException, NoSuchAlgorithmException { + public void i_create_a_transaction_revoking_assets_from_a_second_account_to_creator(Integer int1) { getParams(); - Transaction tx = Transaction.AssetClawbackTransactionBuilder() + this.txn = Transaction.AssetClawbackTransactionBuilder() .sender(getAddress(0)) .assetClawbackFrom(getAddress(1)) .assetReceiver(getAddress(0)) @@ -1233,7 +1066,6 @@ public void i_create_a_transaction_revoking_assets_from_a_second_account_to_crea .note(this.note) .suggestedParams(this.params) .build(); - this.txn = tx; this.pk = getAddress(0); } @@ -1301,7 +1133,7 @@ public void i_dryrun_a_program(String kind, String path) throws Exception { DryrunSource drs = new DryrunSource(); drs.fieldName = "lsig"; drs.source = new String(data); - drs.txnIndex = 0l; + drs.txnIndex = 0L; sources.add(drs); SignedTransaction stxn = new SignedTransaction(txn, new Signature()); stxns.add(stxn); @@ -1316,7 +1148,7 @@ public void i_dryrun_a_program(String kind, String path) throws Exception { } @When("I get execution result {string}") - public void i_get_execution_result(String result) throws Exception { + public void i_get_execution_result(String result) { DryrunResponse ddr = dryrunResponse.body(); assertThat(ddr).isNotNull(); assertThat(ddr.txns).isNotNull(); @@ -1331,14 +1163,12 @@ public void i_get_execution_result(String result) throws Exception { assertThat(msgs.get(msgs.size() - 1)).isEqualTo(result); } - @When("I compile a teal program {string} with mapping enabled") public void i_compile_a_teal_program_with_mapping_enabled(String tealPath) throws Exception { byte[] tealProgram = ResourceUtils.loadResource(tealPath); this.compileResponse = aclv2.TealCompile().source(tealProgram).sourcemap(true).execute(); } - @Then("the resulting source map is the same as the json {string}") public void the_resulting_source_map_is_the_same_as_the_json(String jsonPath) throws Exception { String[] fields = {"version", "sources", "names", "mapping", "mappings"}; diff --git a/src/test/java/com/algorand/algosdk/integration/TransientAccount.java b/src/test/java/com/algorand/algosdk/integration/TransientAccount.java index a571e617b..8e223014e 100644 --- a/src/test/java/com/algorand/algosdk/integration/TransientAccount.java +++ b/src/test/java/com/algorand/algosdk/integration/TransientAccount.java @@ -11,13 +11,11 @@ import io.cucumber.java.en.Given; public class TransientAccount { - public Clients clients; public Stepdefs base; public Account transientAccount = null; - public TransientAccount(Clients clients, Stepdefs base) { - this.clients = clients; + public TransientAccount(Stepdefs base) { this.base = base; } @@ -33,12 +31,12 @@ public void createAndFundTransientAccount(Long amount) throws Exception { .sender(sender) .receiver(this.transientAccount.getAddress()) .amount(amount) - .lookupParams(clients.v2Client) + .lookupParams(base.aclv2) .build(); SignedTransaction stx = base.signWithAddress(tx, sender); - Response rPost = clients.v2Client.RawTransaction().rawtxn(Encoder.encodeToMsgPack(stx)).execute(); - Utils.waitForConfirmation(clients.v2Client, rPost.body().txId, 1); + Response rPost = base.aclv2.RawTransaction().rawtxn(Encoder.encodeToMsgPack(stx)).execute(); + Utils.waitForConfirmation(base.aclv2, rPost.body().txId, 1); } } From d4ebc3270f927c4cdc53b8fe4eaaf9e16b06928e Mon Sep 17 00:00:00 2001 From: Hang Su <87964331+ahangsu@users.noreply.github.com> Date: Tue, 29 Nov 2022 11:36:32 -0500 Subject: [PATCH 4/6] Bug-Fix: parsing type strings for tuples containing static arrays of tuples (#431) --- .../com/algorand/algosdk/abi/ABIType.java | 11 ++++- .../com/algorand/algosdk/abi/TestTypes.java | 48 +++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/algorand/algosdk/abi/ABIType.java b/src/main/java/com/algorand/algosdk/abi/ABIType.java index 8f1c24161..62d0eabb8 100644 --- a/src/main/java/com/algorand/algosdk/abi/ABIType.java +++ b/src/main/java/com/algorand/algosdk/abi/ABIType.java @@ -103,7 +103,7 @@ public static List parseTupleContent(String str) { return new ArrayList<>(); if (str.startsWith(",") || str.endsWith(",")) - throw new IllegalArgumentException("parsing error: tuple content should not start with comma"); + throw new IllegalArgumentException("parsing error: tuple content should not start or end with comma"); if (str.contains(",,")) throw new IllegalArgumentException("parsing error: tuple content should not have consecutive commas"); @@ -118,8 +118,15 @@ else if (str.charAt(i) == ')') { if (parenStack.isEmpty()) throw new IllegalArgumentException("parsing error: tuple parentheses are not balanced: " + str); int leftParenIndex = parenStack.pop(); - if (parenStack.isEmpty()) + if (parenStack.isEmpty()) { + // iterate through the byte str, include all the bytes after closing round bracket, for array indicator + // increase the index until it meets comma, or end of string + int forwardIndex = i + 1; + while (forwardIndex < str.length() && str.charAt(forwardIndex) != ',') + forwardIndex++; + i = forwardIndex - 1; parenSegments.add(new Segment(leftParenIndex, i)); + } } } if (!parenStack.isEmpty()) diff --git a/src/test/java/com/algorand/algosdk/abi/TestTypes.java b/src/test/java/com/algorand/algosdk/abi/TestTypes.java index bd31681bf..f3737cbe3 100644 --- a/src/test/java/com/algorand/algosdk/abi/TestTypes.java +++ b/src/test/java/com/algorand/algosdk/abi/TestTypes.java @@ -238,6 +238,54 @@ public void TestTypeFromStringValid() { ) ) ); + assertThat(ABIType.valueOf("(uint32,(uint64,bool)[10],byte)")).isEqualTo( + new TypeTuple( + Arrays.asList( + new TypeUint(32), + new TypeArrayStatic( + new TypeTuple( + Arrays.asList( + new TypeUint(64), + new TypeBool() + ) + ), + 10), + new TypeByte() + ) + ) + ); + assertThat(ABIType.valueOf("(uint32,byte,(uint64,bool)[10])")).isEqualTo( + new TypeTuple( + Arrays.asList( + new TypeUint(32), + new TypeByte(), + new TypeArrayStatic( + new TypeTuple( + Arrays.asList( + new TypeUint(64), + new TypeBool() + ) + ), + 10) + ) + ) + ); + assertThat(ABIType.valueOf("((uint64,bool)[10],uint32,byte)")).isEqualTo( + new TypeTuple( + Arrays.asList( + new TypeArrayStatic( + new TypeTuple( + Arrays.asList( + new TypeUint(64), + new TypeBool() + ) + ), + 10), + new TypeUint(32), + new TypeByte() + ) + ) + ); } @Test From 276a4ae255939f1c1809b1ca1e1fa0aad192f219 Mon Sep 17 00:00:00 2001 From: Hang Su <87964331+ahangsu@users.noreply.github.com> Date: Tue, 29 Nov 2022 13:54:18 -0500 Subject: [PATCH 5/6] Enhancement: Allowing zero length in static array (#432) --- src/main/java/com/algorand/algosdk/abi/ABIType.java | 2 +- src/main/java/com/algorand/algosdk/abi/TypeArrayStatic.java | 4 ++-- src/test/java/com/algorand/algosdk/abi/TestTypes.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/algorand/algosdk/abi/ABIType.java b/src/main/java/com/algorand/algosdk/abi/ABIType.java index 62d0eabb8..34bfcf40a 100644 --- a/src/main/java/com/algorand/algosdk/abi/ABIType.java +++ b/src/main/java/com/algorand/algosdk/abi/ABIType.java @@ -9,7 +9,7 @@ public abstract class ABIType { public static final int ABI_DYNAMIC_HEAD_BYTE_LEN = 2; - private static final Pattern staticArrayPattern = Pattern.compile("^(?[a-z\\d\\[\\](),]+)\\[(?[1-9][\\d]*)]$"); + private static final Pattern staticArrayPattern = Pattern.compile("^(?[a-z\\d\\[\\](),]+)\\[(?0|[1-9][\\d]*)]$"); private static final Pattern ufixedPattern = Pattern.compile("^ufixed(?[1-9][\\d]*)x(?[1-9][\\d]*)$"); /** diff --git a/src/main/java/com/algorand/algosdk/abi/TypeArrayStatic.java b/src/main/java/com/algorand/algosdk/abi/TypeArrayStatic.java index 3b539dcd2..a56651479 100644 --- a/src/main/java/com/algorand/algosdk/abi/TypeArrayStatic.java +++ b/src/main/java/com/algorand/algosdk/abi/TypeArrayStatic.java @@ -7,8 +7,8 @@ public class TypeArrayStatic extends ABIType { public final int length; public TypeArrayStatic(ABIType elemType, int length) { - if (length < 1) - throw new IllegalArgumentException("static-array initialize failure: array length should be at least 1"); + if (length < 0) + throw new IllegalArgumentException("static-array initialize failure: array length should be non-negative"); this.elemType = elemType; this.length = length; } diff --git a/src/test/java/com/algorand/algosdk/abi/TestTypes.java b/src/test/java/com/algorand/algosdk/abi/TestTypes.java index f3737cbe3..25fc45570 100644 --- a/src/test/java/com/algorand/algosdk/abi/TestTypes.java +++ b/src/test/java/com/algorand/algosdk/abi/TestTypes.java @@ -314,7 +314,7 @@ public void TestTypeFromStringInvalid() { "[][][]", "stuff[]", // static array - "ufixed32x10[0]", + "bool[01]", "byte[10 ]", "uint64[0x21]", // tuple From 5362aaf153d1213f4d4efaf73f3fbcc9483824df Mon Sep 17 00:00:00 2001 From: Barbara Poon Date: Mon, 5 Dec 2022 15:32:52 -0500 Subject: [PATCH 6/6] bump to 1.22.0 --- CHANGELOG.md | 13 +++++++++++++ README.md | 2 +- pom.xml | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce0913c84..0947e2dd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +# 1.22.0 + +### Bugfixes +* BugFix: Fix incorrect reference to global schema by @barnjamin in https://github.com/algorand/java-algorand-sdk/pull/427 +* Bug-Fix: parsing type strings for tuples containing static arrays of tuples by @ahangsu in https://github.com/algorand/java-algorand-sdk/pull/431 +### Enhancements +* REST API: Add KV counts to NodeStatusResponse by @github-actions in https://github.com/algorand/java-algorand-sdk/pull/428 +* Enhancement: Migrate v1 algod dependencies to v2 in cucumber tests by @ahangsu in https://github.com/algorand/java-algorand-sdk/pull/425 +* Enhancement: Allowing zero length in static array by @ahangsu in https://github.com/algorand/java-algorand-sdk/pull/432 + + +**Full Changelog**: https://github.com/algorand/java-algorand-sdk/compare/1.21.1...1.22.0 + # 1.21.1 ## What's Changed diff --git a/README.md b/README.md index d072cfaa9..88c1b1e88 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Maven: com.algorand algosdk - 1.21.1 + 1.22.0 ``` diff --git a/pom.xml b/pom.xml index 242704d8b..48355f23a 100755 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.algorand algosdk - 1.21.1 + 1.22.0 jar ${project.groupId}:${project.artifactId}