support sweeping funds from grpc api, relay multiple txs

This commit is contained in:
woodser 2025-06-13 07:57:02 -04:00 committed by GitHub
parent ab5f6c8191
commit 2f18a74478
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 89 additions and 25 deletions

View file

@ -299,8 +299,12 @@ public class CoreApi {
return walletsService.createXmrTx(destinations); return walletsService.createXmrTx(destinations);
} }
public String relayXmrTx(String metadata) { public List<MoneroTxWallet> createXmrSweepTxs(String address) {
return walletsService.relayXmrTx(metadata); return walletsService.createXmrSweepTxs(address);
}
public List<String> relayXmrTxs(List<String> metadatas) {
return walletsService.relayXmrTxs(metadatas);
} }
public long getAddressBalance(String addressString) { public long getAddressBalance(String addressString) {

View file

@ -173,12 +173,24 @@ class CoreWalletsService {
} }
} }
String relayXmrTx(String metadata) { List<MoneroTxWallet> createXmrSweepTxs(String address) {
accountService.checkAccountOpen(); accountService.checkAccountOpen();
verifyWalletsAreAvailable(); verifyWalletsAreAvailable();
verifyEncryptedWalletIsUnlocked(); verifyEncryptedWalletIsUnlocked();
try { try {
return xmrWalletService.relayTx(metadata); return xmrWalletService.createSweepTxs(address);
} catch (Exception ex) {
log.error("", ex);
throw new IllegalStateException(ex);
}
}
List<String> relayXmrTxs(List<String> metadatas) {
accountService.checkAccountOpen();
verifyWalletsAreAvailable();
verifyEncryptedWalletIsUnlocked();
try {
return xmrWalletService.relayTxs(metadatas);
} catch (Exception ex) { } catch (Exception ex) {
log.error("", ex); log.error("", ex);
throw new IllegalStateException(ex); throw new IllegalStateException(ex);

View file

@ -441,6 +441,12 @@ public class XmrWalletService extends XmrWalletBase {
if (name.contains(File.separator)) throw new IllegalArgumentException("Path not expected: " + name); if (name.contains(File.separator)) throw new IllegalArgumentException("Path not expected: " + name);
} }
public MoneroTxWallet createTx(List<MoneroDestination> destinations) {
MoneroTxWallet tx = createTx(new MoneroTxConfig().setAccountIndex(0).setDestinations(destinations).setRelay(false).setCanSplit(false));
//printTxs("XmrWalletService.createTx", tx);
return tx;
}
public MoneroTxWallet createTx(MoneroTxConfig txConfig) { public MoneroTxWallet createTx(MoneroTxConfig txConfig) {
synchronized (walletLock) { synchronized (walletLock) {
synchronized (HavenoUtils.getWalletFunctionLock()) { synchronized (HavenoUtils.getWalletFunctionLock()) {
@ -455,18 +461,30 @@ public class XmrWalletService extends XmrWalletBase {
} }
} }
public String relayTx(String metadata) { public List<MoneroTxWallet> createSweepTxs(String address) {
return createSweepTxs(new MoneroTxConfig().setAccountIndex(0).setAddress(address).setRelay(false));
}
public List<MoneroTxWallet> createSweepTxs(MoneroTxConfig txConfig) {
synchronized (walletLock) { synchronized (walletLock) {
String txId = wallet.relayTx(metadata); synchronized (HavenoUtils.getWalletFunctionLock()) {
List<MoneroTxWallet> txs = wallet.sweepUnlocked(txConfig);
if (Boolean.TRUE.equals(txConfig.getRelay())) {
for (MoneroTxWallet tx : txs) cachedTxs.addFirst(tx);
cacheWalletInfo();
requestSaveWallet(); requestSaveWallet();
return txId; }
return txs;
}
} }
} }
public MoneroTxWallet createTx(List<MoneroDestination> destinations) { public List<String> relayTxs(List<String> metadatas) {
MoneroTxWallet tx = createTx(new MoneroTxConfig().setAccountIndex(0).setDestinations(destinations).setRelay(false).setCanSplit(false)); synchronized (walletLock) {
//printTxs("XmrWalletService.createTx", tx); List<String> txIds = wallet.relayTxs(metadatas);
return tx; requestSaveWallet();
return txIds;
}
} }
/** /**

View file

@ -43,6 +43,8 @@ import static haveno.core.api.model.XmrTx.toXmrTx;
import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor;
import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter;
import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
import haveno.proto.grpc.CreateXmrSweepTxsReply;
import haveno.proto.grpc.CreateXmrSweepTxsRequest;
import haveno.proto.grpc.CreateXmrTxReply; import haveno.proto.grpc.CreateXmrTxReply;
import haveno.proto.grpc.CreateXmrTxRequest; import haveno.proto.grpc.CreateXmrTxRequest;
import haveno.proto.grpc.GetAddressBalanceReply; import haveno.proto.grpc.GetAddressBalanceReply;
@ -61,8 +63,8 @@ import haveno.proto.grpc.GetXmrTxsReply;
import haveno.proto.grpc.GetXmrTxsRequest; import haveno.proto.grpc.GetXmrTxsRequest;
import haveno.proto.grpc.LockWalletReply; import haveno.proto.grpc.LockWalletReply;
import haveno.proto.grpc.LockWalletRequest; import haveno.proto.grpc.LockWalletRequest;
import haveno.proto.grpc.RelayXmrTxReply; import haveno.proto.grpc.RelayXmrTxsReply;
import haveno.proto.grpc.RelayXmrTxRequest; import haveno.proto.grpc.RelayXmrTxsRequest;
import haveno.proto.grpc.RemoveWalletPasswordReply; import haveno.proto.grpc.RemoveWalletPasswordReply;
import haveno.proto.grpc.RemoveWalletPasswordRequest; import haveno.proto.grpc.RemoveWalletPasswordRequest;
import haveno.proto.grpc.SetWalletPasswordReply; import haveno.proto.grpc.SetWalletPasswordReply;
@ -185,7 +187,7 @@ class GrpcWalletsService extends WalletsImplBase {
.stream() .stream()
.map(s -> new MoneroDestination(s.getAddress(), new BigInteger(s.getAmount()))) .map(s -> new MoneroDestination(s.getAddress(), new BigInteger(s.getAmount())))
.collect(Collectors.toList())); .collect(Collectors.toList()));
log.info("Successfully created XMR tx: hash {}", tx.getHash()); log.info("Successfully created XMR tx, hash: {}", tx.getHash());
var reply = CreateXmrTxReply.newBuilder() var reply = CreateXmrTxReply.newBuilder()
.setTx(toXmrTx(tx).toProtoMessage()) .setTx(toXmrTx(tx).toProtoMessage())
.build(); .build();
@ -197,12 +199,30 @@ class GrpcWalletsService extends WalletsImplBase {
} }
@Override @Override
public void relayXmrTx(RelayXmrTxRequest req, public void createXmrSweepTxs(CreateXmrSweepTxsRequest req,
StreamObserver<RelayXmrTxReply> responseObserver) { StreamObserver<CreateXmrSweepTxsReply> responseObserver) {
try { try {
String txHash = coreApi.relayXmrTx(req.getMetadata()); List<MoneroTxWallet> xmrTxs = coreApi.createXmrSweepTxs(req.getAddress());
var reply = RelayXmrTxReply.newBuilder() log.info("Successfully created XMR sweep txs, hashes: {}", xmrTxs.stream().map(MoneroTxWallet::getHash).collect(Collectors.toList()));
.setHash(txHash) var reply = CreateXmrSweepTxsReply.newBuilder()
.addAllTxs(xmrTxs.stream()
.map(s -> toXmrTx(s).toProtoMessage())
.collect(Collectors.toList()))
.build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
} catch (Throwable cause) {
exceptionHandler.handleException(log, cause, responseObserver);
}
}
@Override
public void relayXmrTxs(RelayXmrTxsRequest req,
StreamObserver<RelayXmrTxsReply> responseObserver) {
try {
List<String> txHashes = coreApi.relayXmrTxs(req.getMetadatasList());
var reply = RelayXmrTxsReply.newBuilder()
.addAllHashes(txHashes)
.build(); .build();
responseObserver.onNext(reply); responseObserver.onNext(reply);
responseObserver.onCompleted(); responseObserver.onCompleted();

View file

@ -944,7 +944,9 @@ service Wallets {
} }
rpc CreateXmrTx (CreateXmrTxRequest) returns (CreateXmrTxReply) { rpc CreateXmrTx (CreateXmrTxRequest) returns (CreateXmrTxReply) {
} }
rpc relayXmrTx (RelayXmrTxRequest) returns (RelayXmrTxReply) { rpc CreateXmrSweepTxs (CreateXmrSweepTxsRequest) returns (CreateXmrSweepTxsReply) {
}
rpc RelayXmrTxs (RelayXmrTxsRequest) returns (RelayXmrTxsReply) {
} }
rpc GetAddressBalance (GetAddressBalanceRequest) returns (GetAddressBalanceReply) { rpc GetAddressBalance (GetAddressBalanceRequest) returns (GetAddressBalanceReply) {
} }
@ -1036,12 +1038,20 @@ message CreateXmrTxReply {
XmrTx tx = 1; XmrTx tx = 1;
} }
message RelayXmrTxRequest { message CreateXmrSweepTxsRequest {
string metadata = 1; string address = 1;
} }
message RelayXmrTxReply { message CreateXmrSweepTxsReply {
string hash = 1; repeated XmrTx txs = 1;
}
message RelayXmrTxsRequest {
repeated string metadatas = 1;
}
message RelayXmrTxsReply {
repeated string hashes = 2;
} }
message GetAddressBalanceRequest { message GetAddressBalanceRequest {