/** * @param BlockIndex $index */ public function updateLastBlock(BlockIndex $index) { if ($this->lastBlock->getHash() !== $index->getHeader()->getPrevBlock()) { throw new \RuntimeException('UpdateLastBlock: Block does not extend this chain'); } if ($this->lastBlock->getHeight() != $index->getHeight() - 1) { throw new \RuntimeException('UpdateLastBlock: Incorrect chain height' . ($index->getHeight() - 1)); } $this->lastBlock = $index; }
/** * @param BlockIndex $index */ public function add(BlockIndex $index) { if ($index->getHeader()->getPrevBlock() !== $this->getHash($index->getHeight() - 1)->getHex()) { throw new \RuntimeException('ChainCache: New BlockIndex does not refer to last'); } $binary = hex2bin($index->getHash()); $this->hashByHeight[] = $binary; $this->heightByHash[$binary] = $index->getHeight(); }
/** * @param BlockIndex $index */ public function updateTip(BlockIndex $index) { if ($this->index->getHash() !== $index->getHeader()->getPrevBlock()) { throw new \RuntimeException('Header: Header does not extend this chain'); } if ($index->getHeight() - 1 != $this->index->getHeight()) { throw new \RuntimeException('Header: Incorrect chain height'); } $this->chainCache->add($index); $this->index = $index; }
public function testBlockIndex() { $headerHex = '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c'; $header = BlockHeaderFactory::fromHex($headerHex); $hash = $header->getHash(); $height = 0; $work = 0; $index = new BlockIndex($hash, $height, $work, $header); $this->assertEquals($hash, $index->getHash()); $this->assertEquals($height, $index->getHeight()); $this->assertEquals($work, $index->getWork()); $this->assertSame($header, $index->getHeader()); }
/** * @param BlockIndex $startIndex * @param BlockIndex[] $index * @return bool * @throws \Exception */ public function insertIndexBatch(BlockIndex $startIndex, array $index) { if ($this->debug) { echo "db: called insertIndexBATCH\n"; } if (null == $this->fetchLftStmt) { $this->fetchLftStmt = $this->dbh->prepare('SELECT lft FROM headerIndex WHERE hash = :prevBlock'); $this->updateIndicesStmt = $this->dbh->prepare(' UPDATE headerIndex SET rgt = rgt + :nTimes2 WHERE rgt > :myLeft ; UPDATE headerIndex SET lft = lft + :nTimes2 WHERE lft > :myLeft ; '); } $fetchParent = $this->fetchLftStmt; $updateIndices = $this->updateIndicesStmt; $fetchParent->bindParam(':prevBlock', $startIndex->getHash()); if ($fetchParent->execute()) { foreach ($fetchParent->fetchAll() as $record) { $myLeft = $record['lft']; } } $fetchParent->closeCursor(); if (!isset($myLeft)) { throw new \RuntimeException('Failed to extract header position'); } $totalN = count($index); $nTimesTwo = 2 * $totalN; $leftOffset = $myLeft; $rightOffset = $myLeft + $nTimesTwo; $this->dbh->beginTransaction(); try { if ($updateIndices->execute(['nTimes2' => $nTimesTwo, 'myLeft' => $myLeft])) { $updateIndices->closeCursor(); $values = []; $query = []; foreach ($index as $c => $i) { $query[] = "(:hash{$c} , :height{$c} , :work{$c} ,\n :version{$c} , :prevBlock{$c} , :merkleRoot{$c} ,\n :nBits{$c} , :nTimestamp{$c} , :nNonce{$c} ,\n :lft{$c} , :rgt{$c} )"; $values['hash' . $c] = $i->getHash(); $values['height' . $c] = $i->getHeight(); $values['work' . $c] = $i->getWork(); $header = $i->getHeader(); $values['version' . $c] = $header->getVersion(); $values['prevBlock' . $c] = $header->getPrevBlock(); $values['merkleRoot' . $c] = $header->getMerkleRoot(); $values['nBits' . $c] = $header->getBits()->getInt(); $values['nTimestamp' . $c] = $header->getTimestamp(); $values['nNonce' . $c] = $header->getNonce(); $values['lft' . $c] = $leftOffset + 1 + $c; $values['rgt' . $c] = $rightOffset - $c; } $stmt = $this->dbh->prepare("\n INSERT INTO headerIndex (hash, height, work, version, prevBlock, merkleRoot, nBits, nTimestamp, nNonce, lft, rgt )\n VALUES " . implode(', ', $query)); $count = $stmt->execute($values); $this->dbh->commit(); if ($count === $totalN) { return true; } else { throw new \RuntimeException('Strange: Failed to update chain!'); } } } catch (\Exception $e) { $this->dbh->rollBack(); throw $e; } throw new \RuntimeException('Failed to update chain!'); }