/** * @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 $outputScript * @return PayToPubKeyHashAddress|ScriptHashAddress */ public static function fromOutputScript(ScriptInterface $outputScript) { $classifier = new OutputClassifier($outputScript); $type = $classifier->classify(); $parsed = $outputScript->getScriptParser()->decode(); if ($type === OutputClassifier::PAYTOPUBKEYHASH) { /** @var \BitWasp\Buffertools\BufferInterface $hash */ $hash = $parsed[2]->getData(); return new PayToPubKeyHashAddress($hash); } else { if ($type === OutputClassifier::PAYTOSCRIPTHASH) { /** @var \BitWasp\Buffertools\BufferInterface $hash */ $hash = $parsed[1]->getData(); return new ScriptHashAddress($hash); } } throw new \RuntimeException('Script type is not associated with an address'); }