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

Update XDR for Protocol 19, add encoding support for CAP-40 SignedPayload Signer #413

Closed
wants to merge 7 commits into from

Conversation

sreuland
Copy link
Contributor

@sreuland sreuland commented Mar 21, 2022

Update the Java SDK to have the new XDR schema for Protocol 19

this change focuses on supporting CAP-40 , namely the new Signed Payload Signer as new StrKey.

Update the StrKey encoding/decoding to include the new Signed Payload Signer, add more tests where signed payload signer could appear such as SetOptionsOperation and AccountEntry.

Closes #412
Closes #410

can ignore all changed files in src/main/java/org/stellar/sdk/xdr, they are generated code from xdrgen tool against the latest xdr schema files.

This is first half of Protocol 19 support, a follow-on PR will be coming for remaining Protocol 19 support of CAP-21 which introduces new tx pre-conditions on of which is extraSigners which this new Signed Payload Signer can be used.

…ignedPayload Signer from CAP40 into StrKey encoding/decoding.
@sreuland sreuland requested a review from a team March 21, 2022 16:06
@sreuland sreuland mentioned this pull request Mar 21, 2022
4 tasks
Copy link
Contributor

@Shaptic Shaptic left a comment

Choose a reason for hiding this comment

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

Definitely coming along, feedback is below!

src/main/java/org/stellar/sdk/Predicate.java Outdated Show resolved Hide resolved
src/main/java/org/stellar/sdk/SignedPayloadSigner.java Outdated Show resolved Hide resolved
src/main/java/org/stellar/sdk/StrKey.java Outdated Show resolved Hide resolved
Comment on lines +254 to +256
if (envelope.getTx().getCond().getDiscriminant().equals(PreconditionType.PRECOND_TIME)) {
mTimeBounds = TimeBounds.fromXdr(envelope.getTx().getCond().getTimeBounds());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

necessary but not sufficient: there can also be timebounds on the PRECOND_V2 type. maybe a helper is in order for a general way to retrieve timebounds given a tx?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, I'll use that suggestion, will be in the next follow-on PR that adds the CAP21 support on those new conditions, I included all the xdr schema changes up front in this pr, but only did the cap40 changes above first, this part ideally was just trying to refactor to maintain present compile/test until then.

Copy link
Contributor

Choose a reason for hiding this comment

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

a way to do it here actually would be to say instead .notEquals(PreconditionType.PRECOND_NONE), since both other forms have a timebound condition 🤔

src/main/java/org/stellar/sdk/SignedPayloadSigner.java Outdated Show resolved Hide resolved
import static com.google.common.base.Preconditions.checkNotNull;

/**
* Signer is a helper class that creates {@link org.stellar.sdk.xdr.SignerKey} objects.
*/
public class Signer {
public static final int SIGNED_PAYLOAD_MAX_PAYLOAD_LENGTH = 64;
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah yeah, I think this belongs above in SignedPayloadSigner

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok, I had located validation here in the Signer.signedPayload(SignedPayloadSigner) factory method which constructs the xdr SignerKey for payload signer from the payload. The intent on SignedPayloadSigner was to be data transfer object, no logic, to your point, it could take on that role also of validation, but thought was keeping that logic closer to when it's used in SignerKey, let me know if you want to discuss more, thanks!

Copy link
Contributor

Choose a reason for hiding this comment

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

You do have validation in two places (signer key and strkey), and imo you'd never want a SignedPayloadSigner that wasn't valid, but your separation of concerns also makes sense. No strong opinion here:+1:

char[] encoded = encodeCheck(VersionByte.SIGNED_PAYLOAD, record.toByteArray());
return String.valueOf(encoded);
} catch (Exception ex) {
throw new FormatException(ex.getMessage());
Copy link
Contributor

Choose a reason for hiding this comment

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

Why rethrow when you can just let it bubble up?

Copy link
Contributor Author

@sreuland sreuland Mar 23, 2022

Choose a reason for hiding this comment

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

to muffle the checked exceptions which otherwise would require adding on a throws declaration on the method for each one, which then forces the callers to specifically handle it, it's mostly for caller convenience as there is no significant app-level meaning to a checked failure that the client could catch and do something else instead, rather they should just let it go up also.

Copy link
Contributor

Choose a reason for hiding this comment

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

makes sense, java-isms.. 👍

Comment on lines +254 to +256
if (envelope.getTx().getCond().getDiscriminant().equals(PreconditionType.PRECOND_TIME)) {
mTimeBounds = TimeBounds.fromXdr(envelope.getTx().getCond().getTimeBounds());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

a way to do it here actually would be to say instead .notEquals(PreconditionType.PRECOND_NONE), since both other forms have a timebound condition 🤔

src/main/java/org/stellar/sdk/xdr/Asset.java Show resolved Hide resolved
@sreuland sreuland requested a review from Shaptic March 23, 2022 18:28
Copy link
Contributor

@Shaptic Shaptic left a comment

Choose a reason for hiding this comment

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

1 small note of clarification around encoding, otherwise LGTM :shipit:

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

/**
* Signer is a helper class that creates {@link org.stellar.sdk.xdr.SignerKey} objects.
*/
public class Signer {
public static final int SIGNED_PAYLOAD_MAX_PAYLOAD_LENGTH = 64;
Copy link
Contributor

Choose a reason for hiding this comment

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

You do have validation in two places (signer key and strkey), and imo you'd never want a SignedPayloadSigner that wasn't valid, but your separation of concerns also makes sense. No strong opinion here:+1:

char[] encoded = encodeCheck(VersionByte.SIGNED_PAYLOAD, record.toByteArray());
return String.valueOf(encoded);
} catch (Exception ex) {
throw new FormatException(ex.getMessage());
Copy link
Contributor

Choose a reason for hiding this comment

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

makes sense, java-isms.. 👍

Comment on lines 241 to +245
// Why not use base32Encoding.encode here?
// We don't want secret seed to be stored as String in memory because of security reasons. It's impossible
// to erase it from memory when we want it to be erased (ASAP).
CharArrayWriter charArrayWriter = new CharArrayWriter(unencoded.length);
OutputStream charOutputStream = StrKey.base32Encoding.encodingStream(charArrayWriter);
OutputStream charOutputStream = base32Encoding.encodingStream(charArrayWriter);
Copy link
Contributor

Choose a reason for hiding this comment

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

Errm, note the comment above this line? I think there's a reason we use StrKey? Maybe @tamirms knows more on this (or git blame it)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this comment was referring to the usage of .encode() vs .encodingStream(), the change here was just source tidy-up, StrKey.base32Encoding was redundant, as within StrKey class scope, it references the same static member declared here at base32Encoding

@sreuland
Copy link
Contributor Author

You do have validation in two places (signer key and strkey), and imo you'd never want a SignedPayloadSigner that wasn't valid

@Shaptic , good point, since it spread to both, best to encapsulate once in the shared data object, updated c61a5d531371

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants