Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FOR REVIEW ONLY: java-algorand-sdk 2.6.0 #765

Merged
merged 5 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- run: mvn test
integration-test:
machine:
image: "ubuntu-2204:2022.04.2"
image: "ubuntu-2204:2022.10.2"
resource_class: medium
steps:
- checkout
Expand Down
2 changes: 1 addition & 1 deletion .test-env
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Configs for testing repo download:
SDK_TESTING_URL="https://github.com/algorand/algorand-sdk-testing"
SDK_TESTING_BRANCH="V2"
SDK_TESTING_BRANCH="master"
SDK_TESTING_HARNESS="test-harness"

INSTALL_ONLY=0
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# 2.6.0

<!-- Release notes generated using configuration in .github/release.yml at release/2.6.0 -->

## What's Changed
### Enhancements
* Simulate: Support `fixSigners` option by @github-actions in https://github.com/algorand/java-algorand-sdk/pull/721
* Incentives: Support heartbeat txn, Java 8 Min Version by @algorandskiy in https://github.com/algorand/java-algorand-sdk/pull/758


**Full Changelog**: https://github.com/algorand/java-algorand-sdk/compare/2.5.0...2.6.0

# 2.5.0

<!-- Release notes generated using configuration in .github/release.yml at release/2.5.0 -->
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Maven:
<dependency>
<groupId>com.algorand</groupId>
<artifactId>algosdk</artifactId>
<version>2.5.0</version>
<version>2.6.0</version>
</dependency>
```

Expand Down
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>com.algorand</groupId>
<artifactId>algosdk</artifactId>
<version>2.5.0</version>
<version>2.6.0</version>
<packaging>jar</packaging>

<name>${project.groupId}:${project.artifactId}</name>
Expand Down Expand Up @@ -42,8 +42,8 @@
<maven.surefire.version>3.0.0-M5</maven.surefire.version>

<!-- Test sources at 1.8 to allow using JUnit5 -->
<java.version>1.7</java.version>
<java.release.version>7</java.release.version>
<java.version>1.8</java.version>
<java.release.version>8</java.release.version>
<java.test.release.version>8</java.test.release.version>

<!-- github server corresponds to entry in ~/.m2/settings.xml -->
Expand Down
74 changes: 74 additions & 0 deletions src/main/java/com/algorand/algosdk/transaction/HeartbeatProof.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.algorand.algosdk.transaction;

import java.io.Serializable;
import java.util.Objects;

import com.algorand.algosdk.crypto.*;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;


@JsonPropertyOrder(alphabetic = true)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
public class HeartbeatProof implements Serializable {
@JsonProperty("s")
public Signature sig = new Signature();

@JsonProperty("p")
public Ed25519PublicKey pk = new Ed25519PublicKey();

@JsonProperty("p2")
public Ed25519PublicKey pk2 = new Ed25519PublicKey();

@JsonProperty("p1s")
public Signature pk1Sig = new Signature();

@JsonProperty("p2s")
public Signature pk2Sig = new Signature();

public HeartbeatProof() {}

public HeartbeatProof(
Signature sig,
Ed25519PublicKey pk,
Ed25519PublicKey pk2,
Signature pk1Sig,
Signature pk2Sig
) {
this.sig = Objects.requireNonNull(sig, "sig must not be null");
this.pk = Objects.requireNonNull(pk, "pk must not be null");
this.pk2 = Objects.requireNonNull(pk2, "pk2 must not be null");
this.pk1Sig = Objects.requireNonNull(pk1Sig, "pk1Sig must not be null");
this.pk2Sig = Objects.requireNonNull(pk2Sig, "pk2Sig must not be null");
}

@JsonCreator
public HeartbeatProof(
@JsonProperty("s") byte[] sig,
@JsonProperty("p") byte[] pk,
@JsonProperty("p2") byte[] pk2,
@JsonProperty("p1s") byte[] pk1Sig,
@JsonProperty("p2s") byte[] pk2Sig
) {
this.sig = new Signature(sig);
this.pk = new Ed25519PublicKey(pk);
this.pk2 = new Ed25519PublicKey(pk2);
this.pk1Sig = new Signature(pk1Sig);
this.pk2Sig = new Signature(pk2Sig);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HeartbeatProof that = (HeartbeatProof) o;
return Objects.equals(sig, that.sig) &&
Objects.equals(pk, that.pk) &&
Objects.equals(pk2, that.pk2) &&
Objects.equals(pk1Sig, that.pk1Sig) &&
Objects.equals(pk2Sig, that.pk2Sig);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.algorand.algosdk.transaction;

import java.io.Serializable;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Objects;

import com.algorand.algosdk.crypto.*;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonPropertyOrder(alphabetic = true)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
public class HeartbeatTxnFields implements Serializable {
@JsonProperty("a")
public Address hbAddress = new Address();

@JsonProperty("prf")
public HeartbeatProof hbProof = new HeartbeatProof();

@JsonProperty("sd")
public byte[] hbSeed = new byte[32]; // committee.Seed

@JsonProperty("vid")
public ParticipationPublicKey hbVoteID = new ParticipationPublicKey();

@JsonProperty("kd")
public BigInteger hbKeyDilution = BigInteger.valueOf(0);

public HeartbeatTxnFields() {}

public HeartbeatTxnFields(
Address hbAddress,
HeartbeatProof hbProof,
byte[] hbSeed,
ParticipationPublicKey hbVoteID,
BigInteger hbKeyDilution
) {
this.hbAddress = Objects.requireNonNull(hbAddress, "hbAddress must not be null");
this.hbProof = Objects.requireNonNull(hbProof, "hbProof must not be null");
this.hbVoteID = Objects.requireNonNull(hbVoteID, "hbVoteID must not be null");
this.hbKeyDilution = Objects.requireNonNull(hbKeyDilution, "hbKeyDilution must not be null");
if (hbSeed == null) {
throw new NullPointerException("hbSeed must not be null");
}
System.arraycopy(hbSeed, 0, this.hbSeed, 0, this.hbSeed.length);
}

@JsonCreator
public HeartbeatTxnFields(
@JsonProperty("a") byte[] hbAddress,
@JsonProperty("prf") HeartbeatProof hbProof,
@JsonProperty("sd") byte[] hbSeed,
@JsonProperty("vid") byte[] hbVoteID,
@JsonProperty("kd") BigInteger hbKeyDilution
) {
if (hbAddress != null) {
this.hbAddress = new Address(hbAddress);
}
if (hbProof != null) {
this.hbProof = hbProof;
}
if (hbSeed != null) {
System.arraycopy(hbSeed, 0, this.hbSeed, 0, this.hbSeed.length);
}
if (hbVoteID != null) {
this.hbVoteID = new ParticipationPublicKey(hbVoteID);
}
if (hbKeyDilution != null) {
this.hbKeyDilution = hbKeyDilution;
}
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HeartbeatTxnFields that = (HeartbeatTxnFields) o;
return hbAddress.equals(that.hbAddress) &&
hbProof.equals(that.hbProof) &&
Arrays.equals(hbSeed, that.hbSeed) &&
hbVoteID.equals(that.hbVoteID) &&
hbKeyDilution.equals(that.hbKeyDilution);
}
}
20 changes: 15 additions & 5 deletions src/main/java/com/algorand/algosdk/transaction/Transaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ public class Transaction implements Serializable {
@JsonProperty("spmsg")
public Map<String,Object> stateProofMessage = null;

@JsonProperty("hb")
public HeartbeatTxnFields heartbeatFields = new HeartbeatTxnFields();

/**
* Helper for Jackson conversion.
*/
Expand Down Expand Up @@ -238,7 +241,9 @@ private Transaction(@JsonProperty("type") Type type,
@JsonProperty("apid") Long applicationId,
@JsonProperty("apls") StateSchema localStateSchema,
@JsonProperty("apsu") byte[] clearStateProgram,
@JsonProperty("apep") Long extraPages
@JsonProperty("apep") Long extraPages,
// heartbeat fields
@JsonProperty("hb") HeartbeatTxnFields heartbeatFields
) throws IOException {
this(
type,
Expand Down Expand Up @@ -289,7 +294,8 @@ private Transaction(@JsonProperty("type") Type type,
applicationId,
localStateSchema,
clearStateProgram == null ? null : new TEALProgram(clearStateProgram),
extraPages
extraPages,
heartbeatFields
);
}

Expand Down Expand Up @@ -348,7 +354,8 @@ private Transaction(
Long applicationId,
StateSchema localStateSchema,
TEALProgram clearStateProgram,
Long extraPages
Long extraPages,
HeartbeatTxnFields heartbeatFields
) {
if (type != null) this.type = type;
if (sender != null) this.sender = sender;
Expand Down Expand Up @@ -393,6 +400,7 @@ private Transaction(
if (localStateSchema != null) this.localStateSchema = localStateSchema;
if (clearStateProgram != null) this.clearStateProgram = clearStateProgram;
if (extraPages != null) this.extraPages = extraPages;
if (heartbeatFields != null) this.heartbeatFields = heartbeatFields;
}

// Used by Jackson to determine "default" values.
Expand Down Expand Up @@ -433,7 +441,8 @@ public enum Type {
AssetTransfer("axfer"),
AssetFreeze("afrz"),
ApplicationCall("appl"),
StateProof("stpf");
StateProof("stpf"),
Heartbeat("hb");

private static Map<String, Type> namesMap = new HashMap<String, Type>(6);

Expand Down Expand Up @@ -604,7 +613,8 @@ public boolean equals(Object o) {
freezeState == that.freezeState &&
rekeyTo.equals(that.rekeyTo) &&
extraPages.equals(that.extraPages) &&
boxReferences.equals(that.boxReferences);
boxReferences.equals(that.boxReferences) &&
heartbeatFields.equals(that.heartbeatFields);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@


/**
* Given a specific account public key, this call returns the accounts status,
* Given a specific account public key, this call returns the account's status,
* balance and spendable amounts
* /v2/accounts/{address}
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
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.BlockHeaderResponse;


/**
* Get the block header for the block on the given round.
* /v2/blocks/{round}/header
*/
public class GetBlockHeader extends Query {

private Long round;

/**
* @param round The round from which to fetch block header information.
*/
public GetBlockHeader(Client client, Long round) {
super(client, new HttpMethod("get"));
addQuery("format", "msgpack");
this.round = round;
}

/**
* Execute the query.
* @return the query response object.
* @throws Exception
*/
@Override
public Response<BlockHeaderResponse> execute() throws Exception {
Response<BlockHeaderResponse> resp = baseExecute();
resp.setValueType(BlockHeaderResponse.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<BlockHeaderResponse> execute(String[] headers, String[] values) throws Exception {
Response<BlockHeaderResponse> resp = baseExecute(headers, values);
resp.setValueType(BlockHeaderResponse.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("header"));

return qd;
}
}
Loading
Loading