Пример #1
0
 /**
  * @param Math $math
  * @param TransactionInterface $transaction
  * @return int|string
  */
 public function getValueIn(Math $math, TransactionInterface $transaction)
 {
     $value = 0;
     foreach ($transaction->getInputs() as $input) {
         $value = $math->add($value, $this->fetchByInput($input)->getOutput()->getValue());
     }
     return $value;
 }
Пример #2
0
 /**
  * @param UtxoView $utxoView
  * @param TransactionInterface $tx
  * @param Flags $flags
  * @return bool
  */
 public function check(UtxoView $utxoView, TransactionInterface $tx, Flags $flags)
 {
     $scripts = [];
     foreach ($tx->getInputs() as $input) {
         $scripts[] = $utxoView->fetchByInput($input)->getOutput()->getScript()->getHex();
     }
     return $this->dispatch($tx, $flags, $scripts);
 }
Пример #3
0
 /**
  * Calculate the hash of the current transaction, when you are looking to
  * spend $txOut, and are signing $inputToSign. The SigHashType defaults to
  * SIGHASH_ALL, though SIGHASH_SINGLE, SIGHASH_NONE, SIGHASH_ANYONECANPAY
  * can be used.
  *
  * @param ScriptInterface $txOutScript
  * @param $inputToSign
  * @param int $sighashType
  * @return Buffer
  * @throws \Exception
  */
 public function calculate(ScriptInterface $txOutScript, $inputToSign, $sighashType = SignatureHashInterface::SIGHASH_ALL)
 {
     $copy = $this->transaction->makeCopy();
     $inputs = $copy->getInputs();
     $outputs = $copy->getOutputs();
     if ($inputToSign > count($inputs)) {
         throw new \Exception('Input does not exist');
     }
     // Default SIGHASH_ALL procedure: null all input scripts
     $inputCount = count($inputs);
     for ($i = 0; $i < $inputCount; $i++) {
         $inputs->getInput($i)->setScript(new Script());
     }
     $inputs->getInput($inputToSign)->setScript($txOutScript);
     $math = Bitcoin::getMath();
     if ($math->bitwiseAnd($sighashType, 31) == SignatureHashInterface::SIGHASH_NONE) {
         // Set outputs to empty vector, and set sequence number of inputs to 0.
         $copy->setOutputs(new TransactionOutputCollection());
         // Let the others update at will. Set sequence of inputs we're not signing to 0.
         $inputCount = count($inputs);
         for ($i = 0; $i < $inputCount; $i++) {
             if ($math->cmp($i, $inputToSign) !== 0) {
                 $inputs->getInput($i)->setSequence(0);
             }
         }
     } elseif ($math->bitwiseAnd($sighashType, 31) == SignatureHashInterface::SIGHASH_SINGLE) {
         // Resize output array to $inputToSign + 1, set remaining scripts to null,
         // and set sequence's to zero.
         $nOutput = $inputToSign;
         if ($math->cmp($nOutput, count($outputs)) >= 0) {
             return Buffer::hex('0100000000000000000000000000000000000000000000000000000000000000');
         }
         // Resize..
         $outputs = $outputs->slice(0, $nOutput + 1)->getOutputs();
         // Set to null
         for ($i = 0; $i < $nOutput; $i++) {
             $outputs[$i] = new TransactionOutput($math->getBinaryMath()->getTwosComplement(-1, 64), new Script());
         }
         $copy->setOutputs(new TransactionOutputCollection($outputs));
         // Let the others update at will. Set sequence of inputs we're not signing to 0.
         $inputCount = count($inputs);
         for ($i = 0; $i < $inputCount; $i++) {
             if ($math->cmp($i, $inputToSign) != 0) {
                 $inputs->getInput($i)->setSequence(0);
             }
         }
     }
     // This can happen regardless of whether it's ALL, NONE, or SINGLE
     if ($math->bitwiseAnd($sighashType, SignatureHashInterface::SIGHASH_ANYONECANPAY)) {
         $input = $inputs->getInput($inputToSign);
         $copy->setInputs(new TransactionInputCollection([$input]));
     }
     // Serialize the TxCopy and append the 4 byte hashtype (little endian);
     $txParser = new Parser($copy->getBuffer());
     $txParser->writeInt(4, $sighashType, true);
     return Hash::sha256d($txParser->getBuffer());
 }
