Search in sources :

Example 1 with SecretPoint

use of com.sparrowwallet.drongo.bip47.SecretPoint in project sparrow by sparrowwallet.

the class PayNymController method addWalletIfNotificationTransactionPresent.

private void addWalletIfNotificationTransactionPresent(Wallet decryptedWallet, Map<BlockTransaction, PayNym> unlinkedPayNyms, Map<BlockTransaction, WalletNode> unlinkedNotifications) {
    List<Wallet> addedWallets = new ArrayList<>();
    for (BlockTransaction blockTransaction : unlinkedNotifications.keySet()) {
        try {
            PayNym payNym = unlinkedPayNyms.get(blockTransaction);
            PaymentCode externalPaymentCode = payNym.paymentCode();
            WalletNode input0Node = unlinkedNotifications.get(blockTransaction);
            Keystore keystore = input0Node.getWallet().isNested() ? decryptedWallet.getChildWallet(input0Node.getWallet().getName()).getKeystores().get(0) : decryptedWallet.getKeystores().get(0);
            ECKey input0Key = keystore.getKey(input0Node);
            TransactionOutPoint input0Outpoint = PaymentCode.getDesignatedInput(blockTransaction.getTransaction()).getOutpoint();
            SecretPoint secretPoint = new SecretPoint(input0Key.getPrivKeyBytes(), externalPaymentCode.getNotificationKey().getPubKey());
            byte[] blindingMask = PaymentCode.getMask(secretPoint.ECDHSecretAsBytes(), input0Outpoint.bitcoinSerialize());
            byte[] blindedPaymentCode = PaymentCode.blind(getMasterWallet().getPaymentCode().getPayload(), blindingMask);
            byte[] opReturnData = PaymentCode.getOpReturnData(blockTransaction.getTransaction());
            if (Arrays.equals(opReturnData, blindedPaymentCode)) {
                addedWallets.addAll(addChildWallets(payNym, externalPaymentCode));
            } else {
                blockTransaction.setLabel(INVALID_PAYMENT_CODE_LABEL);
                EventManager.get().post(new WalletEntryLabelsChangedEvent(input0Node.getWallet(), new TransactionEntry(input0Node.getWallet(), blockTransaction, Collections.emptyMap(), Collections.emptyMap())));
            }
        } catch (Exception e) {
            log.error("Error adding linked contact from notification transaction", e);
        }
    }
    if (!addedWallets.isEmpty()) {
        Wallet masterWallet = getMasterWallet();
        Storage storage = AppServices.get().getOpenWallets().get(masterWallet);
        EventManager.get().post(new ChildWalletsAddedEvent(storage, masterWallet, addedWallets));
        followingList.refresh();
    }
}
Also used : PaymentCode(com.sparrowwallet.drongo.bip47.PaymentCode) ECKey(com.sparrowwallet.drongo.crypto.ECKey) Storage(com.sparrowwallet.sparrow.io.Storage) TransactionEntry(com.sparrowwallet.sparrow.wallet.TransactionEntry) SecretPoint(com.sparrowwallet.drongo.bip47.SecretPoint)

Example 2 with SecretPoint

use of com.sparrowwallet.drongo.bip47.SecretPoint in project sparrow by sparrowwallet.

the class PayNymController method broadcastNotificationTransaction.

