mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-25 07:17:32 +01:00
Fixing issue where we have the wrong version of ScriptSignature in our tree
This commit is contained in:
parent
40929aa5bf
commit
81f2cf3ba2
1 changed files with 180 additions and 200 deletions
|
@ -6,6 +6,7 @@ import org.bitcoins.core.serializers.script.{RawScriptPubKeyParser, RawScriptSig
|
||||||
import org.bitcoins.core.script.constant._
|
import org.bitcoins.core.script.constant._
|
||||||
import org.bitcoins.core.script.crypto.{HashType, HashTypeFactory, OP_CHECKMULTISIG, SIGHASH_ALL}
|
import org.bitcoins.core.script.crypto.{HashType, HashTypeFactory, OP_CHECKMULTISIG, SIGHASH_ALL}
|
||||||
import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil, BitcoinScriptUtil, Factory}
|
import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil, BitcoinScriptUtil, Factory}
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
import scala.util.{Failure, Success, Try}
|
import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
|
@ -15,50 +16,44 @@ import scala.util.{Failure, Success, Try}
|
||||||
*/
|
*/
|
||||||
sealed trait ScriptSignature extends NetworkElement with BitcoinSLogger {
|
sealed trait ScriptSignature extends NetworkElement with BitcoinSLogger {
|
||||||
|
|
||||||
/**
|
|
||||||
* Representation of a scriptSignature in a parsed assembly format
|
|
||||||
* this data structure can be run through the script interpreter to
|
|
||||||
* see if a script evaluates to true
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
def asm : Seq[ScriptToken]
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The digital signatures contained inside of the script signature
|
* Representation of a scriptSignature in a parsed assembly format
|
||||||
* p2pkh script signatures only have one sig
|
* this data structure can be run through the script interpreter to
|
||||||
* p2pk script signatures only have one sigs
|
* see if a script evaluates to true
|
||||||
* p2sh script signatures can have m sigs
|
* @return
|
||||||
* multisignature scripts can have m sigs
|
*/
|
||||||
* @return
|
lazy val asm : Seq[ScriptToken] = ScriptParser.fromHex(hex)
|
||||||
*/
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The digital signatures contained inside of the script signature
|
||||||
|
* p2pkh script signatures only have one sig
|
||||||
|
* p2pk script signatures only have one sigs
|
||||||
|
* p2sh script signatures can have m sigs
|
||||||
|
* multisignature scripts can have m sigs
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
def signatures : Seq[ECDigitalSignature]
|
def signatures : Seq[ECDigitalSignature]
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives the hash type for a given digitalSignature
|
* Derives the hash type for a given digitalSignature
|
||||||
*
|
|
||||||
* @param digitalSignature
|
* @param digitalSignature
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def hashType(digitalSignature: ECDigitalSignature) = {
|
def hashType(digitalSignature: ECDigitalSignature) = {
|
||||||
digitalSignature match {
|
digitalSignature match {
|
||||||
case EmptyDigitalSignature => SIGHASH_ALL()
|
case EmptyDigitalSignature => SIGHASH_ALL()
|
||||||
case sig : ECDigitalSignature => HashTypeFactory.fromByte(digitalSignature.bytes.last)
|
case sig : ECDigitalSignature => HashTypeFactory.fromByte(digitalSignature.bytes.last)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trait NonStandardScriptSignature extends ScriptSignature {
|
trait NonStandardScriptSignature extends ScriptSignature {
|
||||||
def signatures : Seq[ECDigitalSignature] = ???
|
def signatures : Seq[ECDigitalSignature] = Seq()
|
||||||
}
|
}
|
||||||
|
|
||||||
object NonStandardScriptSignatureImpl {
|
|
||||||
def apply(hex : String) : NonStandardScriptSignatureImpl = NonStandardScriptSignatureImpl(hex, RawScriptSignatureParser.read(hex).asm)
|
|
||||||
}
|
|
||||||
case class NonStandardScriptSignatureImpl(hex : String, asm : Seq[ScriptToken]) extends NonStandardScriptSignature
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,24 +66,22 @@ trait P2PKHScriptSignature extends ScriptSignature {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* P2PKH scriptSigs only have one signature
|
* P2PKH scriptSigs only have one signature
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def signature : ECDigitalSignature = signatures.head
|
def signature : ECDigitalSignature = signatures.head
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gives us the public key inside of a p2pkh script signature
|
* Gives us the public key inside of a p2pkh script signature
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def publicKey : ECPublicKey = ECFactory.publicKey(asm.last.bytes)
|
def publicKey : ECPublicKey = ECFactory.publicKey(asm.last.bytes)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the hash type for the p2pkh script signature
|
* Returns the hash type for the p2pkh script signature
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def hashType : HashType = HashTypeFactory.fromByte(signature.bytes.last)
|
def hashType : HashType = HashTypeFactory.fromByte(signature.bytes.last)
|
||||||
|
|
||||||
override def signatures : Seq[ECDigitalSignature] = {
|
override def signatures : Seq[ECDigitalSignature] = {
|
||||||
|
@ -104,37 +97,36 @@ trait P2PKHScriptSignature extends ScriptSignature {
|
||||||
* <sig> [sig] [sig...] <redeemScript>
|
* <sig> [sig] [sig...] <redeemScript>
|
||||||
*/
|
*/
|
||||||
trait P2SHScriptSignature extends ScriptSignature {
|
trait P2SHScriptSignature extends ScriptSignature {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The redeemScript represents the conditions that must be satisfied to spend the output
|
* The redeemScript represents the conditions that must be satisfied to spend the output
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def redeemScript : ScriptPubKey = ScriptPubKey(asm.last.bytes)
|
def redeemScript : ScriptPubKey = ScriptPubKey(asm.last.bytes)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the script signature of this p2shScriptSig with no serialized redeemScript
|
* Returns the script signature of this p2shScriptSig with no serialized redeemScript
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def scriptSignatureNoRedeemScript = ScriptSignature.fromAsm(splitAtRedeemScript(asm)._1)
|
def scriptSignatureNoRedeemScript = ScriptSignature.fromAsm(splitAtRedeemScript(asm)._1)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the public keys for the p2sh scriptSignature
|
* Returns the public keys for the p2sh scriptSignature
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def publicKeys : Seq[ECPublicKey] = {
|
def publicKeys : Seq[ECPublicKey] = {
|
||||||
val pubKeys : Seq[ScriptToken] = redeemScript.asm.filter(_.isInstanceOf[ScriptConstant])
|
val pubKeys : Seq[ScriptToken] = redeemScript.asm.filter(_.isInstanceOf[ScriptConstant])
|
||||||
.filterNot(_.isInstanceOf[ScriptNumberOperation])
|
.filterNot(_.isInstanceOf[ScriptNumberOperation])
|
||||||
pubKeys.map(k => ECFactory.publicKey(k.hex))
|
pubKeys.map(k => ECFactory.publicKey(k.hex))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The digital signatures inside of the scriptSig
|
* The digital signatures inside of the scriptSig
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def signatures : Seq[ECDigitalSignature] = {
|
def signatures : Seq[ECDigitalSignature] = {
|
||||||
val nonRedeemScript = splitAtRedeemScript(asm)._1
|
val nonRedeemScript = splitAtRedeemScript(asm)._1
|
||||||
val sigs = nonRedeemScript.filter(_.isInstanceOf[ScriptConstant]).filterNot(_.isInstanceOf[ScriptNumberOperation])
|
val sigs = nonRedeemScript.filter(_.isInstanceOf[ScriptConstant]).filterNot(_.isInstanceOf[ScriptNumberOperation])
|
||||||
|
@ -143,13 +135,12 @@ trait P2SHScriptSignature extends ScriptSignature {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Splits the given asm into two parts
|
* Splits the given asm into two parts
|
||||||
* the first part is the digital signatures
|
* the first part is the digital signatures
|
||||||
* the second part is the redeem script
|
* the second part is the redeem script
|
||||||
*
|
|
||||||
* @param asm
|
* @param asm
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def splitAtRedeemScript(asm : Seq[ScriptToken]) : (Seq[ScriptToken],Seq[ScriptToken]) = {
|
def splitAtRedeemScript(asm : Seq[ScriptToken]) : (Seq[ScriptToken],Seq[ScriptToken]) = {
|
||||||
//call .tail twice to remove the serialized redeemScript & it's bytesToPushOntoStack constant
|
//call .tail twice to remove the serialized redeemScript & it's bytesToPushOntoStack constant
|
||||||
(asm.reverse.tail.tail.reverse, Seq(asm.last))
|
(asm.reverse.tail.tail.reverse, Seq(asm.last))
|
||||||
|
@ -181,191 +172,180 @@ trait MultiSignatureScriptSignature extends ScriptSignature {
|
||||||
* Signature script: <sig>
|
* Signature script: <sig>
|
||||||
*/
|
*/
|
||||||
trait P2PKScriptSignature extends ScriptSignature {
|
trait P2PKScriptSignature extends ScriptSignature {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the hash type for the signature inside of the p2pk script signature
|
* Returns the hash type for the signature inside of the p2pk script signature
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def hashType = HashTypeFactory.fromByte(signature.bytes.last)
|
def hashType = HashTypeFactory.fromByte(signature.bytes.last)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PubKey scriptSignatures only have one signature
|
* PubKey scriptSignatures only have one signature
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def signature : ECDigitalSignature = signatures.head
|
def signature : ECDigitalSignature = signatures.head
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The digital signatures inside of the scriptSig
|
* The digital signatures inside of the scriptSig
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def signatures : Seq[ECDigitalSignature] = {
|
def signatures : Seq[ECDigitalSignature] = {
|
||||||
Seq(ECFactory.digitalSignature(BitcoinScriptUtil.filterPushOps(asm).head.hex))
|
Seq(ECFactory.digitalSignature(BitcoinScriptUtil.filterPushOps(asm).head.hex))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the empty script signature
|
* Represents the empty script signature
|
||||||
*/
|
*/
|
||||||
case object EmptyScriptSignature extends ScriptSignature {
|
case object EmptyScriptSignature extends ScriptSignature {
|
||||||
def asm = List()
|
|
||||||
def signatures = List()
|
def signatures = List()
|
||||||
def hex = ""
|
def hex = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
object ScriptSignature extends Factory[ScriptSignature] with BitcoinSLogger {
|
object ScriptSignature extends Factory[ScriptSignature] with BitcoinSLogger {
|
||||||
|
|
||||||
private object P2PKHScriptSignatureImpl {
|
private case class NonStandardScriptSignatureImpl(hex : String) extends NonStandardScriptSignature
|
||||||
def apply(hex : String) : P2PKHScriptSignatureImpl = P2PKHScriptSignatureImpl(hex, RawScriptSignatureParser.read(hex).asm)
|
|
||||||
}
|
|
||||||
private case class P2PKHScriptSignatureImpl(hex : String, asm : Seq[ScriptToken]) extends P2PKHScriptSignature
|
|
||||||
|
|
||||||
private object P2SHScriptSignatureImpl {
|
private case class P2PKScriptSignatureImpl(hex : String) extends P2PKScriptSignature
|
||||||
def apply(hex : String) : P2SHScriptSignatureImpl = P2SHScriptSignatureImpl(hex, RawScriptSignatureParser.read(hex).asm)
|
|
||||||
}
|
|
||||||
private case class P2SHScriptSignatureImpl(hex : String, asm : Seq[ScriptToken]) extends P2SHScriptSignature
|
|
||||||
|
|
||||||
private object MultiSignatureScriptSignatureImpl {
|
private case class MultiSignatureScriptSignatureImpl(hex : String) extends MultiSignatureScriptSignature
|
||||||
def apply(hex : String) : MultiSignatureScriptSignatureImpl = MultiSignatureScriptSignatureImpl(hex, RawScriptSignatureParser.read(hex).asm)
|
|
||||||
}
|
|
||||||
private case class MultiSignatureScriptSignatureImpl(hex : String, asm : Seq[ScriptToken]) extends MultiSignatureScriptSignature
|
|
||||||
|
|
||||||
private object P2PKScriptSignatureImpl {
|
private case class P2SHScriptSignatureImpl(hex : String) extends P2SHScriptSignature
|
||||||
def apply(hex : String) : P2PKScriptSignatureImpl = P2PKScriptSignatureImpl(hex, RawScriptSignatureParser.read(hex).asm)
|
|
||||||
}
|
private case class P2PKHScriptSignatureImpl(hex : String) extends P2PKHScriptSignature
|
||||||
private case class P2PKScriptSignatureImpl(hex : String, asm : Seq[ScriptToken]) extends P2PKScriptSignature
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a script signature from a digital signature and a public key
|
* Builds a script signature from a digital signature and a public key
|
||||||
* this is a pay to public key hash script sig
|
* this is a pay to public key hash script sig
|
||||||
*
|
*
|
||||||
* @param signature
|
* @param signature
|
||||||
* @param pubKey
|
* @param pubKey
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def factory(signature : ECDigitalSignature, pubKey : ECPublicKey) : ScriptSignature = {
|
def factory(signature : ECDigitalSignature, pubKey : ECPublicKey) : ScriptSignature = {
|
||||||
val signatureBytesToPushOntoStack = BytesToPushOntoStack(signature.bytes.size)
|
val signatureBytesToPushOntoStack = BytesToPushOntoStack(signature.bytes.size)
|
||||||
val pubKeyBytesToPushOntoStack = BytesToPushOntoStack(pubKey.bytes.size)
|
val pubKeyBytesToPushOntoStack = BytesToPushOntoStack(pubKey.bytes.size)
|
||||||
val asm : Seq[ScriptToken] = Seq(signatureBytesToPushOntoStack, ScriptConstant(signature.hex),
|
val asm : Seq[ScriptToken] = Seq(signatureBytesToPushOntoStack, ScriptConstant(signature.hex),
|
||||||
pubKeyBytesToPushOntoStack, ScriptConstant(pubKey.hex))
|
pubKeyBytesToPushOntoStack, ScriptConstant(pubKey.hex))
|
||||||
fromAsm(asm)
|
fromAsm(asm)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an empty script signature
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
def empty : ScriptSignature = EmptyScriptSignature
|
||||||
|
|
||||||
|
def fromBytes(bytes : Seq[Byte]) : ScriptSignature = RawScriptSignatureParser.read(bytes)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a scriptSignature from the list of script tokens
|
||||||
|
*
|
||||||
|
* @param tokens
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
def fromAsm(tokens : Seq[ScriptToken]) : ScriptSignature = {
|
||||||
|
val scriptSigHex = tokens.map(_.hex).mkString
|
||||||
|
tokens match {
|
||||||
|
case Nil => EmptyScriptSignature
|
||||||
|
case _ if (tokens.size > 1 && isRedeemScript(tokens.last)) =>
|
||||||
|
P2SHScriptSignatureImpl(scriptSigHex)
|
||||||
|
case _ if (isMultiSignatureScriptSignature(tokens)) =>
|
||||||
|
//the head of the asm does not neccessarily have to be an OP_0 if the NULLDUMMY script
|
||||||
|
//flag is not set. It can be any script number operation
|
||||||
|
MultiSignatureScriptSignatureImpl(scriptSigHex)
|
||||||
|
case List(w : BytesToPushOntoStack, x : ScriptConstant, y : BytesToPushOntoStack,
|
||||||
|
z : ScriptConstant) => P2PKHScriptSignatureImpl(scriptSigHex)
|
||||||
|
case List(w : BytesToPushOntoStack, x : ScriptConstant) => P2PKScriptSignatureImpl(scriptSigHex)
|
||||||
|
case _ => NonStandardScriptSignatureImpl(scriptSigHex)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an empty script signature
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
def empty : ScriptSignature = EmptyScriptSignature
|
|
||||||
|
|
||||||
def fromBytes(bytes : Seq[Byte]) : ScriptSignature = {
|
/**
|
||||||
RawScriptSignatureParser.read(bytes)
|
* Creates a script signature from the given tokens and scriptPubKey
|
||||||
|
*
|
||||||
|
* @param tokens the script signature's tokens
|
||||||
|
* @param scriptPubKey the scriptPubKey which the script signature is trying to spend
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
def fromScriptPubKey(tokens : Seq[ScriptToken], scriptPubKey : ScriptPubKey) : ScriptSignature = {
|
||||||
|
val scriptSigHex = tokens.map(_.hex).mkString
|
||||||
|
scriptPubKey match {
|
||||||
|
case s : P2SHScriptPubKey => P2SHScriptSignatureImpl(scriptSigHex)
|
||||||
|
case s : P2PKHScriptPubKey => P2PKHScriptSignatureImpl(scriptSigHex)
|
||||||
|
case s : P2PKScriptPubKey => P2PKScriptSignatureImpl(scriptSigHex)
|
||||||
|
case s : MultiSignatureScriptPubKey => MultiSignatureScriptSignatureImpl(scriptSigHex)
|
||||||
|
case s : NonStandardScriptPubKey => NonStandardScriptSignatureImpl(scriptSigHex)
|
||||||
|
case EmptyScriptPubKey if (tokens.size == 0) => EmptyScriptSignature
|
||||||
|
case EmptyScriptPubKey => NonStandardScriptSignatureImpl(scriptSigHex)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a scriptSignature from the list of script tokens
|
|
||||||
*
|
/**
|
||||||
* @param tokens
|
* Detects if the given script token is a redeem script
|
||||||
* @return
|
*
|
||||||
*/
|
* @param token
|
||||||
def fromAsm(tokens : Seq[ScriptToken]) : ScriptSignature = {
|
* @return
|
||||||
val scriptSigHex = tokens.map(_.hex).mkString
|
*/
|
||||||
tokens match {
|
private def isRedeemScript(token : ScriptToken) : Boolean = {
|
||||||
case Nil => EmptyScriptSignature
|
logger.debug("Checking if last token is redeem script")
|
||||||
case _ if (tokens.size > 1 && isRedeemScript(tokens.last)) =>
|
val redeemScriptTry : Try[ScriptPubKey] = parseRedeemScript(token)
|
||||||
P2SHScriptSignatureImpl(scriptSigHex,tokens)
|
redeemScriptTry match {
|
||||||
case _ if (isMultiSignatureScriptSignature(tokens)) =>
|
case Success(redeemScript) =>
|
||||||
//the head of the asm does not neccessarily have to be an OP_0 if the NULLDUMMY script
|
logger.debug("Possible redeemScript: " + redeemScript)
|
||||||
//flag is not set. It can be any script number operation
|
redeemScript match {
|
||||||
MultiSignatureScriptSignatureImpl(scriptSigHex,tokens)
|
case x : P2PKHScriptPubKey => true
|
||||||
case List(w : BytesToPushOntoStack, x : ScriptConstant, y : BytesToPushOntoStack,
|
case x : MultiSignatureScriptPubKey => true
|
||||||
z : ScriptConstant) => P2PKHScriptSignatureImpl(scriptSigHex,tokens)
|
case x : P2SHScriptPubKey => true
|
||||||
case List(w : BytesToPushOntoStack, x : ScriptConstant) => P2PKScriptSignatureImpl(scriptSigHex,tokens)
|
case x : P2PKScriptPubKey => true
|
||||||
case _ => NonStandardScriptSignatureImpl(scriptSigHex,tokens)
|
case x : NonStandardScriptPubKey => false
|
||||||
}
|
case EmptyScriptPubKey => false
|
||||||
|
}
|
||||||
|
case Failure(_) => false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a redeem script from the given script token
|
||||||
|
*
|
||||||
|
* @param scriptToken
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
def parseRedeemScript(scriptToken : ScriptToken) : Try[ScriptPubKey] = {
|
||||||
|
val redeemScript : Try[ScriptPubKey] = Try(ScriptPubKey(scriptToken.bytes))
|
||||||
|
redeemScript
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a script signature from the given tokens and scriptPubKey
|
* Checks if the given script tokens are a multisignature script sig
|
||||||
*
|
* format: OP_0 <A sig> [B sig] [C sig...]
|
||||||
* @param tokens the script signature's tokens
|
*
|
||||||
* @param scriptPubKey the scriptPubKey which the script signature is trying to spend
|
* @param asm the asm to check if it falls in the multisignature script sig format
|
||||||
* @return
|
* @return boolean indicating if the scriptsignature is a multisignature script signature
|
||||||
*/
|
*/
|
||||||
def fromScriptPubKey(tokens : Seq[ScriptToken], scriptPubKey : ScriptPubKey) : ScriptSignature = {
|
def isMultiSignatureScriptSignature(asm : Seq[ScriptToken]) : Boolean = {
|
||||||
val scriptSigHex = tokens.map(_.hex).mkString
|
asm.isEmpty match {
|
||||||
scriptPubKey match {
|
case true => false
|
||||||
case s : P2SHScriptPubKey => P2SHScriptSignatureImpl(scriptSigHex,tokens)
|
case false if (asm.size == 1) => false
|
||||||
case s : P2PKHScriptPubKey => P2PKHScriptSignatureImpl(scriptSigHex,tokens)
|
case false =>
|
||||||
case s : P2PKScriptPubKey => P2PKScriptSignatureImpl(scriptSigHex,tokens)
|
val firstTokenIsScriptNumberOperation = asm.head.isInstanceOf[ScriptNumberOperation]
|
||||||
case s : MultiSignatureScriptPubKey => MultiSignatureScriptSignatureImpl(scriptSigHex,tokens)
|
val restOfScriptIsPushOpsOrScriptConstants = asm.tail.map(
|
||||||
case s : NonStandardScriptPubKey => NonStandardScriptSignatureImpl(scriptSigHex, tokens)
|
token => token.isInstanceOf[ScriptConstant] || StackPushOperationFactory.isPushOperation(token)
|
||||||
case EmptyScriptPubKey if (tokens.size == 0) => EmptyScriptSignature
|
).exists(_ == false)
|
||||||
case EmptyScriptPubKey => NonStandardScriptSignatureImpl(scriptSigHex,tokens)
|
logger.debug("First number is script op: " + firstTokenIsScriptNumberOperation)
|
||||||
}
|
logger.debug("tail is true: " +restOfScriptIsPushOpsOrScriptConstants )
|
||||||
}
|
firstTokenIsScriptNumberOperation && !restOfScriptIsPushOpsOrScriptConstants
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detects if the given script token is a redeem script
|
|
||||||
*
|
|
||||||
* @param token
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private def isRedeemScript(token : ScriptToken) : Boolean = {
|
|
||||||
logger.debug("Checking if last token is redeem script")
|
|
||||||
val redeemScriptTry : Try[ScriptPubKey] = parseRedeemScript(token)
|
|
||||||
redeemScriptTry match {
|
|
||||||
case Success(redeemScript) =>
|
|
||||||
logger.debug("Possible redeemScript: " + redeemScript)
|
|
||||||
redeemScript match {
|
|
||||||
case x : P2PKHScriptPubKey => true
|
|
||||||
case x : MultiSignatureScriptPubKey => true
|
|
||||||
case x : P2SHScriptPubKey => true
|
|
||||||
case x : P2PKScriptPubKey => true
|
|
||||||
case x : NonStandardScriptPubKey => false
|
|
||||||
case EmptyScriptPubKey => false
|
|
||||||
}
|
|
||||||
case Failure(_) => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a redeem script from the given script token
|
|
||||||
*
|
|
||||||
* @param scriptToken
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
def parseRedeemScript(scriptToken : ScriptToken) : Try[ScriptPubKey] = {
|
|
||||||
val redeemScript : Try[ScriptPubKey] = Try(ScriptPubKey(scriptToken.bytes))
|
|
||||||
redeemScript
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the given script tokens are a multisignature script sig
|
|
||||||
* format: OP_0 <A sig> [B sig] [C sig...]
|
|
||||||
*
|
|
||||||
* @param asm the asm to check if it falls in the multisignature script sig format
|
|
||||||
* @return boolean indicating if the scriptsignature is a multisignature script signature
|
|
||||||
*/
|
|
||||||
def isMultiSignatureScriptSignature(asm : Seq[ScriptToken]) : Boolean = {
|
|
||||||
asm.isEmpty match {
|
|
||||||
case true => false
|
|
||||||
case false if (asm.size == 1) => false
|
|
||||||
case false =>
|
|
||||||
val firstTokenIsScriptNumberOperation = asm.head.isInstanceOf[ScriptNumberOperation]
|
|
||||||
val restOfScriptIsPushOpsOrScriptConstants = asm.tail.map(
|
|
||||||
token => token.isInstanceOf[ScriptConstant] || StackPushOperationFactory.isPushOperation(token)
|
|
||||||
).exists(_ == false)
|
|
||||||
logger.debug("First number is script op: " + firstTokenIsScriptNumberOperation)
|
|
||||||
logger.debug("tail is true: " +restOfScriptIsPushOpsOrScriptConstants )
|
|
||||||
firstTokenIsScriptNumberOperation && !restOfScriptIsPushOpsOrScriptConstants
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def apply(bytes: Seq[Byte]) : ScriptSignature = fromBytes(bytes)
|
def apply(bytes: Seq[Byte]) : ScriptSignature = fromBytes(bytes)
|
||||||
def apply(hex : String) : ScriptSignature = fromHex(hex)
|
def apply(hex : String) : ScriptSignature = fromHex(hex)
|
||||||
|
|
Loading…
Add table
Reference in a new issue