Skip to content

Commit cd4e6df

Browse files
authored
refactor: decouple StrKey muxed helpers from xdr wrappers (#780)
1 parent 2d4d06c commit cd4e6df

4 files changed

Lines changed: 30 additions & 24 deletions

File tree

src/main/java/org/stellar/sdk/Address.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
import org.stellar.sdk.xdr.SCAddress;
1313
import org.stellar.sdk.xdr.SCVal;
1414
import org.stellar.sdk.xdr.SCValType;
15+
import org.stellar.sdk.xdr.Uint256;
16+
import org.stellar.sdk.xdr.Uint64;
17+
import org.stellar.sdk.xdr.XdrUnsignedHyperInteger;
1518

1619
/**
1720
* Represents a single address in the Stellar network. An address can represent an account,
@@ -117,8 +120,8 @@ public static Address fromSCAddress(SCAddress scAddress) {
117120
return fromMuxedAccount(
118121
StrKey.toRawMuxedAccountStrKey(
119122
new StrKey.RawMuxedAccountStrKeyParameter(
120-
scAddress.getMuxedAccount().getEd25519(),
121-
scAddress.getMuxedAccount().getId())));
123+
scAddress.getMuxedAccount().getEd25519().getUint256(),
124+
scAddress.getMuxedAccount().getId().getUint64().getNumber())));
122125
case SC_ADDRESS_TYPE_CLAIMABLE_BALANCE:
123126
if (scAddress.getClaimableBalanceId().getDiscriminant()
124127
!= ClaimableBalanceIDType.CLAIMABLE_BALANCE_ID_TYPE_V0) {
@@ -174,8 +177,8 @@ public SCAddress toSCAddress() {
174177
StrKey.fromRawMuxedAccountStrKey(this.key);
175178
MuxedEd25519Account muxedEd25519Account =
176179
MuxedEd25519Account.builder()
177-
.id(parameter.getId())
178-
.ed25519(parameter.getEd25519())
180+
.id(new Uint64(new XdrUnsignedHyperInteger(parameter.getId())))
181+
.ed25519(new Uint256(parameter.getEd25519()))
179182
.build();
180183
scAddress.setMuxedAccount(muxedEd25519Account);
181184
break;

src/main/java/org/stellar/sdk/MuxedAccount.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ public MuxedAccount(@NonNull String address) {
7070
byte[] rawMed25519 = StrKey.decodeMed25519PublicKey(address);
7171
StrKey.RawMuxedAccountStrKeyParameter parameter =
7272
StrKey.fromRawMuxedAccountStrKey(rawMed25519);
73-
this.accountId = StrKey.encodeEd25519PublicKey(parameter.getEd25519().getUint256());
74-
this.muxedId = parameter.getId().getUint64().getNumber();
73+
this.accountId = StrKey.encodeEd25519PublicKey(parameter.getEd25519());
74+
this.muxedId = parameter.getId();
7575
} else {
7676
throw new IllegalArgumentException("Invalid address");
7777
}
@@ -87,10 +87,10 @@ public String getAddress() {
8787
if (muxedId == null) {
8888
return accountId;
8989
}
90-
org.stellar.sdk.xdr.MuxedAccount.MuxedAccountMed25519 med25519 = toXdr().getMed25519();
9190
return StrKey.encodeMed25519PublicKey(
9291
StrKey.toRawMuxedAccountStrKey(
93-
new StrKey.RawMuxedAccountStrKeyParameter(med25519.getEd25519(), med25519.getId())));
92+
new StrKey.RawMuxedAccountStrKeyParameter(
93+
StrKey.decodeEd25519PublicKey(accountId), muxedId)));
9494
}
9595

9696
/**

src/main/java/org/stellar/sdk/StrKey.java

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,14 @@
1010
import lombok.NonNull;
1111
import lombok.Value;
1212
import org.stellar.sdk.exception.UnexpectedException;
13-
import org.stellar.sdk.xdr.Uint256;
14-
import org.stellar.sdk.xdr.Uint64;
15-
import org.stellar.sdk.xdr.XdrUnsignedHyperInteger;
1613

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

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

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

585583
@Value
586584
static class RawMuxedAccountStrKeyParameter {
587-
@NonNull Uint256 ed25519;
588-
@NonNull Uint64 id;
585+
byte @NonNull [] ed25519;
586+
@NonNull BigInteger id;
589587
}
590588

591589
static byte[] toRawMuxedAccountStrKey(RawMuxedAccountStrKeyParameter parameter) {
590+
byte[] ed25519Bytes = parameter.getEd25519();
591+
if (ed25519Bytes.length != 32) {
592+
throw new IllegalArgumentException(
593+
"Muxed account ed25519 bytes must be 32 bytes long, got " + ed25519Bytes.length);
594+
}
595+
if (parameter.getId().compareTo(BigInteger.ZERO) < 0
596+
|| parameter.getId().compareTo(UINT64_MAX) > 0) {
597+
throw new IllegalArgumentException(
598+
"Muxed account ID must be between 0 and 2^64 - 1 inclusive");
599+
}
600+
592601
// Get the 64-bit ID. This is the critical part of the explanation.
593602
//
594603
// THE KEY INSIGHT: Why using .longValue() is safe for a uint64
@@ -633,8 +642,7 @@ static byte[] toRawMuxedAccountStrKey(RawMuxedAccountStrKeyParameter parameter)
633642
// buffer,
634643
// it correctly serializes the original uint64 value into 8 bytes, regardless of whether Java
635644
// interpreted the intermediate `long` as positive or negative.
636-
long idLong = parameter.getId().getUint64().getNumber().longValue();
637-
byte[] ed25519Bytes = parameter.getEd25519().getUint256();
645+
long idLong = parameter.getId().longValue();
638646
return ByteBuffer.allocate(ed25519Bytes.length + 8).put(ed25519Bytes).putLong(idLong).array();
639647
}
640648

@@ -648,9 +656,7 @@ static RawMuxedAccountStrKeyParameter fromRawMuxedAccountStrKey(byte @NonNull []
648656
buffer.get(ed25519Bytes);
649657
byte[] idBytes = new byte[8];
650658
buffer.get(idBytes);
651-
Uint256 ed25519 = new Uint256(ed25519Bytes);
652-
Uint64 id = new Uint64(new XdrUnsignedHyperInteger(new BigInteger(1, idBytes)));
653-
return new RawMuxedAccountStrKeyParameter(ed25519, id);
659+
return new RawMuxedAccountStrKeyParameter(ed25519Bytes, new BigInteger(1, idBytes));
654660
}
655661

656662
enum VersionByte {

src/test/kotlin/org/stellar/sdk/StrKeyTest.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -461,17 +461,14 @@ class StrKeyTest :
461461
),
462462
) { testCase ->
463463
val ed25519Bytes = Util.hexToBytes(testCase.ed25519Hex)
464-
val ed25519 = org.stellar.sdk.xdr.Uint256(ed25519Bytes)
465-
val id =
466-
org.stellar.sdk.xdr.Uint64(org.stellar.sdk.xdr.XdrUnsignedHyperInteger(testCase.id))
467-
val param = StrKey.RawMuxedAccountStrKeyParameter(ed25519, id)
464+
val param = StrKey.RawMuxedAccountStrKeyParameter(ed25519Bytes, testCase.id)
468465

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

472469
val decoded = StrKey.fromRawMuxedAccountStrKey(bytes)
473-
decoded.ed25519.uint256 shouldBe ed25519Bytes
474-
decoded.id.uint64.number shouldBe testCase.id
470+
decoded.ed25519 shouldBe ed25519Bytes
471+
decoded.id shouldBe testCase.id
475472
}
476473
}
477474

0 commit comments

Comments
 (0)