WalletService: adapt to segwit wallet

This commit is contained in:
Oscar Guindzberg 2020-09-28 21:05:56 -03:00
parent 25515710ab
commit d8b755794e
No known key found for this signature in database
GPG key ID: 209796BF2E1D4F75

View file

@ -17,6 +17,7 @@
package bisq.core.btc.wallet;
import bisq.core.btc.exceptions.SigningException;
import bisq.core.btc.exceptions.TransactionVerificationException;
import bisq.core.btc.exceptions.WalletException;
import bisq.core.btc.listeners.AddressConfidenceListener;
@ -37,12 +38,14 @@ import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Context;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.LegacyAddress;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.core.TransactionWitness;
import org.bitcoinj.core.VerificationException;
import org.bitcoinj.core.listeners.NewBestBlockListener;
import org.bitcoinj.core.listeners.TransactionConfidenceEventListener;
@ -51,6 +54,7 @@ import org.bitcoinj.crypto.KeyCrypter;
import org.bitcoinj.crypto.KeyCrypterScrypt;
import org.bitcoinj.crypto.TransactionSignature;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
import org.bitcoinj.script.ScriptChunk;
import org.bitcoinj.script.ScriptException;
import org.bitcoinj.script.ScriptPattern;
@ -241,7 +245,7 @@ public abstract class WalletService {
int inputIndex) throws TransactionVerificationException {
try {
checkNotNull(input.getConnectedOutput(), "input.getConnectedOutput() must not be null");
input.getScriptSig().correctlySpends(transaction, inputIndex, input.getConnectedOutput().getScriptPubKey(), Script.ALL_VERIFY_FLAGS);
input.getScriptSig().correctlySpends(transaction, inputIndex, input.getWitness(), input.getValue(), input.getConnectedOutput().getScriptPubKey(), Script.ALL_VERIFY_FLAGS);
} catch (Throwable t) {
t.printStackTrace();
log.error(t.getMessage());
@ -265,7 +269,7 @@ public abstract class WalletService {
// We assume if it's already signed, it's hopefully got a SIGHASH type that will not invalidate when
// we sign missing pieces (to check this would require either assuming any signatures are signing
// standard output types or a way to get processed signatures out of script execution)
txIn.getScriptSig().correctlySpends(tx, index, txIn.getConnectedOutput().getScriptPubKey(), Script.ALL_VERIFY_FLAGS);
txIn.getScriptSig().correctlySpends(tx, index, txIn.getWitness(), txIn.getValue(), txIn.getConnectedOutput().getScriptPubKey(), Script.ALL_VERIFY_FLAGS);
log.warn("Input {} already correctly spends output, assuming SIGHASH type used will be safe and skipping signing.", index);
return;
} catch (ScriptException e) {
@ -288,7 +292,7 @@ public abstract class WalletService {
// We assume if it's already signed, it's hopefully got a SIGHASH type that will not invalidate when
// we sign missing pieces (to check this would require either assuming any signatures are signing
// standard output types or a way to get processed signatures out of script execution)
txIn.getScriptSig().correctlySpends(tx, index, txIn.getConnectedOutput().getScriptPubKey(), Script.ALL_VERIFY_FLAGS);
txIn.getScriptSig().correctlySpends(tx, index, txIn.getWitness(), txIn.getValue(), txIn.getConnectedOutput().getScriptPubKey(), Script.ALL_VERIFY_FLAGS);
log.warn("Input {} already correctly spends output, assuming SIGHASH type used will be safe and skipping signing.", index);
return;
} catch (ScriptException e) {
@ -312,14 +316,31 @@ public abstract class WalletService {
Script inputScript = txIn.getScriptSig();
byte[] script = redeemData.redeemScript.getProgram();
try {
TransactionSignature signature = partialTx.calculateSignature(index, key, script, Transaction.SigHash.ALL, false);
inputScript = scriptPubKey.getScriptSigWithSignature(inputScript, signature.encodeToBitcoin(), 0);
txIn.setScriptSig(inputScript);
} catch (ECKey.KeyIsEncryptedException e1) {
throw e1;
} catch (ECKey.MissingPrivateKeyException e1) {
log.warn("No private key in keypair for input {}", index);
if (ScriptPattern.isP2PK(scriptPubKey) || ScriptPattern.isP2PKH(scriptPubKey)) {
try {
TransactionSignature signature = partialTx.calculateSignature(index, key, script, Transaction.SigHash.ALL, false);
inputScript = scriptPubKey.getScriptSigWithSignature(inputScript, signature.encodeToBitcoin(), 0);
txIn.setScriptSig(inputScript);
} catch (ECKey.KeyIsEncryptedException e1) {
throw e1;
} catch (ECKey.MissingPrivateKeyException e1) {
log.warn("No private key in keypair for input {}", index);
}
} else if (ScriptPattern.isP2WPKH(scriptPubKey)) {
// TODO: Consider using this alternative way to build the scriptCode (taken from bitcoinj master)
// Script scriptCode = ScriptBuilder.createP2PKHOutputScript(key);
Script scriptCode = new ScriptBuilder().data(
ScriptBuilder.createOutputScript(LegacyAddress.fromKey(tx.getParams(), key)).getProgram())
.build();
Coin value = txIn.getValue();
TransactionSignature txSig = tx.calculateWitnessSignature(index, key, scriptCode, value,
Transaction.SigHash.ALL, false);
txIn.setScriptSig(ScriptBuilder.createEmpty());
txIn.setWitness(TransactionWitness.redeemP2WPKH(txSig, key));
} else {
// log.error("Unexpected script type.");
throw new RuntimeException("Unexpected script type.");
}
} else {
log.warn("Missing connected output, assuming input {} is already signed.", index);
@ -592,7 +613,7 @@ public abstract class WalletService {
@Nullable
public DeterministicKey findKeyFromPubKey(byte[] pubKey) {
return wallet.getActiveKeyChain().findKeyFromPubKey(pubKey);
return (DeterministicKey) wallet.findKeyFromPubKey(pubKey);
}
public boolean isEncrypted() {