Skip to content

Commit

Permalink
Expose new send transaction params (#588)
Browse files Browse the repository at this point in the history
* clientlib + fakedapp changes

* walletlib + fakewallet changes
  • Loading branch information
Funkatronics authored Nov 10, 2023
1 parent 17c1d06 commit 7028fc0
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,11 @@ class LocalAdapterOperations(
@Suppress("BlockingMethodInNonBlockingContext")
client?.signAndSendTransactions(
transactions,
params.minContextSlot
params.minContextSlot,
params.commitment,
params.skipPreflight,
params.maxRetries,
params.waitForCommitmentToSendNextTransaction
)?.get()
?: throw InvalidObjectException("Provide a client before performing adapter operations")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
Expand Down Expand Up @@ -976,9 +977,25 @@ public void notifyOnComplete(@NonNull OnCompleteCallback<? super NotifyOnComplet
// sign_and_send_transactions
// =============================================================================================

/**
* @deprecated Consumers of {@link #signAndSendTransactions(byte[][], Integer)} should migrate to
* {@link #signAndSendTransactions(byte[][], Integer, String, Boolean, Integer, Boolean)}
* which exposes more transactions options according to the latest protocol specification.
*/
@Deprecated
@NonNull
public SignAndSendTransactionsFuture signAndSendTransactions(@NonNull @Size(min = 1) byte[][] transactions,
@Nullable Integer minContextSlot)
@Nullable Integer minContextSlot) throws IOException {
return signAndSendTransactions(transactions, minContextSlot, null, null, null, null);
}

@NonNull
public SignAndSendTransactionsFuture signAndSendTransactions(@NonNull @Size(min = 1) byte[][] transactions,
@Nullable Integer minContextSlot,
@Nullable String commitment,
@Nullable Boolean skipPreflight,
@Nullable Integer maxRetries,
@Nullable Boolean waitForCommitmentToSendNextTransaction)
throws IOException {
for (byte[] t : transactions) {
if (t == null || t.length == 0) {
Expand All @@ -990,9 +1007,21 @@ public SignAndSendTransactionsFuture signAndSendTransactions(@NonNull @Size(min
final JSONObject signAndSendTransactions = new JSONObject();
try {
signAndSendTransactions.put(ProtocolContract.PARAMETER_PAYLOADS, payloadsArr);
final JSONObject options = new JSONObject();
options.putOpt(ProtocolContract.PARAMETER_OPTIONS_COMMITMENT, commitment);
if (minContextSlot != null) {
final JSONObject options = new JSONObject();
options.put(ProtocolContract.PARAMETER_OPTIONS_MIN_CONTEXT_SLOT, (int)minContextSlot);
options.put(ProtocolContract.PARAMETER_OPTIONS_MIN_CONTEXT_SLOT, (int) minContextSlot);
}
if (skipPreflight != null) {
options.put(ProtocolContract.PARAMETER_OPTIONS_SKIP_PREFLIGHT, (boolean) skipPreflight);
}
if (maxRetries != null) {
options.put(ProtocolContract.PARAMETER_OPTIONS_MAX_RETRIES, (int) maxRetries);
}
if (waitForCommitmentToSendNextTransaction != null) {
options.put(ProtocolContract.PARAMETER_OPTIONS_WAIT_FOR_COMMITMENT, (boolean) waitForCommitmentToSendNextTransaction);
}
if (options.length() > 0) {
signAndSendTransactions.put(ProtocolContract.PARAMETER_OPTIONS, options);
}
} catch (JSONException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,16 @@ object MobileWalletAdapterUseCase {

suspend fun signAndSendTransactions(
transactions: Array<ByteArray>,
minContextSlot: Int? = null
minContextSlot: Int? = null,
commitment: String? = null,
skipPreflight: Boolean? = null,
maxRetries: Int? = null,
waitForCommitmentToSendNextTransaction: Boolean? = null
): Array<ByteArray> = coroutineScope {
try {
runInterruptible(Dispatchers.IO) {
client.signAndSendTransactions(transactions, minContextSlot).get()!!
client.signAndSendTransactions(transactions, minContextSlot, commitment,
skipPreflight, maxRetries, waitForCommitmentToSendNextTransaction).get()!!
}.signatures
} catch (e: ExecutionException) {
when (val cause = e.cause) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,10 @@ class MobileWalletAdapterViewModel(application: Application) : AndroidViewModel(
SendTransactionsUseCase(
request.endpointUri,
request.signedTransactions,
request.request.minContextSlot
request.request.minContextSlot,
request.request.commitment,
request.request.skipPreflight,
request.request.maxRetries
)
Log.d(TAG, "All transactions submitted via RPC")
request.request.completeWithSignatures(request.signatures)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,16 @@ object SendTransactionsUseCase {
suspend operator fun invoke(
rpcUri: Uri,
transactions: Array<ByteArray>,
minContextSlot: Int?
minContextSlot: Int?,
commitment: String?,
skipPreflight: Boolean?,
maxRetries: Int?,
// TODO: wait for commitment to send next transaction
) {
withContext(Dispatchers.IO) {
// Send all transactions and accumulate transaction signatures
val signatures = Array<String?>(transactions.size) { null }
// TODO: wait for commitment to send next transaction
transactions.forEachIndexed { i, transaction ->
val transactionBase64 = Base64.encodeToString(transaction, Base64.NO_WRAP)
Log.d(TAG, "Sending transaction: '$transactionBase64' with minContextSlot=$minContextSlot")
Expand All @@ -41,7 +46,10 @@ object SendTransactionsUseCase {
outputStream.write(
createSendTransactionRequest(
transactionBase64,
minContextSlot
minContextSlot,
commitment,
skipPreflight,
maxRetries
).encodeToByteArray()
)
}
Expand Down Expand Up @@ -72,7 +80,10 @@ object SendTransactionsUseCase {

private fun createSendTransactionRequest(
transactionBase64: String,
minContextSlot: Int?
minContextSlot: Int?,
commitment: String?,
skipPreflight: Boolean?,
maxRetries: Int?
): String {
val jo = JSONObject()
jo.put("jsonrpc", "2.0")
Expand All @@ -87,10 +98,16 @@ object SendTransactionsUseCase {
// Parameter 1 - options
val opt = JSONObject()
opt.put("encoding", "base64")
opt.put("preflightCommitment", "processed")
opt.put("preflightCommitment", commitment ?: "processed")
if (minContextSlot != null) {
opt.put("minContextSlot", minContextSlot)
}
if (skipPreflight != null) {
opt.put("skipPreflight", skipPreflight)
}
if (maxRetries != null) {
opt.put("maxRetries", maxRetries)
}
arr.put(opt)

jo.put("params", arr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -758,12 +758,28 @@ public String toString() {
public static class SignAndSendTransactionsRequest extends SignRequest<SignaturesResult> {
@Nullable
public final Integer minContextSlot;
@Nullable
public final String commitment;
@Nullable
public final Boolean skipPreflight;
@Nullable
public final Integer maxRetries;
@Nullable
public final Boolean waitForCommitmentToSendNextTransaction;

private SignAndSendTransactionsRequest(@Nullable Object id,
@NonNull @Size(min = 1) byte[][] transactions,
@Nullable Integer minContextSlot) {
@Nullable Integer minContextSlot,
@Nullable String commitment,
@Nullable Boolean skipPreflight,
@Nullable Integer maxRetries,
@Nullable Boolean waitForCommitmentToSendNextTransaction) {
super(id, transactions);
this.minContextSlot = minContextSlot;
this.commitment = commitment;
this.skipPreflight = skipPreflight;
this.maxRetries = maxRetries;
this.waitForCommitmentToSendNextTransaction = waitForCommitmentToSendNextTransaction;
}

@Override
Expand All @@ -782,6 +798,10 @@ public boolean completeExceptionally(@NonNull Exception ex) {
public String toString() {
return "SignAndSendTransactionsRequest{" +
"minContextSlot=" + minContextSlot +
", commitment='" + commitment + "'" +
", skipPreflight=" + skipPreflight +
", maxRetries=" + maxRetries +
", waitForCommitmentToSendNextTransaction=" + waitForCommitmentToSendNextTransaction +
", super=" + super.toString() +
'}';
}
Expand Down Expand Up @@ -833,19 +853,71 @@ private void handleSignAndSendTransactions(@Nullable Object id, @Nullable Object
final JSONObject options = o.optJSONObject(ProtocolContract.PARAMETER_OPTIONS);

final Integer minContextSlot;
if (options != null && options.has(ProtocolContract.PARAMETER_OPTIONS_MIN_CONTEXT_SLOT)) {
try {
minContextSlot = options.getInt(ProtocolContract.PARAMETER_OPTIONS_MIN_CONTEXT_SLOT);
} catch (JSONException e) {
handleRpcError(id, ERROR_INVALID_PARAMS, "min_context_slot must be an integer", null);
return;
final String commitment;
final Boolean skipPreflight;
final Integer maxRetries;
final Boolean waitForCommitmentToSendNextTransaction;
if (options != null) {
if (options.has(ProtocolContract.PARAMETER_OPTIONS_MIN_CONTEXT_SLOT)) {
try {
minContextSlot = options.getInt(ProtocolContract.PARAMETER_OPTIONS_MIN_CONTEXT_SLOT);
} catch (JSONException e) {
handleRpcError(id, ERROR_INVALID_PARAMS, "min_context_slot must be an integer", null);
return;
}
} else {
minContextSlot = null;
}
if (options.has(ProtocolContract.PARAMETER_OPTIONS_COMMITMENT)) {
try {
commitment = options.getString(ProtocolContract.PARAMETER_OPTIONS_COMMITMENT);
} catch (JSONException e) {
handleRpcError(id, ERROR_INVALID_PARAMS, "commitment must be a string", null);
return;
}
} else {
commitment = null;
}
if (options.has(ProtocolContract.PARAMETER_OPTIONS_SKIP_PREFLIGHT)) {
try {
skipPreflight = options.getBoolean(ProtocolContract.PARAMETER_OPTIONS_SKIP_PREFLIGHT);
} catch (JSONException e) {
handleRpcError(id, ERROR_INVALID_PARAMS, "skip_preflight must be a boolean", null);
return;
}
} else {
skipPreflight = null;
}
if (options.has(ProtocolContract.PARAMETER_OPTIONS_MAX_RETRIES)) {
try {
maxRetries = options.getInt(ProtocolContract.PARAMETER_OPTIONS_MAX_RETRIES);
} catch (JSONException e) {
handleRpcError(id, ERROR_INVALID_PARAMS, "max_retries must be an integer", null);
return;
}
} else {
maxRetries = null;
}
if (options.has(ProtocolContract.PARAMETER_OPTIONS_WAIT_FOR_COMMITMENT)) {
try {
waitForCommitmentToSendNextTransaction = options.getBoolean(ProtocolContract.PARAMETER_OPTIONS_WAIT_FOR_COMMITMENT);
} catch (JSONException e) {
handleRpcError(id, ERROR_INVALID_PARAMS, "wait_for_commitment_to_send_next_transaction must be a boolean", null);
return;
}
} else {
waitForCommitmentToSendNextTransaction = null;
}
} else {
minContextSlot = null;
commitment = null;
skipPreflight = null;
maxRetries = null;
waitForCommitmentToSendNextTransaction = null;
}

final SignAndSendTransactionsRequest request = new SignAndSendTransactionsRequest(
id, payloads, minContextSlot);
id, payloads, minContextSlot, commitment, skipPreflight, maxRetries, waitForCommitmentToSendNextTransaction);
request.notifyOnComplete((f) -> mHandler.post(() -> onSignAndSendTransactionsComplete(f)));
mMethodHandlers.signAndSendTransactions(request);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,26 @@ public Integer getMinContextSlot() {
return mRequest.minContextSlot;
}

@Nullable
public String getCommitment() {
return mRequest.commitment;
}

@Nullable
public Boolean getSkipPreflight() {
return mRequest.skipPreflight;
}

@Nullable
public Integer getMaxRetries() {
return mRequest.maxRetries;
}

@Nullable
public Boolean getWaitForCommitmentYoSendNExtTransaction() {
return mRequest.waitForCommitmentToSendNextTransaction;
}

public void completeWithSignatures(@NonNull @Size(min = 1) byte[][] signatures) {
mRequest.complete(new MobileWalletAdapterServer.SignaturesResult(signatures));
}
Expand Down

0 comments on commit 7028fc0

Please sign in to comment.