Search in sources :

Example 1 with PSBTEntry

use of com.sparrowwallet.drongo.psbt.PSBTEntry in project drongo by sparrowwallet.

the class PSBT method parseGlobalEntries.

private void parseGlobalEntries(List<PSBTEntry> globalEntries) throws PSBTParseException {
    PSBTEntry duplicate = findDuplicateKey(globalEntries);
    if (duplicate != null) {
        throw new PSBTParseException("Found duplicate key for PSBT global: " + Utils.bytesToHex(duplicate.getKey()));
    }
    for (PSBTEntry entry : globalEntries) {
        switch(entry.getKeyType()) {
            case PSBT_GLOBAL_UNSIGNED_TX:
                entry.checkOneByteKey();
                Transaction transaction = new Transaction(entry.getData());
                transaction.verify();
                inputs = transaction.getInputs().size();
                outputs = transaction.getOutputs().size();
                log.debug("Transaction with txid: " + transaction.getTxId() + " version " + transaction.getVersion() + " size " + transaction.getMessageSize() + " locktime " + transaction.getLocktime());
                for (TransactionInput input : transaction.getInputs()) {
                    if (input.getScriptSig().getProgram().length != 0) {
                        throw new PSBTParseException("Unsigned tx input does not have empty scriptSig");
                    }
                    log.debug(" Transaction input references txid: " + input.getOutpoint().getHash() + " vout " + input.getOutpoint().getIndex() + " with script " + input.getScriptSig());
                }
                for (TransactionOutput output : transaction.getOutputs()) {
                    try {
                        log.debug(" Transaction output value: " + output.getValue() + " to addresses " + Arrays.asList(output.getScript().getToAddresses()) + " with script hex " + Utils.bytesToHex(output.getScript().getProgram()) + " to script " + output.getScript());
                    } catch (NonStandardScriptException e) {
                        log.debug(" Transaction output value: " + output.getValue() + " with script hex " + Utils.bytesToHex(output.getScript().getProgram()) + " to script " + output.getScript());
                    }
                }
                this.transaction = transaction;
                break;
            case PSBT_GLOBAL_BIP32_PUBKEY:
                entry.checkOneBytePlusXpubKey();
                KeyDerivation keyDerivation = parseKeyDerivation(entry.getData());
                ExtendedKey pubKey = ExtendedKey.fromDescriptor(Base58.encodeChecked(entry.getKeyData()));
                this.extendedPublicKeys.put(pubKey, keyDerivation);
                log.debug("Pubkey with master fingerprint " + keyDerivation.getMasterFingerprint() + " at path " + keyDerivation.getDerivationPath() + ": " + pubKey.getExtendedKey());
                break;
            case PSBT_GLOBAL_VERSION:
                entry.checkOneByteKey();
                int version = (int) Utils.readUint32(entry.getData(), 0);
                this.version = version;
                log.debug("PSBT version: " + version);
                break;
            case PSBT_GLOBAL_PROPRIETARY:
                globalProprietary.put(Utils.bytesToHex(entry.getKeyData()), Utils.bytesToHex(entry.getData()));
                log.debug("PSBT global proprietary data: " + Utils.bytesToHex(entry.getData()));
                break;
            default:
                log.warn("PSBT global not recognized key type: " + entry.getKeyType());
        }
    }
}
Also used : KeyDerivation(com.sparrowwallet.drongo.KeyDerivation) PSBTEntry(com.sparrowwallet.drongo.psbt.PSBTEntry) ExtendedKey(com.sparrowwallet.drongo.ExtendedKey)

Example 2 with PSBTEntry

use of com.sparrowwallet.drongo.psbt.PSBTEntry in project drongo by sparrowwallet.

the class PSBT method parseOutputEntries.