Пример #4
0
 /**
  * @param TransactionInterface $tx
  */
 private function saveOutputs(TransactionInterface $tx)
 {
     $txid = $tx->getTransactionId();
     $vout = 0;
     foreach ($tx->getOutputs()->getOutputs() as $output) {
         $this->contents->save($this->cacheIndex($txid, $vout), new Utxo($txid, $vout++, $output));
     }
     $this->size += $vout;
 }
Пример #5
0
 /**
  * @param UtxoView $utxoView
  * @param TransactionInterface $tx
  * @param Flags $flags
  * @return bool
  */
 public function check(UtxoView $utxoView, TransactionInterface $tx, Flags $flags)
 {
     $result = true;
     $consensus = $this->consensus->getConsensus($flags);
     for ($i = 0, $c = count($tx->getInputs()); $i < $c; $i++) {
         $result &= $consensus->verify($tx, $utxoView->fetchByInput($tx->getInput($i))->getOutput()->getScript(), $i);
     }
     return $result;
 }
Пример #6
0
 /**
  * @param ConsensusInterface $consensus
  * @param TransactionOutputInterface[] $outputs
  * @return bool
  */
 public function checkSignatures(ConsensusInterface $consensus, array $outputs)
 {
     if (count($this->transaction->getInputs()) !== count($outputs)) {
         throw new \InvalidArgumentException('Incorrect scriptPubKey count');
     }
     $result = true;
     foreach ($outputs as $i => $txOut) {
         $result = $result && $this->checkSignature($consensus, $i, $txOut);
     }
     return $result;
 }
Пример #7
0
 /**
  * @param UtxoView $utxoView
  * @param TransactionInterface $tx
  * @return ScriptValidationInterface
  */
 public function queue(UtxoView $utxoView, TransactionInterface $tx)
 {
     $hex = $tx->getHex();
     $t = ['txid' => spl_object_hash($tx), 'tx' => $hex, 'scripts' => []];
     for ($i = 0, $c = count($tx->getInputs()); $i < $c; $i++) {
         $output = $utxoView->fetchByInput($tx->getInput($i))->getOutput();
         $witness = isset($tx->getWitnesses()[$i]) ? $tx->getWitness($i) : null;
         $t['scripts'][] = $output->getScript()->getHex();
     }
     $this->results[] = $t;
     return $this;
 }
