Search in sources :

Example 1 with UnspentOutput

use of com.samourai.wallet.api.backend.beans.UnspentOutput in project sparrow by sparrowwallet.

the class SparrowDataSource method computeUtxoSupplier.

@Override
protected BasicUtxoSupplier computeUtxoSupplier(WhirlpoolWallet whirlpoolWallet, WalletSupplier walletSupplier, UtxoConfigSupplier utxoConfigSupplier, ChainSupplier chainSupplier, PoolSupplier poolSupplier, Tx0ParamService tx0ParamService) throws Exception {
    return new BasicUtxoSupplier(walletSupplier, utxoConfigSupplier, chainSupplier, poolSupplier, tx0ParamService) {

        @Override
        public void refresh() throws Exception {
            SparrowDataSource.this.refresh();
        }

        @Override
        protected void onUtxoChanges(UtxoData utxoData) {
            super.onUtxoChanges(utxoData);
            whirlpoolWallet.onUtxoChanges(utxoData);
        }

        @Override
        protected byte[] _getPrivKeyBytes(WhirlpoolUtxo whirlpoolUtxo) {
            UnspentOutput utxo = whirlpoolUtxo.getUtxo();
            Wallet wallet = getWallet(utxo.xpub.m);
            Map<BlockTransactionHashIndex, WalletNode> walletUtxos = wallet.getWalletUtxos();
            WalletNode node = walletUtxos.entrySet().stream().filter(entry -> entry.getKey().getHash().equals(Sha256Hash.wrap(utxo.tx_hash)) && entry.getKey().getIndex() == utxo.tx_output_n).map(Map.Entry::getValue).findFirst().orElseThrow(() -> new IllegalStateException("Cannot find UTXO " + utxo));
            if (node.getWallet().isBip47()) {
                try {
                    Keystore keystore = node.getWallet().getKeystores().get(0);
                    return keystore.getKey(node).getPrivKeyBytes();
                } catch (Exception e) {
                    log.error("Error getting private key", e);
                }
            }
            return null;
        }
    };
}
Also used : BasicUtxoSupplier(com.samourai.whirlpool.client.wallet.data.utxo.BasicUtxoSupplier) java.util(java.util) Whirlpool(com.sparrowwallet.sparrow.whirlpool.Whirlpool) ExtendedKey(com.sparrowwallet.drongo.ExtendedKey) com.sparrowwallet.drongo.wallet(com.sparrowwallet.drongo.wallet) UtxoConfigSupplier(com.samourai.whirlpool.client.wallet.data.utxoConfig.UtxoConfigSupplier) WalletAddressesChangedEvent(com.sparrowwallet.sparrow.event.WalletAddressesChangedEvent) LoggerFactory(org.slf4j.LoggerFactory) ChainSupplier(com.samourai.whirlpool.client.wallet.data.chain.ChainSupplier) MinerFeeSupplier(com.samourai.whirlpool.client.wallet.data.minerFee.MinerFeeSupplier) PoolSupplier(com.samourai.whirlpool.client.wallet.data.pool.PoolSupplier) WalletSupplier(com.samourai.whirlpool.client.wallet.data.wallet.WalletSupplier) WalletHistoryChangedEvent(com.sparrowwallet.sparrow.event.WalletHistoryChangedEvent) WhirlpoolWallet(com.samourai.whirlpool.client.wallet.WhirlpoolWallet) UtxoData(com.samourai.whirlpool.client.wallet.data.utxo.UtxoData) TransactionOutput(com.sparrowwallet.drongo.protocol.TransactionOutput) Utils(com.sparrowwallet.drongo.Utils) WalletResponseDataSource(com.samourai.whirlpool.client.wallet.data.dataSource.WalletResponseDataSource) BasicUtxoSupplier(com.samourai.whirlpool.client.wallet.data.utxo.BasicUtxoSupplier) WalletResponse(com.samourai.wallet.api.backend.beans.WalletResponse) DataPersister(com.samourai.whirlpool.client.wallet.data.dataPersister.DataPersister) Subscribe(com.google.common.eventbus.Subscribe) UnspentOutput(com.samourai.wallet.api.backend.beans.UnspentOutput) HD_Wallet(com.samourai.wallet.hd.HD_Wallet) Tx0ParamService(com.samourai.whirlpool.client.tx0.Tx0ParamService) Transaction(com.sparrowwallet.drongo.protocol.Transaction) Logger(org.slf4j.Logger) WhirlpoolUtxo(com.samourai.whirlpool.client.wallet.beans.WhirlpoolUtxo) Platform(javafx.application.Platform) AppServices(com.sparrowwallet.sparrow.AppServices) KeyPurpose(com.sparrowwallet.drongo.KeyPurpose) Network(com.sparrowwallet.drongo.Network) ElectrumServer(com.sparrowwallet.sparrow.net.ElectrumServer) EventManager(com.sparrowwallet.sparrow.EventManager) Sha256Hash(com.sparrowwallet.drongo.protocol.Sha256Hash) NewBlockEvent(com.sparrowwallet.sparrow.event.NewBlockEvent) MinerFeeTarget(com.samourai.wallet.api.backend.MinerFeeTarget) TransactionInput(com.sparrowwallet.drongo.protocol.TransactionInput) WhirlpoolWallet(com.samourai.whirlpool.client.wallet.WhirlpoolWallet) HD_Wallet(com.samourai.wallet.hd.HD_Wallet) WhirlpoolUtxo(com.samourai.whirlpool.client.wallet.beans.WhirlpoolUtxo) UnspentOutput(com.samourai.wallet.api.backend.beans.UnspentOutput) UtxoData(com.samourai.whirlpool.client.wallet.data.utxo.UtxoData)

