Ejemplo n.º 1
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;
 }
Ejemplo n.º 2
0
 /**
  * @param int $sighashType
  * @return Buffer|BufferInterface
  */
 public function hashSequences($sighashType)
 {
     if (!($sighashType & SigHash::ANYONECANPAY) && ($sighashType & 0x1f) != SigHash::SINGLE && ($sighashType & 0x1f) != SigHash::NONE) {
         $binary = '';
         foreach ($this->transaction->getInputs() as $input) {
             $binary .= Buffer::int($input->getSequence())->flip()->getBinary();
         }
         return Hash::sha256d(new Buffer($binary));
     }
     return new Buffer('', 32);
 }
Ejemplo n.º 3
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;
 }
Ejemplo n.º 4
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);
 }
Ejemplo n.º 5
0
 /**
  * @param TransactionInterface $tx
  */
 private function deleteSpends(TransactionInterface $tx)
 {
     foreach ($tx->getInputs()->getInputs() as $v => $input) {
         if (!$input->isCoinBase()) {
             $this->delete($input->getTransactionId(), $input->getVout());
         }
     }
 }
Ejemplo n.º 6
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;
 }
Ejemplo n.º 7
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;
 }
Ejemplo n.º 8
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;
 }
Ejemplo n.º 9
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;
 }
Ejemplo n.º 10
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);
 }
Ejemplo n.º 11
0
 /**
  * @param array $array
  * @return $this
  */
 private function replace(array $array = [])
 {
     $this->transaction = new Transaction(array_key_exists('version', $array) ? $array['version'] : $this->transaction->getVersion(), array_key_exists('inputs', $array) ? $array['inputs'] : $this->transaction->getInputs(), array_key_exists('outputs', $array) ? $array['outputs'] : $this->transaction->getOutputs(), array_key_exists('witness', $array) ? $array['witness'] : $this->transaction->getWitnesses(), array_key_exists('nLockTime', $array) ? $array['nLockTime'] : $this->transaction->getLockTime());
     return $this;
 }
Ejemplo n.º 12
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)];
 }
Ejemplo n.º 13
0
 /**
  * @param UtxoView $view
  * @param TransactionInterface $tx
  * @param int $spendHeight
  * @return $this
  */
 public function checkContextualInputs(UtxoView $view, TransactionInterface $tx, $spendHeight)
 {
     $valueIn = gmp_init(0);
     for ($i = 0, $nInputs = count($tx->getInputs()); $i < $nInputs; $i++) {
         /*if ($out->isCoinbase()) {
               // todo: cb / height
               if ($spendHeight - $out->getHeight() < $this->params->coinbaseMaturityAge()) {
                   return false;
               }
           }*/
         $value = gmp_init($view->fetchByInput($tx->getInput($i))->getOutput()->getValue(), 10);
         $valueIn = $this->math->add($valueIn, $value);
         $this->consensus->checkAmount($valueIn);
     }
     $valueOut = gmp_init(0);
     foreach ($tx->getOutputs() as $output) {
         $valueOut = $this->math->add($valueOut, gmp_init($output->getValue(), 10));
         $this->consensus->checkAmount($valueOut);
     }
     if ($this->math->cmp($valueIn, $valueOut) < 0) {
         throw new \RuntimeException('Value-in is less than value-out');
     }
     $fee = $this->math->sub($valueIn, $valueOut);
     $this->consensus->checkAmount($fee);
     return $this;
 }
