/**
  * @param EcAdapterInterface $ecAdapter
  * @param ScriptInterface $outputScript
  * @param RedeemScript $redeemScript
  */
 public function __construct(EcAdapterInterface $ecAdapter, ScriptInterface $outputScript, RedeemScript $redeemScript = null)
 {
     $classifier = new OutputClassifier($outputScript);
     $this->scriptType = $this->prevOutType = $classifier->classify();
     // Reclassify if the output is P2SH, so we know how to sign it.
     if ($this->scriptType == OutputClassifier::PAYTOSCRIPTHASH) {
         if (null === $redeemScript) {
             throw new \InvalidArgumentException('Redeem script is required when output is P2SH');
         }
         $rsClassifier = new OutputClassifier($redeemScript);
         $this->scriptType = $rsClassifier->classify();
     }
     // Gather public keys from redeemScript / outputScript
     $this->ecAdapter = $ecAdapter;
     $this->redeemScript = $redeemScript;
     $this->prevOutScript = $outputScript;
     // According to scriptType, extract public keys
     $this->execForInputTypes(function () {
         // For pay to pub key hash - nothing useful in output script
         $this->publicKeys = [];
     }, function () {
         // For pay to pub key - we can extract this from the output script
         $chunks = $this->prevOutScript->getScriptParser()->parse();
         $this->publicKeys = [PublicKeyFactory::fromHex($chunks[0]->getHex(), $this->ecAdapter)];
     }, function () {
         // Multisig - refer to the redeemScript
         $this->publicKeys = $this->redeemScript->getKeys();
     });
 }
 /**
  * @return bool
  */
 public function isPayToScriptHash()
 {
     if (count($this->evalScript) == 0) {
         return false;
     }
     $final = end($this->evalScript);
     if (!$final || !$final instanceof Buffer) {
         return false;
     }
     $type = new OutputClassifier(new Script($final));
     return false === in_array($type->classify(), [self::UNKNOWN, self::PAYTOSCRIPTHASH]);
 }
 /**
  * @return bool
  */
 public function isPayToScriptHash()
 {
     if (count($this->decoded) < 1) {
         return false;
     }
     $final = end($this->decoded);
     if (!$final || !$final->isPush()) {
         return false;
     }
     $type = new OutputClassifier(new Script($final->getData()));
     return false === in_array($type->classify(), [self::UNKNOWN, self::PAYTOSCRIPTHASH], true);
 }
 /**
  * @param ScriptInterface $script
  * @param NetworkInterface $network
  * @return String
  * @throws \RuntimeException
  */
 public static function getAssociatedAddress(ScriptInterface $script, NetworkInterface $network = null)
 {
     $classifier = new OutputClassifier($script);
     $network = $network ?: Bitcoin::getNetwork();
     try {
         if ($classifier->isPayToPublicKey()) {
             $address = PublicKeyFactory::fromHex($script->getScriptParser()->decode()[0]->getData())->getAddress();
         } else {
             $address = self::fromOutputScript($script);
         }
         return Base58::encodeCheck(Buffer::hex($network->getAddressByte() . $address->getHash(), 21));
     } catch (\Exception $e) {
         throw new \RuntimeException('No address associated with this script type');
     }
 }
 /**
  * @param ScriptInterface $scriptSig
  * @param ScriptInterface $scriptPubKey
  * @param $nInputToSign
  * @return bool
  * @throws \Exception
  */
 public function verify(ScriptInterface $scriptSig, ScriptInterface $scriptPubKey, $nInputToSign)
 {
     $this->inputToSign = $nInputToSign;
     if (!$this->setScript($scriptSig)->run()) {
         return false;
     }
     $mainStack = $this->state->getMainStack();
     $stackCopy = new ScriptStack();
     if ($this->flags->checkFlags(InterpreterInterface::VERIFY_P2SH)) {
         $stackCopy = $this->state->cloneMainStack();
     }
     if (!$this->setScript($scriptPubKey)->run()) {
         return false;
     }
     if ($mainStack->size() == 0) {
         return false;
     }
     if (false === $this->castToBool($mainStack->top(-1))) {
         return false;
     }
     $verifier = new OutputClassifier($scriptPubKey);
     if ($this->flags->checkFlags(InterpreterInterface::VERIFY_P2SH) && $verifier->isPayToScriptHash()) {
         if (!$scriptSig->isPushOnly()) {
             return false;
         }
         // Restore mainStack to how it was after evaluating scriptSig
         $mainStack = $this->state->restoreMainStack($stackCopy)->getMainStack();
         if ($mainStack->size() == 0) {
             return false;
         }
         // Load redeemscript as the scriptPubKey
         $scriptPubKey = new Script($mainStack->top(-1));
         $mainStack->pop();
         if (!$this->setScript($scriptPubKey)->run()) {
             return false;
         }
     }
     return true;
 }