Пример #8
0
 /**
  * @return $this
  */
 public function extractSignatures()
 {
     $type = (new OutputClassifier($this->txOut->getScript()))->classify();
     $scriptPubKey = $this->txOut->getScript();
     $scriptSig = $this->tx->getInput($this->nInput)->getScript();
     if ($type === OutputClassifier::PAYTOPUBKEYHASH || $type === OutputClassifier::PAYTOPUBKEY || $type === OutputClassifier::MULTISIG) {
         $values = [];
         foreach ($scriptSig->getScriptParser()->decode() as $o) {
             $values[] = $o->getData();
         }
         $this->extractFromValues($type, $scriptPubKey, $values, 0);
     }
     if ($type === OutputClassifier::PAYTOSCRIPTHASH) {
         $decodeSig = $scriptSig->getScriptParser()->decode();
         if (count($decodeSig) > 0) {
             $redeemScript = new Script(end($decodeSig)->getData());
             $p2shType = (new OutputClassifier($redeemScript))->classify();
             if (count($decodeSig) > 1) {
                 $decodeSig = array_slice($decodeSig, 0, -1);
             }
             $internalSig = [];
             foreach ($decodeSig as $operation) {
                 $internalSig[] = $operation->getData();
             }
             $this->redeemScript = $redeemScript;
             $this->extractFromValues($p2shType, $redeemScript, $internalSig, 0);
             $type = $p2shType;
         }
     }
     $witnesses = $this->tx->getWitnesses();
     if ($type === OutputClassifier::WITNESS_V0_KEYHASH) {
         $this->requiredSigs = 1;
         if (isset($witnesses[$this->nInput])) {
             $witness = $witnesses[$this->nInput];
             $this->signatures = [TransactionSignatureFactory::fromHex($witness[0], $this->ecAdapter)];
             $this->publicKeys = [PublicKeyFactory::fromHex($witness[1], $this->ecAdapter)];
         }
     } else {
         if ($type === OutputClassifier::WITNESS_V0_SCRIPTHASH) {
             if (isset($witnesses[$this->nInput])) {
                 $witness = $witnesses[$this->nInput];
                 $witCount = count($witnesses[$this->nInput]);
                 if ($witCount > 0) {
                     $witnessScript = new Script($witness[$witCount - 1]);
                     $vWitness = $witness->all();
                     if (count($vWitness) > 1) {
                         $vWitness = array_slice($witness->all(), 0, -1);
                     }
                     $witnessType = (new OutputClassifier($witnessScript))->classify();
                     $this->extractFromValues($witnessType, $witnessScript, $vWitness, 1);
                     $this->witnessScript = $witnessScript;
                 }
             }
         }
     }
     return $this;
 }
Пример #9
0
 /**
  * Calculate the hash of the current transaction, when you are looking to
  * spend $txOut, and are signing $inputToSign. The SigHashType defaults to
  * SIGHASH_ALL, though SIGHASH_SINGLE, SIGHASH_NONE, SIGHASH_ANYONECANPAY
  * can be used.
  *
  * @param ScriptInterface $txOutScript
  * @param int $inputToSign
  * @param int $sighashType
  * @return BufferInterface
  * @throws \Exception
  */
 public function calculate(ScriptInterface $txOutScript, $inputToSign, $sighashType = SigHash::ALL)
 {
     $sighashType = (int) $sighashType;
     $hashPrevOuts = $this->hashPrevOuts($sighashType);
     $hashSequence = $this->hashSequences($sighashType);
     $hashOutputs = $this->hashOutputs($sighashType, $inputToSign);
     $input = $this->transaction->getInput($inputToSign);
     return Hash::sha256d(new Buffer(pack("V", $this->transaction->getVersion()) . $hashPrevOuts->getBinary() . $hashSequence->getBinary() . $input->getOutPoint()->getBinary() . ScriptFactory::create()->push($txOutScript->getBuffer())->getScript()->getBinary() . Buffer::int($this->amount, 8)->flip()->getBinary() . pack("V", $input->getSequence()) . $hashOutputs->getBinary() . pack("V", $this->transaction->getLockTime()) . pack("V", $sighashType)));
 }
Пример #10
0
 /**
  * @param ScriptInterface $script
  * @param Buffer $sigBuf
  * @param Buffer $keyBuf
  * @return bool
  * @throws ScriptRuntimeException
  * @throws \Exception
  */
 private function checkSig(ScriptInterface $script, Buffer $sigBuf, Buffer $keyBuf)
 {
     $this->checkSignatureEncoding($sigBuf)->checkPublicKeyEncoding($keyBuf);
     try {
         $txSignature = TransactionSignatureFactory::fromHex($sigBuf->getHex());
         $publicKey = PublicKeyFactory::fromHex($keyBuf->getHex());
         $sigHash = $this->transaction->getSignatureHash()->calculate($script, $this->inputToSign, $txSignature->getHashType());
         return $this->ecAdapter->verify($sigHash, $publicKey, $txSignature->getSignature());
     } catch (\Exception $e) {
         return false;
     }
 }
