From 1541a2ac3e49f3912d5781882b813a42099fa001 Mon Sep 17 00:00:00 2001 From: Will Winder Date: Fri, 7 Oct 2022 10:55:26 -0400 Subject: [PATCH 1/2] REST API: Add algod block hash endpoint, add indexer block header-only param. (#413) --- .test-env | 2 + Makefile | 5 +- .../algosdk/v2/client/algod/GetBlockHash.java | 65 +++++++++++++++++++ .../algosdk/v2/client/common/AlgodClient.java | 9 +++ .../v2/client/indexer/LookupBlock.java | 9 +++ .../algosdk/v2/client/model/Block.java | 7 ++ .../v2/client/model/BlockHashResponse.java | 30 +++++++++ .../v2/client/model/ParticipationUpdates.java | 33 ++++++++++ .../com/algorand/algosdk/unit/AlgodPaths.java | 5 ++ .../algorand/algosdk/unit/IndexerPaths.java | 7 ++ .../algosdk/unit/ResponsesShared.java | 3 + src/test/unit.tags | 2 + test-harness.sh | 55 ++++++++++++++++ 13 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/algorand/algosdk/v2/client/algod/GetBlockHash.java create mode 100644 src/main/java/com/algorand/algosdk/v2/client/model/BlockHashResponse.java create mode 100644 src/main/java/com/algorand/algosdk/v2/client/model/ParticipationUpdates.java diff --git a/.test-env b/.test-env index 3b17bb191..df783a4fd 100644 --- a/.test-env +++ b/.test-env @@ -3,6 +3,8 @@ SDK_TESTING_URL="https://github.com/algorand/algorand-sdk-testing" SDK_TESTING_BRANCH="master" SDK_TESTING_HARNESS="test-harness" +INSTALL_ONLY=0 + VERBOSE_HARNESS=0 # WARNING: If set to 1, new features will be LOST when downloading the test harness. diff --git a/Makefile b/Makefile index be60d45d2..609884968 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,10 @@ display-all-java-steps: find src/test/java/com/algorand/algosdk -name "*.java" | xargs grep "io.cucumber.java.en" 2>/dev/null | grep -v Binary | cut -d: -f1 | sort | uniq | xargs grep -E "@(Given|Then|When)" harness: - ./test-harness.sh + ./test-harness.sh up + +harness-down: + ./test-harness.sh down docker-javasdk-build: # Build SDK testing environment diff --git a/src/main/java/com/algorand/algosdk/v2/client/algod/GetBlockHash.java b/src/main/java/com/algorand/algosdk/v2/client/algod/GetBlockHash.java new file mode 100644 index 000000000..e07dd89fc --- /dev/null +++ b/src/main/java/com/algorand/algosdk/v2/client/algod/GetBlockHash.java @@ -0,0 +1,65 @@ +package com.algorand.algosdk.v2.client.algod; + +import com.algorand.algosdk.v2.client.common.Client; +import com.algorand.algosdk.v2.client.common.HttpMethod; +import com.algorand.algosdk.v2.client.common.Query; +import com.algorand.algosdk.v2.client.common.QueryData; +import com.algorand.algosdk.v2.client.common.Response; +import com.algorand.algosdk.v2.client.model.BlockHashResponse; + + +/** + * Get the block hash for the block on the given round. + * /v2/blocks/{round}/hash + */ +public class GetBlockHash extends Query { + + private Long round; + + /** + * @param round The round from which to fetch block hash information. + */ + public GetBlockHash(Client client, Long round) { + super(client, new HttpMethod("get")); + this.round = round; + } + + /** + * Execute the query. + * @return the query response object. + * @throws Exception + */ + @Override + public Response execute() throws Exception { + Response resp = baseExecute(); + resp.setValueType(BlockHashResponse.class); + return resp; + } + + /** + * Execute the query with custom headers, there must be an equal number of keys and values + * or else an error will be generated. + * @param headers an array of header keys + * @param values an array of header values + * @return the query response object. + * @throws Exception + */ + @Override + public Response execute(String[] headers, String[] values) throws Exception { + Response resp = baseExecute(headers, values); + resp.setValueType(BlockHashResponse.class); + return resp; + } + + protected QueryData getRequestString() { + if (this.round == null) { + throw new RuntimeException("round is not set. It is a required parameter."); + } + addPathSegment(String.valueOf("v2")); + addPathSegment(String.valueOf("blocks")); + addPathSegment(String.valueOf(round)); + addPathSegment(String.valueOf("hash")); + + return qd; + } +} 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 920996c26..f37482abf 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 @@ -10,6 +10,7 @@ import com.algorand.algosdk.v2.client.algod.AccountApplicationInformation; import com.algorand.algosdk.v2.client.algod.GetPendingTransactionsByAddress; import com.algorand.algosdk.v2.client.algod.GetBlock; +import com.algorand.algosdk.v2.client.algod.GetBlockHash; import com.algorand.algosdk.v2.client.algod.GetTransactionProof; import com.algorand.algosdk.v2.client.algod.GetSupply; import com.algorand.algosdk.v2.client.algod.GetStatus; @@ -141,6 +142,14 @@ public GetBlock GetBlock(Long round) { return new GetBlock((Client) this, round); } + /** + * Get the block hash for the block on the given round. + * /v2/blocks/{round}/hash + */ + public GetBlockHash GetBlockHash(Long round) { + return new GetBlockHash((Client) this, round); + } + /** * Get a proof for a transaction in a block. * /v2/blocks/{round}/transactions/{txid}/proof diff --git a/src/main/java/com/algorand/algosdk/v2/client/indexer/LookupBlock.java b/src/main/java/com/algorand/algosdk/v2/client/indexer/LookupBlock.java index 0e6d117cc..1794d77e3 100644 --- a/src/main/java/com/algorand/algosdk/v2/client/indexer/LookupBlock.java +++ b/src/main/java/com/algorand/algosdk/v2/client/indexer/LookupBlock.java @@ -24,6 +24,15 @@ public LookupBlock(Client client, Long roundNumber) { this.roundNumber = roundNumber; } + /** + * Header only flag. When this is set to true, returned block does not contain the + * transactions + */ + public LookupBlock headerOnly(Boolean headerOnly) { + addQuery("header-only", String.valueOf(headerOnly)); + return this; + } + /** * Execute the query. * @return the query response object. 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 83078c5ee..dc4feb686 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 @@ -33,6 +33,12 @@ public String genesisHash() { @JsonProperty("genesis-id") public String genesisId; + /** + * Participation account data that needs to be checked/acted on by the network. + */ + @JsonProperty("participation-updates") + public ParticipationUpdates participationUpdates; + /** * (prev) Previous block hash. */ @@ -150,6 +156,7 @@ public boolean equals(Object o) { Block other = (Block) o; if (!Objects.deepEquals(this.genesisHash, other.genesisHash)) return false; if (!Objects.deepEquals(this.genesisId, other.genesisId)) return false; + if (!Objects.deepEquals(this.participationUpdates, other.participationUpdates)) return false; if (!Objects.deepEquals(this.previousBlockHash, other.previousBlockHash)) return false; if (!Objects.deepEquals(this.rewards, other.rewards)) return false; if (!Objects.deepEquals(this.round, other.round)) return false; diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/BlockHashResponse.java b/src/main/java/com/algorand/algosdk/v2/client/model/BlockHashResponse.java new file mode 100644 index 000000000..8ccb0e91a --- /dev/null +++ b/src/main/java/com/algorand/algosdk/v2/client/model/BlockHashResponse.java @@ -0,0 +1,30 @@ +package com.algorand.algosdk.v2.client.model; + +import java.util.Objects; + +import com.algorand.algosdk.v2.client.common.PathResponse; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Hash of a block header. + */ +public class BlockHashResponse extends PathResponse { + + /** + * Block header hash. + */ + @JsonProperty("blockHash") + public String blockHash; + + @Override + public boolean equals(Object o) { + + if (this == o) return true; + if (o == null) return false; + + BlockHashResponse other = (BlockHashResponse) o; + if (!Objects.deepEquals(this.blockHash, other.blockHash)) return false; + + return true; + } +} diff --git a/src/main/java/com/algorand/algosdk/v2/client/model/ParticipationUpdates.java b/src/main/java/com/algorand/algosdk/v2/client/model/ParticipationUpdates.java new file mode 100644 index 000000000..554274a9a --- /dev/null +++ b/src/main/java/com/algorand/algosdk/v2/client/model/ParticipationUpdates.java @@ -0,0 +1,33 @@ +package com.algorand.algosdk.v2.client.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import com.algorand.algosdk.v2.client.common.PathResponse; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Participation account data that needs to be checked/acted on by the network. + */ +public class ParticipationUpdates extends PathResponse { + + /** + * (partupdrmv) a list of online accounts that needs to be converted to offline + * since their participation key expired. + */ + @JsonProperty("expired-participation-accounts") + public List expiredParticipationAccounts = new ArrayList(); + + @Override + public boolean equals(Object o) { + + if (this == o) return true; + if (o == null) return false; + + ParticipationUpdates other = (ParticipationUpdates) o; + if (!Objects.deepEquals(this.expiredParticipationAccounts, other.expiredParticipationAccounts)) return false; + + return true; + } +} diff --git a/src/test/java/com/algorand/algosdk/unit/AlgodPaths.java b/src/test/java/com/algorand/algosdk/unit/AlgodPaths.java index 59bae3fd3..222fdace5 100644 --- a/src/test/java/com/algorand/algosdk/unit/AlgodPaths.java +++ b/src/test/java/com/algorand/algosdk/unit/AlgodPaths.java @@ -98,4 +98,9 @@ public void getLightBlockHeaderProof(Long round) { public void getStateProof(Long round) { ps.q = algodClient.GetStateProof(round); } + + @When("we make a Lookup Block Hash call against round {long}") + public void getBlockHash(Long round) { + ps.q = algodClient.GetBlockHash(round); + } } diff --git a/src/test/java/com/algorand/algosdk/unit/IndexerPaths.java b/src/test/java/com/algorand/algosdk/unit/IndexerPaths.java index 8c9cb43e8..2af398823 100644 --- a/src/test/java/com/algorand/algosdk/unit/IndexerPaths.java +++ b/src/test/java/com/algorand/algosdk/unit/IndexerPaths.java @@ -333,4 +333,11 @@ public void searchForApplications(String string) { ps.q = q; } + + @When("we make a Lookup Block call against round {long} and header {string}") + public void anyBlockLookupCall(Long round, String headerOnly) { + LookupBlock q = this.indexerClient.lookupBlock(round); + if (headerOnly.contentEquals("true")) q.headerOnly(true); + ps.q = q; + } } diff --git a/src/test/java/com/algorand/algosdk/unit/ResponsesShared.java b/src/test/java/com/algorand/algosdk/unit/ResponsesShared.java index ae4f37c96..2565d51cd 100644 --- a/src/test/java/com/algorand/algosdk/unit/ResponsesShared.java +++ b/src/test/java/com/algorand/algosdk/unit/ResponsesShared.java @@ -191,6 +191,9 @@ public void we_make_any_call_to(String client, String endpoint) throws Exception Response r = algod.GetStateProof(1234L).execute(); response = r; break; + case "GetBlockHash": + response = algod.GetBlockHash(1234L).execute(); + break; default: Assertions.fail("Unsupported algod endpoint: " + endpoint); } diff --git a/src/test/unit.tags b/src/test/unit.tags index a3f91cec3..0c4b9f876 100644 --- a/src/test/unit.tags +++ b/src/test/unit.tags @@ -4,6 +4,7 @@ @unit.algod.ledger_refactoring @unit.applications @unit.atomic_transaction_composer +@unit.blocksummary @unit.dryrun @unit.dryrun.trace.application @unit.feetest @@ -19,6 +20,7 @@ @unit.responses.messagepack @unit.responses.messagepack.231 @unit.responses.unlimited_assets +@unit.responses.blocksummary @unit.sourcemap @unit.stateproof.paths @unit.stateproof.responses diff --git a/test-harness.sh b/test-harness.sh index a5d28a781..c348966d4 100755 --- a/test-harness.sh +++ b/test-harness.sh @@ -1,6 +1,47 @@ #!/usr/bin/env bash set -euo pipefail +# test-harness.sh setup/start cucumber test environment. +# +# Configuration is managed with environment variables, the ones you +# are most likely to reconfigured are stored in '.test-env'. +# +# Variables: +# SDK_TESTING_URL - URL to algorand-sdk-testing, useful for forks. +# SDK_TESTING_BRANCH - branch to checkout, useful for new tests. +# SDK_TESTING_HARNESS - local directory that the algorand-sdk-testing repo is cloned into. +# VERBOSE_HARNESS - more output while the script runs. +# INSTALL_ONLY - installs feature files only, useful for unit tests. +# +# WARNING: If set to 1, new features will be LOST when downloading the test harness. +# REGARDLESS: modified features are ALWAYS overwritten. +# REMOVE_LOCAL_FEATURES - delete all local cucumber feature files before downloading these from github. +# +# WARNING: Be careful when turning on the next variable. +# In that case you'll need to provide all variables expected by `algorand-sdk-testing`'s `.env` +# OVERWRITE_TESTING_ENVIRONMENT=0 + +SHUTDOWN=0 +if [ $# -ne 0 ]; then + if [ $# -ne 1 ]; then + echo "this script accepts a single argument, which must be 'up' or 'down'." + exit 1 + fi + + case $1 in + 'up') + ;; # default. + 'down') + SHUTDOWN=1 + ;; + *) + echo "unknown parameter '$1'." + echo "this script accepts a single argument, which must be 'up' or 'down'." + exit 1 + ;; + esac +fi + START=$(date "+%s") THIS=$(basename "$0") @@ -23,10 +64,19 @@ if [ -d "$SDK_TESTING_HARNESS" ]; then ./scripts/down.sh popd rm -rf "$SDK_TESTING_HARNESS" + if [[ $SHUTDOWN == 1 ]]; then + echo "$THIS: network shutdown complete." + exit 0 + fi else echo "$THIS: directory $SDK_TESTING_HARNESS does not exist - NOOP" fi +if [[ $SHUTDOWN == 1 ]]; then + echo "$THIS: unable to shutdown network." + exit 1 +fi + git clone --depth 1 --single-branch --branch "$SDK_TESTING_BRANCH" "$SDK_TESTING_URL" "$SDK_TESTING_HARNESS" @@ -63,6 +113,11 @@ if [[ $VERBOSE_HARNESS == 1 ]]; then fi echo "$THIS: seconds it took to get to end of cloning and copying: $(($(date "+%s") - START))s" +if [[ $INSTALL_ONLY == 1 ]]; then + echo "$THIS: configured to install feature files only. Not starting test harness environment." + exit 0 +fi + ## Start test harness environment pushd "$SDK_TESTING_HARNESS" From f4186e4dd1da412e37094b6b5005960a9fcd19ae Mon Sep 17 00:00:00 2001 From: Barbara Poon Date: Tue, 11 Oct 2022 16:43:09 -0400 Subject: [PATCH 2/2] bump to 1.20.0 --- CHANGELOG.md | 5 +++++ README.md | 2 +- pom.xml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01b89e70e..19c94e171 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.20.0 + +### Enhancements +* REST API: Add algod block hash endpoint, add indexer block header-only param. by @winder in https://github.com/algorand/java-algorand-sdk/pull/413 + # 1.19.0 ### Enhancements diff --git a/README.md b/README.md index 66b0fdff8..3201a8f04 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Maven: com.algorand algosdk - 1.19.0 + 1.20.0 ``` diff --git a/pom.xml b/pom.xml index 0f6585109..1544dfa91 100755 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.algorand algosdk - 1.19.0 + 1.20.0 jar ${project.groupId}:${project.artifactId}