mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-20 02:11:40 +01:00
Added handling of p2sh outputs in TxBuilder -- no support for p2sh(segwit) outputs yet
This commit is contained in:
parent
29510ad638
commit
fe03a35018
@ -18,4 +18,14 @@ object TxBuilderError {
|
||||
*/
|
||||
case object TooManyKeys extends TxBuilderError
|
||||
|
||||
/** Means that you are using the wrong [[org.bitcoins.core.wallet.signer.Signer]] to
|
||||
* sign the given [[org.bitcoins.core.protocol.script.ScriptPubKey]]
|
||||
*/
|
||||
case object WrongSigner extends TxBuilderError
|
||||
|
||||
/** Can occurr when we are trying to sign a [[org.bitcoins.core.protocol.script.P2SHScriptPubKey]] but
|
||||
* we do not have a redeem script for that p2sh spk.
|
||||
*/
|
||||
case object NoRedeemScript extends TxBuilderError
|
||||
|
||||
}
|
@ -3,13 +3,14 @@ package org.bitcoins.core.wallet.signer
|
||||
import org.bitcoins.core.crypto._
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.policy.Policy
|
||||
import org.bitcoins.core.protocol.script.P2PKHScriptSignature
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionInput, TransactionOutPoint, TransactionOutput}
|
||||
import org.bitcoins.core.script.crypto.HashType
|
||||
import org.bitcoins.core.wallet.builder.TxBuilderError
|
||||
|
||||
/** The class used to represent a signing process for a specific [[org.bitcoins.core.protocol.script.ScriptPubKey]] type */
|
||||
sealed abstract class Signer {
|
||||
|
||||
/**
|
||||
* The method used to sign a bitcoin unspent transaction output
|
||||
* @param privKey the private keys needed to sign the utxo
|
||||
@ -22,25 +23,69 @@ sealed abstract class Signer {
|
||||
def sign(privKey: Seq[ECPrivateKey], output: TransactionOutput, unsignedTx: Transaction, inputIndex: UInt32, hashType: HashType): Either[TxSigComponent, TxBuilderError]
|
||||
}
|
||||
|
||||
|
||||
sealed abstract class BitcoinSigner extends Signer
|
||||
|
||||
sealed abstract class P2PKHSigner extends BitcoinSigner {
|
||||
/** Used to sign a [[org.bitcoins.core.protocol.script.P2PKScriptPubKey]] */
|
||||
sealed abstract class P2PKSigner extends BitcoinSigner {
|
||||
|
||||
/** Helper function to sign a [[org.bitcoins.core.protocol.script.P2PKHScriptPubKey]], this is slightly different
|
||||
* than the other sign variant because it only takes ONE PRIVATE KEY rather than a Seq[ECPrivateKey].
|
||||
* Only one private key is required to spend a p2pkh spk/
|
||||
*/
|
||||
def sign(privKey: ECPrivateKey, output: TransactionOutput, unsignedTx: Transaction,
|
||||
inputIndex: UInt32, hashType: HashType): Either[TxSigComponent, TxBuilderError] = {
|
||||
sign(Seq(privKey), output, unsignedTx, inputIndex, hashType)
|
||||
}
|
||||
|
||||
/** This sign function gives you full customizability of what version/locktime/sequence number are used on the tx */
|
||||
override def sign(privKeys: Seq[ECPrivateKey], output: TransactionOutput, unsignedTx: Transaction,
|
||||
inputIndex: UInt32, hashType: HashType): Either[TxSigComponent, TxBuilderError] = {
|
||||
inputIndex: UInt32, hashType: HashType): Either[TxSigComponent, TxBuilderError] = {
|
||||
val spk = output.scriptPubKey
|
||||
if (privKeys.size != 1) {
|
||||
Right(TxBuilderError.TooManyKeys)
|
||||
} else if (!spk.isInstanceOf[P2PKScriptPubKey]) {
|
||||
Right(TxBuilderError.WrongSigner)
|
||||
} else {
|
||||
val privKey = privKeys.head
|
||||
val spk = output.scriptPubKey
|
||||
val publicKey = privKey.publicKey
|
||||
val unsignedInput = unsignedTx.inputs(inputIndex.toInt)
|
||||
//val inputIndex = UInt32(unsignedInputs.indexOf(unsignedInput))
|
||||
val txSigComponent = TxSigComponent(unsignedTx,inputIndex,spk, Policy.standardFlags)
|
||||
val signature = TransactionSignatureCreator.createSig(txSigComponent,privKey,hashType)
|
||||
val p2pkScriptSig = P2PKScriptSignature(signature)
|
||||
val signedInput = TransactionInput(unsignedInput.previousOutput,p2pkScriptSig,unsignedInput.sequence)
|
||||
val signedInputs = unsignedTx.inputs.updated(inputIndex.toInt,signedInput)
|
||||
val signedTx = Transaction(unsignedTx.version,signedInputs, unsignedTx.outputs, unsignedTx.lockTime)
|
||||
Left(TxSigComponent(signedTx,inputIndex,spk,txSigComponent.flags))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object P2PKSigner extends P2PKSigner
|
||||
|
||||
/** Used to sign a [[org.bitcoins.core.protocol.script.P2PKHScriptPubKey]] */
|
||||
sealed abstract class P2PKHSigner extends BitcoinSigner {
|
||||
|
||||
/** Helper function to sign a [[org.bitcoins.core.protocol.script.P2PKHScriptPubKey]], this is slightly different
|
||||
* than the other sign variant because it only takes ONE PRIVATE KEY rather than a Seq[ECPrivateKey].
|
||||
* Only one private key is required to spend a p2pkh spk/
|
||||
*/
|
||||
def sign(privKey: ECPrivateKey, output: TransactionOutput, unsignedTx: Transaction,
|
||||
inputIndex: UInt32, hashType: HashType): Either[TxSigComponent, TxBuilderError] = {
|
||||
sign(Seq(privKey), output, unsignedTx, inputIndex, hashType)
|
||||
}
|
||||
/** This sign function gives you full customizability of what version/locktime/sequence number are used on the tx */
|
||||
override def sign(privKeys: Seq[ECPrivateKey], output: TransactionOutput, unsignedTx: Transaction,
|
||||
inputIndex: UInt32, hashType: HashType): Either[TxSigComponent, TxBuilderError] = {
|
||||
val spk = output.scriptPubKey
|
||||
if (privKeys.size != 1) {
|
||||
Right(TxBuilderError.TooManyKeys)
|
||||
} else if (!spk.isInstanceOf[P2PKHScriptPubKey]) {
|
||||
Right(TxBuilderError.WrongSigner)
|
||||
} else {
|
||||
val privKey = privKeys.head
|
||||
val publicKey = privKey.publicKey
|
||||
val unsignedInput = unsignedTx.inputs(inputIndex.toInt)
|
||||
val txSigComponent = TxSigComponent(unsignedTx,inputIndex,spk, Policy.standardFlags)
|
||||
val signature = TransactionSignatureCreator.createSig(txSigComponent,privKey,hashType)
|
||||
val signedInput = buildP2PKHInput(signature,publicKey,unsignedInput.previousOutput,unsignedInput.sequence)
|
||||
val signedInputs = unsignedTx.inputs.updated(inputIndex.toInt,signedInput)
|
||||
val signedTx = Transaction(unsignedTx.version,signedInputs, unsignedTx.outputs, unsignedTx.lockTime)
|
||||
@ -48,6 +93,7 @@ sealed abstract class P2PKHSigner extends BitcoinSigner {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private def buildP2PKHInput(signature: ECDigitalSignature, publicKey: ECPublicKey,
|
||||
outPoint: TransactionOutPoint, sequence: UInt32): TransactionInput = {
|
||||
val scriptSig = P2PKHScriptSignature(signature,publicKey)
|
||||
@ -55,4 +101,32 @@ sealed abstract class P2PKHSigner extends BitcoinSigner {
|
||||
}
|
||||
}
|
||||
|
||||
object P2PKHSigner extends P2PKHSigner
|
||||
object P2PKHSigner extends P2PKHSigner
|
||||
|
||||
sealed abstract class MultiSigSigner extends BitcoinSigner {
|
||||
override def sign(privKeys: Seq[ECPrivateKey], output: TransactionOutput, unsignedTx: Transaction,
|
||||
inputIndex: UInt32, hashType: HashType): Either[TxSigComponent, TxBuilderError] = {
|
||||
val spk = output.scriptPubKey
|
||||
if (!spk.isInstanceOf[MultiSignatureScriptPubKey]) {
|
||||
Right(TxBuilderError.WrongSigner)
|
||||
} else {
|
||||
val multisig = spk.asInstanceOf[MultiSignatureScriptPubKey]
|
||||
val requiredSigs = multisig.requiredSigs
|
||||
val emptyDigitalSignatures = privKeys.map(_ => EmptyDigitalSignature)
|
||||
val emptyScriptSig = MultiSignatureScriptSignature(emptyDigitalSignatures)
|
||||
val oldInput = unsignedTx.inputs(inputIndex.toInt)
|
||||
val emptyInput = TransactionInput(oldInput.previousOutput,emptyScriptSig,oldInput.sequence)
|
||||
val unsignedSpendingTx = Transaction(unsignedTx.version,unsignedTx.inputs.updated(inputIndex.toInt,emptyInput), unsignedTx.outputs, unsignedTx.lockTime)
|
||||
val txSignatureComponent = TxSigComponent(unsignedSpendingTx,inputIndex,
|
||||
multisig,Policy.standardFlags)
|
||||
val sigs = (0 until requiredSigs).map(i => TransactionSignatureCreator.createSig(txSignatureComponent, privKeys(i), hashType))
|
||||
val signedScriptSig = MultiSignatureScriptSignature(sigs)
|
||||
val signedInput = TransactionInput(oldInput.previousOutput,signedScriptSig,oldInput.sequence)
|
||||
val signedTx = Transaction(unsignedTx.version, unsignedTx.inputs.updated(inputIndex.toInt, signedInput),
|
||||
unsignedTx.outputs,unsignedTx.lockTime)
|
||||
Left(TxSigComponent(signedTx,inputIndex,multisig,Policy.standardFlags))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object MultiSigSigner extends MultiSigSigner
|
Loading…
Reference in New Issue
Block a user