Пример #11
0
 /**
  * @param \BitWasp\Bitcoin\Script\Interpreter\Number $sequence
  * @return bool
  */
 private function checkSequence(Number $sequence)
 {
     $txSequence = $this->transaction->getInput($this->inputToSign)->getSequence();
     if ($this->transaction->getVersion() < 2) {
         return false;
     }
     if ($this->math->cmp($this->math->bitwiseAnd($txSequence, TransactionInputInterface::SEQUENCE_LOCKTIME_DISABLE_FLAG), 0) !== 0) {
         return 0;
     }
     $mask = $this->math->bitwiseOr(TransactionInputInterface::SEQUENCE_LOCKTIME_TYPE_FLAG, TransactionInputInterface::SEQUENCE_LOCKTIME_MASK);
     return $this->verifyLockTime($this->math->bitwiseAnd($txSequence, $mask), TransactionInputInterface::SEQUENCE_LOCKTIME_TYPE_FLAG, Number::int($this->math->bitwiseAnd($sequence->getInt(), $mask)));
 }
Пример #12
0
 /**
  * @param \BitWasp\Bitcoin\Script\Interpreter\Number $sequence
  * @return bool
  */
 public function checkSequence(\BitWasp\Bitcoin\Script\Interpreter\Number $sequence)
 {
     $math = $this->adapter->getMath();
     $txSequence = $this->transaction->getInput($this->nInput)->getSequence();
     if ($this->transaction->getVersion() < 2) {
         return false;
     }
     if ($math->cmp($math->bitwiseAnd($txSequence, TransactionInputInterface::SEQUENCE_LOCKTIME_DISABLE_FLAG), 0) !== 0) {
         return 0;
     }
     $mask = $math->bitwiseOr(TransactionInputInterface::SEQUENCE_LOCKTIME_TYPE_FLAG, TransactionInputInterface::SEQUENCE_LOCKTIME_MASK);
     return $this->verifyLockTime($math->bitwiseAnd($txSequence, $mask), TransactionInputInterface::SEQUENCE_LOCKTIME_TYPE_FLAG, Number::int($math->bitwiseAnd($sequence->getInt(), $mask)));
 }
Пример #13
0
 /**
  * @return bool
  */
 public function isFullySigned()
 {
     foreach ($this->transaction->getInputs() as $i => $input) {
         if (array_key_exists($i, $this->inputStates)) {
             /** @var TxSignerContext $state */
             $state = $this->inputStates[$i];
             if (!$state->isFullySigned()) {
                 return false;
             }
         }
     }
     return true;
 }
Пример #14
0
 /**
  * @param UtxoView $utxoView
  * @param TransactionInterface $tx
  * @return ScriptValidationInterface
  */
 public function queue(UtxoView $utxoView, TransactionInterface $tx)
 {
     for ($i = 0, $c = count($tx->getInputs()); $i < $c; $i++) {
         $output = $utxoView->fetchByInput($tx->getInput($i))->getOutput();
         $witness = isset($tx->getWitnesses()[$i]) ? $tx->getWitness($i) : null;
         $this->results[] = $this->consensus->verify($tx, $output->getScript(), $i, $output->getValue(), $witness);
     }
     return $this;
 }
Пример #15
0
 /**
  * @return Transaction
  */
 public function getTransaction()
 {
     $transaction = $this->transaction;
     $inCount = count($transaction->getInputs());
     for ($i = 0; $i < $inCount; $i++) {
         // Call regenerateScript if inputState is set, otherwise defer to previous script.
         try {
             $script = $this->getInputState($i)->regenerateScript();
         } catch (BuilderNoInputState $e) {
             $script = $this->transaction->getInputs()->getInput($i)->getScript();
         }
         $transaction->getInputs()->getInput($i)->setScript($script);
     }
     return $transaction;
 }