Example 2 with UnspentOutput

use of com.samourai.wallet.api.backend.beans.UnspentOutput in project sparrow by sparrowwallet.

the class SparrowDataSource method fetchWalletResponse.

@Override
protected WalletResponse fetchWalletResponse() throws Exception {
    WalletResponse walletResponse = new WalletResponse();
    walletResponse.wallet = new WalletResponse.Wallet();
    Map<Sha256Hash, BlockTransaction> allTransactions = new HashMap<>();
    Map<Sha256Hash, String> allTransactionsZpubs = new HashMap<>();
    List<WalletResponse.Address> addresses = new ArrayList<>();
    List<WalletResponse.Tx> txes = new ArrayList<>();
    List<UnspentOutput> unspentOutputs = new ArrayList<>();
    int storedBlockHeight = 0;
    String[] zpubs = getWalletSupplier().getPubs(true);
    for (String zpub : zpubs) {
        Wallet wallet = getWallet(zpub);
        if (wallet == null) {
            log.debug("No wallet for " + zpub + " found");
            continue;
        }
        Map<Sha256Hash, BlockTransaction> walletTransactions = wallet.getWalletTransactions();
        allTransactions.putAll(walletTransactions);
        walletTransactions.keySet().forEach(txid -> allTransactionsZpubs.put(txid, zpub));
        if (wallet.getStoredBlockHeight() != null) {
            storedBlockHeight = Math.max(storedBlockHeight, wallet.getStoredBlockHeight());
        }
        WalletResponse.Address address = new WalletResponse.Address();
        List<ExtendedKey.Header> headers = ExtendedKey.Header.getHeaders(Network.get());
        ExtendedKey.Header header = headers.stream().filter(head -> head.getDefaultScriptType().equals(wallet.getScriptType()) && !head.isPrivateKey()).findFirst().orElse(ExtendedKey.Header.xpub);
        address.address = wallet.getKeystores().get(0).getExtendedPublicKey().toString(header);
        int receiveIndex = wallet.getNode(KeyPurpose.RECEIVE).getHighestUsedIndex() == null ? 0 : wallet.getNode(KeyPurpose.RECEIVE).getHighestUsedIndex() + 1;
        address.account_index = wallet.getMixConfig() != null ? Math.max(receiveIndex, wallet.getMixConfig().getReceiveIndex()) : receiveIndex;
        int changeIndex = wallet.getNode(KeyPurpose.CHANGE).getHighestUsedIndex() == null ? 0 : wallet.getNode(KeyPurpose.CHANGE).getHighestUsedIndex() + 1;
        address.change_index = wallet.getMixConfig() != null ? Math.max(changeIndex, wallet.getMixConfig().getChangeIndex()) : changeIndex;
        address.n_tx = walletTransactions.size();
        addresses.add(address);
        for (Map.Entry<BlockTransactionHashIndex, WalletNode> utxo : wallet.getWalletUtxos().entrySet()) {
            BlockTransaction blockTransaction = wallet.getWalletTransaction(utxo.getKey().getHash());
            if (blockTransaction != null && utxo.getKey().getStatus() != Status.FROZEN) {
                unspentOutputs.add(Whirlpool.getUnspentOutput(utxo.getValue(), blockTransaction, (int) utxo.getKey().getIndex()));
            }
        }
    }
    for (BlockTransaction blockTransaction : allTransactions.values()) {
        WalletResponse.Tx tx = new WalletResponse.Tx();
        tx.block_height = blockTransaction.getHeight();
        tx.hash = blockTransaction.getHashAsString();
        tx.locktime = blockTransaction.getTransaction().getLocktime();
        tx.version = (int) blockTransaction.getTransaction().getVersion();
        tx.inputs = new WalletResponse.TxInput[blockTransaction.getTransaction().getInputs().size()];
        for (int i = 0; i < blockTransaction.getTransaction().getInputs().size(); i++) {
            TransactionInput txInput = blockTransaction.getTransaction().getInputs().get(i);
            tx.inputs[i] = new WalletResponse.TxInput();
            tx.inputs[i].vin = txInput.getIndex();
            tx.inputs[i].sequence = txInput.getSequenceNumber();
            if (allTransactionsZpubs.containsKey(txInput.getOutpoint().getHash())) {
                tx.inputs[i].prev_out = new WalletResponse.TxOut();
                tx.inputs[i].prev_out.txid = txInput.getOutpoint().getHash().toString();
                tx.inputs[i].prev_out.vout = (int) txInput.getOutpoint().getIndex();
                BlockTransaction spentTransaction = allTransactions.get(txInput.getOutpoint().getHash());
                if (spentTransaction != null) {
                    TransactionOutput spentOutput = spentTransaction.getTransaction().getOutputs().get((int) txInput.getOutpoint().getIndex());
                    tx.inputs[i].prev_out.value = spentOutput.getValue();
                }
                tx.inputs[i].prev_out.xpub = new UnspentOutput.Xpub();
                tx.inputs[i].prev_out.xpub.m = allTransactionsZpubs.get(txInput.getOutpoint().getHash());
            }
        }
        tx.out = new WalletResponse.TxOutput[blockTransaction.getTransaction().getOutputs().size()];
        for (int i = 0; i < blockTransaction.getTransaction().getOutputs().size(); i++) {
            TransactionOutput txOutput = blockTransaction.getTransaction().getOutputs().get(i);
            tx.out[i] = new WalletResponse.TxOutput();
            tx.out[i].n = txOutput.getIndex();
            tx.out[i].value = txOutput.getValue();
            tx.out[i].xpub = new UnspentOutput.Xpub();
            tx.out[i].xpub.m = allTransactionsZpubs.get(blockTransaction.getHash());
        }
        txes.add(tx);
    }
    walletResponse.addresses = addresses.toArray(new WalletResponse.Address[0]);
    walletResponse.txs = txes.toArray(new WalletResponse.Tx[0]);
    walletResponse.unspent_outputs = unspentOutputs.toArray(new UnspentOutput[0]);
    walletResponse.info = new WalletResponse.Info();
    walletResponse.info.latest_block = new WalletResponse.InfoBlock();
    walletResponse.info.latest_block.height = AppServices.getCurrentBlockHeight() == null ? storedBlockHeight : AppServices.getCurrentBlockHeight();
    walletResponse.info.latest_block.hash = Sha256Hash.ZERO_HASH.toString();
    walletResponse.info.latest_block.time = AppServices.getLatestBlockHeader() == null ? 1 : AppServices.getLatestBlockHeader().getTime();
    walletResponse.info.fees = new LinkedHashMap<>();
    for (MinerFeeTarget target : MinerFeeTarget.values()) {
        walletResponse.info.fees.put(target.getValue(), getMinerFeeSupplier().getFee(target));
    }
    return walletResponse;
}
Also used : TransactionOutput(com.sparrowwallet.drongo.protocol.TransactionOutput) WalletResponse(com.samourai.wallet.api.backend.beans.WalletResponse) Sha256Hash(com.sparrowwallet.drongo.protocol.Sha256Hash) UnspentOutput(com.samourai.wallet.api.backend.beans.UnspentOutput) TransactionInput(com.sparrowwallet.drongo.protocol.TransactionInput) MinerFeeTarget(com.samourai.wallet.api.backend.MinerFeeTarget) WhirlpoolWallet(com.samourai.whirlpool.client.wallet.WhirlpoolWallet) HD_Wallet(com.samourai.wallet.hd.HD_Wallet) ExtendedKey(com.sparrowwallet.drongo.ExtendedKey)