private void parseOutputEntries(List<List<PSBTEntry>> outputEntryLists) throws PSBTParseException {
    for (List<PSBTEntry> outputEntries : outputEntryLists) {
        PSBTEntry duplicate = findDuplicateKey(outputEntries);
        if (duplicate != null) {
            throw new PSBTParseException("Found duplicate key for PSBT output: " + Utils.bytesToHex(duplicate.getKey()));
        }
        PSBTOutput output = new PSBTOutput(outputEntries);
        this.psbtOutputs.add(output);
    }
}
Also used : PSBTOutput(com.sparrowwallet.drongo.psbt.PSBTOutput) PSBTEntry(com.sparrowwallet.drongo.psbt.PSBTEntry)

Example 3 with PSBTEntry

use of com.sparrowwallet.drongo.psbt.PSBTEntry in project drongo by sparrowwallet.

the class PSBT method parseInputEntries.

private void parseInputEntries(List<List<PSBTEntry>> inputEntryLists, boolean verifySignatures) throws PSBTParseException {
    for (List<PSBTEntry> inputEntries : inputEntryLists) {
        PSBTEntry duplicate = findDuplicateKey(inputEntries);
        if (duplicate != null) {
            throw new PSBTParseException("Found duplicate key for PSBT input: " + Utils.bytesToHex(duplicate.getKey()));
        }
        int inputIndex = this.psbtInputs.size();
        PSBTInput input = new PSBTInput(this, inputEntries, transaction, inputIndex);
        this.psbtInputs.add(input);
    }
    if (verifySignatures) {
        for (PSBTInput input : psbtInputs) {
            boolean verified = input.verifySignatures();
            if (!verified && input.getPartialSignatures().size() > 0) {
                throw new PSBTSignatureException("Unverifiable partial signatures provided");
            }
        }
    }
}
Also used : PSBTEntry(com.sparrowwallet.drongo.psbt.PSBTEntry) PSBTInput(com.sparrowwallet.drongo.psbt.PSBTInput)

Example 4 with PSBTEntry

use of com.sparrowwallet.drongo.psbt.PSBTEntry in project drongo by sparrowwallet.

the class PSBT method serialize.

public byte[] serialize(boolean includeXpubs) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    baos.writeBytes(Utils.hexToBytes(PSBT_MAGIC_HEX));
    baos.writeBytes(new byte[] { (byte) 0xff });
    List<PSBTEntry> globalEntries = getGlobalEntries();
    for (PSBTEntry entry : globalEntries) {
        if (includeXpubs || (entry.getKeyType() != PSBT_GLOBAL_BIP32_PUBKEY && entry.getKeyType() != PSBT_GLOBAL_PROPRIETARY)) {
            entry.serializeToStream(baos);
        }
    }
    baos.writeBytes(new byte[] { (byte) 0x00 });
    for (PSBTInput psbtInput : getPsbtInputs()) {
        List<PSBTEntry> inputEntries = psbtInput.getInputEntries();
        for (PSBTEntry entry : inputEntries) {
            if (includeXpubs || (entry.getKeyType() != PSBT_IN_BIP32_DERIVATION && entry.getKeyType() != PSBT_IN_PROPRIETARY && entry.getKeyType() != PSBT_IN_TAP_INTERNAL_KEY && entry.getKeyType() != PSBT_IN_TAP_BIP32_DERIVATION)) {
                entry.serializeToStream(baos);
            }
        }
        baos.writeBytes(new byte[] { (byte) 0x00 });
    }
    for (PSBTOutput psbtOutput : getPsbtOutputs()) {
        List<PSBTEntry> outputEntries = psbtOutput.getOutputEntries();
        for (PSBTEntry entry : outputEntries) {
            if (includeXpubs || (entry.getKeyType() != PSBT_OUT_REDEEM_SCRIPT && entry.getKeyType() != PSBT_OUT_WITNESS_SCRIPT && entry.getKeyType() != PSBT_OUT_BIP32_DERIVATION && entry.getKeyType() != PSBT_OUT_PROPRIETARY && entry.getKeyType() != PSBT_OUT_TAP_INTERNAL_KEY && entry.getKeyType() != PSBT_OUT_TAP_BIP32_DERIVATION)) {
                entry.serializeToStream(baos);
            }
        }
        baos.writeBytes(new byte[] { (byte) 0x00 });
    }
    return baos.toByteArray();
}
Also used : PSBTOutput(com.sparrowwallet.drongo.psbt.PSBTOutput) PSBTEntry(com.sparrowwallet.drongo.psbt.PSBTEntry) PSBTInput(com.sparrowwallet.drongo.psbt.PSBTInput)

