Skip to content

Commit be204c1

Browse files
authored
StateProofs: Add State Proof support. (#360)
* Regenerate client. * Implement cucumber response tests. * Implement path tests, update Makefile, update README. * Revert * Add state proof fields to Transaction. * Update README.md * Update src/main/java/com/algorand/algosdk/transaction/Transaction.java * publish results. * Add transaction-root-256
1 parent d9b2699 commit be204c1

31 files changed

+983
-780
lines changed

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,14 @@ mvn clean site -P github,default # for javadoc
236236
mvn clean deploy -P release,default
237237
```
238238

239+
# Testing
240+
241+
Many cross-SDK tests are defined in [algorand-sdk-testing](https://github.com/algorand/algorand-sdk-testing/). Some are integration tests with additional dependencies. These dependencies are containerized in a docker file, which can be executed with `make docker-test`.
242+
243+
It is occasionally useful to run locally, or against alternate integration branches. To do this:
244+
1. Install feature files for your test branch "./run_integration_tests.sh -feature-only -test-branch <branch here>"
245+
2. Run locally with `make integration` and `make unit`, or from the IDE by running "RunCucumberUnitTest.java"
246+
239247
# Android Support
240248

241249
Significant work has been taken to ensure Android compatibility (in particular for `minSdkVersion` 16). Note that the
@@ -252,7 +260,7 @@ A testing framework can also be generated with: `com.algorand.sdkutils.RunQueryM
252260

253261
## Regenerate the Client Code
254262

255-
To actually regenerate the code, use `run_generator.sh` with paths to the `*.oas2.json` files mentioned above.
263+
The actual generation is done using the `generate_java.sh` script in the [generator](https://github.com/algorand/generator/) repo.
256264

257265
# Updating the `kmd` REST client
258266
The `kmd` REST client has not been upgraded to use the new code generation, it is still largely autogenerated by `swagger-codegen`. [https://github.com/swagger-api/swagger-codegen]

src/main/java/com/algorand/algosdk/transaction/Transaction.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,16 @@ public class Transaction implements Serializable {
162162
@JsonProperty("apep")
163163
public Long extraPages = 0L;
164164

165+
/* state proof fields */
166+
@JsonProperty("sptype")
167+
public Integer stateProofType = null;
168+
169+
@JsonProperty("sp")
170+
public Map<String,Object> stateProof = null;
171+
172+
@JsonProperty("spmsg")
173+
public Map<String,Object> stateProofMessage = null;
174+
165175
/**
166176
* Create a payment transaction
167177
* @param fromAddr source address
@@ -722,7 +732,7 @@ private Transaction(@JsonProperty("type") Type type,
722732
}
723733

724734
/**
725-
* Constructor which takes all the fields of Transaction except for nonpart and state proof.
735+
* Constructor which takes all the fields of Transaction except for nonpart.
726736
* For details about which fields to use with different transaction types, refer to the developer documentation:
727737
* https://developer.algorand.org/docs/reference/transactions/#asset-transfer-transaction
728738
*/
@@ -1250,7 +1260,8 @@ public enum Type {
12501260
AssetConfig("acfg"),
12511261
AssetTransfer("axfer"),
12521262
AssetFreeze("afrz"),
1253-
ApplicationCall("appl");
1263+
ApplicationCall("appl"),
1264+
StateProof("stpf");
12541265

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

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.algorand.algosdk.v2.client.algod;
2+
3+
import com.algorand.algosdk.v2.client.common.Client;
4+
import com.algorand.algosdk.v2.client.common.HttpMethod;
5+
import com.algorand.algosdk.v2.client.common.Query;
6+
import com.algorand.algosdk.v2.client.common.QueryData;
7+
import com.algorand.algosdk.v2.client.common.Response;
8+
import com.algorand.algosdk.v2.client.model.LightBlockHeaderProof;
9+
10+
11+
/**
12+
* Gets a proof for a given light block header inside a state proof commitment
13+
* /v2/blocks/{round}/lightheader/proof
14+
*/
15+
public class GetLightBlockHeaderProof extends Query {
16+
17+
private Long round;
18+
19+
/**
20+
* @param round The round to which the light block header belongs.
21+
*/
22+
public GetLightBlockHeaderProof(Client client, Long round) {
23+
super(client, new HttpMethod("get"));
24+
this.round = round;
25+
}
26+
27+
/**
28+
* Execute the query.
29+
* @return the query response object.
30+
* @throws Exception
31+
*/
32+
@Override
33+
public Response<LightBlockHeaderProof> execute() throws Exception {
34+
Response<LightBlockHeaderProof> resp = baseExecute();
35+
resp.setValueType(LightBlockHeaderProof.class);
36+
return resp;
37+
}
38+
39+
/**
40+
* Execute the query with custom headers, there must be an equal number of keys and values
41+
* or else an error will be generated.
42+
* @param headers an array of header keys
43+
* @param values an array of header values
44+
* @return the query response object.
45+
* @throws Exception
46+
*/
47+
@Override
48+
public Response<LightBlockHeaderProof> execute(String[] headers, String[] values) throws Exception {
49+
Response<LightBlockHeaderProof> resp = baseExecute(headers, values);
50+
resp.setValueType(LightBlockHeaderProof.class);
51+
return resp;
52+
}
53+
54+
protected QueryData getRequestString() {
55+
if (this.round == null) {
56+
throw new RuntimeException("round is not set. It is a required parameter.");
57+
}
58+
addPathSegment(String.valueOf("v2"));
59+
addPathSegment(String.valueOf("blocks"));
60+
addPathSegment(String.valueOf(round));
61+
addPathSegment(String.valueOf("lightheader"));
62+
addPathSegment(String.valueOf("proof"));
63+
64+
return qd;
65+
}
66+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.algorand.algosdk.v2.client.algod;
2+
3+
import com.algorand.algosdk.v2.client.common.Client;
4+
import com.algorand.algosdk.v2.client.common.HttpMethod;
5+
import com.algorand.algosdk.v2.client.common.Query;
6+
import com.algorand.algosdk.v2.client.common.QueryData;
7+
import com.algorand.algosdk.v2.client.common.Response;
8+
import com.algorand.algosdk.v2.client.model.StateProof;
9+
10+
11+
/**
12+
* Get a state proof that covers a given round
13+
* /v2/stateproofs/{round}
14+
*/
15+
public class GetStateProof extends Query {
16+
17+
private Long round;
18+
19+
/**
20+
* @param round The round for which a state proof is desired.
21+
*/
22+
public GetStateProof(Client client, Long round) {
23+
super(client, new HttpMethod("get"));
24+
this.round = round;
25+
}
26+
27+
/**
28+
* Execute the query.
29+
* @return the query response object.
30+
* @throws Exception
31+
*/
32+
@Override
33+
public Response<StateProof> execute() throws Exception {
34+
Response<StateProof> resp = baseExecute();
35+
resp.setValueType(StateProof.class);
36+
return resp;
37+
}
38+
39+
/**
40+
* Execute the query with custom headers, there must be an equal number of keys and values
41+
* or else an error will be generated.
42+
* @param headers an array of header keys
43+
* @param values an array of header values
44+
* @return the query response object.
45+
* @throws Exception
46+
*/
47+
@Override
48+
public Response<StateProof> execute(String[] headers, String[] values) throws Exception {
49+
Response<StateProof> resp = baseExecute(headers, values);
50+
resp.setValueType(StateProof.class);
51+
return resp;
52+
}
53+
54+
protected QueryData getRequestString() {
55+
if (this.round == null) {
56+
throw new RuntimeException("round is not set. It is a required parameter.");
57+
}
58+
addPathSegment(String.valueOf("v2"));
59+
addPathSegment(String.valueOf("stateproofs"));
60+
addPathSegment(String.valueOf(round));
61+
62+
return qd;
63+
}
64+
}

src/main/java/com/algorand/algosdk/v2/client/algod/GetProof.java renamed to src/main/java/com/algorand/algosdk/v2/client/algod/GetTransactionProof.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
import com.algorand.algosdk.v2.client.common.QueryData;
77
import com.algorand.algosdk.v2.client.common.Response;
88
import com.algorand.algosdk.v2.client.model.Enums;
9-
import com.algorand.algosdk.v2.client.model.ProofResponse;
9+
import com.algorand.algosdk.v2.client.model.TransactionProofResponse;
1010

1111

1212
/**
13-
* Get a Merkle proof for a transaction in a block.
13+
* Get a proof for a transaction in a block.
1414
* /v2/blocks/{round}/transactions/{txid}/proof
1515
*/
16-
public class GetProof extends Query {
16+
public class GetTransactionProof extends Query {
1717

1818
private Long round;
1919
private String txid;
@@ -22,7 +22,7 @@ public class GetProof extends Query {
2222
* @param round The round in which the transaction appears.
2323
* @param txid The transaction ID for which to generate a proof.
2424
*/
25-
public GetProof(Client client, Long round, String txid) {
25+
public GetTransactionProof(Client client, Long round, String txid) {
2626
super(client, new HttpMethod("get"));
2727
addQuery("format", "msgpack");
2828
this.round = round;
@@ -34,7 +34,7 @@ public GetProof(Client client, Long round, String txid) {
3434
* sha512_256
3535
* sha256
3636
*/
37-
public GetProof hashtype(Enums.Hashtype hashtype) {
37+
public GetTransactionProof hashtype(Enums.Hashtype hashtype) {
3838
addQuery("hashtype", String.valueOf(hashtype));
3939
return this;
4040
}
@@ -45,9 +45,9 @@ public GetProof hashtype(Enums.Hashtype hashtype) {
4545
* @throws Exception
4646
*/
4747
@Override
48-
public Response<ProofResponse> execute() throws Exception {
49-
Response<ProofResponse> resp = baseExecute();
50-
resp.setValueType(ProofResponse.class);
48+
public Response<TransactionProofResponse> execute() throws Exception {
49+
Response<TransactionProofResponse> resp = baseExecute();
50+
resp.setValueType(TransactionProofResponse.class);
5151
return resp;
5252
}
5353

@@ -60,9 +60,9 @@ public Response<ProofResponse> execute() throws Exception {
6060
* @throws Exception
6161
*/
6262
@Override
63-
public Response<ProofResponse> execute(String[] headers, String[] values) throws Exception {
64-
Response<ProofResponse> resp = baseExecute(headers, values);
65-
resp.setValueType(ProofResponse.class);
63+
public Response<TransactionProofResponse> execute(String[] headers, String[] values) throws Exception {
64+
Response<TransactionProofResponse> resp = baseExecute(headers, values);
65+
resp.setValueType(TransactionProofResponse.class);
6666
return resp;
6767
}
6868

src/main/java/com/algorand/algosdk/v2/client/common/AlgodClient.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@
1010
import com.algorand.algosdk.v2.client.algod.AccountApplicationInformation;
1111
import com.algorand.algosdk.v2.client.algod.GetPendingTransactionsByAddress;
1212
import com.algorand.algosdk.v2.client.algod.GetBlock;
13-
import com.algorand.algosdk.v2.client.algod.GetProof;
13+
import com.algorand.algosdk.v2.client.algod.GetTransactionProof;
1414
import com.algorand.algosdk.v2.client.algod.GetSupply;
1515
import com.algorand.algosdk.v2.client.algod.GetStatus;
1616
import com.algorand.algosdk.v2.client.algod.WaitForBlock;
1717
import com.algorand.algosdk.v2.client.algod.RawTransaction;
1818
import com.algorand.algosdk.v2.client.algod.TransactionParams;
1919
import com.algorand.algosdk.v2.client.algod.GetPendingTransactions;
2020
import com.algorand.algosdk.v2.client.algod.PendingTransactionInformation;
21+
import com.algorand.algosdk.v2.client.algod.GetStateProof;
22+
import com.algorand.algosdk.v2.client.algod.GetLightBlockHeaderProof;
2123
import com.algorand.algosdk.v2.client.algod.GetApplicationByID;
2224
import com.algorand.algosdk.v2.client.algod.GetAssetByID;
2325
import com.algorand.algosdk.v2.client.algod.TealCompile;
@@ -140,12 +142,12 @@ public GetBlock GetBlock(Long round) {
140142
}
141143

142144
/**
143-
* Get a Merkle proof for a transaction in a block.
145+
* Get a proof for a transaction in a block.
144146
* /v2/blocks/{round}/transactions/{txid}/proof
145147
*/
146-
public GetProof GetProof(Long round,
148+
public GetTransactionProof GetTransactionProof(Long round,
147149
String txid) {
148-
return new GetProof((Client) this, round, txid);
150+
return new GetTransactionProof((Client) this, round, txid);
149151
}
150152

151153
/**
@@ -213,6 +215,22 @@ public PendingTransactionInformation PendingTransactionInformation(String txid)
213215
return new PendingTransactionInformation((Client) this, txid);
214216
}
215217

218+
/**
219+
* Get a state proof that covers a given round
220+
* /v2/stateproofs/{round}
221+
*/
222+
public GetStateProof GetStateProof(Long round) {
223+
return new GetStateProof((Client) this, round);
224+
}
225+
226+
/**
227+
* Gets a proof for a given light block header inside a state proof commitment
228+
* /v2/blocks/{round}/lightheader/proof
229+
*/
230+
public GetLightBlockHeaderProof GetLightBlockHeaderProof(Long round) {
231+
return new GetLightBlockHeaderProof((Client) this, round);
232+
}
233+
216234
/**
217235
* Given a application ID, it returns application information including creator,
218236
* approval and clear programs, global and local schemas, and global state.

src/main/java/com/algorand/algosdk/v2/client/model/Block.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ public String seed() {
6969
}
7070
public byte[] seed;
7171

72+
/**
73+
* Tracks the status of state proofs.
74+
*/
75+
@JsonProperty("state-proof-tracking")
76+
public List<StateProofTracking> stateProofTracking = new ArrayList<StateProofTracking>();
77+
7278
/**
7379
* (ts) Block creation timestamp in seconds since eposh
7480
*/
@@ -98,6 +104,21 @@ public String transactionsRoot() {
98104
}
99105
public byte[] transactionsRoot;
100106

107+
/**
108+
* (txn256) TransactionsRootSHA256 is an auxiliary TransactionRoot, built using a
109+
* vector commitment instead of a merkle tree, and SHA256 hash function instead of
110+
* the default SHA512_256. This commitment can be used on environments where only
111+
* the SHA256 function exists.
112+
*/
113+
@JsonProperty("transactions-root-sha256")
114+
public void transactionsRootSha256(String base64Encoded) {
115+
this.transactionsRootSha256 = Encoder.decodeFromBase64(base64Encoded);
116+
}
117+
public String transactionsRootSha256() {
118+
return Encoder.encodeToBase64(this.transactionsRootSha256);
119+
}
120+
public byte[] transactionsRootSha256;
121+
101122
/**
102123
* (tc) TxnCounter counts the number of transactions committed in the ledger, from
103124
* the time at which support for this feature was introduced.
@@ -133,9 +154,11 @@ public boolean equals(Object o) {
133154
if (!Objects.deepEquals(this.rewards, other.rewards)) return false;
134155
if (!Objects.deepEquals(this.round, other.round)) return false;
135156
if (!Objects.deepEquals(this.seed, other.seed)) return false;
157+
if (!Objects.deepEquals(this.stateProofTracking, other.stateProofTracking)) return false;
136158
if (!Objects.deepEquals(this.timestamp, other.timestamp)) return false;
137159
if (!Objects.deepEquals(this.transactions, other.transactions)) return false;
138160
if (!Objects.deepEquals(this.transactionsRoot, other.transactionsRoot)) return false;
161+
if (!Objects.deepEquals(this.transactionsRootSha256, other.transactionsRootSha256)) return false;
139162
if (!Objects.deepEquals(this.txnCounter, other.txnCounter)) return false;
140163
if (!Objects.deepEquals(this.upgradeState, other.upgradeState)) return false;
141164
if (!Objects.deepEquals(this.upgradeVote, other.upgradeVote)) return false;

src/main/java/com/algorand/algosdk/v2/client/model/Enums.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ public static SigType forValue(String value) {
191191
* (axfer) asset-transfer-transaction
192192
* (afrz) asset-freeze-transaction
193193
* (appl) application-transaction
194+
* (stpf) state-proof-transaction
194195
*/
195196
public enum TxType {
196197
@JsonProperty("pay") PAY("pay"),
@@ -199,6 +200,7 @@ public enum TxType {
199200
@JsonProperty("axfer") AXFER("axfer"),
200201
@JsonProperty("afrz") AFRZ("afrz"),
201202
@JsonProperty("appl") APPL("appl"),
203+
@JsonProperty("stpf") STPF("stpf"),
202204
@JsonProperty("") UNKNOWN("");
203205

204206
final String serializedName;

0 commit comments

Comments
 (0)