Пример #16
0
 /**
  * @param TransactionInterface $transaction
  */
 private function processTransaction(TransactionInterface $transaction)
 {
     $results = [];
     $nOut = count($transaction->getOutputs());
     for ($i = 0; $i < $nOut; $i++) {
         $output = $transaction->getOutput($i);
         $script = $output->getScript()->getBinary();
         if (!isset($results[$script])) {
             $results[$script] = $output->getValue();
         } else {
             $results[$script] += $output->getValue();
         }
     }
     // Compare results to known contracts
     foreach ($this->contracts as $contract) {
         $requirements = $contract['requirements'];
         $rCount = count($requirements);
         $have = 0;
         foreach ($requirements as $script => $value) {
             if (isset($results[$script])) {
                 echo 'pmt';
                 if ($results[$script] >= $value) {
                     $have++;
                 }
             }
         }
         if ($have > 0) {
             if ($have < $rCount) {
                 $command = 'tx.partial';
             } else {
                 $command = 'tx.complete';
             }
             $this->listener->send(json_encode(['slug' => $contract['slug'], 'command' => $command, 'tx' => $transaction->getHex()]));
         }
     }
 }
Пример #17
0
 /**
  * @param TransactionInterface $transaction
  * @param bool $allowExtremeFees
  * @return string
  */
 public function sendrawtransaction(TransactionInterface $transaction, $allowExtremeFees = false)
 {
     $send = $this->client->execute('sendrawtransaction', [$transaction->getHex(), $allowExtremeFees]);
     $this->checkNotNull($send);
     return $send;
 }
 /**
  * @param TransactionInterface $transaction
  * @return string
  */
 public function serialize(TransactionInterface $transaction)
 {
     return $this->getTemplate()->write([$transaction->getVersion(), $transaction->getInputs()->getInputs(), $transaction->getOutputs()->getOutputs(), $transaction->getLockTime()]);
 }
Пример #19
0
 /**
  * {@inheritdoc}
  * @see \BitWasp\Bitcoin\SerializableInterface::getBuffer()
  */
 public function getBuffer()
 {
     return $this->transaction->getBuffer();
 }
Пример #20
0
 /**
  * @param TransactionInterface $transaction
  * @return \React\Promise\Promise
  */
 public function transactionBroadcast(TransactionInterface $transaction)
 {
     return $this->client->request('blockchain.transaction.broadcast', [$transaction->getHex()]);
 }
Пример #21
0
 /**
  * @param TransactionInterface $transaction
  * @return BufferInterface
  */
 public function serialize(TransactionInterface $transaction)
 {
     $math = Bitcoin::getMath();
     $int8le = new Int8($math, ByteOrder::LE);
     $int32le = new Int32($math, ByteOrder::LE);
     $uint32le = new Uint32($math, ByteOrder::LE);
     $varint = new VarInt($math, ByteOrder::LE);
     $vector = new Vector($varint, function () {
     });
     $binary = $int32le->write($transaction->getVersion());
     $flags = 0;
     if (!$transaction->getWitnesses()->isNull()) {
         $flags |= 1;
     }
     if ($flags) {
         $binary .= $int8le->write(0);
         $binary .= $int8le->write($flags);
     }
     $binary .= $vector->write($transaction->getInputs()->all());
     $binary .= $vector->write($transaction->getOutputs()->all());
     if ($flags & 1) {
         foreach ($transaction->getWitnesses() as $witness) {
             $binary .= $witness->getBuffer()->getBinary();
         }
     }
     $binary .= $uint32le->write($transaction->getLockTime());
     return new Buffer($binary);
 }
Пример #22
0
 /**
  * @param TransactionInterface $transaction
  * @param int $outputToSpend
  * @param ScriptInterface|null $script
  * @param int $nSequence
  * @return $this
  */
 public function spendOutputFrom(TransactionInterface $transaction, $outputToSpend, ScriptInterface $script = null, $nSequence = TransactionInputInterface::SEQUENCE_FINAL)
 {
     // Check TransactionOutput exists in $tx
     $transaction->getOutput($outputToSpend);
     $this->input($transaction->getTxId(), $outputToSpend, $script, $nSequence);
     return $this;
 }
