Skip to content
Open
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
30 changes: 30 additions & 0 deletions src/main/java/org/p2p/solanaj/rpc/RpcApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import org.p2p.solanaj.rpc.types.TokenResultObjects.TokenAmountInfo;
import org.p2p.solanaj.rpc.types.config.*;
import org.p2p.solanaj.rpc.types.config.RpcSendTransactionConfig.Encoding;
import org.p2p.solanaj.transaction.confirm.SolanaPollingTransactionConfirmProcessor;
import org.p2p.solanaj.transaction.confirm.SolanaTransactionConfirmProcessor;
import org.p2p.solanaj.transaction.exceptions.SolanaTransactionException;
import org.p2p.solanaj.ws.SubscriptionWebSocketClient;
import org.p2p.solanaj.ws.listeners.NotificationEventListener;

Expand Down Expand Up @@ -133,6 +136,24 @@ public void sendAndConfirmTransaction(Transaction transaction, List<Account> sig
subClient.signatureSubscribe(signature, listener);
}

/**
* Send the transaction and block the current thread until the transaction status is confirmed or the waiting time is exceeded.
* @param transaction the transaction to send
* @param signers the list of accounts that will sign the transaction
* @param confirmProcessor the processor that will process the transaction
* @return the confirmation transaction
* @throws RpcException if an error occurs during the RPC call
* @throws SolanaTransactionException Transaction confirmation failed or exceeded the maximum waiting time.
*/
public ConfirmedTransaction sendAndConfirmTransaction(Transaction transaction, List<Account> signers, SolanaTransactionConfirmProcessor confirmProcessor) throws RpcException, SolanaTransactionException {
String signature = sendTransaction(transaction, signers, null);
return confirmProcessor.waitForTransactionConfirm(signature);
}

public ConfirmedTransaction sendAndConfirmTransaction(Transaction transaction, List<Account> signers) throws RpcException, SolanaTransactionException {
return sendAndConfirmTransaction(transaction, signers, new SolanaPollingTransactionConfirmProcessor());
}

public void sendAndConfirmRawTransaction(String encodeSerializedTransaction, RpcSendTransactionConfig rpcSendTransactionConfig,
NotificationEventListener listener) throws RpcException {
String signature = sendRawTransaction(encodeSerializedTransaction, rpcSendTransactionConfig);
Expand All @@ -141,6 +162,15 @@ public void sendAndConfirmRawTransaction(String encodeSerializedTransaction, Rpc
subClient.signatureSubscribe(signature, listener);
}

public ConfirmedTransaction sendAndConfirmRawTransaction(String encodeSerializedTransaction, RpcSendTransactionConfig rpcSendTransactionConfig, SolanaTransactionConfirmProcessor confirmProcessor) throws RpcException, SolanaTransactionException {
String signature = sendRawTransaction(encodeSerializedTransaction, rpcSendTransactionConfig);
return confirmProcessor.waitForTransactionConfirm(signature);
}

public ConfirmedTransaction sendAndConfirmRawTransaction(String encodeSerializedTransaction, RpcSendTransactionConfig rpcSendTransactionConfig) throws RpcException, SolanaTransactionException {
return sendAndConfirmRawTransaction(encodeSerializedTransaction, rpcSendTransactionConfig, new SolanaPollingTransactionConfirmProcessor());
}

public long getBalance(PublicKey account) throws RpcException {
return getBalance(account, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ public static class Transaction {


}
@Json(name = "blockTime")
private long blocktime;

@Json(name = "meta")
private Meta meta;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.p2p.solanaj.transaction.confirm;

import org.p2p.solanaj.rpc.Cluster;
import org.p2p.solanaj.rpc.RpcClient;
import org.p2p.solanaj.rpc.RpcException;
import org.p2p.solanaj.rpc.types.ConfirmedTransaction;
import org.p2p.solanaj.rpc.types.config.Commitment;
import org.p2p.solanaj.transaction.exceptions.SolanaTransactionException;


/**
* 使用每个提供的事务id,轮询直到我们获到确认交易
*/
public class SolanaPollingTransactionConfirmProcessor extends SolanaTransactionConfirmProcessor {
protected final long sleepDuration;
protected final int attempts;

public SolanaPollingTransactionConfirmProcessor(RpcClient rpcClient, Commitment commitment, long sleepDuration, int attempts) {
super(rpcClient, commitment);
this.sleepDuration = sleepDuration;
this.attempts = attempts;
}

public SolanaPollingTransactionConfirmProcessor(RpcClient rpcClient, Commitment commitment) {
this(rpcClient, commitment, 1000, 120);
}

public SolanaPollingTransactionConfirmProcessor(RpcClient rpcClient) {
this(rpcClient, Commitment.FINALIZED);
}

public SolanaPollingTransactionConfirmProcessor() {
this(new RpcClient(Cluster.MAINNET));
}

@Override
public ConfirmedTransaction waitForTransactionConfirm(String txid) throws SolanaTransactionException, RpcException {
return getTransactionReceipt(txid, sleepDuration, attempts);
}

private ConfirmedTransaction getTransactionReceipt(
String txid, long sleepDuration, int attempts)
throws SolanaTransactionException, RpcException {

for (int i = 0; i < attempts; i++) {
ConfirmedTransaction confirmedTransaction = sendConfirmTransactionRequest(txid);

if (confirmedTransaction != null) {
return confirmedTransaction;
}

// Sleep unless it is the last attempt.
if (i < attempts - 1) {
try {
Thread.sleep(sleepDuration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

throw new SolanaTransactionException(
"Transaction confirm was not generated after "
+ ((sleepDuration * attempts) / 1000
+ " seconds for txid: "
+ txid),
txid);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.p2p.solanaj.transaction.confirm;

import org.p2p.solanaj.rpc.RpcClient;
import org.p2p.solanaj.rpc.RpcException;
import org.p2p.solanaj.rpc.types.ConfirmedTransaction;
import org.p2p.solanaj.rpc.types.config.Commitment;
import org.p2p.solanaj.transaction.exceptions.SolanaTransactionException;


/**
* solana交易状态确认检查处理
*/
public abstract class SolanaTransactionConfirmProcessor {
private final RpcClient rpcClient;
private final Commitment commitment;

public SolanaTransactionConfirmProcessor(RpcClient rpcClient, Commitment commitment) {
this.rpcClient = rpcClient;
this.commitment = commitment;
}

public abstract ConfirmedTransaction waitForTransactionConfirm(String txid)
throws SolanaTransactionException, RpcException;

ConfirmedTransaction sendConfirmTransactionRequest(String txid)
throws RpcException, SolanaTransactionException {
ConfirmedTransaction confirmedTransaction = rpcClient.getApi().getTransaction(txid, commitment);

if (confirmedTransaction == null) {
return null;
}
if (confirmedTransaction.getMeta().getErr() != null) {
throw new SolanaTransactionException(
"Error processing request: " + confirmedTransaction.getMeta().getErr());
}

return confirmedTransaction;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.p2p.solanaj.transaction.exceptions;


import lombok.Getter;

import java.util.Optional;

public class SolanaTransactionException extends Exception {

@Getter
private Optional<String> txid = Optional.empty();

public SolanaTransactionException(String message) {
super(message);
}

public SolanaTransactionException(String message, String txid) {
super(message);
this.txid = Optional.ofNullable(txid);
}

public SolanaTransactionException(Throwable cause) {
super(cause);
}


}