/** * @param Container $container */ public function register(Container $container) { $headers = $this->node->headers(); $headers->on('headers', function (HeadersBatch $batch) use($container) { /** @var DbInterface $db */ $db = $container['db']; /** @var DebugInterface $debug */ $debug = $container['debug']; if (count($batch->getIndices()) > 0) { $first = $batch->getIndices()[0]; $prevIndex = $db->fetchIndex($first->getHeader()->getPrevBlock()); $versionInfo = $db->findSuperMajorityInfoByHash($prevIndex->getHash()); $forks = new Forks($this->params, $prevIndex, $versionInfo); $first = $forks->toArray(); $changes = []; foreach ($batch->getIndices() as $index) { $forks->next($index); $new = $forks->toArray(); if ($first !== $new) { $changes[] = [$index, $first, $new]; $first = $new; } } foreach ($changes as $change) { /** @var BlockIndexInterface $index */ list($index, $first, $features) = $change; $debug->log('fork.new', ['hash' => $index->getHash()->getHex(), 'height' => $index->getHeight(), 'old' => $first, 'features' => $features]); } } }); }
/** * @param ChainAccessInterface $chain * @param BlockIndexInterface $index * @param BlockIndexInterface $prevIndex * @param Forks $forks * @return $this */ public function checkContextual(ChainAccessInterface $chain, BlockIndexInterface $index, BlockIndexInterface $prevIndex, Forks $forks) { $work = $this->getWorkRequired($chain, $prevIndex); $header = $index->getHeader(); if ($this->math->cmp(gmp_init($header->getBits(), 10), gmp_init($work, 10)) != 0) { throw new \RuntimeException('Headers::CheckContextual(): invalid proof of work : ' . $header->getBits() . '? ' . $work); } if ($header->getVersion() < $forks->getMajorityVersion()) { echo $index->getHash()->getHex() . PHP_EOL; echo "Heaader: " . $header->getVersion() . "\nMajority: " . $forks->getMajorityVersion() . PHP_EOL; throw new \RuntimeException('Rejected version'); } return $this; }
/** * @param HeaderChainViewInterface $headersView * @param BlockIndexInterface $index * @return Forks */ public function prepareForks(HeaderChainViewInterface $headersView, BlockIndexInterface $index) { if ($this->forks instanceof Forks && $this->forks->isNext($index)) { $forks = $this->forks; } else { $versionInfo = $this->db->findSuperMajorityInfoByHash($index->getHeader()->getPrevBlock()); $forks = $this->forks = new Forks($this->consensus->getParams(), $headersView->getLastBlock(), $versionInfo); } return $forks; }
/** * @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); }