
fr.acinq.bitcoin.scalacompat.Script.scala Maven / Gradle / Ivy
package fr.acinq.bitcoin.scalacompat
import fr.acinq.bitcoin
import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
import fr.acinq.bitcoin.scalacompat.KotlinUtils._
import scodec.bits.ByteVector
import scala.jdk.CollectionConverters.{ListHasAsScala, SeqHasAsJava}
object Script {
import fr.acinq.bitcoin.ScriptFlags._
def parse(blob: ByteVector): List[ScriptElt] = parse(blob.toArray)
def parse(blob: Array[Byte]): List[ScriptElt] = bitcoin.Script.parse(blob).asScala.toList.map(kmp2scala)
def write(script: Seq[ScriptElt]): ByteVector = ByteVector.view(bitcoin.Script.write(script.map(scala2kmp).asJava))
def encodeNumber(value: Long): ByteVector = ByteVector.view(bitcoin.Script.encodeNumber(value).toByteArray)
def decodeNumber(input: ByteVector, checkMinimalEncoding: Boolean, maximumSize: Int = 4): Long = bitcoin.Script.decodeNumber(input.toArray, checkMinimalEncoding, maximumSize)
def isSimpleValue(op: ScriptElt): Boolean = bitcoin.Script.isSimpleValue(op)
def simpleValue(op: ScriptElt): Byte = bitcoin.Script.simpleValue(op)
def isPushOnly(script: Seq[ScriptElt]): Boolean = bitcoin.Script.isPushOnly(script.map(scala2kmp).asJava)
def isPayToScript(script: ByteVector): Boolean = bitcoin.Script.isPayToScript(script.toArray)
def isNativeWitnessScript(script: Seq[ScriptElt]): Boolean = bitcoin.Script.isNativeWitnessScript(script.map(scala2kmp).asJava)
def isNativeWitnessScript(script: ByteVector): Boolean = isNativeWitnessScript(parse(script))
def getWitnessVersion(script: Seq[ScriptElt]): Option[Int] = bitcoin.Script.getWitnessVersion(script.map(scala2kmp).asJava) match {
case null => None
case version => Some(version)
}
def getWitnessVersion(script: ByteVector): Option[Int] = getWitnessVersion(parse(script))
def checkLockTime(lockTime: Long, tx: Transaction, inputIndex: Int): Boolean = bitcoin.Script.INSTANCE.checkLockTime(lockTime, tx, inputIndex)
def checkSequence(sequence: Long, tx: Transaction, inputIndex: Int): Boolean = bitcoin.Script.INSTANCE.checkSequence(sequence, tx, inputIndex)
/**
* Execution context of a tx script. A script is always executed in the "context" of a transaction that is being
* verified.
*
* @param tx transaction that is being verified
* @param inputIndex 0-based index of the tx input that is being processed
*/
case class Context(tx: Transaction, inputIndex: Int, amount: Satoshi) {
require(inputIndex >= 0 && inputIndex < tx.txIn.length, "invalid input index")
}
/**
* Bitcoin script runner
*
* @param context script execution context
* @param scriptFlag script flags
*/
class Runner(context: Context, scriptFlag: Int = MANDATORY_SCRIPT_VERIFY_FLAGS) {
private val runner = new bitcoin.Script.Runner(
new bitcoin.Script.Context(context.tx, context.inputIndex, context.amount), scriptFlag, null
)
def verifyWitnessProgram(witness: ScriptWitness, witnessVersion: Long, program: ByteVector): Unit = runner.verifyWitnessProgram(witness, witnessVersion, program.toArray)
def verifyScripts(scriptSig: ByteVector, scriptPubKey: ByteVector): Boolean = verifyScripts(scriptSig, scriptPubKey, ScriptWitness.empty)
/**
* verify a script sig/script pubkey pair:
*
* - parse and run script sig
* - parse and run script pubkey using the stack generated by the previous step
* - check the final stack
* - extract and run embedded pay2sh scripts if any and check the stack again
*
*
* @param scriptSig signature script
* @param scriptPubKey public key script
* @return true if the scripts were successfully verified
*/
def verifyScripts(scriptSig: ByteVector, scriptPubKey: ByteVector, witness: ScriptWitness): Boolean = runner.verifyScripts(scriptSig, scriptPubKey, witness)
}
/**
* extract a public key hash from a public key script
*
* @param script public key script
* @return the public key hash wrapped in the script
*/
def publicKeyHash(script: List[ScriptElt]): ByteVector = script match {
case OP_DUP :: OP_HASH160 :: OP_PUSHDATA(data, _) :: OP_EQUALVERIFY :: OP_CHECKSIG :: OP_NOP :: Nil => data // non standard pay to pubkey...
case OP_DUP :: OP_HASH160 :: OP_PUSHDATA(data, _) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil => data // standard pay to pubkey
case OP_HASH160 :: OP_PUSHDATA(data, _) :: OP_EQUAL :: Nil if data.size == 20 => data // standard pay to script
}
def publicKeyHash(script: ByteVector): ByteVector = publicKeyHash(parse(script))
/**
* extract a public key from a signature script
*
* @param script signature script
* @return the public key wrapped in the script
*/
def publicKey(script: List[ScriptElt]): ByteVector = script match {
case OP_PUSHDATA(data1, _) :: OP_PUSHDATA(data2, _) :: Nil if data1.length > 2 && data2.length > 2 => data2
case OP_PUSHDATA(data, _) :: OP_CHECKSIG :: Nil => data
}
/**
* Creates a m-of-n multisig script.
*
* @param m is the number of required signatures
* @param pubkeys are the public keys signatures will be checked against (there should be at least as many public keys
* as required signatures)
* @return a multisig redeem script
*/
def createMultiSigMofN(m: Int, pubkeys: Seq[PublicKey]): Seq[ScriptElt] = bitcoin.Script.createMultiSigMofN(m, pubkeys.map(_.pub).asJava).asScala.map(kmp2scala).toList
/**
* @param pubKeys are the public keys signatures will be checked against.
* @param sigs are the signatures for a subset of the public keys.
* @return script witness for the pay-to-witness-script-hash script containing a multisig script.
*/
def witnessMultiSigMofN(pubKeys: Seq[PublicKey], sigs: Seq[ByteVector]): ScriptWitness = bitcoin.Script.witnessMultiSigMofN(pubKeys.map(_.pub).asJava, sigs.map(scala2kmp).asJava)
/**
* @param pubKeyHash public key hash
* @return a pay-to-public-key-hash script
*/
def pay2pkh(pubKeyHash: ByteVector): Seq[ScriptElt] = bitcoin.Script.pay2pkh(pubKeyHash.toArray).asScala.map(kmp2scala).toList
/**
* @param pubKey public key
* @return a pay-to-public-key-hash script
*/
def pay2pkh(pubKey: PublicKey): Seq[ScriptElt] = pay2pkh(pubKey.hash160)
def isPay2pkh(script: Seq[ScriptElt]): Boolean = bitcoin.Script.isPay2pkh(script.map(scala2kmp).asJava)
/**
* @param script bitcoin script
* @return a pay-to-script script
*/
def pay2sh(script: Seq[ScriptElt]): Seq[ScriptElt] = pay2sh(Script.write(script))
/**
* @param script bitcoin script
* @return a pay-to-script script
*/
def pay2sh(script: ByteVector): Seq[ScriptElt] = bitcoin.Script.pay2sh(script.toArray).asScala.map(kmp2scala).toList
def isPay2sh(script: Seq[ScriptElt]): Boolean = bitcoin.Script.isPay2sh(script.map(scala2kmp).asJava)
/**
* @param script bitcoin script
* @return a pay-to-witness-script script
*/
def pay2wsh(script: Seq[ScriptElt]): Seq[ScriptElt] = pay2wsh(Script.write(script))
/**
* @param script bitcoin script
* @return a pay-to-witness-script script
*/
def pay2wsh(script: ByteVector): Seq[ScriptElt] = bitcoin.Script.pay2wsh(script.toArray).asScala.map(kmp2scala).toList
def isPay2wsh(script: Seq[ScriptElt]): Boolean = bitcoin.Script.isPay2wsh(script.map(scala2kmp).asJava)
/**
* @param pubKeyHash public key hash
* @return a pay-to-witness-public-key-hash script
*/
def pay2wpkh(pubKeyHash: ByteVector): Seq[ScriptElt] = bitcoin.Script.pay2wpkh(pubKeyHash.toArray).asScala.map(kmp2scala).toList
/**
* @param pubKey public key
* @return a pay-to-witness-public-key-hash script
*/
def pay2wpkh(pubKey: PublicKey): Seq[ScriptElt] = pay2wpkh(pubKey.hash160)
def isPay2wpkh(script: Seq[ScriptElt]): Boolean = bitcoin.Script.isPay2wsh(script.map(scala2kmp).asJava)
/**
* @param pubKey public key
* @param sig signature matching the public key
* @return script witness for the corresponding pay-to-witness-public-key-hash script
*/
def witnessPay2wpkh(pubKey: PublicKey, sig: ByteVector): ScriptWitness = bitcoin.Script.witnessPay2wpkh(pubKey, sig)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy