mirror of
https://github.com/sparrowwallet/drongo.git
synced 2024-12-26 10:06:45 +00:00
support for better combining and finalising psbts
This commit is contained in:
parent
3ce2394813
commit
4b4a980a9b
4 changed files with 116 additions and 10 deletions
|
@ -153,6 +153,16 @@ public class Transaction extends ChildMessage {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean hasScriptSigs() {
|
||||
for(TransactionInput in : inputs) {
|
||||
if(in.getScriptBytes().length > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasWitnesses() {
|
||||
for(TransactionInput in : inputs) {
|
||||
if(in.hasWitness()) {
|
||||
|
|
|
@ -393,6 +393,16 @@ public class PSBT {
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean isFinalized() {
|
||||
for(PSBTInput psbtInput : getPsbtInputs()) {
|
||||
if(psbtInput.getFinalScriptSig() != null || psbtInput.getFinalScriptWitness() != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<PSBTEntry> getGlobalEntries() {
|
||||
List<PSBTEntry> entries = new ArrayList<>();
|
||||
|
||||
|
@ -462,11 +472,9 @@ public class PSBT {
|
|||
throw new IllegalArgumentException("Provided PSBT does contain a matching global transaction");
|
||||
}
|
||||
|
||||
for(PSBTInput psbtInput : psbt.getPsbtInputs()) {
|
||||
if(psbtInput.getFinalScriptSig() != null || psbtInput.getFinalScriptWitness() != null) {
|
||||
if(isFinalized() || psbt.isFinalized()) {
|
||||
throw new IllegalArgumentException("Cannot combine an already finalised PSBT");
|
||||
}
|
||||
}
|
||||
|
||||
if(psbt.getVersion() != null) {
|
||||
version = psbt.getVersion();
|
||||
|
@ -499,12 +507,14 @@ public class PSBT {
|
|||
}
|
||||
}
|
||||
|
||||
if(hasWitness && !transaction.isSegwit()) {
|
||||
transaction.setSegwitVersion(1);
|
||||
Transaction finalTransaction = new Transaction(transaction.bitcoinSerialize());
|
||||
|
||||
if(hasWitness && !finalTransaction.isSegwit()) {
|
||||
finalTransaction.setSegwitVersion(1);
|
||||
}
|
||||
|
||||
for(int i = 0; i < transaction.getInputs().size(); i++) {
|
||||
TransactionInput txInput = transaction.getInputs().get(i);
|
||||
for(int i = 0; i < finalTransaction.getInputs().size(); i++) {
|
||||
TransactionInput txInput = finalTransaction.getInputs().get(i);
|
||||
PSBTInput psbtInput = getPsbtInputs().get(i);
|
||||
txInput.setScriptBytes(psbtInput.getFinalScriptSig().getProgram());
|
||||
|
||||
|
@ -512,12 +522,12 @@ public class PSBT {
|
|||
if(psbtInput.getFinalScriptWitness() != null) {
|
||||
txInput.setWitness(psbtInput.getFinalScriptWitness());
|
||||
} else {
|
||||
txInput.setWitness(new TransactionWitness(transaction));
|
||||
txInput.setWitness(new TransactionWitness(finalTransaction));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return transaction;
|
||||
return finalTransaction;
|
||||
}
|
||||
|
||||
public List<PSBTInput> getPsbtInputs() {
|
||||
|
|
|
@ -395,6 +395,16 @@ public class PSBTInput {
|
|||
}
|
||||
}
|
||||
|
||||
public Collection<TransactionSignature> getSignatures() {
|
||||
if(getFinalScriptWitness() != null) {
|
||||
return getFinalScriptWitness().getSignatures();
|
||||
} else if(getFinalScriptSig() != null) {
|
||||
return getFinalScriptSig().getSignatures();
|
||||
} else {
|
||||
return getPartialSignatures().values();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean sign(ECKey privKey) {
|
||||
SigHash localSigHash = getSigHash();
|
||||
if(localSigHash == null) {
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
package com.sparrowwallet.drongo.wallet;
|
||||
|
||||
import com.sparrowwallet.drongo.crypto.ECKey;
|
||||
import com.sparrowwallet.drongo.policy.Miniscript;
|
||||
import com.sparrowwallet.drongo.policy.Policy;
|
||||
import com.sparrowwallet.drongo.policy.PolicyType;
|
||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||
import com.sparrowwallet.drongo.protocol.TransactionSignature;
|
||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||
import com.sparrowwallet.drongo.psbt.PSBTInput;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* This is a special wallet that is used solely to finalize a fully signed PSBT by reading from the partial signatures and UTXO scriptPubKey
|
||||
*
|
||||
*/
|
||||
public class FinalizingPSBTWallet extends Wallet {
|
||||
private final Map<PSBTInput, WalletNode> signedInputNodes = new LinkedHashMap<>();
|
||||
private final Map<WalletNode, List<ECKey>> signedNodeKeys = new LinkedHashMap<>();
|
||||
private int numSignatures;
|
||||
|
||||
public FinalizingPSBTWallet(PSBT psbt) {
|
||||
super("Finalizing PSBT Wallet");
|
||||
|
||||
Map<PSBTInput, WalletNode> signingNodes = new LinkedHashMap<>();
|
||||
for(int i = 0; i < psbt.getPsbtInputs().size(); i++) {
|
||||
PSBTInput psbtInput = psbt.getPsbtInputs().get(i);
|
||||
Set<ECKey> keys = psbtInput.getPartialSignatures().keySet();
|
||||
WalletNode signedNode = new WalletNode("m/" + i);
|
||||
signedInputNodes.put(psbtInput, signedNode);
|
||||
signedNodeKeys.put(signedNode, new ArrayList<>(keys));
|
||||
numSignatures = keys.size();
|
||||
setScriptType(ScriptType.getType(psbtInput.getUtxo().getScript()));
|
||||
}
|
||||
|
||||
setPolicyType(numSignatures == 1 ? PolicyType.SINGLE : PolicyType.MULTI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<PSBTInput, List<Keystore>> getSignedKeystores(PSBT psbt) {
|
||||
Map<PSBTInput, List<Keystore>> signedKeystores = new LinkedHashMap<>();
|
||||
for(PSBTInput psbtInput : psbt.getPsbtInputs()) {
|
||||
Collection<TransactionSignature> signatures = psbtInput.getSignatures();
|
||||
signedKeystores.put(psbtInput, IntStream.range(1, signatures.size() + 1).mapToObj(i -> new Keystore("Keystore " + i)).collect(Collectors.toList()));
|
||||
}
|
||||
return signedKeystores;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy getDefaultPolicy() {
|
||||
return new Policy(new Miniscript("")) {
|
||||
@Override
|
||||
public int getNumSignaturesRequired() {
|
||||
return numSignatures;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<PSBTInput, WalletNode> getSigningNodes(PSBT psbt) {
|
||||
return signedInputNodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ECKey getPubKey(WalletNode node) {
|
||||
return signedNodeKeys.get(node).get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ECKey> getPubKeys(WalletNode node) {
|
||||
return signedNodeKeys.get(node);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue