From 9fb9c79ba862d0e7dba8401a9ede223ccb8c9b2d Mon Sep 17 00:00:00 2001 From: Andrea Reguzzoni <56118242+Reguzzoni@users.noreply.github.com> Date: Tue, 12 Apr 2022 23:18:05 +0200 Subject: [PATCH 1/6] add error message with atomic transaction composer (#311) --- .../algorand/algosdk/transaction/AtomicTransactionComposer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/algorand/algosdk/transaction/AtomicTransactionComposer.java b/src/main/java/com/algorand/algosdk/transaction/AtomicTransactionComposer.java index 0f3788124..9640e7872 100644 --- a/src/main/java/com/algorand/algosdk/transaction/AtomicTransactionComposer.java +++ b/src/main/java/com/algorand/algosdk/transaction/AtomicTransactionComposer.java @@ -371,7 +371,7 @@ public List submit(AlgodClient client) throws Exception { Response rPost = client.RawTransaction().rawtxn(encoded).execute(); if (!rPost.isSuccessful()) - throw new Exception("transaction should be submitted successfully"); + throw new Exception("transaction should be submitted successfully cause : " + rPost.message()); this.status = Status.SUBMITTED; return this.getTxIDs(); From a1f7d3403ac8f909c95ac3bc3289e9f45893f95a Mon Sep 17 00:00:00 2001 From: Ben Guidarelli Date: Wed, 13 Apr 2022 09:31:49 -0400 Subject: [PATCH 2/6] Update generated client code. (#307) --- .../com/algorand/algosdk/v2/client/algod/TealCompile.java | 2 +- .../java/com/algorand/algosdk/v2/client/algod/TealDryrun.java | 2 +- .../com/algorand/algosdk/v2/client/common/AlgodClient.java | 4 ++-- .../algosdk/v2/client/model/AccountParticipation.java | 3 --- .../algorand/algosdk/v2/client/model/ApplicationParams.java | 2 -- .../com/algorand/algosdk/v2/client/model/AssetParams.java | 4 ---- src/main/java/com/algorand/algosdk/v2/client/model/Block.java | 4 ---- .../com/algorand/algosdk/v2/client/model/ProofResponse.java | 2 -- .../com/algorand/algosdk/v2/client/model/Transaction.java | 4 ---- .../algosdk/v2/client/model/TransactionApplication.java | 2 -- .../algorand/algosdk/v2/client/model/TransactionKeyreg.java | 3 --- .../v2/client/model/TransactionParametersResponse.java | 1 - .../algosdk/v2/client/model/TransactionSignature.java | 1 - .../algosdk/v2/client/model/TransactionSignatureLogicsig.java | 2 -- .../model/TransactionSignatureMultisigSubsignature.java | 2 -- .../java/com/algorand/algosdk/v2/client/model/Version.java | 1 - 16 files changed, 4 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/algorand/algosdk/v2/client/algod/TealCompile.java b/src/main/java/com/algorand/algosdk/v2/client/algod/TealCompile.java index 2b0db42f7..aadd2b545 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/algod/TealCompile.java +++ b/src/main/java/com/algorand/algosdk/v2/client/algod/TealCompile.java @@ -11,7 +11,7 @@ /** * Given TEAL source code in plain text, return base64 encoded program bytes and * base32 SHA512_256 hash of program bytes (Address style). This endpoint is only - * enabled when a node's configureation file sets EnableDeveloperAPI to true. + * enabled when a node's configuration file sets EnableDeveloperAPI to true. * /v2/teal/compile */ public class TealCompile extends Query { diff --git a/src/main/java/com/algorand/algosdk/v2/client/algod/TealDryrun.java b/src/main/java/com/algorand/algosdk/v2/client/algod/TealDryrun.java index 335692b4e..5b6f6a766 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/algod/TealDryrun.java +++ b/src/main/java/com/algorand/algosdk/v2/client/algod/TealDryrun.java @@ -13,7 +13,7 @@ /** * Executes TEAL program(s) in context and returns debugging information about the - * execution. This endpoint is only enabled when a node's configureation file sets + * execution. This endpoint is only enabled when a node's configuration file sets * EnableDeveloperAPI to true. * /v2/teal/dryrun */ diff --git a/src/main/java/com/algorand/algosdk/v2/client/common/AlgodClient.java b/src/main/java/com/algorand/algosdk/v2/client/common/AlgodClient.java index c0be5ea34..e6632efa6 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/common/AlgodClient.java +++ b/src/main/java/com/algorand/algosdk/v2/client/common/AlgodClient.java @@ -233,7 +233,7 @@ public GetAssetByID GetAssetByID(Long assetId) { /** * Given TEAL source code in plain text, return base64 encoded program bytes and * base32 SHA512_256 hash of program bytes (Address style). This endpoint is only - * enabled when a node's configureation file sets EnableDeveloperAPI to true. + * enabled when a node's configuration file sets EnableDeveloperAPI to true. * /v2/teal/compile */ public TealCompile TealCompile() { @@ -242,7 +242,7 @@ public TealCompile TealCompile() { /** * Executes TEAL program(s) in context and returns debugging information about the - * execution. This endpoint is only enabled when a node's configureation file sets + * execution. This endpoint is only enabled when a node's configuration file sets * EnableDeveloperAPI to true. * /v2/teal/dryrun */ diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/AccountParticipation.java b/src/main/java/com/algorand/algosdk/v2/client/model/AccountParticipation.java index 130f35e15..aab24a9c2 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/AccountParticipation.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/AccountParticipation.java @@ -19,7 +19,6 @@ public class AccountParticipation extends PathResponse { public void selectionParticipationKey(String base64Encoded) { this.selectionParticipationKey = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("selection-participation-key") public String selectionParticipationKey() { return Encoder.encodeToBase64(this.selectionParticipationKey); } @@ -32,7 +31,6 @@ public String selectionParticipationKey() { public void stateProofKey(String base64Encoded) { this.stateProofKey = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("state-proof-key") public String stateProofKey() { return Encoder.encodeToBase64(this.stateProofKey); } @@ -64,7 +62,6 @@ public String stateProofKey() { public void voteParticipationKey(String base64Encoded) { this.voteParticipationKey = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("vote-participation-key") public String voteParticipationKey() { return Encoder.encodeToBase64(this.voteParticipationKey); } diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/ApplicationParams.java b/src/main/java/com/algorand/algosdk/v2/client/model/ApplicationParams.java index faf1cdb7c..f1ffad82c 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/ApplicationParams.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/ApplicationParams.java @@ -22,7 +22,6 @@ public class ApplicationParams extends PathResponse { public void approvalProgram(String base64Encoded) { this.approvalProgram = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("approval-program") public String approvalProgram() { return Encoder.encodeToBase64(this.approvalProgram); } @@ -35,7 +34,6 @@ public String approvalProgram() { public void clearStateProgram(String base64Encoded) { this.clearStateProgram = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("clear-state-program") public String clearStateProgram() { return Encoder.encodeToBase64(this.clearStateProgram); } diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/AssetParams.java b/src/main/java/com/algorand/algosdk/v2/client/model/AssetParams.java index 5838eed60..c2aed5072 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/AssetParams.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/AssetParams.java @@ -65,7 +65,6 @@ public class AssetParams extends PathResponse { public void metadataHash(String base64Encoded) { this.metadataHash = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("metadata-hash") public String metadataHash() { return Encoder.encodeToBase64(this.metadataHash); } @@ -85,7 +84,6 @@ public String metadataHash() { public void nameB64(String base64Encoded) { this.nameB64 = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("name-b64") public String nameB64() { return Encoder.encodeToBase64(this.nameB64); } @@ -117,7 +115,6 @@ public String nameB64() { public void unitNameB64(String base64Encoded) { this.unitNameB64 = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("unit-name-b64") public String unitNameB64() { return Encoder.encodeToBase64(this.unitNameB64); } @@ -137,7 +134,6 @@ public String unitNameB64() { public void urlB64(String base64Encoded) { this.urlB64 = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("url-b64") public String urlB64() { return Encoder.encodeToBase64(this.urlB64); } diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/Block.java b/src/main/java/com/algorand/algosdk/v2/client/model/Block.java index 72ef06667..442ab604c 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/Block.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/Block.java @@ -22,7 +22,6 @@ public class Block extends PathResponse { public void genesisHash(String base64Encoded) { this.genesisHash = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("genesis-hash") public String genesisHash() { return Encoder.encodeToBase64(this.genesisHash); } @@ -41,7 +40,6 @@ public String genesisHash() { public void previousBlockHash(String base64Encoded) { this.previousBlockHash = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("previous-block-hash") public String previousBlockHash() { return Encoder.encodeToBase64(this.previousBlockHash); } @@ -66,7 +64,6 @@ public String previousBlockHash() { public void seed(String base64Encoded) { this.seed = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("seed") public String seed() { return Encoder.encodeToBase64(this.seed); } @@ -96,7 +93,6 @@ public String seed() { public void transactionsRoot(String base64Encoded) { this.transactionsRoot = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("transactions-root") public String transactionsRoot() { return Encoder.encodeToBase64(this.transactionsRoot); } diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/ProofResponse.java b/src/main/java/com/algorand/algosdk/v2/client/model/ProofResponse.java index 543c8127b..71b4e8c89 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/ProofResponse.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/ProofResponse.java @@ -32,7 +32,6 @@ public class ProofResponse extends PathResponse { public void proof(String base64Encoded) { this.proof = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("proof") public String proof() { return Encoder.encodeToBase64(this.proof); } @@ -45,7 +44,6 @@ public String proof() { public void stibhash(String base64Encoded) { this.stibhash = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("stibhash") public String stibhash() { return Encoder.encodeToBase64(this.stibhash); } diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/Transaction.java b/src/main/java/com/algorand/algosdk/v2/client/model/Transaction.java index 0d338fd5d..345e6b61f 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/Transaction.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/Transaction.java @@ -124,7 +124,6 @@ public String authAddr() throws NoSuchAlgorithmException { public void genesisHash(String base64Encoded) { this.genesisHash = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("genesis-hash") public String genesisHash() { return Encoder.encodeToBase64(this.genesisHash); } @@ -152,7 +151,6 @@ public String genesisHash() { public void group(String base64Encoded) { this.group = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("group") public String group() { return Encoder.encodeToBase64(this.group); } @@ -201,7 +199,6 @@ public String group() { public void lease(String base64Encoded) { this.lease = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("lease") public String lease() { return Encoder.encodeToBase64(this.lease); } @@ -242,7 +239,6 @@ public List logs() { public void note(String base64Encoded) { this.note = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("note") public String note() { return Encoder.encodeToBase64(this.note); } diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/TransactionApplication.java b/src/main/java/com/algorand/algosdk/v2/client/model/TransactionApplication.java index faebcbbbc..3b6bbcf81 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/TransactionApplication.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/TransactionApplication.java @@ -77,7 +77,6 @@ public List applicationArgs() { public void approvalProgram(String base64Encoded) { this.approvalProgram = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("approval-program") public String approvalProgram() { return Encoder.encodeToBase64(this.approvalProgram); } @@ -93,7 +92,6 @@ public String approvalProgram() { public void clearStateProgram(String base64Encoded) { this.clearStateProgram = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("clear-state-program") public String clearStateProgram() { return Encoder.encodeToBase64(this.clearStateProgram); } diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/TransactionKeyreg.java b/src/main/java/com/algorand/algosdk/v2/client/model/TransactionKeyreg.java index a5e0d1fde..d3677cf8e 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/TransactionKeyreg.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/TransactionKeyreg.java @@ -27,7 +27,6 @@ public class TransactionKeyreg extends PathResponse { public void selectionParticipationKey(String base64Encoded) { this.selectionParticipationKey = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("selection-participation-key") public String selectionParticipationKey() { return Encoder.encodeToBase64(this.selectionParticipationKey); } @@ -40,7 +39,6 @@ public String selectionParticipationKey() { public void stateProofKey(String base64Encoded) { this.stateProofKey = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("state-proof-key") public String stateProofKey() { return Encoder.encodeToBase64(this.stateProofKey); } @@ -71,7 +69,6 @@ public String stateProofKey() { public void voteParticipationKey(String base64Encoded) { this.voteParticipationKey = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("vote-participation-key") public String voteParticipationKey() { return Encoder.encodeToBase64(this.voteParticipationKey); } diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/TransactionParametersResponse.java b/src/main/java/com/algorand/algosdk/v2/client/model/TransactionParametersResponse.java index 1145fba40..12b366e94 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/TransactionParametersResponse.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/TransactionParametersResponse.java @@ -35,7 +35,6 @@ public class TransactionParametersResponse extends PathResponse { public void genesisHash(String base64Encoded) { this.genesisHash = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("genesis-hash") public String genesisHash() { return Encoder.encodeToBase64(this.genesisHash); } diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/TransactionSignature.java b/src/main/java/com/algorand/algosdk/v2/client/model/TransactionSignature.java index 77937651a..986a8aa86 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/TransactionSignature.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/TransactionSignature.java @@ -35,7 +35,6 @@ public class TransactionSignature extends PathResponse { public void sig(String base64Encoded) { this.sig = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("sig") public String sig() { return Encoder.encodeToBase64(this.sig); } diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/TransactionSignatureLogicsig.java b/src/main/java/com/algorand/algosdk/v2/client/model/TransactionSignatureLogicsig.java index 1ed3a9408..194042d47 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/TransactionSignatureLogicsig.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/TransactionSignatureLogicsig.java @@ -45,7 +45,6 @@ public List args() { public void logic(String base64Encoded) { this.logic = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("logic") public String logic() { return Encoder.encodeToBase64(this.logic); } @@ -66,7 +65,6 @@ public String logic() { public void signature(String base64Encoded) { this.signature = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("signature") public String signature() { return Encoder.encodeToBase64(this.signature); } diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/TransactionSignatureMultisigSubsignature.java b/src/main/java/com/algorand/algosdk/v2/client/model/TransactionSignatureMultisigSubsignature.java index 121cb468a..3e81343f4 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/TransactionSignatureMultisigSubsignature.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/TransactionSignatureMultisigSubsignature.java @@ -15,7 +15,6 @@ public class TransactionSignatureMultisigSubsignature extends PathResponse { public void publicKey(String base64Encoded) { this.publicKey = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("public-key") public String publicKey() { return Encoder.encodeToBase64(this.publicKey); } @@ -28,7 +27,6 @@ public String publicKey() { public void signature(String base64Encoded) { this.signature = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("signature") public String signature() { return Encoder.encodeToBase64(this.signature); } diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/Version.java b/src/main/java/com/algorand/algosdk/v2/client/model/Version.java index 8cb2e630e..4a0320382 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/model/Version.java +++ b/src/main/java/com/algorand/algosdk/v2/client/model/Version.java @@ -20,7 +20,6 @@ public class Version extends PathResponse { public void genesis_hash_b64(String base64Encoded) { this.genesis_hash_b64 = Encoder.decodeFromBase64(base64Encoded); } - @JsonProperty("genesis_hash_b64") public String genesis_hash_b64() { return Encoder.encodeToBase64(this.genesis_hash_b64); } From 3a2cde2256d9e5fad6dcc01252a3e6714f2e7a58 Mon Sep 17 00:00:00 2001 From: Ben Guidarelli Date: Thu, 14 Apr 2022 09:13:20 -0400 Subject: [PATCH 3/6] Add createDryrun helper function. (#284) Co-authored-by: Hang Su <87964331+ahangsu@users.noreply.github.com> --- .../algorand/algosdk/logic/StateSchema.java | 4 +- .../com/algorand/algosdk/v2/client/Utils.java | 168 +++++++++++++++++- 2 files changed, 166 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/algorand/algosdk/logic/StateSchema.java b/src/main/java/com/algorand/algosdk/logic/StateSchema.java index c0b6534cc..e99322f1d 100644 --- a/src/main/java/com/algorand/algosdk/logic/StateSchema.java +++ b/src/main/java/com/algorand/algosdk/logic/StateSchema.java @@ -12,10 +12,10 @@ @JsonPropertyOrder(alphabetic = true) public class StateSchema implements Serializable { @JsonProperty("nui") - BigInteger numUint = BigInteger.ZERO; + public BigInteger numUint = BigInteger.ZERO; @JsonProperty("nbs") - BigInteger numByteSlice = BigInteger.ZERO; + public BigInteger numByteSlice = BigInteger.ZERO; // Used by Jackson to figure out the default value. public StateSchema() { } diff --git a/src/main/java/com/algorand/algosdk/v2/client/Utils.java b/src/main/java/com/algorand/algosdk/v2/client/Utils.java index 9af94ca17..52200d970 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/Utils.java +++ b/src/main/java/com/algorand/algosdk/v2/client/Utils.java @@ -1,19 +1,178 @@ package com.algorand.algosdk.v2.client; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.HashSet; +import java.util.Set; + +import com.algorand.algosdk.crypto.Address; +import com.algorand.algosdk.transaction.SignedTransaction; +import com.algorand.algosdk.transaction.Transaction; +import com.algorand.algosdk.transaction.Transaction.Type; import com.algorand.algosdk.v2.client.common.AlgodClient; import com.algorand.algosdk.v2.client.common.Response; +import com.algorand.algosdk.v2.client.model.DryrunRequest; +import com.algorand.algosdk.v2.client.model.Application; +import com.algorand.algosdk.v2.client.model.ApplicationParams; +import com.algorand.algosdk.v2.client.model.ApplicationStateSchema; +import com.algorand.algosdk.v2.client.model.Account; +import com.algorand.algosdk.v2.client.model.Asset; import com.algorand.algosdk.v2.client.model.NodeStatusResponse; import com.algorand.algosdk.v2.client.model.PendingTransactionResponse; public class Utils { + + // https://github.com/algorand/go-algorand/blob/e466aa18d4d963868d6d15279b1c881977fa603f/libgoal/libgoal.go#L1089-L1090 + private static final Long defaultAppId = 1380011588L; + + /** + * Construct a DryruynRequest object from a set of transactions. + * A DryrunRequest is composed of static balance information. This function uses the ApplicationCall transaction + * parameters to infer what Application State and Account balance information to query using the client and adds it to the DryrunRequest object. + * If foreign assets are passed, it will also add the creators balance information to the DryrunRequest. + * + * @param client an Algod v2 client + * @param txns the array of SignedTransactions that should be used + * to generate the DryrunRequest + * @return DryrunRequest to be submitted to TealDryrun endpoint + * @throws Exception if transaction is rejected or the transaction is not + * confirmed before wait round + * + */ + public static DryrunRequest createDryrun(AlgodClient client, List txns) throws Exception { + return Utils.createDryrun(client, txns, "", 0L, 0L); + } + + /** + * Construct a DryruynRequest object from a set of transactions. + * A DryrunRequest is composed of static balance information. This function uses the ApplicationCall transaction + * parameters to infer what Application State and Account balance information to query using the client and adds it to the DryrunRequest object. + * If foreign assets are passed, it will also add the creators balance information to the DryrunRequest. + * + * @param client an Algod v2 client + * @param txns the array of SignedTransactions that should be used + * to generate the DryrunRequest + * @param protocol_version The protocol version the dryrun should include + * @param latest_timestamp The latest timestamp the dryrun should include + * @param round The agreement round or block height the dryrun should + * include + * @return DryrunRequest to be submitted to TealDryrun endpoint + * @throws Exception if transaction is rejected or the transaction is not + * confirmed before wait round + */ + public static DryrunRequest createDryrun(AlgodClient client, List txns, String protocol_version, + Long latest_timestamp, Long round) + throws Exception { + + if (client == null || txns.size() == 0) { + throw new IllegalArgumentException("Bad arguments for createDryrun."); + } + + // The details we need to add to DryrunRequest object + ArrayList app_infos = new ArrayList<>(); + ArrayList acct_infos = new ArrayList<>(); + + // These are populated from the transactions passed + Set apps = new HashSet<>(); + Set assets = new HashSet<>(); + Set accts = new HashSet<>(); + + for (SignedTransaction txn : txns) { + Transaction tx = txn.tx; + + // We're only interested to pull state for app calls + if (tx.type != Type.ApplicationCall) { + continue; + } + + // If this is a create transaction + if (tx.applicationId == 0 || tx.applicationId == null) { + // Prepare and set param fields for Application being created + // from the transaction passed + ApplicationParams params = new ApplicationParams(); + params.creator = tx.sender; + params.approvalProgram = tx.approvalProgram.getBytes(); + params.clearStateProgram = tx.clearStateProgram.getBytes(); + + ApplicationStateSchema localState = new ApplicationStateSchema(); + localState.numByteSlice = tx.localStateSchema.numByteSlice.longValue(); + localState.numUint = tx.localStateSchema.numUint.longValue(); + params.localStateSchema = localState; + + ApplicationStateSchema globalState = new ApplicationStateSchema(); + globalState.numByteSlice = tx.globalStateSchema.numByteSlice.longValue(); + globalState.numUint = tx.globalStateSchema.numUint.longValue(); + params.globalStateSchema = globalState; + + Application app = new Application(); + app.id = Utils.defaultAppId; + app.params = params; + + app_infos.add(app); + } else { + apps.add(tx.applicationId); + accts.add(Address.forApplication(tx.applicationId).toString()); + } + + if (tx.foreignApps.size() > 0) { + apps.addAll(tx.foreignApps); + } + + if (tx.foreignAssets.size() > 0) { + assets.addAll(tx.foreignAssets); + } + + if (tx.accounts.size() > 0) { + for (Address acct : tx.accounts) { + accts.add(acct.toString()); + } + } + } + + for (Long asset : assets) { + Response ar = client.GetAssetByID(asset).execute(); + if(ar.isSuccessful()){ + Asset a = ar.body(); + accts.add(a.params.creator); + } + } + + for (Long app : apps) { + Response ar = client.GetApplicationByID(app).execute(); + if(ar.isSuccessful()){ + app_infos.add(ar.body()); + accts.add(ar.body().params.creator.toString()); + } + } + + for (String acct : accts) { + Response ar = client.AccountInformation(new Address(acct)).execute(); + if(ar.isSuccessful()){ + acct_infos.add(ar.body()); + } + } + + DryrunRequest drr = new DryrunRequest(); + drr.accounts = acct_infos; + drr.apps = app_infos; + drr.txns = txns; + drr.protocolVersion = protocol_version; + drr.latestTimestamp = latest_timestamp; + drr.round = BigInteger.valueOf(round); + return drr; + } + /** * Wait until a transaction has been confirmed or rejected by the network * or wait until waitRound fully elapsed - * @param client an Algod v2 client - * @param txID the transaction ID that we are waiting + * + * @param client an Algod v2 client + * @param txID the transaction ID that we are waiting * @param waitRounds The maximum number of rounds to wait for. * @return TransactionResponse of the confirmed transaction - * @throws Exception if transaction is rejected or the transaction is not confirmed before wait round + * @throws Exception if transaction is rejected or the transaction is not + * confirmed before wait round */ public static PendingTransactionResponse waitForConfirmation(AlgodClient client, String txID, int waitRounds) throws Exception { @@ -39,7 +198,8 @@ public static PendingTransactionResponse waitForConfirmation(AlgodClient client, } if (pendingInfo.poolError != null && pendingInfo.poolError.length() > 0) { // If there was a pool error, then the transaction has been rejected! - throw new Exception("The transaction has been rejected with a pool error: " + pendingInfo.poolError); + throw new Exception( + "The transaction has been rejected with a pool error: " + pendingInfo.poolError); } } } From b7eeed47287e0907aa456b775e2b857e1136cf73 Mon Sep 17 00:00:00 2001 From: Ben Guidarelli Date: Thu, 21 Apr 2022 08:32:43 -0400 Subject: [PATCH 4/6] Add appTrace and lsigTrace DryrunTxnResult printer utility functions. (#305) --- Makefile | 2 +- .../com/algorand/algosdk/v2/client/Utils.java | 192 ++++++++++++++++-- .../algosdk/unit/ResponsesShared.java | 31 +++ 3 files changed, 208 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index 417da9061..b69f2199e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ unit: - mvn test -Dcucumber.filter.tags="@unit.offline or @unit.algod or @unit.indexer or @unit.rekey or @unit.indexer.rekey or @unit.transactions or @unit.transactions.keyreg or @unit.responses or @unit.applications or @unit.dryrun or @unit.tealsign or @unit.responses.messagepack or @unit.responses.231 or @unit.responses.messagepack.231 or @unit.feetest or @unit.indexer.logs or @unit.abijson or @unit.atomic_transaction_composer or @unit.transactions.payment or @unit.responses.unlimited_assets or @unit.algod.ledger_refactoring or @unit.indexer.ledger_refactoring" + mvn test -Dcucumber.filter.tags="@unit.offline or @unit.algod or @unit.indexer or @unit.rekey or @unit.indexer.rekey or @unit.transactions or @unit.transactions.keyreg or @unit.responses or @unit.applications or @unit.dryrun or @unit.tealsign or @unit.responses.messagepack or @unit.responses.231 or @unit.responses.messagepack.231 or @unit.feetest or @unit.indexer.logs or @unit.abijson or @unit.atomic_transaction_composer or @unit.transactions.payment or @unit.responses.unlimited_assets or @unit.algod.ledger_refactoring or @unit.indexer.ledger_refactoring or @unit.dryrun.trace.application" integration: mvn test -Dcucumber.filter.tags="@algod or @assets or @auction or @kmd or @send or @send.keyregtxn or @indexer or @rekey or @applications.verified or @applications or @compile or @dryrun or @indexer.applications or @indexer.231 or @abi or @c2c" diff --git a/src/main/java/com/algorand/algosdk/v2/client/Utils.java b/src/main/java/com/algorand/algosdk/v2/client/Utils.java index 52200d970..4c6c98695 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/Utils.java +++ b/src/main/java/com/algorand/algosdk/v2/client/Utils.java @@ -2,7 +2,9 @@ import java.math.BigInteger; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.HashSet; import java.util.Set; @@ -10,9 +12,12 @@ import com.algorand.algosdk.transaction.SignedTransaction; import com.algorand.algosdk.transaction.Transaction; import com.algorand.algosdk.transaction.Transaction.Type; +import com.algorand.algosdk.util.Encoder; import com.algorand.algosdk.v2.client.common.AlgodClient; import com.algorand.algosdk.v2.client.common.Response; import com.algorand.algosdk.v2.client.model.DryrunRequest; +import com.algorand.algosdk.v2.client.model.DryrunState; +import com.algorand.algosdk.v2.client.model.DryrunTxnResult; import com.algorand.algosdk.v2.client.model.Application; import com.algorand.algosdk.v2.client.model.ApplicationParams; import com.algorand.algosdk.v2.client.model.ApplicationStateSchema; @@ -20,22 +25,29 @@ import com.algorand.algosdk.v2.client.model.Asset; import com.algorand.algosdk.v2.client.model.NodeStatusResponse; import com.algorand.algosdk.v2.client.model.PendingTransactionResponse; +import com.algorand.algosdk.v2.client.model.TealValue; + +import org.apache.commons.lang3.StringUtils; public class Utils { // https://github.com/algorand/go-algorand/blob/e466aa18d4d963868d6d15279b1c881977fa603f/libgoal/libgoal.go#L1089-L1090 private static final Long defaultAppId = 1380011588L; + private static final int defaultMaxWidth = 30; /** - * Construct a DryruynRequest object from a set of transactions. - * A DryrunRequest is composed of static balance information. This function uses the ApplicationCall transaction - * parameters to infer what Application State and Account balance information to query using the client and adds it to the DryrunRequest object. - * If foreign assets are passed, it will also add the creators balance information to the DryrunRequest. + * Construct a DryrunRequest object from a set of transactions. + * A DryrunRequest is composed of static balance information. This function uses + * the ApplicationCall transaction + * parameters to infer what Application State and Account balance information to + * query using the client and adds it to the DryrunRequest object. + * If foreign assets are passed, it will also add the creators balance + * information to the DryrunRequest. * - * @param client an Algod v2 client - * @param txns the array of SignedTransactions that should be used - * to generate the DryrunRequest - * @return DryrunRequest to be submitted to TealDryrun endpoint + * @param client an Algod v2 client + * @param txns the array of SignedTransactions that should be used + * to generate the DryrunRequest + * @return DryrunRequest to be submitted to TealDryrun endpoint * @throws Exception if transaction is rejected or the transaction is not * confirmed before wait round * @@ -45,10 +57,13 @@ public static DryrunRequest createDryrun(AlgodClient client, List ar = client.GetAssetByID(asset).execute(); - if(ar.isSuccessful()){ + if (ar.isSuccessful()) { Asset a = ar.body(); accts.add(a.params.creator); } @@ -140,7 +155,7 @@ public static DryrunRequest createDryrun(AlgodClient client, List ar = client.GetApplicationByID(app).execute(); - if(ar.isSuccessful()){ + if (ar.isSuccessful()) { app_infos.add(ar.body()); accts.add(ar.body().params.creator.toString()); } @@ -148,7 +163,7 @@ public static DryrunRequest createDryrun(AlgodClient client, List ar = client.AccountInformation(new Address(acct)).execute(); - if(ar.isSuccessful()){ + if (ar.isSuccessful()) { acct_infos.add(ar.body()); } } @@ -163,6 +178,151 @@ public static DryrunRequest createDryrun(AlgodClient client, List maxWidth && maxWidth > 0) { + return s.substring(0, maxWidth) + "..."; + } + return s; + } + + private static String stackToString(List stack, boolean reverse) { + if (reverse) { + Collections.reverse(stack); + } + + List elems = new ArrayList(); + for (int i = 0; i < stack.size(); i++) { + TealValue tv = stack.get(i); + switch (tv.type.intValue()) { + case 1: + byte[] decoded = Encoder.decodeFromBase64(tv.bytes); + elems.add("0x" + Encoder.encodeToHexStr(decoded)); + break; + case 2: + elems.add(tv.uint.toString()); + break; + default: + break; + } + } + + return String.format("[%s]", StringUtils.join(elems, ", ")); + } + + private static String scratchToString(List prevScratch, List currScratch) { + if (currScratch.size() == 0) + return ""; + + int newIdx = -1; + for (int i = 0; i < currScratch.size(); i++) { + if (i >= prevScratch.size()) { + newIdx = i; + continue; + } + + if (!Objects.deepEquals(prevScratch.get(i), currScratch.get(i))) { + newIdx = i; + } + } + + if (newIdx < 0) + return ""; + + TealValue tv = currScratch.get(newIdx); + if (tv.bytes.length() > 0) { + byte[] decoded = Encoder.decodeFromBase64(tv.bytes); + String newValue = "0x" + Encoder.encodeToHexStr(decoded); + return String.format("%d = %s", newIdx, newValue); + } + return String.format("%d = %d", newIdx, tv.uint); + } + + private static String trace(List state, List disassembly, StackPrinterConfig spc) { + List lines = new ArrayList(); + lines.add(new String[] { "pc#", "ln#", "source", "scratch", "stack" }); + + // Create lines for trace + for (int i = 0; i < state.size(); i++) { + DryrunState s = state.get(i); + + boolean hasError = s.error != null && s.error != ""; + String src = hasError ? String.format("!! %s !!", s.error) : disassembly.get(s.line.intValue()); + + List currScratch = s.scratch; + List prevScratch = i > 0 ? state.get(i - 1).scratch : new ArrayList(); + + lines.add(new String[] { + String.format("%-3d", s.pc), + String.format("%-3d", s.line), + truncate(src, spc.maxValueWidth), + truncate(scratchToString(prevScratch, currScratch), spc.maxValueWidth), + truncate(stackToString(s.stack, spc.topOfStackFirst), spc.maxValueWidth) + }); + } + + // Get max length of each column + int columns = lines.get(0).length; + int[] maxLengths = new int[columns]; + for (int i = 0; i < lines.size(); i++) { + String[] line = lines.get(i); + for (int j = 0; j < columns; j++) { + if (line[j].length() > maxLengths[j]) { + maxLengths[j] = line[j].length(); + } + } + } + + // Create formatter + List fmts = new ArrayList(); + for (int i = 0; i < columns; i++) { + fmts.add(String.format("%%-%ds", maxLengths[i] + 1)); + } + + String fmt = StringUtils.join(fmts, "|"); + StringBuilder sb = new StringBuilder(); + for (String[] line : lines) { + sb.append(String.format(fmt, line).trim() + "\n"); + } + return sb.toString(); + } + + public static String appTrace(DryrunTxnResult dtr) { + StackPrinterConfig spc = new StackPrinterConfig(); + spc.maxValueWidth = defaultMaxWidth; + spc.topOfStackFirst = true; + return trace( + dtr.appCallTrace, + dtr.disassembly, + spc); + } + + public static String appTrace(DryrunTxnResult dtr, StackPrinterConfig spc) { + return trace(dtr.appCallTrace, dtr.disassembly, spc); + } + + public static String lsigTrace(DryrunTxnResult dtr) { + StackPrinterConfig spc = new StackPrinterConfig(); + spc.maxValueWidth = defaultMaxWidth; + spc.topOfStackFirst = true; + return trace( + dtr.logicSigTrace, + dtr.logicSigDisassembly, + spc); + } + + public static String lsigTrace(DryrunTxnResult dtr, StackPrinterConfig spc) { + return trace(dtr.logicSigTrace, dtr.logicSigDisassembly, spc); + } + /** * Wait until a transaction has been confirmed or rejected by the network * or wait until waitRound fully elapsed diff --git a/src/test/java/com/algorand/algosdk/unit/ResponsesShared.java b/src/test/java/com/algorand/algosdk/unit/ResponsesShared.java index adc7fb65a..65889dfe4 100644 --- a/src/test/java/com/algorand/algosdk/unit/ResponsesShared.java +++ b/src/test/java/com/algorand/algosdk/unit/ResponsesShared.java @@ -2,9 +2,14 @@ import com.algorand.algosdk.crypto.Address; import com.algorand.algosdk.unit.utils.ClientMocker; +import com.algorand.algosdk.util.Encoder; +import com.algorand.algosdk.util.ResourceUtils; +import com.algorand.algosdk.v2.client.Utils; 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.DryrunResponse; +import com.algorand.algosdk.v2.client.model.DryrunTxnResult; import com.google.common.io.Files; import io.cucumber.java.en.Given; import io.cucumber.java.en.Then; @@ -13,6 +18,7 @@ import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; import static com.algorand.algosdk.unit.utils.TestingUtils.verifyResponse; import static org.assertj.core.api.Assertions.assertThat; @@ -21,6 +27,7 @@ public class ResponsesShared { public File bodyFile; @SuppressWarnings("rawtypes") public Response response; + public DryrunTxnResult dryrunTxnResult; public AlgodClient algod = new AlgodClient("localhost", 123, ""); public IndexerClient indexer = new IndexerClient("localhost", 123); @@ -182,4 +189,28 @@ public void the_parsed_response_should_equal() throws IOException { verifyResponse(response, bodyFile); } + @Given("a dryrun response file {string} and a transaction at index {string}") + public void a_dryrun_response_file_and_a_transaction_at_index(String path, String strIdx) { + byte[] b = ResourceUtils.loadResource(path); + String str_resource = new String(b, StandardCharsets.UTF_8); + try{ + DryrunResponse drr = Encoder.decodeFromJson(str_resource, DryrunResponse.class); + int idx = Integer.parseInt(strIdx); + this.dryrunTxnResult = drr.txns.get(idx); + }catch(Exception e){ + assertThat(e).isNull(); + } + } + + @Then("calling app trace produces {string}") + public void calling_app_trace_produces(String path) { + byte[] b = ResourceUtils.loadResource(path); + String str_resource = new String(b, StandardCharsets.UTF_8); + Utils.StackPrinterConfig spc = new Utils.StackPrinterConfig(); + spc.maxValueWidth = 30; + spc.topOfStackFirst = false; + + String trace = Utils.appTrace(this.dryrunTxnResult, spc); + assertThat(str_resource).isEqualTo(trace); + } } From 4c993d42b4414ea850401c9b3c0ebf6f3664fb06 Mon Sep 17 00:00:00 2001 From: Ben Guidarelli Date: Tue, 26 Apr 2022 12:46:53 -0400 Subject: [PATCH 5/6] adding foreign app address to dryrun creator (#315) --- src/main/java/com/algorand/algosdk/v2/client/Utils.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/algorand/algosdk/v2/client/Utils.java b/src/main/java/com/algorand/algosdk/v2/client/Utils.java index 4c6c98695..3f87f1e1a 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/Utils.java +++ b/src/main/java/com/algorand/algosdk/v2/client/Utils.java @@ -132,6 +132,9 @@ public static DryrunRequest createDryrun(AlgodClient client, List 0) { apps.addAll(tx.foreignApps); + for(Long aidx: tx.foreignApps){ + accts.add(Address.forApplication(aidx).toString()); + } } if (tx.foreignAssets.size() > 0) { From 75a879989bffa2428d2d92cf4a24a73a9702212b Mon Sep 17 00:00:00 2001 From: John Lee Date: Fri, 29 Apr 2022 14:21:35 -0400 Subject: [PATCH 6/6] Bump to 1.14.0 --- CHANGELOG.md | 9 +++++++++ README.md | 2 +- pom.xml | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55a800ef2..9cebd8b68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# 1.14.0 +## Added +- Add foreign app address to dryrun creator (#315) +- Add appTrace and lsigTrace DryrunTxnResult printer utility functions. (#305) +- Add createDryrun helper function. (#284) +- Add error message with atomic transaction composer (#311) +## Changed +- Update generated client code. (#307) + # 1.13.0 - Unlimited assets regenerated code. (#302) diff --git a/README.md b/README.md index 8d9a8b021..f0fb9f3b1 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Maven: com.algorand algosdk - 1.13.0 + 1.14.0 ``` diff --git a/pom.xml b/pom.xml index eb9239525..734777fa0 100755 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.algorand algosdk - 1.13.0 + 1.14.0 jar ${project.groupId}:${project.artifactId}