/**
  * Given a sequence, get the human readable node. Ie, 0 -> 0, 0x80000000 -> 0h
  * @param $sequence
  * @return string
  */
 public function getNode($sequence)
 {
     if ($this->isHardened($sequence)) {
         $sequence = $this->math->sub($sequence, self::START_HARDENED) . 'h';
     }
     return $sequence;
 }
Beispiel #2
0
 /**
  * Convert a lock time to the timestamp it's locked to.
  * Throws an exception when:
  *  - Lock time appears to be in the block locktime range ( < Locktime::BLOCK_MAX )
  *  - When the lock time exceeds the max possible lock time ( > Locktime::INT_MAX )
  *
  * @param int|string $lockTime
  * @return int|string
  * @throws \Exception
  */
 public function toTimestamp($lockTime)
 {
     if ($this->math->cmp($lockTime, self::BLOCK_MAX) <= 0) {
         throw new \Exception('Lock time out of range for timestamp');
     }
     if ($this->math->cmp($lockTime, self::INT_MAX) > 0) {
         throw new \Exception('Lock time too large');
     }
     $timestamp = $this->math->sub($lockTime, self::BLOCK_MAX);
     return $timestamp;
 }
Beispiel #3
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;
 }
Beispiel #4
0
 /**
  * @return BufferInterface
  */
 private function serialize()
 {
     if ($this->math->cmp($this->number, '0') === 0) {
         return new Buffer('', 0);
     }
     // Using array of integers instead of bytes
     $result = [];
     $negative = $this->math->cmp($this->number, 0) < 0;
     $abs = $negative ? $this->math->sub(0, $this->number) : $this->number;
     while ($this->math->cmp($abs, 0) > 0) {
         //array_unshift($result, (int)$this->math->bitwiseAnd($abs, 0xff));
         $result[] = (int) $this->math->bitwiseAnd($abs, 0xff);
         $abs = $this->math->rightShift($abs, 8);
     }
     if ($result[count($result) - 1] & 0x80) {
         //array_unshift($result, $negative ? 0x80 : 0);
         $result[] = $negative ? 0x80 : 0;
     } else {
         if ($negative) {
             //$result[0] |= 0x80;
             $result[count($result) - 1] |= 0x80;
         }
     }
     $s = '';
     foreach ($result as $i) {
         $s .= chr($i);
     }
     return new Buffer($s, null, $this->math);
 }
 /**
  * @param Parser $parser
  * @return CompactSignature
  * @throws ParserOutOfRange
  */
 public function fromParser(Parser &$parser)
 {
     try {
         list($byte, $r, $s) = $this->getTemplate()->parse($parser);
         $recoveryFlags = $this->math->sub($byte, 27);
         if ($recoveryFlags < 0 || $recoveryFlags > 7) {
             throw new \InvalidArgumentException('invalid signature type');
         }
         $isCompressed = $this->math->bitwiseAnd($recoveryFlags, 4) != 0;
         $recoveryId = $recoveryFlags - ($isCompressed ? 4 : 0);
     } catch (ParserOutOfRange $e) {
         throw new ParserOutOfRange('Failed to extract full signature from parser');
     }
     $signature = new CompactSignature($r, $s, $recoveryId, $isCompressed);
     return $signature;
 }
 /**
  * @param Peer $sender
  * @param TransactionSignatureInterface $txSig
  * @return TransactionSignatureInterface
  */
 public function fixSig(Peer $sender, TransactionSignatureInterface $txSig, &$wasMalleated = false)
 {
     $sig = $txSig->getSignature();
     if (!$this->adapter->validateSignatureElement($sig->getS(), true)) {
         $ip = $sender->getRemoteAddr()->getIp();
         if (!isset($this->violators[$ip])) {
             $this->violators[$sender->getRemoteAddr()->getIp()] = 1;
         } else {
             $this->violators[$sender->getRemoteAddr()->getIp()]++;
         }
         $wasMalleated = true;
         $this->counter++;
         $txSig = new TransactionSignature($this->adapter, new Signature($this->adapter, $sig->getR(), $this->math->sub($this->order, $sig->getS())), $txSig->getHashType());
         if (!$this->adapter->validateSignatureElement($txSig->getSignature()->getS(), true)) {
             die('failed to produce a low-s signature');
         }
     }
     return $txSig;
 }