Example 3 with UnspentOutput

use of com.samourai.wallet.api.backend.beans.UnspentOutput in project sparrow by sparrowwallet.

the class SparrowCahootsWallet method addUtxo.

public void addUtxo(WalletNode node, BlockTransaction blockTransaction, int index) {
    if (node.getWallet().getScriptType() != ScriptType.P2WPKH) {
        return;
    }
    UnspentOutput unspentOutput = Whirlpool.getUnspentOutput(node, blockTransaction, index);
    MyTransactionOutPoint myTransactionOutPoint = unspentOutput.computeOutpoint(getParams());
    CahootsUtxo cahootsUtxo;
    if (node.getWallet().isBip47()) {
        try {
            String strPaymentCode = node.getWallet().getKeystores().get(0).getExternalPaymentCode().toString();
            HD_Address hdAddress = getBip47Wallet().getAccount(getBip47Account()).addressAt(node.getIndex());
            PaymentAddress paymentAddress = Bip47UtilJava.getInstance().getPaymentAddress(new PaymentCode(strPaymentCode), 0, hdAddress, getParams());
            cahootsUtxo = new CahootsUtxo(myTransactionOutPoint, node.getDerivationPath(), paymentAddress.getReceiveECKey());
        } catch (Exception e) {
            throw new IllegalStateException("Cannot add BIP47 UTXO", e);
        }
    } else {
        HD_Address hdAddress = getBip84Wallet().getAddressAt(account, unspentOutput);
        cahootsUtxo = new CahootsUtxo(myTransactionOutPoint, node.getDerivationPath(), hdAddress.getECKey());
    }
    addUtxo(account, cahootsUtxo);
}
Also used : PaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode) HD_Address(com.samourai.wallet.hd.HD_Address) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) UnspentOutput(com.samourai.wallet.api.backend.beans.UnspentOutput) PaymentAddress(com.samourai.wallet.bip47.rpc.PaymentAddress) CahootsUtxo(com.samourai.wallet.cahoots.CahootsUtxo)