Пример #23
0
 /**
  * @param TransactionInterface $tx
  * @param ScriptInterface $scriptPubKey
  * @param int $nInputToSign
  * @return bool
  */
 public function verify(TransactionInterface $tx, ScriptInterface $scriptPubKey, $nInputToSign)
 {
     $error = 0;
     return (bool) bitcoinconsensus_verify_script($scriptPubKey->getBinary(), $tx->getBinary(), $nInputToSign, $this->flags->getFlags(), $error);
 }
Пример #24
0
 /**
  * @param TransactionInterface $transaction
  */
 public function __construct(TransactionInterface $transaction)
 {
     $this->transaction = $transaction;
     $this->nInputs = count($this->transaction->getInputs());
     $this->nOutputs = count($this->transaction->getOutputs());
 }
Пример #25
0
 /**
  * @param TransactionInterface $transaction
  * @return array
  */
 public function convertTransactionToArray(TransactionInterface $transaction)
 {
     $inputs = [];
     foreach ($transaction->getInputs() as $input) {
         $inputs[] = $this->convertTxinToArray($input);
     }
     $outputs = [];
     foreach ($transaction->getOutputs() as $output) {
         $outputs[] = $this->convertTxoutToArray($output);
     }
     $buf = $transaction->getBuffer()->getBinary();
     return ['hash' => $transaction->getTxId()->getHex(), 'version' => $transaction->getVersion(), 'inputs' => $inputs, 'outputs' => $outputs, 'locktime' => $transaction->getLockTime(), 'raw' => bin2hex($buf), 'size' => strlen($buf)];
 }
Пример #26
0
 /**
  * @param TransactionInterface $tx
  * @return bool
  */
 public function isRelevantAndUpdate(TransactionInterface $tx)
 {
     $this->updateEmptyFull();
     $found = false;
     if ($this->isFull()) {
         return true;
     }
     if ($this->isEmpty()) {
         return false;
     }
     // Check if the txid hash is in the filter
     $txHash = $tx->getTxId();
     if ($this->containsData($txHash)) {
         $found = true;
     }
     // Check for relevant output scripts. We add the outpoint to the filter if found.
     foreach ($tx->getOutputs() as $vout => $output) {
         $script = $output->getScript();
         $parser = $script->getScriptParser();
         foreach ($parser as $exec) {
             if ($exec->isPush() && $this->containsData($exec->getData())) {
                 $found = true;
                 if ($this->isUpdateAll()) {
                     $this->insertOutPoint($tx->makeOutPoint($vout));
                 } else {
                     if ($this->isUpdatePubKeyOnly()) {
                         $type = ScriptFactory::scriptPubKey()->classify($script);
                         if ($type->isMultisig() || $type->isPayToPublicKey()) {
                             $this->insertOutPoint($tx->makeOutPoint($vout));
                         }
                     }
                 }
             }
         }
     }
     if ($found) {
         return true;
     }
     foreach ($tx->getInputs() as $txIn) {
         if ($this->containsOutPoint($txIn->getOutPoint())) {
             return true;
         }
         $parser = $txIn->getScript()->getScriptParser();
         foreach ($parser as $exec) {
             if ($exec->isPush() > 0 && $this->containsData($exec->getData())) {
                 return true;
             }
         }
     }
     return false;
 }
 /**
  * @param TransactionInterface $tx
  * @return Transaction
  */
 public function fixTransaction(Peer $sender, TransactionInterface $tx, &$wasMalleated = false)
 {
     $c = count($tx->getInputs());
     $new = new TransactionInputCollection();
     for ($i = 0; $i < $c; $i++) {
         $input = $tx->getInput($i);
         $script = $input->getScript();
         $classify = ScriptFactory::scriptSig()->classify($input->getScript());
         $this->inputs++;
         if ($classify->isPayToPublicKeyHash()) {
             $parsed = $input->getScript()->getScriptParser()->parse();
             $txSig = TransactionSignatureFactory::fromHex($parsed[0]);
             $txSig = $this->fixSig($sender, $txSig, $wasMalleated);
             $script = ScriptFactory::create()->push($txSig->getBuffer())->push($parsed[1])->getScript();
         }
         $new->addInput(new TransactionInput($input->getTransactionId(), $input->getVout(), $script, $input->getSequence()));
     }
     return new Transaction($tx->getVersion(), $new, $tx->getOutputs(), $tx->getLockTime());
 }