Example 5 with PSBTEntry

use of com.sparrowwallet.drongo.psbt.PSBTEntry in project drongo by sparrowwallet.

the class PSBT method parse.

private void parse(boolean verifySignatures) throws PSBTParseException {
    int seenInputs = 0;
    int seenOutputs = 0;
    ByteBuffer psbtByteBuffer = ByteBuffer.wrap(psbtBytes);
    byte[] magicBuf = new byte[4];
    psbtByteBuffer.get(magicBuf);
    if (!PSBT_MAGIC_HEX.equalsIgnoreCase(Utils.bytesToHex(magicBuf))) {
        throw new PSBTParseException("PSBT has invalid magic value");
    }
    byte sep = psbtByteBuffer.get();
    if (sep != (byte) 0xff) {
        throw new PSBTParseException("PSBT has bad initial separator: " + Utils.bytesToHex(new byte[] { sep }));
    }
    int currentState = STATE_GLOBALS;
    List<PSBTEntry> globalEntries = new ArrayList<>();
    List<List<PSBTEntry>> inputEntryLists = new ArrayList<>();
    List<List<PSBTEntry>> outputEntryLists = new ArrayList<>();
    List<PSBTEntry> inputEntries = new ArrayList<>();
    List<PSBTEntry> outputEntries = new ArrayList<>();
    while (psbtByteBuffer.hasRemaining()) {
        PSBTEntry entry = new PSBTEntry(psbtByteBuffer);
        if (entry.getKey() == null) {
            // length == 0
            switch(currentState) {
                case STATE_GLOBALS:
                    currentState = STATE_INPUTS;
                    parseGlobalEntries(globalEntries);
                    break;
                case STATE_INPUTS:
                    inputEntryLists.add(inputEntries);
                    inputEntries = new ArrayList<>();
                    seenInputs++;
                    if (seenInputs == inputs) {
                        currentState = STATE_OUTPUTS;
                        parseInputEntries(inputEntryLists, verifySignatures);
                    }
                    break;
                case STATE_OUTPUTS:
                    outputEntryLists.add(outputEntries);
                    outputEntries = new ArrayList<>();
                    seenOutputs++;
                    if (seenOutputs == outputs) {
                        currentState = STATE_END;
                        parseOutputEntries(outputEntryLists);
                    }
                    break;
                case STATE_END:
                    break;
                default:
                    throw new PSBTParseException("PSBT structure invalid");
            }
        } else if (currentState == STATE_GLOBALS) {
            globalEntries.add(entry);
        } else if (currentState == STATE_INPUTS) {
            inputEntries.add(entry);
        } else if (currentState == STATE_OUTPUTS) {
            outputEntries.add(entry);
        } else {
            throw new PSBTParseException("PSBT structure invalid");
        }
    }
    if (currentState != STATE_END) {
        if (transaction == null) {
            throw new PSBTParseException("Missing transaction");
        }
    }
    if (log.isDebugEnabled()) {
        log.debug("Calculated fee at " + getFee());
    }
}
Also used : PSBTEntry(com.sparrowwallet.drongo.psbt.PSBTEntry) ByteBuffer(java.nio.ByteBuffer)

Aggregations

PSBTEntry (com.sparrowwallet.drongo.psbt.PSBTEntry)5 PSBTInput (com.sparrowwallet.drongo.psbt.PSBTInput)2 PSBTOutput (com.sparrowwallet.drongo.psbt.PSBTOutput)2 ExtendedKey (com.sparrowwallet.drongo.ExtendedKey)1 KeyDerivation (com.sparrowwallet.drongo.KeyDerivation)1 ByteBuffer (java.nio.ByteBuffer)1