From 894754f784ec381ad70706891412c0a3075830c7 Mon Sep 17 00:00:00 2001
From: overcat <4catcode@gmail.com>
Date: Sun, 13 Aug 2023 11:26:28 +0800
Subject: [PATCH 1/6] Add SorobanDataBuilder to prepare sorobanData easily.
---
.../org/stellar/sdk/SorobanDataBuilder.java | 173 ++++++++++++++++++
.../java/org/stellar/sdk/Transaction.java | 2 +-
.../org/stellar/sdk/TransactionBuilder.java | 12 +-
.../stellar/sdk/SorobanDataBuilderTest.java | 161 ++++++++++++++++
.../org/stellar/sdk/SorobanServerTest.java | 63 ++++---
5 files changed, 372 insertions(+), 39 deletions(-)
create mode 100644 src/main/java/org/stellar/sdk/SorobanDataBuilder.java
create mode 100644 src/test/java/org/stellar/sdk/SorobanDataBuilderTest.java
diff --git a/src/main/java/org/stellar/sdk/SorobanDataBuilder.java b/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
new file mode 100644
index 000000000..3368f7275
--- /dev/null
+++ b/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
@@ -0,0 +1,173 @@
+package org.stellar.sdk;
+
+import java.io.IOException;
+import java.util.Collection;
+import javax.annotation.Nullable;
+import org.stellar.sdk.xdr.ExtensionPoint;
+import org.stellar.sdk.xdr.Int64;
+import org.stellar.sdk.xdr.LedgerFootprint;
+import org.stellar.sdk.xdr.LedgerKey;
+import org.stellar.sdk.xdr.SorobanResources;
+import org.stellar.sdk.xdr.SorobanTransactionData;
+import org.stellar.sdk.xdr.Uint32;
+import org.stellar.sdk.xdr.XdrUnsignedInteger;
+
+/**
+ * Supports building {@link SorobanTransactionData} structures with various items set to specific
+ * values.
+ *
+ *
This is recommended for when you are building {@link BumpFootprintExpirationOperation} {@link
+ * RestoreFootprintOperation} operations to avoid (re)building the entire data structure from
+ * scratch.
+ */
+public class SorobanDataBuilder {
+ private final SorobanTransactionData data;
+
+ /** Creates a new builder with an empty {@link SorobanTransactionData}. */
+ public SorobanDataBuilder() {
+ data =
+ new SorobanTransactionData.Builder()
+ .resources(
+ new SorobanResources.Builder()
+ .footprint(
+ new LedgerFootprint.Builder()
+ .readOnly(new LedgerKey[] {})
+ .readWrite(new LedgerKey[] {})
+ .build())
+ .instructions(new Uint32(new XdrUnsignedInteger(0)))
+ .readBytes(new Uint32(new XdrUnsignedInteger(0)))
+ .writeBytes(new Uint32(new XdrUnsignedInteger(0)))
+ .extendedMetaDataSizeBytes(new Uint32(new XdrUnsignedInteger(0)))
+ .build())
+ .refundableFee(new Int64(0L))
+ .ext(new ExtensionPoint.Builder().discriminant(0).build())
+ .build();
+ }
+
+ /**
+ * Creates a new builder from a base64 representation of {@link SorobanTransactionData}.
+ *
+ * @param sorobanData base64 representation of {@link SorobanTransactionData}
+ */
+ public SorobanDataBuilder(String sorobanData) {
+ try {
+ data = SorobanTransactionData.fromXdrBase64(sorobanData);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Invalid SorobanData: " + sorobanData, e);
+ }
+ }
+
+ /**
+ * Creates a new builder from a {@link SorobanTransactionData}.
+ *
+ * @param sorobanData {@link SorobanTransactionData}.
+ */
+ public SorobanDataBuilder(SorobanTransactionData sorobanData) {
+ try {
+ data = SorobanTransactionData.fromXdrByteArray(sorobanData.toXdrByteArray());
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Invalid SorobanData: " + sorobanData, e);
+ }
+ }
+
+ /**
+ * Sets the "refundable" fee portion of the Soroban data.
+ *
+ * @param fee the refundable fee to set (int64)
+ * @return this builder instance
+ */
+ public SorobanDataBuilder setRefundableFee(long fee) {
+ data.setRefundableFee(new Int64(fee));
+ return this;
+ }
+
+ /**
+ * Sets up the resource metrics.
+ *
+ *
You should almost NEVER need this, as its often generated / provided to you by transaction
+ * simulation/preflight from a Soroban RPC server.
+ *
+ * @param cpuInstructions number of CPU instructions (uint32)
+ * @param readBytes number of bytes being read (uint32)
+ * @param writeBytes number of bytes being written (uint32)
+ * @param metadataBytes number of extended metadata bytes (uint32)
+ * @return this builder instance
+ */
+ public SorobanDataBuilder setResources(
+ long cpuInstructions, long readBytes, long writeBytes, long metadataBytes) {
+ data.getResources().setInstructions(new Uint32(new XdrUnsignedInteger(cpuInstructions)));
+ data.getResources().setReadBytes(new Uint32(new XdrUnsignedInteger(readBytes)));
+ data.getResources().setWriteBytes(new Uint32(new XdrUnsignedInteger(writeBytes)));
+ data.getResources()
+ .setExtendedMetaDataSizeBytes(new Uint32(new XdrUnsignedInteger(metadataBytes)));
+ return this;
+ }
+
+ /**
+ * Sets the storage access footprint to be a certain set of ledger keys.
+ *
+ *
You can also set each field explicitly via {@link
+ * SorobanDataBuilder#setReadOnly(Collection)} and {@link
+ * SorobanDataBuilder#setReadWrite(Collection)}.
+ *
+ *
Passing {@code null} to either parameter will IGNORE the existing values. If you want to
+ * clear them, pass empty collection instead.
+ *
+ * @param readOnly the set of ledger keys to set in the read-only portion of the transaction's
+ * sorobanData
+ * @param readWrite the set of ledger keys to set in the read-write portion of the transaction's
+ * sorobanData
+ * @return this builder instance
+ */
+ public SorobanDataBuilder setFootprint(
+ @Nullable Collection readOnly, @Nullable Collection readWrite) {
+ if (readOnly != null) {
+ data.getResources().getFootprint().setReadOnly(readOnly.toArray(new LedgerKey[0]));
+ }
+ if (readWrite != null) {
+ data.getResources().getFootprint().setReadWrite(readWrite.toArray(new LedgerKey[0]));
+ }
+ return this;
+ }
+
+ /**
+ * Sets the read-only portion of the storage access footprint to be a certain set of ledger keys.
+ *
+ * @param readOnly the set of ledger keys to set in the read-only portion of the transaction's
+ * sorobanData
+ * @return this builder instance
+ */
+ public SorobanDataBuilder setReadOnly(@Nullable Collection readOnly) {
+ if (readOnly != null) {
+ data.getResources().getFootprint().setReadOnly(readOnly.toArray(new LedgerKey[0]));
+ }
+ return this;
+ }
+
+ /**
+ * Sets the read-write portion of the storage access footprint to be a certain set of ledger keys.
+ *
+ * @param readWrite the set of ledger keys to set in the read-write portion of the transaction's
+ * sorobanData
+ * @return this builder instance
+ */
+ public SorobanDataBuilder setReadWrite(@Nullable Collection readWrite) {
+ if (readWrite != null) {
+ data.getResources().getFootprint().setReadWrite(readWrite.toArray(new LedgerKey[0]));
+ }
+ return this;
+ }
+
+ /**
+ * Returns the copy of the final {@link SorobanTransactionData} built by this builder.
+ *
+ * @return the copy of the final {@link SorobanTransactionData}.
+ */
+ public SorobanTransactionData build() {
+ try {
+ return SorobanTransactionData.fromXdrByteArray(data.toXdrByteArray());
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Copy SorobanData failed, please report this bug.", e);
+ }
+ }
+}
diff --git a/src/main/java/org/stellar/sdk/Transaction.java b/src/main/java/org/stellar/sdk/Transaction.java
index 2bc6df2ad..316c88c93 100644
--- a/src/main/java/org/stellar/sdk/Transaction.java
+++ b/src/main/java/org/stellar/sdk/Transaction.java
@@ -58,7 +58,7 @@ public class Transaction extends AbstractTransaction {
this.mPreconditions = preconditions;
this.mFee = fee;
this.mMemo = memo != null ? memo : Memo.none();
- this.mSorobanData = sorobanData;
+ this.mSorobanData = sorobanData != null ? new SorobanDataBuilder(sorobanData).build() : null;
}
// setEnvelopeType is only used in tests which is why this method is package protected
diff --git a/src/main/java/org/stellar/sdk/TransactionBuilder.java b/src/main/java/org/stellar/sdk/TransactionBuilder.java
index da85d14f5..8459dd934 100644
--- a/src/main/java/org/stellar/sdk/TransactionBuilder.java
+++ b/src/main/java/org/stellar/sdk/TransactionBuilder.java
@@ -5,7 +5,6 @@
import static org.stellar.sdk.TransactionPreconditions.TIMEOUT_INFINITE;
import com.google.common.base.Function;
-import java.io.IOException;
import java.math.BigInteger;
import java.util.Collection;
import java.util.List;
@@ -270,7 +269,7 @@ public static org.stellar.sdk.xdr.TimeBounds buildTimeBounds(long minTime, long
* @return Builder object so you can chain methods.
*/
public TransactionBuilder setSorobanData(SorobanTransactionData sorobanData) {
- this.mSorobanData = sorobanData;
+ this.mSorobanData = new SorobanDataBuilder(sorobanData).build();
return this;
}
@@ -281,12 +280,7 @@ public TransactionBuilder setSorobanData(SorobanTransactionData sorobanData) {
* @return Builder object so you can chain methods.
*/
public TransactionBuilder setSorobanData(String sorobanData) {
- SorobanTransactionData data;
- try {
- data = SorobanTransactionData.fromXdrBase64(sorobanData);
- } catch (IOException e) {
- throw new IllegalArgumentException("Invalid Soroban data: " + sorobanData, e);
- }
- return setSorobanData(data);
+ this.mSorobanData = new SorobanDataBuilder(sorobanData).build();
+ return this;
}
}
diff --git a/src/test/java/org/stellar/sdk/SorobanDataBuilderTest.java b/src/test/java/org/stellar/sdk/SorobanDataBuilderTest.java
new file mode 100644
index 000000000..dc12f0e88
--- /dev/null
+++ b/src/test/java/org/stellar/sdk/SorobanDataBuilderTest.java
@@ -0,0 +1,161 @@
+package org.stellar.sdk;
+
+import static com.google.common.collect.ImmutableList.of;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import org.junit.Test;
+import org.stellar.sdk.xdr.ExtensionPoint;
+import org.stellar.sdk.xdr.Int64;
+import org.stellar.sdk.xdr.LedgerEntryType;
+import org.stellar.sdk.xdr.LedgerFootprint;
+import org.stellar.sdk.xdr.LedgerKey;
+import org.stellar.sdk.xdr.SorobanResources;
+import org.stellar.sdk.xdr.SorobanTransactionData;
+import org.stellar.sdk.xdr.Uint32;
+import org.stellar.sdk.xdr.XdrUnsignedInteger;
+
+public class SorobanDataBuilderTest {
+ LedgerKey readOnly =
+ new LedgerKey.Builder()
+ .discriminant(LedgerEntryType.ACCOUNT)
+ .account(
+ new LedgerKey.LedgerKeyAccount.Builder()
+ .accountID(
+ KeyPair.fromAccountId(
+ "GB7TAYRUZGE6TVT7NHP5SMIZRNQA6PLM423EYISAOAP3MKYIQMVYP2JO")
+ .getXdrAccountId())
+ .build())
+ .build();
+ LedgerKey readWrite =
+ new LedgerKey.Builder()
+ .discriminant(LedgerEntryType.ACCOUNT)
+ .account(
+ new LedgerKey.LedgerKeyAccount.Builder()
+ .accountID(
+ KeyPair.fromAccountId(
+ "GAHJJJKMOKYE4RVPZEWZTKH5FVI4PA3VL7GK2LFNUBSGBV6OJP7TQSLX")
+ .getXdrAccountId())
+ .build())
+ .build();
+
+ SorobanTransactionData emptySorobanData =
+ new SorobanTransactionData.Builder()
+ .resources(
+ new SorobanResources.Builder()
+ .footprint(
+ new LedgerFootprint.Builder()
+ .readOnly(new LedgerKey[] {})
+ .readWrite(new LedgerKey[] {})
+ .build())
+ .instructions(new Uint32(new XdrUnsignedInteger(0)))
+ .readBytes(new Uint32(new XdrUnsignedInteger(0)))
+ .writeBytes(new Uint32(new XdrUnsignedInteger(0)))
+ .extendedMetaDataSizeBytes(new Uint32(new XdrUnsignedInteger(0)))
+ .build())
+ .refundableFee(new Int64(0L))
+ .ext(new ExtensionPoint.Builder().discriminant(0).build())
+ .build();
+
+ SorobanTransactionData presetSorobanData =
+ new SorobanTransactionData.Builder()
+ .resources(
+ new SorobanResources.Builder()
+ .footprint(
+ new LedgerFootprint.Builder()
+ .readOnly(new LedgerKey[] {readOnly})
+ .readWrite(new LedgerKey[] {readWrite})
+ .build())
+ .instructions(new Uint32(new XdrUnsignedInteger(1)))
+ .readBytes(new Uint32(new XdrUnsignedInteger(2)))
+ .writeBytes(new Uint32(new XdrUnsignedInteger(3)))
+ .extendedMetaDataSizeBytes(new Uint32(new XdrUnsignedInteger(4)))
+ .build())
+ .refundableFee(new Int64(5L))
+ .ext(new ExtensionPoint.Builder().discriminant(0).build())
+ .build();
+
+ @Test
+ public void testConstructorFromEmpty() {
+ SorobanTransactionData actualData = new SorobanDataBuilder().build();
+ assertEquals(emptySorobanData, actualData);
+ }
+
+ @Test
+ public void testConstructorFromBase64() throws IOException {
+ String base64 = presetSorobanData.toXdrBase64();
+ SorobanTransactionData actualData = new SorobanDataBuilder(base64).build();
+ assertEquals(presetSorobanData, actualData);
+ }
+
+ @Test
+ public void testConstructorFromSorobanTransactionData() {
+ SorobanTransactionData actualData = new SorobanDataBuilder(presetSorobanData).build();
+ assertEquals(presetSorobanData, actualData);
+ }
+
+ @Test
+ public void testSetProperties() {
+ SorobanTransactionData actualData0 =
+ new SorobanDataBuilder()
+ .setReadOnly(of(readOnly))
+ .setReadWrite(of(readWrite))
+ .setRefundableFee(5)
+ .setResources(1, 2, 3, 4)
+ .build();
+ assertEquals(presetSorobanData, actualData0);
+
+ SorobanTransactionData actualData1 =
+ new SorobanDataBuilder()
+ .setFootprint(of(readOnly), of(readWrite))
+ .setRefundableFee(5)
+ .setResources(1, 2, 3, 4)
+ .build();
+ assertEquals(presetSorobanData, actualData1);
+ }
+
+ @Test
+ public void testLeavesUntouchedFootprintsUntouched() {
+ SorobanTransactionData data0 =
+ new SorobanDataBuilder(presetSorobanData).setReadOnly(null).build();
+ assertArrayEquals(
+ new LedgerKey[] {readOnly}, data0.getResources().getFootprint().getReadOnly());
+
+ SorobanTransactionData data1 =
+ new SorobanDataBuilder(presetSorobanData).setReadOnly(new ArrayList<>()).build();
+ assertArrayEquals(new LedgerKey[] {}, data1.getResources().getFootprint().getReadOnly());
+
+ SorobanTransactionData data3 =
+ new SorobanDataBuilder(presetSorobanData).setReadWrite(null).build();
+ assertArrayEquals(
+ new LedgerKey[] {readWrite}, data3.getResources().getFootprint().getReadWrite());
+
+ SorobanTransactionData data4 =
+ new SorobanDataBuilder(presetSorobanData).setReadWrite(new ArrayList<>()).build();
+ assertArrayEquals(new LedgerKey[] {}, data4.getResources().getFootprint().getReadWrite());
+
+ SorobanTransactionData data5 =
+ new SorobanDataBuilder(presetSorobanData).setFootprint(null, null).build();
+ assertArrayEquals(
+ new LedgerKey[] {readOnly}, data5.getResources().getFootprint().getReadOnly());
+ assertArrayEquals(
+ new LedgerKey[] {readWrite}, data5.getResources().getFootprint().getReadWrite());
+
+ SorobanTransactionData data6 =
+ new SorobanDataBuilder(presetSorobanData)
+ .setFootprint(new ArrayList<>(), new ArrayList<>())
+ .build();
+ assertArrayEquals(new LedgerKey[] {}, data6.getResources().getFootprint().getReadOnly());
+ assertArrayEquals(new LedgerKey[] {}, data6.getResources().getFootprint().getReadWrite());
+ }
+
+ @Test
+ public void testBuildCopy() {
+ SorobanTransactionData actualData = new SorobanDataBuilder(presetSorobanData).build();
+ assertEquals(presetSorobanData, actualData);
+ assertNotSame(presetSorobanData, actualData);
+ }
+}
diff --git a/src/test/java/org/stellar/sdk/SorobanServerTest.java b/src/test/java/org/stellar/sdk/SorobanServerTest.java
index 57bba78ee..58cf86bfd 100644
--- a/src/test/java/org/stellar/sdk/SorobanServerTest.java
+++ b/src/test/java/org/stellar/sdk/SorobanServerTest.java
@@ -1362,35 +1362,40 @@ private Transaction buildSorobanTransaction(
auth = new ArrayList<>();
}
- return new TransactionBuilder(AccountConverter.enableMuxed(), source, Network.STANDALONE)
- .setBaseFee(50000)
- .addPreconditions(
- TransactionPreconditions.builder().timeBounds(new TimeBounds(0, 0)).build())
- .addOperation(
- InvokeHostFunctionOperation.builder()
- .sourceAccount(opInvokerKp.getAccountId())
- .hostFunction(
- new HostFunction.Builder()
- .discriminant(HostFunctionType.HOST_FUNCTION_TYPE_INVOKE_CONTRACT)
- .invokeContract(
- new SCVec(
- new SCVal[] {
- new Address(contractId).toSCVal(),
- new SCVal.Builder()
- .discriminant(SCValType.SCV_SYMBOL)
- .sym(new SCSymbol(new XdrString("increment")))
- .build(),
- new Address(opInvokerKp.getAccountId()).toSCVal(),
- new SCVal.Builder()
- .discriminant(SCValType.SCV_U32)
- .u32(new Uint32(new XdrUnsignedInteger(10)))
- .build()
- }))
- .build())
- .auth(auth)
- .build())
- .setSorobanData(sorobanData)
- .build();
+ TransactionBuilder transactionBuilder =
+ new TransactionBuilder(AccountConverter.enableMuxed(), source, Network.STANDALONE)
+ .setBaseFee(50000)
+ .addPreconditions(
+ TransactionPreconditions.builder().timeBounds(new TimeBounds(0, 0)).build())
+ .addOperation(
+ InvokeHostFunctionOperation.builder()
+ .sourceAccount(opInvokerKp.getAccountId())
+ .hostFunction(
+ new HostFunction.Builder()
+ .discriminant(HostFunctionType.HOST_FUNCTION_TYPE_INVOKE_CONTRACT)
+ .invokeContract(
+ new SCVec(
+ new SCVal[] {
+ new Address(contractId).toSCVal(),
+ new SCVal.Builder()
+ .discriminant(SCValType.SCV_SYMBOL)
+ .sym(new SCSymbol(new XdrString("increment")))
+ .build(),
+ new Address(opInvokerKp.getAccountId()).toSCVal(),
+ new SCVal.Builder()
+ .discriminant(SCValType.SCV_U32)
+ .u32(new Uint32(new XdrUnsignedInteger(10)))
+ .build()
+ }))
+ .build())
+ .auth(auth)
+ .build());
+
+ if (sorobanData != null) {
+ transactionBuilder.setSorobanData(sorobanData);
+ }
+
+ return transactionBuilder.build();
}
private static SorobanAuthorizationEntry sorobanAuthorizationEntryFromXdrBase64(
From 27134f51edea232ff9b4aec2e06c8230b2579be4 Mon Sep 17 00:00:00 2001
From: overcat <4catcode@gmail.com>
Date: Sun, 13 Aug 2023 19:13:18 +0800
Subject: [PATCH 2/6] fix docs
---
src/main/java/org/stellar/sdk/SorobanDataBuilder.java | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/main/java/org/stellar/sdk/SorobanDataBuilder.java b/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
index 3368f7275..e0942510c 100644
--- a/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
+++ b/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
@@ -16,8 +16,8 @@
* Supports building {@link SorobanTransactionData} structures with various items set to specific
* values.
*
- * This is recommended for when you are building {@link BumpFootprintExpirationOperation} {@link
- * RestoreFootprintOperation} operations to avoid (re)building the entire data structure from
+ *
This is recommended for when you are building {@link BumpFootprintExpirationOperation} and
+ * {@link RestoreFootprintOperation} operations to avoid (re)building the entire data structure from
* scratch.
*/
public class SorobanDataBuilder {
@@ -84,7 +84,7 @@ public SorobanDataBuilder setRefundableFee(long fee) {
/**
* Sets up the resource metrics.
*
- *
You should almost NEVER need this, as its often generated / provided to you by transaction
+ *
You should almost NEVER need this, as its often generated/provided to you by transaction
* simulation/preflight from a Soroban RPC server.
*
* @param cpuInstructions number of CPU instructions (uint32)
@@ -159,8 +159,6 @@ public SorobanDataBuilder setReadWrite(@Nullable Collection readWrite
}
/**
- * Returns the copy of the final {@link SorobanTransactionData} built by this builder.
- *
* @return the copy of the final {@link SorobanTransactionData}.
*/
public SorobanTransactionData build() {
From f4213a10918772e2b124efea02c5a7b810367aa3 Mon Sep 17 00:00:00 2001
From: overcat <4catcode@gmail.com>
Date: Mon, 14 Aug 2023 07:49:37 +0800
Subject: [PATCH 3/6] improve docs
---
src/main/java/org/stellar/sdk/SorobanDataBuilder.java | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/stellar/sdk/SorobanDataBuilder.java b/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
index e0942510c..faf9b0cf2 100644
--- a/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
+++ b/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
@@ -110,8 +110,8 @@ public SorobanDataBuilder setResources(
* SorobanDataBuilder#setReadOnly(Collection)} and {@link
* SorobanDataBuilder#setReadWrite(Collection)}.
*
- * Passing {@code null} to either parameter will IGNORE the existing values. If you want to
- * clear them, pass empty collection instead.
+ *
Passing {@code null} to either parameter will leave that portion of the footprint untouched.
+ * If you want to clear a portion of the footprint, pass an empty collection.
*
* @param readOnly the set of ledger keys to set in the read-only portion of the transaction's
* sorobanData
@@ -133,6 +133,9 @@ public SorobanDataBuilder setFootprint(
/**
* Sets the read-only portion of the storage access footprint to be a certain set of ledger keys.
*
+ *
Passing {@code null} will leave that portion of the footprint untouched. If you want to
+ * clear a portion of the footprint, pass an empty collection.
+ *
* @param readOnly the set of ledger keys to set in the read-only portion of the transaction's
* sorobanData
* @return this builder instance
@@ -147,6 +150,9 @@ public SorobanDataBuilder setReadOnly(@Nullable Collection readOnly)
/**
* Sets the read-write portion of the storage access footprint to be a certain set of ledger keys.
*
+ * Passing {@code null} will leave that portion of the footprint untouched. If you want to
+ * clear a portion of the footprint, pass an empty collection.
+ *
* @param readWrite the set of ledger keys to set in the read-write portion of the transaction's
* sorobanData
* @return this builder instance
From 9acb4552df8cfdf2a2b462ed5e6cc4c9d431a066 Mon Sep 17 00:00:00 2001
From: overcat <4catcode@gmail.com>
Date: Mon, 14 Aug 2023 08:07:25 +0800
Subject: [PATCH 4/6] improve docs
---
.../java/org/stellar/sdk/TransactionBuilder.java | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/stellar/sdk/TransactionBuilder.java b/src/main/java/org/stellar/sdk/TransactionBuilder.java
index 8459dd934..c1b900697 100644
--- a/src/main/java/org/stellar/sdk/TransactionBuilder.java
+++ b/src/main/java/org/stellar/sdk/TransactionBuilder.java
@@ -263,7 +263,13 @@ public static org.stellar.sdk.xdr.TimeBounds buildTimeBounds(long minTime, long
}
/**
- * Sets Soroban data to the transaction. TODO: After adding SorobanServer, add more descriptions.
+ * Sets the transaction's internal Soroban transaction data (resources, footprint, etc.).
+ *
+ *
For non-contract(non-Soroban) transactions, this setting has no effect. In the case of
+ * Soroban transactions, this is either an instance of {@link SorobanTransactionData} or a
+ * base64-encoded string of said structure. This is usually obtained from the simulation response
+ * based on a transaction with a Soroban operation (e.g. {@link InvokeHostFunctionOperation},
+ * providing necessary resource and storage footprint estimations for contract invocation.
*
* @param sorobanData Soroban data to set
* @return Builder object so you can chain methods.
@@ -274,7 +280,13 @@ public TransactionBuilder setSorobanData(SorobanTransactionData sorobanData) {
}
/**
- * Sets Soroban data to the transaction. TODO: After adding SorobanServer, add more descriptions.
+ * Sets the transaction's internal Soroban transaction data (resources, footprint, etc.).
+ *
+ *
For non-contract(non-Soroban) transactions, this setting has no effect. In the case of
+ * Soroban transactions, this is either an instance of {@link SorobanTransactionData} or a
+ * base64-encoded string of said structure. This is usually obtained from the simulation response
+ * based on a transaction with a Soroban operation (e.g. {@link InvokeHostFunctionOperation},
+ * providing necessary resource and storage footprint estimations for contract invocation.
*
* @param sorobanData Soroban data to set
* @return Builder object so you can chain methods.
From 4da8f8120aed245180142d4a3c7a4873b14d9a46 Mon Sep 17 00:00:00 2001
From: overcat <4catcode@gmail.com>
Date: Mon, 14 Aug 2023 23:20:33 +0800
Subject: [PATCH 5/6] remove setFootprint
---
.../org/stellar/sdk/SorobanDataBuilder.java | 27 -------------------
.../stellar/sdk/SorobanDataBuilderTest.java | 26 ++----------------
2 files changed, 2 insertions(+), 51 deletions(-)
diff --git a/src/main/java/org/stellar/sdk/SorobanDataBuilder.java b/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
index faf9b0cf2..acfcc8a35 100644
--- a/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
+++ b/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
@@ -103,33 +103,6 @@ public SorobanDataBuilder setResources(
return this;
}
- /**
- * Sets the storage access footprint to be a certain set of ledger keys.
- *
- *
You can also set each field explicitly via {@link
- * SorobanDataBuilder#setReadOnly(Collection)} and {@link
- * SorobanDataBuilder#setReadWrite(Collection)}.
- *
- *
Passing {@code null} to either parameter will leave that portion of the footprint untouched.
- * If you want to clear a portion of the footprint, pass an empty collection.
- *
- * @param readOnly the set of ledger keys to set in the read-only portion of the transaction's
- * sorobanData
- * @param readWrite the set of ledger keys to set in the read-write portion of the transaction's
- * sorobanData
- * @return this builder instance
- */
- public SorobanDataBuilder setFootprint(
- @Nullable Collection readOnly, @Nullable Collection readWrite) {
- if (readOnly != null) {
- data.getResources().getFootprint().setReadOnly(readOnly.toArray(new LedgerKey[0]));
- }
- if (readWrite != null) {
- data.getResources().getFootprint().setReadWrite(readWrite.toArray(new LedgerKey[0]));
- }
- return this;
- }
-
/**
* Sets the read-only portion of the storage access footprint to be a certain set of ledger keys.
*
diff --git a/src/test/java/org/stellar/sdk/SorobanDataBuilderTest.java b/src/test/java/org/stellar/sdk/SorobanDataBuilderTest.java
index dc12f0e88..6d616d78d 100644
--- a/src/test/java/org/stellar/sdk/SorobanDataBuilderTest.java
+++ b/src/test/java/org/stellar/sdk/SorobanDataBuilderTest.java
@@ -99,22 +99,14 @@ public void testConstructorFromSorobanTransactionData() {
@Test
public void testSetProperties() {
- SorobanTransactionData actualData0 =
+ SorobanTransactionData actualData =
new SorobanDataBuilder()
.setReadOnly(of(readOnly))
.setReadWrite(of(readWrite))
.setRefundableFee(5)
.setResources(1, 2, 3, 4)
.build();
- assertEquals(presetSorobanData, actualData0);
-
- SorobanTransactionData actualData1 =
- new SorobanDataBuilder()
- .setFootprint(of(readOnly), of(readWrite))
- .setRefundableFee(5)
- .setResources(1, 2, 3, 4)
- .build();
- assertEquals(presetSorobanData, actualData1);
+ assertEquals(presetSorobanData, actualData);
}
@Test
@@ -136,20 +128,6 @@ public void testLeavesUntouchedFootprintsUntouched() {
SorobanTransactionData data4 =
new SorobanDataBuilder(presetSorobanData).setReadWrite(new ArrayList<>()).build();
assertArrayEquals(new LedgerKey[] {}, data4.getResources().getFootprint().getReadWrite());
-
- SorobanTransactionData data5 =
- new SorobanDataBuilder(presetSorobanData).setFootprint(null, null).build();
- assertArrayEquals(
- new LedgerKey[] {readOnly}, data5.getResources().getFootprint().getReadOnly());
- assertArrayEquals(
- new LedgerKey[] {readWrite}, data5.getResources().getFootprint().getReadWrite());
-
- SorobanTransactionData data6 =
- new SorobanDataBuilder(presetSorobanData)
- .setFootprint(new ArrayList<>(), new ArrayList<>())
- .build();
- assertArrayEquals(new LedgerKey[] {}, data6.getResources().getFootprint().getReadOnly());
- assertArrayEquals(new LedgerKey[] {}, data6.getResources().getFootprint().getReadWrite());
}
@Test
From 9f5f23145e0d1eb4d814d17b408019b45eee1bba Mon Sep 17 00:00:00 2001
From: overcat <4catcode@gmail.com>
Date: Mon, 14 Aug 2023 23:32:01 +0800
Subject: [PATCH 6/6] add resource builder
---
.../org/stellar/sdk/SorobanDataBuilder.java | 36 +++++++++++++------
.../stellar/sdk/SorobanDataBuilderTest.java | 8 ++++-
2 files changed, 33 insertions(+), 11 deletions(-)
diff --git a/src/main/java/org/stellar/sdk/SorobanDataBuilder.java b/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
index acfcc8a35..23480f4ca 100644
--- a/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
+++ b/src/main/java/org/stellar/sdk/SorobanDataBuilder.java
@@ -3,6 +3,9 @@
import java.io.IOException;
import java.util.Collection;
import javax.annotation.Nullable;
+import lombok.Builder;
+import lombok.NonNull;
+import lombok.Value;
import org.stellar.sdk.xdr.ExtensionPoint;
import org.stellar.sdk.xdr.Int64;
import org.stellar.sdk.xdr.LedgerFootprint;
@@ -87,19 +90,18 @@ public SorobanDataBuilder setRefundableFee(long fee) {
* You should almost NEVER need this, as its often generated/provided to you by transaction
* simulation/preflight from a Soroban RPC server.
*
- * @param cpuInstructions number of CPU instructions (uint32)
- * @param readBytes number of bytes being read (uint32)
- * @param writeBytes number of bytes being written (uint32)
- * @param metadataBytes number of extended metadata bytes (uint32)
+ * @param resources the resource metrics to set
* @return this builder instance
*/
- public SorobanDataBuilder setResources(
- long cpuInstructions, long readBytes, long writeBytes, long metadataBytes) {
- data.getResources().setInstructions(new Uint32(new XdrUnsignedInteger(cpuInstructions)));
- data.getResources().setReadBytes(new Uint32(new XdrUnsignedInteger(readBytes)));
- data.getResources().setWriteBytes(new Uint32(new XdrUnsignedInteger(writeBytes)));
+ public SorobanDataBuilder setResources(Resources resources) {
data.getResources()
- .setExtendedMetaDataSizeBytes(new Uint32(new XdrUnsignedInteger(metadataBytes)));
+ .setInstructions(new Uint32(new XdrUnsignedInteger(resources.getCpuInstructions())));
+ data.getResources().setReadBytes(new Uint32(new XdrUnsignedInteger(resources.getReadBytes())));
+ data.getResources()
+ .setWriteBytes(new Uint32(new XdrUnsignedInteger(resources.getWriteBytes())));
+ data.getResources()
+ .setExtendedMetaDataSizeBytes(
+ new Uint32(new XdrUnsignedInteger(resources.getMetadataBytes())));
return this;
}
@@ -147,4 +149,18 @@ public SorobanTransactionData build() {
throw new IllegalArgumentException("Copy SorobanData failed, please report this bug.", e);
}
}
+
+ /** Represents the resource metrics of the Soroban data. */
+ @Builder(toBuilder = true)
+ @Value
+ public static class Resources {
+ // number of CPU instructions (uint32)
+ @NonNull Long cpuInstructions;
+ // number of bytes being read (uint32)
+ @NonNull Long readBytes;
+ // number of bytes being written (uint32)
+ @NonNull Long writeBytes;
+ // number of extended metadata bytes (uint32)
+ @NonNull Long metadataBytes;
+ }
}
diff --git a/src/test/java/org/stellar/sdk/SorobanDataBuilderTest.java b/src/test/java/org/stellar/sdk/SorobanDataBuilderTest.java
index 6d616d78d..f55a4ae74 100644
--- a/src/test/java/org/stellar/sdk/SorobanDataBuilderTest.java
+++ b/src/test/java/org/stellar/sdk/SorobanDataBuilderTest.java
@@ -104,7 +104,13 @@ public void testSetProperties() {
.setReadOnly(of(readOnly))
.setReadWrite(of(readWrite))
.setRefundableFee(5)
- .setResources(1, 2, 3, 4)
+ .setResources(
+ new SorobanDataBuilder.Resources.ResourcesBuilder()
+ .cpuInstructions(1L)
+ .readBytes(2L)
+ .writeBytes(3L)
+ .metadataBytes(4L)
+ .build())
.build();
assertEquals(presetSorobanData, actualData);
}