Skip to content
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions src/main/java/org/stellar/sdk/Address.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
import org.stellar.sdk.xdr.SCAddress;
import org.stellar.sdk.xdr.SCVal;
import org.stellar.sdk.xdr.SCValType;
import org.stellar.sdk.xdr.Uint256;
import org.stellar.sdk.xdr.Uint64;
import org.stellar.sdk.xdr.XdrUnsignedHyperInteger;

/**
* Represents a single address in the Stellar network. An address can represent an account,
Expand Down Expand Up @@ -117,8 +120,8 @@ public static Address fromSCAddress(SCAddress scAddress) {
return fromMuxedAccount(
StrKey.toRawMuxedAccountStrKey(
new StrKey.RawMuxedAccountStrKeyParameter(
scAddress.getMuxedAccount().getEd25519(),
scAddress.getMuxedAccount().getId())));
scAddress.getMuxedAccount().getEd25519().getUint256(),
scAddress.getMuxedAccount().getId().getUint64().getNumber())));
case SC_ADDRESS_TYPE_CLAIMABLE_BALANCE:
if (scAddress.getClaimableBalanceId().getDiscriminant()
!= ClaimableBalanceIDType.CLAIMABLE_BALANCE_ID_TYPE_V0) {
Expand Down Expand Up @@ -174,8 +177,8 @@ public SCAddress toSCAddress() {
StrKey.fromRawMuxedAccountStrKey(this.key);
MuxedEd25519Account muxedEd25519Account =
MuxedEd25519Account.builder()
.id(parameter.getId())
.ed25519(parameter.getEd25519())
.id(new Uint64(new XdrUnsignedHyperInteger(parameter.getId())))
.ed25519(new Uint256(parameter.getEd25519()))
.build();
scAddress.setMuxedAccount(muxedEd25519Account);
break;
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/org/stellar/sdk/MuxedAccount.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ public MuxedAccount(@NonNull String address) {
byte[] rawMed25519 = StrKey.decodeMed25519PublicKey(address);
StrKey.RawMuxedAccountStrKeyParameter parameter =
StrKey.fromRawMuxedAccountStrKey(rawMed25519);
this.accountId = StrKey.encodeEd25519PublicKey(parameter.getEd25519().getUint256());
this.muxedId = parameter.getId().getUint64().getNumber();
this.accountId = StrKey.encodeEd25519PublicKey(parameter.getEd25519());
this.muxedId = parameter.getId();
} else {
throw new IllegalArgumentException("Invalid address");
}
Expand All @@ -87,10 +87,10 @@ public String getAddress() {
if (muxedId == null) {
return accountId;
}
org.stellar.sdk.xdr.MuxedAccount.MuxedAccountMed25519 med25519 = toXdr().getMed25519();
return StrKey.encodeMed25519PublicKey(
StrKey.toRawMuxedAccountStrKey(
new StrKey.RawMuxedAccountStrKeyParameter(med25519.getEd25519(), med25519.getId())));
new StrKey.RawMuxedAccountStrKeyParameter(
StrKey.decodeEd25519PublicKey(accountId), muxedId)));
}

/**
Expand Down
26 changes: 16 additions & 10 deletions src/main/java/org/stellar/sdk/StrKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,14 @@
import lombok.NonNull;
import lombok.Value;
import org.stellar.sdk.exception.UnexpectedException;
import org.stellar.sdk.xdr.Uint256;
import org.stellar.sdk.xdr.Uint64;
import org.stellar.sdk.xdr.XdrUnsignedHyperInteger;

/**
* StrKey is a helper class that allows encoding and decoding Stellar keys to/from strings, i.e.
* between their binary and string (i.e. "GABCD...", etc.) representations.
*/
public class StrKey {

private static final BigInteger UINT64_MAX = new BigInteger("18446744073709551615");
private static final byte[] b32Table = decodingTable();
private static final Base32 base32Codec = Base32Factory.getInstance();

Expand Down Expand Up @@ -584,11 +582,22 @@ private static boolean isInAlphabet(final byte[] arrayOctet) {

@Value
static class RawMuxedAccountStrKeyParameter {
@NonNull Uint256 ed25519;
@NonNull Uint64 id;
byte @NonNull [] ed25519;
@NonNull BigInteger id;
}

static byte[] toRawMuxedAccountStrKey(RawMuxedAccountStrKeyParameter parameter) {
byte[] ed25519Bytes = parameter.getEd25519();
if (ed25519Bytes.length != 32) {
throw new IllegalArgumentException(
"Muxed account ed25519 bytes must be 32 bytes long, got " + ed25519Bytes.length);
}
if (parameter.getId().compareTo(BigInteger.ZERO) < 0
|| parameter.getId().compareTo(UINT64_MAX) > 0) {
throw new IllegalArgumentException(
"Muxed account ID must be between 0 and 2^64 - 1 inclusive");
}

// Get the 64-bit ID. This is the critical part of the explanation.
//
// THE KEY INSIGHT: Why using .longValue() is safe for a uint64
Expand Down Expand Up @@ -633,8 +642,7 @@ static byte[] toRawMuxedAccountStrKey(RawMuxedAccountStrKeyParameter parameter)
// buffer,
// it correctly serializes the original uint64 value into 8 bytes, regardless of whether Java
// interpreted the intermediate `long` as positive or negative.
long idLong = parameter.getId().getUint64().getNumber().longValue();
byte[] ed25519Bytes = parameter.getEd25519().getUint256();
long idLong = parameter.getId().longValue();
return ByteBuffer.allocate(ed25519Bytes.length + 8).put(ed25519Bytes).putLong(idLong).array();
}

Expand All @@ -648,9 +656,7 @@ static RawMuxedAccountStrKeyParameter fromRawMuxedAccountStrKey(byte @NonNull []
buffer.get(ed25519Bytes);
byte[] idBytes = new byte[8];
buffer.get(idBytes);
Uint256 ed25519 = new Uint256(ed25519Bytes);
Uint64 id = new Uint64(new XdrUnsignedHyperInteger(new BigInteger(1, idBytes)));
return new RawMuxedAccountStrKeyParameter(ed25519, id);
return new RawMuxedAccountStrKeyParameter(ed25519Bytes, new BigInteger(1, idBytes));
}

enum VersionByte {
Expand Down
9 changes: 3 additions & 6 deletions src/test/kotlin/org/stellar/sdk/StrKeyTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -461,17 +461,14 @@ class StrKeyTest :
),
) { testCase ->
val ed25519Bytes = Util.hexToBytes(testCase.ed25519Hex)
val ed25519 = org.stellar.sdk.xdr.Uint256(ed25519Bytes)
val id =
org.stellar.sdk.xdr.Uint64(org.stellar.sdk.xdr.XdrUnsignedHyperInteger(testCase.id))
val param = StrKey.RawMuxedAccountStrKeyParameter(ed25519, id)
val param = StrKey.RawMuxedAccountStrKeyParameter(ed25519Bytes, testCase.id)

val bytes = StrKey.toRawMuxedAccountStrKey(param)
bytes.size shouldBe 40

val decoded = StrKey.fromRawMuxedAccountStrKey(bytes)
decoded.ed25519.uint256 shouldBe ed25519Bytes
decoded.id.uint64.number shouldBe testCase.id
decoded.ed25519 shouldBe ed25519Bytes
decoded.id shouldBe testCase.id
}
}

Expand Down
Loading