Example 4 with UnspentOutput

use of com.samourai.wallet.api.backend.beans.UnspentOutput in project sparrow by sparrowwallet.

the class Whirlpool method getUnspentOutput.

public static UnspentOutput getUnspentOutput(WalletNode node, BlockTransaction blockTransaction, int index) {
    TransactionOutput txOutput = blockTransaction.getTransaction().getOutputs().get(index);
    UnspentOutput out = new UnspentOutput();
    out.tx_hash = txOutput.getHash().toString();
    out.tx_output_n = txOutput.getIndex();
    out.value = txOutput.getValue();
    out.script = Utils.bytesToHex(txOutput.getScriptBytes());
    try {
        out.addr = txOutput.getScript().getToAddresses()[0].toString();
    } catch (Exception e) {
    // ignore
    }
    Transaction transaction = (Transaction) txOutput.getParent();
    out.tx_version = (int) transaction.getVersion();
    out.tx_locktime = transaction.getLocktime();
    if (AppServices.getCurrentBlockHeight() != null) {
        out.confirmations = blockTransaction.getConfirmations(AppServices.getCurrentBlockHeight());
    }
    Wallet wallet = node.getWallet().isBip47() ? node.getWallet().getMasterWallet() : node.getWallet();
    if (wallet.getKeystores().size() != 1) {
        throw new IllegalStateException("Cannot mix outputs from a wallet with multiple keystores");
    }
    UnspentOutput.Xpub xpub = new UnspentOutput.Xpub();
    List<ExtendedKey.Header> headers = ExtendedKey.Header.getHeaders(Network.get());
    ExtendedKey.Header header = headers.stream().filter(head -> head.getDefaultScriptType().equals(wallet.getScriptType()) && !head.isPrivateKey()).findFirst().orElse(ExtendedKey.Header.xpub);
    xpub.m = wallet.getKeystores().get(0).getExtendedPublicKey().toString(header);
    xpub.path = node.getDerivationPath().toUpperCase();
    out.xpub = xpub;
    return out;
}
Also used : WhirlpoolWallet(com.samourai.whirlpool.client.wallet.WhirlpoolWallet) HD_Wallet(com.samourai.wallet.hd.HD_Wallet) UnspentOutput(com.samourai.wallet.api.backend.beans.UnspentOutput) ExtendedKey(com.sparrowwallet.drongo.ExtendedKey)

