Skip to content

Commit 69d92ca

Browse files
authored
tests: add resource reordering test (#872)
1 parent 1561fd1 commit 69d92ca

File tree

2 files changed

+58
-16
lines changed

2 files changed

+58
-16
lines changed

src/main/java/com/algorand/algosdk/builder/transaction/ApplicationBaseTransactionBuilder.java

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import com.algorand.algosdk.transaction.AccessConverter;
55
import com.algorand.algosdk.transaction.AppBoxReference;
66
import com.algorand.algosdk.transaction.AppResourceRef;
7-
import com.algorand.algosdk.transaction.ResourceRef;
87
import com.algorand.algosdk.transaction.Transaction;
98
import com.algorand.algosdk.util.Encoder;
109

@@ -14,27 +13,27 @@
1413

1514
@SuppressWarnings("unchecked")
1615
public abstract class ApplicationBaseTransactionBuilder<T extends ApplicationBaseTransactionBuilder<T>> extends TransactionBuilder<T> implements ApplicationCallReferencesSetter<T> {
17-
16+
1817
/**
1918
* Represents a holding reference for asset holdings of an account.
2019
*/
2120
public static class HoldingReference {
2221
public final Address address;
2322
public final long assetId;
24-
23+
2524
public HoldingReference(Address address, long assetId) {
2625
this.address = address;
2726
this.assetId = assetId;
2827
}
2928
}
30-
29+
3130
/**
3231
* Represents a locals reference for local state of an account in an app.
3332
*/
3433
public static class LocalsReference {
3534
public final Address address;
3635
public final long appId;
37-
36+
3837
public LocalsReference(Address address, long appId) {
3938
this.address = address;
4039
this.appId = appId;
@@ -68,7 +67,7 @@ protected void applyTo(Transaction txn) {
6867
// Check if advanced features are being used
6968
boolean hasAdvancedFeatures = (holdings != null && !holdings.isEmpty()) ||
7069
(locals != null && !locals.isEmpty());
71-
70+
7271
if (useAccess) {
7372
// Using access field mode - translate all references into access list
7473
List<AppResourceRef> allRefs = new ArrayList<>();
@@ -78,19 +77,19 @@ protected void applyTo(Transaction txn) {
7877
allRefs.add(AppResourceRef.forAddress(account));
7978
}
8079
}
81-
80+
8281
if (foreignApps != null && !foreignApps.isEmpty()) {
8382
for (Long appId : foreignApps) {
8483
allRefs.add(AppResourceRef.forApp(appId));
8584
}
8685
}
87-
86+
8887
if (foreignAssets != null && !foreignAssets.isEmpty()) {
8988
for (Long assetId : foreignAssets) {
9089
allRefs.add(AppResourceRef.forAsset(assetId));
9190
}
9291
}
93-
92+
9493
if (appBoxReferences != null && !appBoxReferences.isEmpty()) {
9594
for (AppBoxReference boxRef : appBoxReferences) {
9695
allRefs.add(AppResourceRef.forBox(boxRef.getAppId(), boxRef.getName()));
@@ -102,23 +101,23 @@ protected void applyTo(Transaction txn) {
102101
allRefs.add(AppResourceRef.forHolding(holdingRef.address, holdingRef.assetId));
103102
}
104103
}
105-
104+
106105
if (locals != null && !locals.isEmpty()) {
107106
for (LocalsReference localsRef : locals) {
108107
allRefs.add(AppResourceRef.forLocals(localsRef.address, localsRef.appId));
109108
}
110109
}
111110

112111
txn.access = AccessConverter.convertToResourceRefs(allRefs, sender, applicationId);
113-
112+
114113
} else {
115114
// Using legacy fields mode
116115
if (hasAdvancedFeatures) {
117116
throw new IllegalArgumentException(
118117
"Holdings and locals references require useAccess=true as they cannot be represented in legacy transaction format"
119118
);
120119
}
121-
120+
122121
// Use legacy fields directly
123122
if (accounts != null) txn.accounts = accounts;
124123
if (foreignApps != null) txn.foreignApps = foreignApps;
@@ -203,8 +202,8 @@ public T boxReferences(List<AppBoxReference> boxReferences) {
203202
/**
204203
* Set asset holding references that need to be accessible in this transaction.
205204
* Holdings references allow the transaction to access asset balances of specific accounts.
206-
*
207-
* Note: Holdings references are only available when useAccess=true as they cannot be
205+
*
206+
* Note: Holdings references are only available when useAccess=true as they cannot be
208207
* represented in legacy transaction format.
209208
*/
210209
public T holdings(List<HoldingReference> holdings) {
@@ -215,8 +214,8 @@ public T holdings(List<HoldingReference> holdings) {
215214
/**
216215
* Set local state references that need to be accessible in this transaction.
217216
* Locals references allow the transaction to access local state of specific accounts in specific apps.
218-
*
219-
* Note: Locals references are only available when useAccess=true as they cannot be
217+
*
218+
* Note: Locals references are only available when useAccess=true as they cannot be
220219
* represented in legacy transaction format.
221220
*/
222221
public T locals(List<LocalsReference> locals) {

src/test/java/com/algorand/algosdk/transaction/TestTransaction.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.algorand.algosdk.transaction;
22

33
import com.algorand.algosdk.account.Account;
4+
import com.algorand.algosdk.builder.transaction.ApplicationBaseTransactionBuilder.HoldingReference;
45
import com.algorand.algosdk.crypto.*;
56
import com.algorand.algosdk.mnemonic.Mnemonic;
7+
import com.algorand.algosdk.unit.utils.TestingUtils;
68
import com.algorand.algosdk.util.Encoder;
79
import com.algorand.algosdk.util.TestUtil;
810
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -14,6 +16,7 @@
1416
import java.math.BigInteger;
1517
import java.nio.charset.StandardCharsets;
1618
import java.security.NoSuchAlgorithmException;
19+
import java.util.ArrayList;
1720
import java.util.Arrays;
1821
import java.util.Base64;
1922

@@ -1121,4 +1124,44 @@ public void testApplicationCallRejectVersion() throws Exception {
11211124
assertThat(txExplicitZeroJson).doesNotContain("aprv");
11221125
}
11231126

1127+
@Test
1128+
public void testApplicationCallAccessOrdering() throws Exception {
1129+
Address from = new Address("BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4");
1130+
byte[] gh = Encoder.decodeFromBase64("SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=");
1131+
1132+
Address addr1 = new Address("FDMKB5D72THLYSJEBHBDHUE7XFRDOM5IHO44SOJ7AWPD6EZMWOQ2WKN7HQ");
1133+
HoldingReference holding = new HoldingReference(addr1, 123L);
1134+
1135+
Transaction tx = Transaction.ApplicationCallTransactionBuilder()
1136+
.sender(from)
1137+
.applicationId(111L)
1138+
.firstValid(322575)
1139+
.lastValid(322575)
1140+
.genesisHash(gh)
1141+
.holdings(Arrays.asList(holding))
1142+
.useAccess(true)
1143+
.build();
1144+
1145+
// Verify access field ordering
1146+
assertThat(tx.access.size()).isEqualTo(3);
1147+
assertThat(tx.access.get(2).holding.addressIndex).isEqualTo(1); // index=1
1148+
1149+
// Make a deep copy
1150+
String encoded = Encoder.encodeToBase64(Encoder.encodeToMsgPack(tx));
1151+
Transaction tx2 = Encoder.decodeFromMsgPack(encoded, tx.getClass());
1152+
assertEqual(tx, tx2);
1153+
1154+
// Reorder holdings
1155+
ArrayList<ResourceRef> reorderedAccess = new ArrayList<>();
1156+
reorderedAccess.add(tx.access.get(2)); // index=1
1157+
reorderedAccess.add(tx.access.get(0)); // index=0
1158+
reorderedAccess.add(tx.access.get(1)); // index=2
1159+
tx.access = reorderedAccess;
1160+
1161+
TestUtil.serializeDeserializeCheck(tx);
1162+
1163+
encoded = Encoder.encodeToBase64(Encoder.encodeToMsgPack(tx));
1164+
Transaction decoded = Encoder.decodeFromMsgPack(encoded, tx.getClass());
1165+
assertEqual(tx2, decoded);
1166+
}
11241167
}

0 commit comments

Comments
 (0)