private void broadcastNotificationTransaction(Wallet decryptedWallet, WalletTransaction walletTransaction, PaymentCode paymentCode, PayNym payNym) {
    try {
        PaymentCode externalPaymentCode = payNym.paymentCode();
        WalletNode input0Node = walletTransaction.getSelectedUtxos().entrySet().iterator().next().getValue();
        Keystore keystore = input0Node.getWallet().isNested() ? decryptedWallet.getChildWallet(input0Node.getWallet().getName()).getKeystores().get(0) : decryptedWallet.getKeystores().get(0);
        ECKey input0Key = keystore.getKey(input0Node);
        TransactionOutPoint input0Outpoint = walletTransaction.getTransaction().getInputs().iterator().next().getOutpoint();
        SecretPoint secretPoint = new SecretPoint(input0Key.getPrivKeyBytes(), externalPaymentCode.getNotificationKey().getPubKey());
        byte[] blindingMask = PaymentCode.getMask(secretPoint.ECDHSecretAsBytes(), input0Outpoint.bitcoinSerialize());
        byte[] blindedPaymentCode = PaymentCode.blind(paymentCode.getPayload(), blindingMask);
        WalletTransaction finalWalletTx = getWalletTransaction(decryptedWallet, payNym, blindedPaymentCode, walletTransaction.getSelectedUtxos().keySet());
        PSBT psbt = finalWalletTx.createPSBT();
        decryptedWallet.sign(psbt);
        decryptedWallet.finalise(psbt);
        Transaction transaction = psbt.extractTransaction();
        ElectrumServer.BroadcastTransactionService broadcastTransactionService = new ElectrumServer.BroadcastTransactionService(transaction);
        broadcastTransactionService.setOnSucceeded(successEvent -> {
            ElectrumServer.TransactionMempoolService transactionMempoolService = new ElectrumServer.TransactionMempoolService(walletTransaction.getWallet(), transaction.getTxId(), new HashSet<>(walletTransaction.getSelectedUtxos().values()));
            transactionMempoolService.setDelay(Duration.seconds(2));
            transactionMempoolService.setPeriod(Duration.seconds(5));
            transactionMempoolService.setRestartOnFailure(false);
            transactionMempoolService.setOnSucceeded(mempoolWorkerStateEvent -> {
                Set<String> scriptHashes = transactionMempoolService.getValue();
                if (!scriptHashes.isEmpty()) {
                    transactionMempoolService.cancel();
                    List<Wallet> addedWallets = addChildWallets(payNym, externalPaymentCode);
                    Wallet masterWallet = getMasterWallet();
                    Storage storage = AppServices.get().getOpenWallets().get(masterWallet);
                    EventManager.get().post(new ChildWalletsAddedEvent(storage, masterWallet, addedWallets));
                    retrievePayNymProgress.setVisible(false);
                    followingList.refresh();
                    BlockTransaction blockTransaction = walletTransaction.getWallet().getWalletTransaction(transaction.getTxId());
                    if (blockTransaction != null && blockTransaction.getLabel() == null) {
                        blockTransaction.setLabel("Link " + payNym.nymName());
                        TransactionEntry transactionEntry = new TransactionEntry(walletTransaction.getWallet(), blockTransaction, Collections.emptyMap(), Collections.emptyMap());
                        EventManager.get().post(new WalletEntryLabelsChangedEvent(walletTransaction.getWallet(), List.of(transactionEntry)));
                    }
                }
                if (transactionMempoolService.getIterationCount() > 5 && transactionMempoolService.isRunning()) {
                    transactionMempoolService.cancel();
                    retrievePayNymProgress.setVisible(false);
                    followingList.refresh();
                    log.error("Timeout searching for broadcasted notification transaction");
                    AppServices.showErrorDialog("Timeout searching for broadcasted transaction", "The transaction was broadcast but the server did not register it in the mempool. It is safe to try linking again.");
                }
            });
            transactionMempoolService.setOnFailed(mempoolWorkerStateEvent -> {
                transactionMempoolService.cancel();
                log.error("Error searching for broadcasted notification transaction", mempoolWorkerStateEvent.getSource().getException());
                retrievePayNymProgress.setVisible(false);
                followingList.refresh();
                AppServices.showErrorDialog("Timeout searching for broadcasted transaction", "The transaction was broadcast but the server did not register it in the mempool. It is safe to try linking again.");
            });
            transactionMempoolService.start();
        });
        broadcastTransactionService.setOnFailed(failedEvent -> {
            log.error("Error broadcasting notification transaction", failedEvent.getSource().getException());
            retrievePayNymProgress.setVisible(false);
            followingList.refresh();
            AppServices.showErrorDialog("Error broadcasting notification transaction", failedEvent.getSource().getException().getMessage());
        });
        retrievePayNymProgress.setVisible(true);
        notificationTransactions.put(transaction.getTxId(), payNym);
        broadcastTransactionService.start();
    } catch (Exception e) {
        log.error("Error creating notification transaction", e);
        retrievePayNymProgress.setVisible(false);
        followingList.refresh();
        AppServices.showErrorDialog("Error creating notification transaction", e.getMessage());
    }
}
Also used : ECKey(com.sparrowwallet.drongo.crypto.ECKey) SecureString(com.sparrowwallet.drongo.SecureString) SecretPoint(com.sparrowwallet.drongo.bip47.SecretPoint) PaymentCode(com.sparrowwallet.drongo.bip47.PaymentCode) PSBT(com.sparrowwallet.drongo.psbt.PSBT) ElectrumServer(com.sparrowwallet.sparrow.net.ElectrumServer) Storage(com.sparrowwallet.sparrow.io.Storage) TransactionEntry(com.sparrowwallet.sparrow.wallet.TransactionEntry)

