Exemplo n.º 1
0
 /**
  * @param Consensus $consensus
  * @param EcAdapterInterface $ecAdapter
  * @param ScriptCheckInterface $scriptCheck
  */
 public function __construct(Consensus $consensus, EcAdapterInterface $ecAdapter, ScriptCheckInterface $scriptCheck)
 {
     $this->consensus = $consensus;
     $this->math = $ecAdapter->getMath();
     $this->scriptCheck = $scriptCheck;
     $this->params = $consensus->getParams();
 }
Exemplo n.º 2
0
 /**
  * @param ChainAccessInterface $chain
  * @param BlockIndexInterface $prevIndex
  * @return int
  */
 public function getWorkRequired(ChainAccessInterface $chain, BlockIndexInterface $prevIndex)
 {
     $params = $this->consensus->getParams();
     if (($prevIndex->getHeight() + 1) % $params->powRetargetInterval() !== 0) {
         // No change in difficulty
         return $prevIndex->getHeader()->getBits();
     }
     // Re-target
     $heightLastRetarget = $prevIndex->getHeight() - ($params->powRetargetInterval() - 1);
     $lastTime = $chain->fetchAncestor($heightLastRetarget)->getHeader()->getTimestamp();
     return $this->consensus->calculateNextWorkRequired($prevIndex, $lastTime);
 }
Exemplo n.º 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;
 }
Exemplo n.º 4
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;
 }
Exemplo n.º 5
0
 /**
  * @param BlockHeaderInterface[] $headers
  * @return HeadersBatch
  */
 public function prepareBatch(array $headers)
 {
     $countHeaders = count($headers);
     if (0 === $countHeaders) {
         return new HeadersBatch($this->chains->best($this->math), []);
     }
     $bestPrev = null;
     $firstUnknown = null;
     $hashStorage = new HashStorage();
     foreach ($headers as $i => &$head) {
         if ($this->chains->isKnownHeader($head->getPrevBlock())) {
             $bestPrev = $head->getPrevBlock();
         }
         $hash = Hash::sha256d($head->getBuffer())->flip();
         $hashStorage->attach($head, $hash);
         if ($firstUnknown === null && !$this->chains->isKnownHeader($hash)) {
             $firstUnknown = $i;
         }
     }
     if (!$bestPrev instanceof BufferInterface) {
         throw new \RuntimeException('Headers::accept(): Unknown start header');
     }
     $view = $this->chains->isTip($bestPrev);
     if ($view === false) {
         throw new \RuntimeException('Headers::accept(): Unhandled fork');
     }
     $prevIndex = $view->getIndex();
     $access = $this->chains->access($view);
     $batch = [];
     if ($firstUnknown !== null) {
         $versionInfo = $this->db->findSuperMajorityInfoByView($view);
         $forks = new Forks($this->consensus->getParams(), $prevIndex, $versionInfo);
         for ($i = $firstUnknown; $i < $countHeaders; $i++) {
             /**
              * @var BufferInterface $hash
              * @var BlockHeaderInterface $header
              */
             $header = $headers[$i];
             $hash = $hashStorage[$header];
             $this->headerCheck->check($hash, $header);
             $index = $this->getNextIndex($hash, $prevIndex, $header);
             $forks->next($index);
             $this->headerCheck->checkContextual($access, $index, $prevIndex, $forks);
             $batch[] = $index;
             $prevIndex = $index;
         }
     }
     return new HeadersBatch($view, $batch);
 }
Exemplo n.º 6
0
 /**
  * @param BlockInterface $block
  * @param BlockData $blockData
  * @param bool $checkSignatures
  * @param bool $flags
  * @param $height
  */
 public function checkBlockData(BlockInterface $block, BlockData $blockData, $checkSignatures, $flags, $height)
 {
     $validation = new ScriptValidation($checkSignatures, $flags);
     foreach ($block->getTransactions() as $tx) {
         $blockData->nSigOps += $this->blockCheck->getLegacySigOps($tx);
         if ($blockData->nSigOps > $this->consensus->getParams()->getMaxBlockSigOps()) {
             throw new \RuntimeException('Blocks::accept() - too many sigops');
         }
         if (!$tx->isCoinbase()) {
             if ($flags & InterpreterInterface::VERIFY_P2SH) {
                 $blockData->nSigOps += $this->blockCheck->getP2shSigOps($blockData->utxoView, $tx);
                 if ($blockData->nSigOps > $this->consensus->getParams()->getMaxBlockSigOps()) {
                     throw new \RuntimeException('Blocks::accept() - too many sigops');
                 }
             }
             $blockData->nFees = $this->math->add($blockData->nFees, $blockData->utxoView->getFeePaid($this->math, $tx));
             $this->blockCheck->checkInputs($blockData->utxoView, $tx, $height, $flags, $validation);
         }
     }
     if ($validation->active() && !$validation->result()) {
         throw new \RuntimeException('ScriptValidation failed!');
     }
     $this->blockCheck->checkCoinbaseSubsidy($block->getTransaction(0), $blockData->nFees, $height);
 }