/** * @param BlockIndexInterface $index */ public function next(BlockIndexInterface $index) { if (!$this->index->isNext($index)) { throw new \InvalidArgumentException('Provided Index does not elongate this Chain'); } $this->index = $index; $this->emit('tip', [$index]); }
/** * @param BlockIndexInterface $index * @return bool */ public function isNext(BlockIndexInterface $index) { if (false === $this->hash->equals($index->getHeader()->getPrevBlock())) { return false; } if (false === ($index->getHeight() == $this->height + 1)) { return false; } return true; }
/** * @param ChainStateInterface $chain * @param BlockIndexInterface $prevIndex * @return int|string */ public function getWorkRequired(ChainStateInterface $chain, BlockIndexInterface $prevIndex) { $math = $this->math; if ($math->cmp($math->mod($math->add($prevIndex->getHeight(), 1), $this->params->powRetargetInterval()), 0) !== 0) { // No change in difficulty return $prevIndex->getHeader()->getBits()->getInt(); } // Re-target $heightLastRetarget = $math->sub($prevIndex->getHeight(), $math->sub($this->params->powRetargetInterval(), 1)); $lastTime = $chain->fetchAncestor($heightLastRetarget)->getHeader()->getTimestamp(); return $this->calculateNextWorkRequired($prevIndex, $lastTime); }
/** * @return ChainSegment[] */ public function getHistory() { $height = $this->index->getHeight(); $history = []; foreach ($this->getHistory() as $segment) { if ($segment->getLast()->getHeight() <= $height) { $history[] = $segment; } else { break; } } return $history; }
/** * @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 BufferInterface $hash * @param BlockIndexInterface $prevIndex * @param BlockHeaderInterface $header * @return BlockIndex */ public function getNextIndex(BufferInterface $hash, BlockIndexInterface $prevIndex, BlockHeaderInterface $header) { return new BlockIndex($hash, $prevIndex->getHeight() + 1, $this->math->toString($this->math->add($this->proofOfWork->getWork($header->getBits()), gmp_init($prevIndex->getWork()))), $header); }
/** * @param BlockIndexInterface $index * @return array */ public function convertIndexToArray(BlockIndexInterface $index) { $header = $index->getHeader(); return ['height' => $index->getHeight(), 'hash' => $index->getHash()->getHex(), 'work' => $index->getWork(), 'version' => $header->getVersion(), 'prevBlock' => $header->getPrevBlock()->getHex(), 'merkleRoot' => $header->getMerkleRoot()->getHex(), 'nBits' => $header->getBits(), 'nTimestamp' => $header->getTimestamp(), 'nNonce' => $header->getNonce()]; }
/** * @param BlockIndexInterface $index * @param BlockInterface $block * @param BlockData $blockData */ public function logBlock(BlockIndexInterface $index, BlockInterface $block, BlockData $blockData) { echo count($blockData->remainingNew) . "created and " . count($blockData->requiredOutpoints) . " destroyed\n"; $this->log('block', ['hash' => $index->getHash()->getHex(), 'height' => $index->getHeight(), 'txs' => count($block->getTransactions()), 'nFees' => gmp_strval($blockData->nFees, 10), 'nSigOps' => $blockData->nSigOps, 'utxos' => ['created' => count($blockData->remainingNew), 'removed' => count($blockData->requiredOutpoints)]]); }
/** * @param BlockInterface $block * @param BlockIndexInterface $prevBlockIndex * @return $this */ public function checkContextual(BlockInterface $block, BlockIndexInterface $prevBlockIndex) { $newHeight = $prevBlockIndex->getHeight() + 1; $newTime = $block->getHeader()->getTimestamp(); foreach ($block->getTransactions() as $transaction) { if (!$this->checkTransactionIsFinal($transaction, $newHeight, $newTime)) { throw new \RuntimeException('Block contains a non-final transaction'); } } return $this; }
/** * @param BlockIndexInterface $index * @return bool */ public function isNext(BlockIndexInterface $index) { return $this->index->isNext($index); }