From 48599b52ab417c170239659f5d9f912fa8b681c3 Mon Sep 17 00:00:00 2001 From: Jun Luo <4catcode@gmail.com> Date: Sat, 13 Jan 2024 08:58:14 +0800 Subject: [PATCH] Add `TransactionBuilder#TransactionBuilder(Transaction)` constructor. (#567) --- CHANGELOG.md | 1 + .../org/stellar/sdk/TransactionBuilder.java | 37 +++++++++++++ .../stellar/sdk/TransactionBuilderTest.java | 54 +++++++++++++++++++ 3 files changed, 92 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b255dfa0..7e2c09bd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ As this project is pre 1.0, breaking changes may happen for minor version bumps. ### Update * Support resource leeway parameter when simulating Soroban transactions. ([#561](https://github.com/stellar/java-stellar-sdk/pull/561)) * Support for the new, optional `diagnosticEventsXdr` field on the `SorobanServer.sendTransaction` method. ([#564](https://github.com/stellar/java-stellar-sdk/pull/564)) +* Add `TransactionBuilder#TransactionBuilder(Transaction)` constructor. ([#567](https://github.com/stellar/java-stellar-sdk/pull/567)) ### Breaking changes * The types of the following fields have changed. ([#560](https://github.com/stellar/java-stellar-sdk/pull/560)) diff --git a/src/main/java/org/stellar/sdk/TransactionBuilder.java b/src/main/java/org/stellar/sdk/TransactionBuilder.java index 0747c0521..0c1676795 100644 --- a/src/main/java/org/stellar/sdk/TransactionBuilder.java +++ b/src/main/java/org/stellar/sdk/TransactionBuilder.java @@ -2,8 +2,10 @@ import static org.stellar.sdk.TransactionPreconditions.TIMEOUT_INFINITE; +import java.io.IOException; import java.math.BigInteger; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.function.Function; @@ -57,6 +59,41 @@ public TransactionBuilder(TransactionBuilderAccount sourceAccount, Network netwo this(AccountConverter.enableMuxed(), sourceAccount, network); } + /** + * Construct a new transaction builder from a transaction. + * + * @param transaction the transaction to rebuild + */ + public TransactionBuilder(Transaction transaction) { + AbstractTransaction abstractTransaction; + try { + // deep copy + abstractTransaction = + Transaction.fromEnvelopeXdr( + transaction.getAccountConverter(), + transaction.toEnvelopeXdrBase64(), + transaction.getNetwork()); + } catch (IOException e) { + // This should never happen + throw new RuntimeException(e); + } + + if (!(abstractTransaction instanceof Transaction)) { + // This should never happen + throw new RuntimeException("TransactionBuilder can only be used to rebuild a Transaction"); + } + Transaction tx = (Transaction) abstractTransaction; + + this.sourceAccount = new Account(tx.getSourceAccount(), tx.getSequenceNumber() - 1); + this.accountConverter = tx.accountConverter; + this.memo = tx.getMemo(); + this.operations = Arrays.asList(tx.getOperations()); + this.baseFee = tx.getFee() / tx.getOperations().length; + this.network = tx.getNetwork(); + this.preconditions = tx.getPreconditions(); + this.sorobanData = tx.getSorobanData(); + } + public int getOperationsCount() { return operations.size(); } diff --git a/src/test/java/org/stellar/sdk/TransactionBuilderTest.java b/src/test/java/org/stellar/sdk/TransactionBuilderTest.java index 28cd47ef4..6a3a1f4dd 100644 --- a/src/test/java/org/stellar/sdk/TransactionBuilderTest.java +++ b/src/test/java/org/stellar/sdk/TransactionBuilderTest.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.math.BigInteger; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import org.junit.Test; @@ -940,6 +941,59 @@ public void testNoNetworkSet() throws FormatException { } } + @Test + public void testBuilderFromTx() { + KeyPair source = + KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + + Account account = new Account(source.getAccountId(), 2908908335136768L); + BumpSequenceOperation operation0 = new BumpSequenceOperation.Builder(1L).build(); + BumpSequenceOperation operation1 = new BumpSequenceOperation.Builder(2L).build(); + LedgerKey ledgerKey = + new LedgerKey.Builder() + .discriminant(LedgerEntryType.ACCOUNT) + .account( + new LedgerKey.LedgerKeyAccount.Builder() + .accountID( + KeyPair.fromAccountId( + "GB7TAYRUZGE6TVT7NHP5SMIZRNQA6PLM423EYISAOAP3MKYIQMVYP2JO") + .getXdrAccountId()) + .build()) + .build(); + SorobanTransactionData sorobanData = + new SorobanTransactionData.Builder() + .resources( + new SorobanResources.Builder() + .footprint( + new LedgerFootprint.Builder() + .readOnly(new LedgerKey[] {ledgerKey}) + .readWrite(new LedgerKey[] {}) + .build()) + .readBytes(new Uint32(new XdrUnsignedInteger(699))) + .writeBytes(new Uint32(new XdrUnsignedInteger(0))) + .instructions(new Uint32(new XdrUnsignedInteger(34567))) + .build()) + .resourceFee(new Int64(100L)) + .ext(new ExtensionPoint.Builder().discriminant(0).build()) + .build(); + + Transaction transaction = + new Transaction( + AccountConverter.enableMuxed(), + account.getAccountId(), + 980, + account.getIncrementedSequenceNumber(), + new org.stellar.sdk.Operation[] {operation0, operation1}, + new MemoText("hello"), + new TransactionPreconditions( + null, null, BigInteger.ZERO, 0, new ArrayList<>(), new TimeBounds(100, 200)), + sorobanData, // For testing purposes, it is impossible to occur in a real environment. + Network.PUBLIC); + + TransactionBuilder builder = new TransactionBuilder(transaction); + assertEquals(transaction, builder.build()); + } + @Test public void voidBuilderSorobanDataXdrString() { KeyPair source =