Ejemplo n.º 14
0
 /**
  * @param TransactionInterface $tx
  * @param $inputToExtract
  * @return $this
  */
 public function extractSigs(TransactionInterface $tx, $inputToExtract)
 {
     $inputs = $tx->getInputs();
     $parsed = $inputs[$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();
             $keys = $this->scriptInfo->getKeys();
             foreach ($keys as $idx => $key) {
                 $this->setSignature($idx, null);
             }
             if ($size > 2 && $size <= $this->scriptInfo->getKeyCount() + 2) {
                 $sigs = [];
                 foreach ($keys as $key) {
                     $sigs[$key->getPubKeyHash()->getHex()] = [];
                 }
                 // Extract Signatures (as buffers), then compile arrays of [pubkeyHash => signature]
                 $sigHash = new Hasher($tx);
                 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);
                         $linked = $this->ecAdapter->associateSigs([$txSig->getSignature()], $sigHash->calculate($redeemScript, $inputToExtract, $txSig->getHashType()), $keys);
                         if (count($linked)) {
                             $key = array_keys($linked)[0];
                             $sigs[$key] = array_merge($sigs[$key], [$txSig]);
                         }
                     }
                 }
                 // We have all the signatures from the tx now. array_shift the sigs for a public key, as it's encountered.
                 foreach ($keys as $idx => $key) {
                     $hash = $key->getPubKeyHash()->getHex();
                     $this->setSignature($idx, isset($sigs[$hash]) ? array_shift($sigs[$hash]) : null);
                 }
             }
             break;
     }
     return $this;
 }
Ejemplo n.º 15
0
 /**
  * @param UtxoView $view
  * @param TransactionInterface $tx
  * @param $spendHeight
  * @return bool
  */
 public function checkContextualInputs(UtxoView $view, TransactionInterface $tx, $spendHeight)
 {
     $valueIn = 0;
     for ($i = 0; $i < count($tx->getInputs()); $i++) {
         $utxo = $view->fetchByInput($tx->getInput($i));
         /*if ($out->isCoinbase()) {
               // todo: cb / height
               if ($spendHeight - $out->getHeight() < $this->params->coinbaseMaturityAge()) {
                   return false;
               }
           }*/
         $value = $utxo->getOutput()->getValue();
         $valueIn = $this->math->add($value, $valueIn);
         if (!$this->consensus->checkAmount($valueIn) || !$this->consensus->checkAmount($value)) {
             throw new \RuntimeException('CheckAmount failed for inputs value');
         }
     }
     $valueOut = 0;
     foreach ($tx->getOutputs() as $output) {
         $valueOut = $this->math->add($output->getValue(), $valueOut);
         if (!$this->consensus->checkAmount($valueOut) || !$this->consensus->checkAmount($output->getValue())) {
             throw new \RuntimeException('CheckAmount failed for outputs value');
         }
     }
     if ($this->math->cmp($valueIn, $valueOut) < 0) {
         throw new \RuntimeException('Value-in is less than value out');
     }
     $fee = $this->math->sub($valueIn, $valueOut);
     if ($this->math->cmp($fee, 0) < 0) {
         throw new \RuntimeException('Fee is less than zero');
     }
     if (!$this->consensus->checkAmount($fee)) {
         throw new \RuntimeException('CheckAmount failed for fee');
     }
     return true;
 }
 /**
  * @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());
 }
Ejemplo n.º 17
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 $transaction
  * @return string
  */
 public function serialize(TransactionInterface $transaction)
 {
     return $this->getTemplate()->write([$transaction->getVersion(), $transaction->getInputs()->getInputs(), $transaction->getOutputs()->getOutputs(), $transaction->getLockTime()]);
 }
Ejemplo n.º 19
0
 /**
  * @param TransactionInterface $transaction
  */
 public function __construct(TransactionInterface $transaction)
 {
     $this->transaction = $transaction;
     $this->nInputs = count($this->transaction->getInputs());
     $this->nOutputs = count($this->transaction->getOutputs());
 }
Ejemplo n.º 20
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);
 }
Ejemplo n.º 21
0
 /**
  * @param TransactionInterface $tx
  * @param ScriptInterface $scriptPubKey
  * @param int $nInputToSign
  * @param int $amount
  * @param ScriptWitnessInterface|null $witness
  * @return bool
  */
 public function verify(TransactionInterface $tx, ScriptInterface $scriptPubKey, $nInputToSign, $amount, ScriptWitnessInterface $witness = null)
 {
     $inputs = $tx->getInputs();
     $interpreter = new Interpreter($this->adapter);
     return $interpreter->verify($inputs[$nInputToSign]->getScript(), $scriptPubKey, $this->flags, new Checker($this->adapter, $tx, $nInputToSign, $amount), $witness);
 }