Beispiel #7
0
 /**
  * @param ChainState $state
  * @param BlockInterface $block
  * @param Headers $headers
  * @param UtxoIdx $utxoIdx
  * @return BlockIndex
  */
 public function accept(ChainState $state, BlockInterface $block, Headers $headers, UtxoIdx $utxoIdx)
 {
     $bestBlock = $state->getLastBlock();
     if ($bestBlock->getHash() !== $block->getHeader()->getPrevBlock()) {
         throw new \RuntimeException('Blocks:accept() Block does not extend this chain!');
     }
     $index = $headers->accept($state, $block->getHeader());
     $this->blockCheck->check($block)->checkContextual($block, $bestBlock);
     //$view = $utxoIdx->fetchView($state, $block);
     $view = $this->db->fetchUtxoView($block);
     $flagP2sh = $this->consensus->scriptVerifyPayToScriptHash($bestBlock->getHeader()->getTimestamp());
     $flags = new Flags($flagP2sh ? InterpreterInterface::VERIFY_P2SH : InterpreterInterface::VERIFY_NONE);
     $nInputs = 0;
     $nFees = 0;
     $nSigOps = 0;
     $txs = $block->getTransactions();
     foreach ($block->getTransactions() as $tx) {
         $nInputs += count($tx->getInputs());
         $nSigOps += $this->blockCheck->getLegacySigOps($tx);
         if ($nSigOps > $this->consensus->getParams()->getMaxBlockSigOps()) {
             throw new \RuntimeException('Blocks::accept() - too many sigops');
         }
         if (!$tx->isCoinbase()) {
             if ($flagP2sh) {
                 $nSigOps = $this->blockCheck->getP2shSigOps($view, $tx);
                 if ($nSigOps > $this->consensus->getParams()->getMaxBlockSigOps()) {
                     throw new \RuntimeException('Blocks::accept() - too many sigops');
                 }
             }
             $fee = $this->math->sub($view->getValueIn($this->math, $tx), $tx->getValueOut());
             $nFees = $this->math->add($nFees, $fee);
             $this->blockCheck->checkInputs($view, $tx, $index->getHeight(), $flags);
         }
     }
     $this->blockCheck->checkCoinbaseSubsidy($txs[0], $nFees, $index->getHeight());
     $this->db->insertBlock($block);
     $state->updateLastBlock($index);
     return $index;
 }
Beispiel #8
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;
 }
