/** * @param Buffer $hash * @return BlockIndex */ public function fetchIndex(Buffer $hash) { if (!$this->chainCache->containsHash($hash)) { throw new \RuntimeException('Index by this hash not known'); } return $this->headers->fetch($hash); }
/** * BetterNode constructor. * @param ConfigProviderInterface $config * @param ParamsInterface $params * @param DbInterface $db */ public function __construct(ConfigProviderInterface $config, ParamsInterface $params, DbInterface $db) { $math = Bitcoin::getMath(); $adapter = Bitcoin::getEcAdapter($math); $this->chains = new ChainContainer($math, $params); $consensus = new Consensus($math, $params); $pow = new ProofOfWork($math, $params); $this->headers = new Index\Headers($db, $adapter, $this->chains, $consensus, $pow); $this->blocks = new Index\Blocks($db, $config, $adapter, $this->chains, $consensus); $this->transactions = new Index\Transactions($db); $genesis = $params->getGenesisBlock(); $this->headers->init($genesis->getHeader()); $this->blocks->init($genesis); $this->db = $db; $segments = $this->db->fetchChainSegments(); foreach ($segments as $segment) { $this->chains->addSegment($segment); } $this->chains->initialize($this->db); }
/** * @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; }
/** * @param Peer $peer * @param Headers $headers */ public function onHeaders(Peer $peer, Headers $headers) { $state = $this->chain(); $vHeaders = $headers->getHeaders(); $count = count($vHeaders); if ($count === 0) { return; } $this->headers->acceptBatch($state, $vHeaders); $this->chains->checkTips(); $last = end($vHeaders); $this->peerState->fetch($peer)->updateBlockAvailability($state, $last->getHash()); if (2000 === $count) { $peer->getheaders($state->getHeadersLocator()); } if ($count < 2000) { echo 'start download' . PHP_EOL; $this->blockDownload->start($state, $peer); } }
/** * @param BlockInterface $block * @param HeaderChainViewInterface $chainView * @param Headers $headers * @param bool $checkSignatures * @param bool $checkSize * @param bool $checkMerkleRoot * @return BlockIndexInterface */ public function accept(BlockInterface $block, HeaderChainViewInterface $chainView, Headers $headers, $checkSignatures = true, $checkSize = true, $checkMerkleRoot = true) { $hash = $block->getHeader()->getHash(); $index = $headers->accept($hash, $block->getHeader(), true); $outpointSerializer = new CachingOutPointSerializer(); $txSerializer = new CachingTransactionSerializer(new TransactionInputSerializer($outpointSerializer)); $blockSerializer = new CachingBlockSerializer($this->math, new BlockHeaderSerializer(), $txSerializer); $utxoSet = new UtxoSet($this->db, $outpointSerializer); $blockData = $this->prepareBatch($block, $txSerializer, $utxoSet); $this->blockCheck->check($block, $txSerializer, $blockSerializer, $checkSize, $checkMerkleRoot)->checkContextual($block, $chainView->getLastBlock()); $forks = $this->prepareForks($chainView, $index); $this->checkBlockData($block, $blockData, $checkSignatures, $forks->getFlags(), $index->getHeight()); $this->db->transaction(function () use($hash, $block, $blockSerializer, $utxoSet, $blockData) { $this->db->insertBlock($hash, $block, $blockSerializer); $utxoSet->applyBlock($blockData); }); $chainView->blocks()->updateTip($index); $forks->next($index); $this->emit('block', [$index, $block, $blockData]); print_r($outpointSerializer->stats()); return $index; }