Aggregations

UnspentOutput (com.samourai.wallet.api.backend.beans.UnspentOutput)4 HD_Wallet (com.samourai.wallet.hd.HD_Wallet)3 WhirlpoolWallet (com.samourai.whirlpool.client.wallet.WhirlpoolWallet)3 ExtendedKey (com.sparrowwallet.drongo.ExtendedKey)3 MinerFeeTarget (com.samourai.wallet.api.backend.MinerFeeTarget)2 WalletResponse (com.samourai.wallet.api.backend.beans.WalletResponse)2 Sha256Hash (com.sparrowwallet.drongo.protocol.Sha256Hash)2 TransactionInput (com.sparrowwallet.drongo.protocol.TransactionInput)2 TransactionOutput (com.sparrowwallet.drongo.protocol.TransactionOutput)2 Subscribe (com.google.common.eventbus.Subscribe)1 PaymentAddress (com.samourai.wallet.bip47.rpc.PaymentAddress)1 PaymentCode (com.samourai.wallet.bip47.rpc.PaymentCode)1 CahootsUtxo (com.samourai.wallet.cahoots.CahootsUtxo)1 HD_Address (com.samourai.wallet.hd.HD_Address)1 MyTransactionOutPoint (com.samourai.wallet.send.MyTransactionOutPoint)1 Tx0ParamService (com.samourai.whirlpool.client.tx0.Tx0ParamService)1 WhirlpoolUtxo (com.samourai.whirlpool.client.wallet.beans.WhirlpoolUtxo)1 ChainSupplier (com.samourai.whirlpool.client.wallet.data.chain.ChainSupplier)1 DataPersister (com.samourai.whirlpool.client.wallet.data.dataPersister.DataPersister)1 WalletResponseDataSource (com.samourai.whirlpool.client.wallet.data.dataSource.WalletResponseDataSource)1