Пример #28
0
 /**
  * @param UtxoView $view
  * @param TransactionInterface $tx
  * @param int $height
  * @param Flags $flags
  * @param bool|true $checkScripts
  * @return bool
  */
 public function checkInputs(UtxoView $view, TransactionInterface $tx, $height, Flags $flags, $checkScripts = true)
 {
     if (!$tx->isCoinbase()) {
         $this->checkContextualInputs($view, $tx, $height);
         if ($checkScripts) {
             if (!$this->scriptCheck->check($view, $tx, $flags)) {
                 throw new \RuntimeException('Script verification failed');
             }
         }
     }
     return true;
 }
Пример #29
0
 /**
  * @param TransactionInterface $tx
  * @param int $inputToExtract
  * @return $this
  */
 public function extractSigs(TransactionInterface $tx, $inputToExtract)
 {
     $parsed = $tx->getInput($inputToExtract)->getScript()->getScriptParser()->decode();
     $size = count($parsed);
     switch ($this->getScriptType()) {
         case OutputClassifier::PAYTOPUBKEYHASH:
             // Supply signature and public key in scriptSig
             if ($size === 2) {
                 $this->signatures = [TransactionSignatureFactory::fromHex($parsed[0]->getData(), $this->ecAdapter)];
                 $this->publicKeys = [PublicKeyFactory::fromHex($parsed[1]->getData(), $this->ecAdapter)];
             }
             break;
         case OutputClassifier::PAYTOPUBKEY:
             // Only has a signature in the scriptSig
             if ($size === 1) {
                 $this->signatures = [TransactionSignatureFactory::fromHex($parsed[0]->getData(), $this->ecAdapter)];
             }
             break;
         case OutputClassifier::MULTISIG:
             $redeemScript = $this->getRedeemScript();
             $this->signatures = array_fill(0, count($this->publicKeys), null);
             if ($size > 2 && $size <= $this->scriptInfo->getKeyCount() + 2) {
                 $sigHash = $tx->getSignatureHash();
                 $sigSort = new SignatureSort($this->ecAdapter);
                 $sigs = new \SplObjectStorage();
                 foreach (array_slice($parsed, 1, -1) as $item) {
                     /** @var \BitWasp\Bitcoin\Script\Parser\Operation $item */
                     if ($item->isPush()) {
                         $txSig = TransactionSignatureFactory::fromHex($item->getData(), $this->ecAdapter);
                         $hash = $sigHash->calculate($redeemScript, $inputToExtract, $txSig->getHashType());
                         $linked = $sigSort->link([$txSig->getSignature()], $this->publicKeys, $hash);
                         foreach ($this->publicKeys as $key) {
                             if ($linked->contains($key)) {
                                 $sigs[$key] = $txSig;
                             }
                         }
                     }
                 }
                 // We have all the signatures from the input now. array_shift the sigs for a public key, as it's encountered.
                 foreach ($this->publicKeys as $idx => $key) {
                     $this->signatures[$idx] = isset($sigs[$key]) ? $sigs[$key] : null;
                 }
             }
             break;
     }
     return $this;
 }
Пример #30
0
 /**
  * @param TransactionInterface $tx
  * @param ScriptInterface $scriptPubKey
  * @param int $nInputToSign
  * @return bool
  */
 public function verify(TransactionInterface $tx, ScriptInterface $scriptPubKey, $nInputToSign)
 {
     $inputs = $tx->getInputs();
     $interpreter = new Interpreter($this->adapter, $tx, $this->flags);
     return $interpreter->verify($inputs[$nInputToSign]->getScript(), $scriptPubKey, $nInputToSign);
 }