All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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