Beispiel #9
0
 /**
  * @return Buffer
  */
 private function serialize()
 {
     if ($this->math->cmp($this->number, '0') === 0) {
         return new Buffer('', 4);
     }
     // Using array of integers instead of bytes
     $result = [];
     $negative = $this->math->cmp($this->number, 0) < 0;
     $abs = $negative ? $this->math->sub(0, $this->number) : $this->number;
     while ($this->math->cmp($abs, 0) > 0) {
         array_unshift($result, (int) $this->math->bitwiseAnd($abs, 0xff));
         $abs = $this->math->rightShift($abs, 8);
     }
     if ($result[0] & 0x80) {
         array_unshift($result, $negative ? 0x80 : 0x0);
     } else {
         if ($negative) {
             array_unshift($result, 0x80);
         }
     }
     return new Buffer(array_reduce($result, function ($agg, $current) {
         return $agg . chr($current);
     }), 4, $this->math);
 }
 /**
  * @param $opCode
  * @param ScriptStack $mainStack
  * @param ScriptStack $altStack
  * @throws \BitWasp\Bitcoin\Exceptions\ScriptStackException
  * @throws \Exception
  */
 public function op($opCode, ScriptStack $mainStack, ScriptStack $altStack)
 {
     $opCodes = $this->opCodes;
     $opName = $this->opCodes->getOp($opCode);
     $castToBool = $this->castToBool;
     if ($opName == 'OP_TOALTSTACK') {
         if ($mainStack->size() < 1) {
             throw new \Exception('Invalid stack operation OP_TOALTSTACK');
         }
         $altStack->push($mainStack->pop());
         return;
     } else {
         if ($opName == 'OP_FROMALTSTACK') {
             if ($altStack->size() < 1) {
                 throw new \Exception('Invalid alt-stack operation OP_FROMALTSTACK');
             }
             $mainStack->push($altStack->pop());
             return;
         } else {
             if ($opName == 'OP_IFDUP') {
                 // If top value not zero, duplicate it.
                 if ($mainStack->size() < 1) {
                     throw new \Exception('Invalid stack operation OP_IFDUP');
                 }
                 $vch = $mainStack->top(-1);
                 if ($castToBool($vch)) {
                     $mainStack->push($vch);
                 }
                 return;
             } else {
                 if ($opName == 'OP_DEPTH') {
                     $num = $mainStack->size();
                     $bin = Buffer::hex($this->math->decHex($num));
                     $mainStack->push($bin);
                     return;
                 } else {
                     if ($opName == 'OP_DROP') {
                         if ($mainStack->size() < 1) {
                             throw new \Exception('Invalid stack operation OP_DROP');
                         }
                         $mainStack->pop();
                         return;
                     } else {
                         if ($opName == 'OP_DUP') {
                             if ($mainStack->size() < 1) {
                                 throw new \Exception('Invalid stack operation OP_DUP');
                             }
                             $vch = $mainStack->top(-1);
                             $mainStack->push($vch);
                             return;
                         } else {
                             if ($opName == 'OP_NIP') {
                                 if ($mainStack->size() < 2) {
                                     throw new \Exception('Invalid stack operation OP_NIP');
                                 }
                                 $mainStack->erase(-2);
                                 return;
                             } else {
                                 if ($opName == 'OP_OVER') {
                                     if ($mainStack->size() < 2) {
                                         throw new \Exception('Invalid stack operation OP_OVER');
                                     }
                                     $vch = $mainStack->top(-2);
                                     $mainStack->push($vch);
                                     return;
                                 } else {
                                     if (in_array($opName, ['OP_PICK', 'OP_ROLL'])) {
                                         // cscriptnum
                                         if ($mainStack->size() < 2) {
                                             throw new \Exception('Invalid stack operation OP_PICK');
                                         }
                                         $n = $mainStack->top(-1)->getInt();
                                         $mainStack->pop();
                                         if ($this->math->cmp($n, 0) < 0 || $this->math->cmp($n, $mainStack->size()) >= 0) {
                                             throw new \Exception('Invalid stack operation OP_PICK');
                                         }
                                         $pos = $this->math->sub($this->math->sub(0, $n), 1);
                                         $vch = $mainStack->top($pos);
                                         if ($opCodes->isOp($opCode, 'OP_ROLL')) {
                                             $mainStack->erase($pos);
                                         }
                                         $mainStack->push($vch);
                                         return;
                                     } else {
                                         if ($opName == 'OP_ROT') {
                                             if ($mainStack->size() < 3) {
                                                 throw new \Exception('Invalid stack operation OP_ROT');
                                             }
                                             $mainStack->swap(-3, -2);
                                             $mainStack->swap(-2, -1);
                                             return;
                                         } else {
                                             if ($opName == 'OP_SWAP') {
                                                 if ($mainStack->size() < 2) {
                                                     throw new \Exception('Invalid stack operation OP_SWAP');
                                                 }
                                                 $mainStack->swap(-2, -1);
                                                 return;
                                             } else {
                                                 if ($opName == 'OP_TUCK') {
                                                     if ($mainStack->size() < 2) {
                                                         throw new \Exception('Invalid stack operation OP_TUCK');
                                                     }
                                                     $vch = $mainStack->top(-1);
                                                     $mainStack->insert($mainStack->end() - 2, $vch);
                                                     return;
                                                 } else {
                                                     if ($opName == 'OP_2DROP') {
                                                         if ($mainStack->size() < 2) {
                                                             throw new \Exception('Invalid stack operation OP_2DROP');
                                                         }
                                                         $mainStack->pop();
                                                         $mainStack->pop();
                                                         return;
                                                     } else {
                                                         if ($opName == 'OP_2DUP') {
                                                             if ($mainStack->size() < 2) {
                                                                 throw new \Exception('Invalid stack operation OP_2DUP');
                                                             }
                                                             $string1 = $mainStack->top(-2);
                                                             $string2 = $mainStack->top(-1);
                                                             $mainStack->push($string1);
                                                             $mainStack->push($string2);
                                                             return;
                                                         } else {
                                                             if ($opName == 'OP_3DUP') {
                                                                 if ($mainStack->size() < 3) {
                                                                     throw new \Exception('Invalid stack operation OP_3DUP');
                                                                 }
                                                                 $string1 = $mainStack->top(-3);
                                                                 $string2 = $mainStack->top(-2);
                                                                 $string3 = $mainStack->top(-1);
                                                                 $mainStack->push($string1);
                                                                 $mainStack->push($string2);
                                                                 $mainStack->push($string3);
                                                                 return;
                                                             } else {
                                                                 if ($opName == 'OP_2OVER') {
                                                                     if ($mainStack->size() < 4) {
                                                                         throw new \Exception('Invalid stack operation OP_2OVER');
                                                                     }
                                                                     $string1 = $mainStack->top(-4);
                                                                     $string2 = $mainStack->top(-3);
                                                                     $mainStack->push($string1);
                                                                     $mainStack->push($string2);
                                                                     return;
                                                                 } else {
                                                                     if ($opName == 'OP_2ROT') {
                                                                         if ($mainStack->size() < 6) {
                                                                             throw new \Exception('Invalid stack operation OP_2ROT');
                                                                         }
                                                                         $string1 = $mainStack->top(-6);
                                                                         $string2 = $mainStack->top(-5);
                                                                         $mainStack->erase(-6);
                                                                         $mainStack->erase(-5);
                                                                         $mainStack->push($string1);
                                                                         $mainStack->push($string2);
                                                                         return;
                                                                     } else {
                                                                         if ($opName == 'OP_2SWAP') {
                                                                             if ($mainStack->size() < 4) {
                                                                                 throw new \Exception('Invalid stack operation OP_2SWAP');
                                                                             }
                                                                             $mainStack->swap(-3, -1);
                                                                             $mainStack->swap(-4, -2);
                                                                             return;
                                                                         }
                                                                     }
                                                                 }
                                                             }
                                                         }
                                                     }
                                                 }
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     throw new \Exception('Opcode not found');
 }
Beispiel #11
0
 /**
  * @param Math $math
  * @param TransactionInterface $tx
  * @return \GMP
  */
 public function getFeePaid(Math $math, TransactionInterface $tx)
 {
     return $math->sub($this->getValueIn($math, $tx), gmp_init($tx->getValueOut()));
 }