/** * @param ScriptInterface $scriptSig * @param ScriptInterface $scriptPubKey * @param int $flags * @param Checker $checker * @param ScriptWitnessInterface|null $witness * @return bool */ public function verify(ScriptInterface $scriptSig, ScriptInterface $scriptPubKey, $flags, Checker $checker, ScriptWitnessInterface $witness = null) { static $emptyWitness = null; if ($emptyWitness === null) { $emptyWitness = new ScriptWitness([]); } $witness = $witness ?: $emptyWitness; if (($flags & self::VERIFY_SIGPUSHONLY) != 0 && !$scriptSig->isPushOnly()) { return false; } $stack = new Stack(); if (!$this->evaluate($scriptSig, $stack, 0, $flags, $checker)) { return false; } $backup = []; if ($flags & self::VERIFY_P2SH) { foreach ($stack as $s) { $backup[] = $s; } } if (!$this->evaluate($scriptPubKey, $stack, 0, $flags, $checker)) { return false; } if ($stack->isEmpty()) { return false; } if (false === $this->castToBool($stack[-1])) { return false; } $program = null; if ($flags & self::VERIFY_WITNESS) { if ($scriptPubKey->isWitness($program)) { /** @var WitnessProgram $program */ if ($scriptSig->getBuffer()->getSize() !== 0) { return false; } if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) { return false; } $stack->resize(1); } } if ($flags & self::VERIFY_P2SH && (new OutputClassifier($scriptPubKey))->isPayToScriptHash()) { if (!$scriptSig->isPushOnly()) { return false; } $stack = new Stack(); foreach ($backup as $i) { $stack->push($i); } // Restore mainStack to how it was after evaluating scriptSig if ($stack->isEmpty()) { return false; } // Load redeemscript as the scriptPubKey $scriptPubKey = new Script($stack->bottom()); $stack->pop(); if (!$this->evaluate($scriptPubKey, $stack, 0, $flags, $checker)) { return false; } if ($stack->isEmpty()) { return false; } if (!$this->castToBool($stack->bottom())) { return false; } if ($flags & self::VERIFY_WITNESS) { if ($scriptPubKey->isWitness($program)) { /** @var WitnessProgram $program */ if ($scriptSig != ScriptFactory::create()->push($scriptPubKey->getBuffer())->getScript()) { return false; // SCRIPT_ERR_WITNESS_MALLEATED_P2SH } if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) { return false; } $stack->resize(1); } } } if ($flags & self::VERIFY_CLEAN_STACK != 0) { if (!($flags & self::VERIFY_P2SH != 0 && $flags & self::VERIFY_WITNESS != 0)) { return false; // implied flags required } if (count($stack) != 1) { return false; // Cleanstack } } if ($flags & self::VERIFY_WITNESS) { if (!$flags & self::VERIFY_P2SH) { return false; // } if ($program === null && !$witness->isNull()) { return false; // SCRIPT_ERR_WITNESS_UNEXPECTED } } return true; }