Example 3 with SecretPoint

use of com.sparrowwallet.drongo.bip47.SecretPoint in project sparrow by sparrowwallet.

the class SendController method broadcastNotification.

public void broadcastNotification(Wallet decryptedWallet) {
    try {
        PaymentCode paymentCode = decryptedWallet.getPaymentCode();
        PaymentCode externalPaymentCode = paymentCodeProperty.get();
        WalletTransaction walletTransaction = walletTransactionProperty.get();
        WalletNode input0Node = walletTransaction.getSelectedUtxos().entrySet().iterator().next().getValue();
        Keystore keystore = input0Node.getWallet().isNested() ? decryptedWallet.getChildWallet(input0Node.getWallet().getName()).getKeystores().get(0) : decryptedWallet.getKeystores().get(0);
        ECKey input0Key = keystore.getKey(input0Node);
        TransactionOutPoint input0Outpoint = walletTransaction.getTransaction().getInputs().iterator().next().getOutpoint();
        SecretPoint secretPoint = new SecretPoint(input0Key.getPrivKeyBytes(), externalPaymentCode.getNotificationKey().getPubKey());
        byte[] blindingMask = PaymentCode.getMask(secretPoint.ECDHSecretAsBytes(), input0Outpoint.bitcoinSerialize());
        byte[] blindedPaymentCode = PaymentCode.blind(paymentCode.getPayload(), blindingMask);
        List<UtxoSelector> utxoSelectors = List.of(new PresetUtxoSelector(walletTransaction.getSelectedUtxos().keySet(), true));
        Long userFee = userFeeSet.get() ? getFeeValueSats() : null;
        double feeRate = getUserFeeRate();
        Integer currentBlockHeight = AppServices.getCurrentBlockHeight();
        boolean groupByAddress = Config.get().isGroupByAddress();
        boolean includeMempoolOutputs = Config.get().isIncludeMempoolOutputs();
        boolean includeSpentMempoolOutputs = includeSpentMempoolOutputsProperty.get();
        WalletTransaction finalWalletTx = decryptedWallet.createWalletTransaction(utxoSelectors, getUtxoFilters(), walletTransaction.getPayments(), List.of(blindedPaymentCode), excludedChangeNodes, feeRate, getMinimumFeeRate(), userFee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs);
        PSBT psbt = finalWalletTx.createPSBT();
        decryptedWallet.sign(psbt);
        decryptedWallet.finalise(psbt);
        Transaction transaction = psbt.extractTransaction();
        ServiceProgressDialog.ProxyWorker proxyWorker = new ServiceProgressDialog.ProxyWorker();
        ElectrumServer.BroadcastTransactionService broadcastTransactionService = new ElectrumServer.BroadcastTransactionService(transaction);
        broadcastTransactionService.setOnSucceeded(successEvent -> {
            ElectrumServer.TransactionMempoolService transactionMempoolService = new ElectrumServer.TransactionMempoolService(walletTransaction.getWallet(), transaction.getTxId(), new HashSet<>(walletTransaction.getSelectedUtxos().values()));
            transactionMempoolService.setDelay(Duration.seconds(2));
            transactionMempoolService.setPeriod(Duration.seconds(5));
            transactionMempoolService.setRestartOnFailure(false);
            transactionMempoolService.setOnSucceeded(mempoolWorkerStateEvent -> {
                Set<String> scriptHashes = transactionMempoolService.getValue();
                if (!scriptHashes.isEmpty()) {
                    transactionMempoolService.cancel();
                    clear(null);
                    if (Config.get().isUsePayNym()) {
                        proxyWorker.setMessage("Finding PayNym...");
                        AppServices.getPayNymService().getPayNym(externalPaymentCode.toString()).subscribe(payNym -> {
                            proxyWorker.end();
                            addChildWallets(walletTransaction.getWallet(), externalPaymentCode, transaction, payNym);
                        }, error -> {
                            proxyWorker.end();
                            addChildWallets(walletTransaction.getWallet(), externalPaymentCode, transaction, null);
                        });
                    } else {
                        proxyWorker.end();
                        addChildWallets(walletTransaction.getWallet(), externalPaymentCode, transaction, null);
                    }
                }
                if (transactionMempoolService.getIterationCount() > 5 && transactionMempoolService.isRunning()) {
                    transactionMempoolService.cancel();
                    proxyWorker.end();
                    log.error("Timeout searching for broadcasted notification transaction");
                    AppServices.showErrorDialog("Timeout searching for broadcasted transaction", "The transaction was broadcast but the server did not register it in the mempool. It is safe to try broadcasting again.");
                }
            });
            transactionMempoolService.setOnFailed(mempoolWorkerStateEvent -> {
                transactionMempoolService.cancel();
                proxyWorker.end();
                log.error("Error searching for broadcasted notification transaction", mempoolWorkerStateEvent.getSource().getException());
                AppServices.showErrorDialog("Timeout searching for broadcasted transaction", "The transaction was broadcast but the server did not register it in the mempool. It is safe to try broadcasting again.");
            });
            proxyWorker.setMessage("Receiving notification transaction...");
            transactionMempoolService.start();
        });
        broadcastTransactionService.setOnFailed(failedEvent -> {
            proxyWorker.end();
            log.error("Error broadcasting notification transaction", failedEvent.getSource().getException());
            AppServices.showErrorDialog("Error broadcasting notification transaction", failedEvent.getSource().getException().getMessage());
        });
        ServiceProgressDialog progressDialog = new ServiceProgressDialog("Broadcast", "Broadcast Notification Transaction", "/image/paynym.png", proxyWorker);
        AppServices.moveToActiveWindowScreen(progressDialog);
        proxyWorker.setMessage("Broadcasting notification transaction...");
        proxyWorker.start();
        broadcastTransactionService.start();
    } catch (Exception e) {
        log.error("Error creating notification transaction", e);
        AppServices.showErrorDialog("Error creating notification transaction", e.getMessage());
    }
}
Also used : ECKey(com.sparrowwallet.drongo.crypto.ECKey) SecureString(com.sparrowwallet.drongo.SecureString) SecretPoint(com.sparrowwallet.drongo.bip47.SecretPoint) PaymentCode(com.sparrowwallet.drongo.bip47.PaymentCode) InvalidAddressException(com.sparrowwallet.drongo.address.InvalidAddressException) IOException(java.io.IOException) PSBT(com.sparrowwallet.drongo.psbt.PSBT) Transaction(com.sparrowwallet.drongo.protocol.Transaction) TransactionOutPoint(com.sparrowwallet.drongo.protocol.TransactionOutPoint)

Aggregations

PaymentCode (com.sparrowwallet.drongo.bip47.PaymentCode)3 SecretPoint (com.sparrowwallet.drongo.bip47.SecretPoint)3 ECKey (com.sparrowwallet.drongo.crypto.ECKey)3 SecureString (com.sparrowwallet.drongo.SecureString)2 PSBT (com.sparrowwallet.drongo.psbt.PSBT)2 Storage (com.sparrowwallet.sparrow.io.Storage)2 TransactionEntry (com.sparrowwallet.sparrow.wallet.TransactionEntry)2 InvalidAddressException (com.sparrowwallet.drongo.address.InvalidAddressException)1 Transaction (com.sparrowwallet.drongo.protocol.Transaction)1 TransactionOutPoint (com.sparrowwallet.drongo.protocol.TransactionOutPoint)1 ElectrumServer (com.sparrowwallet.sparrow.net.ElectrumServer)1 IOException (java.io.IOException)1