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

Add the fromXdrBase64, fromXdrByteArray, toXdrBase64 and toXdrByteArray methods to the XDR classes. #503

Merged
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
34 changes: 9 additions & 25 deletions src/main/java/org/stellar/sdk/AbstractTransaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

import com.google.common.collect.ImmutableList;
import com.google.common.io.BaseEncoding;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -15,8 +13,6 @@
import org.stellar.sdk.xdr.SignatureHint;
import org.stellar.sdk.xdr.TransactionEnvelope;
import org.stellar.sdk.xdr.TransactionSignaturePayload;
import org.stellar.sdk.xdr.XdrDataInputStream;
import org.stellar.sdk.xdr.XdrDataOutputStream;

public abstract class AbstractTransaction {
protected final Network mNetwork;
Expand Down Expand Up @@ -120,13 +116,7 @@ public void addSignature(DecoratedSignature signature) {
*/
public String toEnvelopeXdrBase64() {
try {
TransactionEnvelope envelope = this.toEnvelopeXdr();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
XdrDataOutputStream xdrOutputStream = new XdrDataOutputStream(outputStream);
TransactionEnvelope.encode(xdrOutputStream, envelope);

BaseEncoding base64Encoding = BaseEncoding.base64();
return base64Encoding.encode(outputStream.toByteArray());
return toEnvelopeXdr().toXdrBase64();
} catch (IOException e) {
throw new AssertionError(e);
}
Expand Down Expand Up @@ -176,11 +166,7 @@ public static AbstractTransaction fromEnvelopeXdr(TransactionEnvelope envelope,
*/
public static AbstractTransaction fromEnvelopeXdr(
AccountConverter accountConverter, String envelope, Network network) throws IOException {
BaseEncoding base64Encoding = BaseEncoding.base64();
byte[] bytes = base64Encoding.decode(envelope);

TransactionEnvelope transactionEnvelope =
TransactionEnvelope.decode(new XdrDataInputStream(new ByteArrayInputStream(bytes)));
TransactionEnvelope transactionEnvelope = TransactionEnvelope.fromXdrBase64(envelope);
return fromEnvelopeXdr(accountConverter, transactionEnvelope, network);
}

Expand All @@ -201,15 +187,13 @@ public static byte[] getTransactionSignatureBase(
TransactionSignaturePayload.TransactionSignaturePayloadTaggedTransaction taggedTransaction,
Network network) {
try {
TransactionSignaturePayload payload = new TransactionSignaturePayload();
Hash hash = new Hash();
hash.setHash(network.getNetworkId());
payload.setNetworkId(hash);
payload.setTaggedTransaction(taggedTransaction);
ByteArrayOutputStream txOutputStream = new ByteArrayOutputStream();
XdrDataOutputStream xdrOutputStream = new XdrDataOutputStream(txOutputStream);
payload.encode(xdrOutputStream);
return txOutputStream.toByteArray();
Hash networkIdHash = new Hash(network.getNetworkId());
TransactionSignaturePayload payload =
new TransactionSignaturePayload.Builder()
.networkId(networkIdHash)
.taggedTransaction(taggedTransaction)
.build();
return payload.toXdrByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
Expand Down
18 changes: 16 additions & 2 deletions src/main/java/org/stellar/sdk/ClaimClaimableBalanceOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.base.Objects;
import com.google.common.io.BaseEncoding;
import java.io.IOException;
import org.stellar.sdk.xdr.*;

public class ClaimClaimableBalanceOperation extends Operation {
Expand All @@ -18,8 +20,16 @@ public String getBalanceId() {

@Override
org.stellar.sdk.xdr.Operation.OperationBody toOperationBody(AccountConverter accountConverter) {
byte[] balanceIdBytes = BaseEncoding.base16().lowerCase().decode(this.balanceId.toLowerCase());
ClaimableBalanceID balanceId;
try {
balanceId = ClaimableBalanceID.fromXdrByteArray(balanceIdBytes);
} catch (IOException e) {
throw new IllegalArgumentException("invalid balanceId: " + this.balanceId, e);
}

ClaimClaimableBalanceOp op = new ClaimClaimableBalanceOp();
op.setBalanceID(Util.claimableBalanceIdToXDR(balanceId));
op.setBalanceID(balanceId);
org.stellar.sdk.xdr.Operation.OperationBody body =
new org.stellar.sdk.xdr.Operation.OperationBody();
body.setDiscriminant(OperationType.CLAIM_CLAIMABLE_BALANCE);
Expand All @@ -38,7 +48,11 @@ public static class Builder {
* @param op {@link ClaimClaimableBalanceOp}
*/
Builder(ClaimClaimableBalanceOp op) {
balanceId = Util.xdrToClaimableBalanceId(op.getBalanceID());
try {
balanceId = BaseEncoding.base16().lowerCase().encode(op.getBalanceID().toXdrByteArray());
} catch (IOException e) {
throw new IllegalArgumentException("Invalid balanceId in the operation", e);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.base.Objects;
import com.google.common.io.BaseEncoding;
import java.io.IOException;
import org.stellar.sdk.xdr.ClaimableBalanceID;
import org.stellar.sdk.xdr.ClawbackClaimableBalanceOp;
import org.stellar.sdk.xdr.OperationType;

Expand All @@ -26,9 +29,17 @@ public String getBalanceId() {

@Override
org.stellar.sdk.xdr.Operation.OperationBody toOperationBody(AccountConverter accountConverter) {
byte[] balanceIdBytes = BaseEncoding.base16().lowerCase().decode(this.balanceId.toLowerCase());
ClaimableBalanceID balanceId;
try {
balanceId = ClaimableBalanceID.fromXdrByteArray(balanceIdBytes);
} catch (IOException e) {
throw new IllegalArgumentException("invalid balanceId: " + this.balanceId, e);
}

ClawbackClaimableBalanceOp op = new ClawbackClaimableBalanceOp();

op.setBalanceID(Util.claimableBalanceIdToXDR(balanceId));
op.setBalanceID(balanceId);

org.stellar.sdk.xdr.Operation.OperationBody body =
new org.stellar.sdk.xdr.Operation.OperationBody();
Expand All @@ -48,7 +59,11 @@ public static class Builder {
private String mSourceAccount;

Builder(ClawbackClaimableBalanceOp op) {
balanceId = Util.xdrToClaimableBalanceId(op.getBalanceID());
try {
balanceId = BaseEncoding.base16().lowerCase().encode(op.getBalanceID().toXdrByteArray());
} catch (IOException e) {
throw new IllegalArgumentException("Invalid balanceId in the operation", e);
}
}

/**
Expand Down
10 changes: 1 addition & 9 deletions src/main/java/org/stellar/sdk/Operation.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.io.BaseEncoding;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import org.stellar.sdk.xdr.XdrDataOutputStream;

/** Abstract class for operations. */
@SuperBuilder(toBuilder = true)
Expand Down Expand Up @@ -51,12 +48,7 @@ public org.stellar.sdk.xdr.Operation toXdr() {
/** Returns base64-encoded Operation XDR object. */
public String toXdrBase64(AccountConverter accountConverter) {
try {
org.stellar.sdk.xdr.Operation operation = this.toXdr(accountConverter);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
XdrDataOutputStream xdrOutputStream = new XdrDataOutputStream(outputStream);
org.stellar.sdk.xdr.Operation.encode(xdrOutputStream, operation);
BaseEncoding base64Encoding = BaseEncoding.base64();
return base64Encoding.encode(outputStream.toByteArray());
return toXdr(accountConverter).toXdrBase64();
} catch (IOException e) {
throw new AssertionError(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.base.Objects;
import com.google.common.io.BaseEncoding;
import java.io.IOException;
import org.stellar.sdk.xdr.*;

public class RevokeClaimableBalanceSponsorshipOperation extends Operation {
Expand All @@ -18,13 +20,21 @@ public String getBalanceId() {

@Override
org.stellar.sdk.xdr.Operation.OperationBody toOperationBody(AccountConverter accountConverter) {
byte[] balanceIdBytes = BaseEncoding.base16().lowerCase().decode(this.balanceId.toLowerCase());
ClaimableBalanceID balanceId;
try {
balanceId = ClaimableBalanceID.fromXdrByteArray(balanceIdBytes);
} catch (IOException e) {
throw new IllegalArgumentException("invalid balanceId: " + this.balanceId, e);
}

RevokeSponsorshipOp op = new RevokeSponsorshipOp();
LedgerKey key = new LedgerKey();
key.setDiscriminant(LedgerEntryType.CLAIMABLE_BALANCE);
LedgerKey.LedgerKeyClaimableBalance claimableBalance =
new LedgerKey.LedgerKeyClaimableBalance();

claimableBalance.setBalanceID(Util.claimableBalanceIdToXDR(balanceId));
claimableBalance.setBalanceID(balanceId);
key.setClaimableBalance(claimableBalance);
op.setLedgerKey(key);
op.setDiscriminant(RevokeSponsorshipType.REVOKE_SPONSORSHIP_LEDGER_ENTRY);
Expand All @@ -49,8 +59,14 @@ public static class Builder {
* @param op {@link RevokeSponsorshipOp}
*/
Builder(RevokeSponsorshipOp op) {
balanceId =
Util.xdrToClaimableBalanceId(op.getLedgerKey().getClaimableBalance().getBalanceID());
try {
balanceId =
BaseEncoding.base16()
.lowerCase()
.encode(op.getLedgerKey().getClaimableBalance().getBalanceID().toXdrByteArray());
} catch (IOException e) {
throw new IllegalArgumentException("Invalid claimableBalance in the operation", e);
}
}

/**
Expand Down
80 changes: 29 additions & 51 deletions src/main/java/org/stellar/sdk/SorobanServer.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package org.stellar.sdk;

import com.google.common.io.BaseEncoding;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
Expand All @@ -14,7 +11,6 @@
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
Expand Down Expand Up @@ -48,8 +44,6 @@
import org.stellar.sdk.xdr.SCVal;
import org.stellar.sdk.xdr.SorobanAuthorizationEntry;
import org.stellar.sdk.xdr.SorobanTransactionData;
import org.stellar.sdk.xdr.XdrDataInputStream;
import org.stellar.sdk.xdr.XdrDataOutputStream;

/**
* Main class used to connect to the Soroban-RPC instance and exposes an interface for requests to
Expand Down Expand Up @@ -122,8 +116,12 @@ public TransactionBuilderAccount getAccount(String accountId)
if (entries == null || entries.isEmpty()) {
throw new AccountNotFoundException(accountId);
}
LedgerEntry.LedgerEntryData ledgerEntryData =
ledgerEntryDataFromXdrBase64(entries.get(0).getXdr());
LedgerEntry.LedgerEntryData ledgerEntryData;
try {
Copy link
Contributor

@sreuland sreuland Aug 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
try {
try {
LedgerEntry.LedgerEntryData ledgerEntryData = LedgerEntry.LedgerEntryData.fromXdrBase64(entries.get(0).getXdr());
long sequence = ledgerEntryData.getAccount().getSeqNum().getSequenceNumber().getInt64();
return new Account(accountId, sequence);
} catch (IOException e) {
throw new IllegalArgumentException("Invalid ledgerEntryData: " + entries.get(0).getXdr(), e);
}

rather than declare ledgerEntryData outside of try/catch, just use it inside when it's valid.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally prefer to include as little code as possible within the try block. Assuming there is some other business logic before returning Account, should we also place it within the try block?

ledgerEntryData = LedgerEntry.LedgerEntryData.fromXdrBase64(entries.get(0).getXdr());
} catch (IOException e) {
throw new IllegalArgumentException("Invalid ledgerEntryData: " + entries.get(0).getXdr(), e);
}
long sequence = ledgerEntryData.getAccount().getSeqNum().getSequenceNumber().getInt64();
return new Account(accountId, sequence);
}
Expand Down Expand Up @@ -220,8 +218,16 @@ public GetLedgerEntriesResponse getLedgerEntries(Collection<LedgerKey> keys)
throw new IllegalArgumentException("At least one key must be provided.");
}

List<String> xdrKeys =
keys.stream().map(SorobanServer::ledgerKeyToXdrBase64).collect(Collectors.toList());
List<String> xdrKeys = new ArrayList<>(keys.size());
for (LedgerKey key : keys) {
String xdrBase64;
try {
xdrBase64 = key.toXdrBase64();
} catch (IOException e) {
throw new IllegalArgumentException("Invalid ledgerKey: " + key, e);
}
xdrKeys.add(xdrBase64);
}
GetLedgerEntriesRequest params = new GetLedgerEntriesRequest(xdrKeys);
return this.sendRequest(
"getLedgerEntries",
Expand Down Expand Up @@ -421,7 +427,11 @@ private Transaction assembleTransaction(
List<SorobanAuthorizationEntry> newEntries = new ArrayList<>(originalEntries);
if (simulateHostFunctionResult.getAuth() != null) {
for (String auth : simulateHostFunctionResult.getAuth()) {
newEntries.add(sorobanAuthorizationEntryFromXdrBase64(auth));
try {
newEntries.add(SorobanAuthorizationEntry.fromXdrBase64(auth));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@overcat , please refer to the js soroban client for a reference on how it merges simulation results to original transaction,

https://github.com/stellar/js-soroban-client/blob/main/src/transaction.ts#L21

the java sdk should be consistent to how that handles merging auths, the js sdk will not apply simulated auths if the original tx had auths.

Copy link
Member Author

@overcat overcat Aug 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that this is a recent change introduced in the JS SDK. Let's track it in the new issue.
[update] Fixed in #505

} catch (IOException e) {
throw new IllegalArgumentException("Invalid auth: " + auth, e);
}
}
}
operation =
Expand All @@ -432,8 +442,14 @@ private Transaction assembleTransaction(
.build();
}

SorobanTransactionData sorobanData =
Util.sorobanTransactionDataToXDR(simulateTransactionResponse.getTransactionData());
SorobanTransactionData sorobanData;
try {
sorobanData =
SorobanTransactionData.fromXdrBase64(simulateTransactionResponse.getTransactionData());
} catch (IOException e) {
throw new IllegalArgumentException(
"Invalid transactionData: " + simulateTransactionResponse.getTransactionData(), e);
}

return new Transaction(
transaction.getAccountConverter(),
Expand Down Expand Up @@ -477,44 +493,6 @@ private static String generateRequestId() {
return UUID.randomUUID().toString();
}

private static String ledgerKeyToXdrBase64(LedgerKey ledgerKey) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
XdrDataOutputStream xdrDataOutputStream = new XdrDataOutputStream(byteArrayOutputStream);
try {
ledgerKey.encode(xdrDataOutputStream);
} catch (IOException e) {
throw new IllegalArgumentException("invalid ledgerKey.", e);
}
BaseEncoding base64Encoding = BaseEncoding.base64();
return base64Encoding.encode(byteArrayOutputStream.toByteArray());
}

private static LedgerEntry.LedgerEntryData ledgerEntryDataFromXdrBase64(String ledgerEntryData) {
BaseEncoding base64Encoding = BaseEncoding.base64();
byte[] bytes = base64Encoding.decode(ledgerEntryData);
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
XdrDataInputStream xdrInputStream = new XdrDataInputStream(inputStream);
try {
return LedgerEntry.LedgerEntryData.decode(xdrInputStream);
} catch (IOException e) {
throw new IllegalArgumentException("invalid ledgerEntryData: " + ledgerEntryData, e);
}
}

private static SorobanAuthorizationEntry sorobanAuthorizationEntryFromXdrBase64(
String sorobanAuthorizationEntry) {
BaseEncoding base64Encoding = BaseEncoding.base64();
byte[] bytes = base64Encoding.decode(sorobanAuthorizationEntry);
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
XdrDataInputStream xdrInputStream = new XdrDataInputStream(inputStream);
try {
return SorobanAuthorizationEntry.decode(xdrInputStream);
} catch (IOException e) {
throw new IllegalArgumentException(
"invalid ledgerEntryData: " + sorobanAuthorizationEntry, e);
}
}

/**
* Represents the "durability keyspace" that this ledger key belongs to, check {@link
* SorobanServer#getContractData} for more details.
Expand Down
11 changes: 3 additions & 8 deletions src/main/java/org/stellar/sdk/StrKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,7 @@ public static AccountID encodeToXDRAccountId(String data) {
PublicKey publicKey = new PublicKey();
publicKey.setDiscriminant(PublicKeyType.PUBLIC_KEY_TYPE_ED25519);
try {
publicKey.setEd25519(
Uint256.decode(
new XdrDataInputStream(new ByteArrayInputStream(decodeStellarAccountId(data)))));
publicKey.setEd25519(Uint256.fromXdrByteArray(decodeStellarAccountId(data)));
} catch (IOException e) {
throw new IllegalArgumentException("invalid address: " + data, e);
}
Expand All @@ -118,9 +116,7 @@ public static MuxedAccount encodeToXDRMuxedAccount(String data) {
case ACCOUNT_ID:
muxed.setDiscriminant(CryptoKeyType.KEY_TYPE_ED25519);
try {
muxed.setEd25519(
Uint256.decode(
new XdrDataInputStream(new ByteArrayInputStream(decodeStellarAccountId(data)))));
muxed.setEd25519(Uint256.fromXdrByteArray(decodeStellarAccountId(data)));
} catch (IOException e) {
throw new IllegalArgumentException("invalid address: " + data, e);
}
Expand Down Expand Up @@ -176,8 +172,7 @@ public static SignedPayloadSigner decodeSignedPayload(char[] data) {
byte[] signedPayloadRaw = decodeCheck(VersionByte.SIGNED_PAYLOAD, data);

SignerKey.SignerKeyEd25519SignedPayload xdrPayloadSigner =
SignerKey.SignerKeyEd25519SignedPayload.decode(
new XdrDataInputStream(new ByteArrayInputStream(signedPayloadRaw)));
SignerKey.SignerKeyEd25519SignedPayload.fromXdrByteArray(signedPayloadRaw);

return new SignedPayloadSigner(
xdrPayloadSigner.getEd25519().getUint256(), xdrPayloadSigner.getPayload());
Expand Down
Loading