Ejemplo n.º 1
0
 /**
  * @param BlockHeaderInterface $header
  * @return $this
  * @throws \Exception
  */
 public function save(BlockHeaderInterface $header)
 {
     $height = $this->height();
     $this->index->save('height', ++$height);
     $key = $this->cacheIndex($height);
     $this->index->save($key, $header->getBlockHash());
     return $this;
 }
Ejemplo n.º 2
0
 /**
  * @param BufferInterface $hash
  * @param BlockHeaderInterface $header
  * @param bool $checkPow
  * @return $this
  */
 public function check(BufferInterface $hash, BlockHeaderInterface $header, $checkPow = true)
 {
     try {
         if ($checkPow) {
             $this->pow->check($hash, $header->getBits());
         }
     } catch (\Exception $e) {
         throw new \RuntimeException('Headers::check() - failed validating header proof-of-work');
     }
     return $this;
 }
Ejemplo n.º 3
0
 /**
  * @param ChainState $state
  * @param BlockHeaderInterface $header
  * @return BlockIndex
  */
 public function accept(ChainState $state, BlockHeaderInterface $header)
 {
     $hash = $header->getHash();
     if ($state->getChain()->containsHash($hash)) {
         // todo: check for rejected block
         return $this->db->fetchIndex($hash);
     }
     $prevIndex = $state->getChain()->getIndex();
     $index = $this->headerCheck->check($header)->checkContextual($state, $header)->makeIndex($prevIndex, $header);
     $this->db->insertIndexBatch($prevIndex, [$index]);
     $state->getChain()->updateTip($index);
     return $index;
 }
Ejemplo n.º 4
0
 /**
  * @param BlockHeaderInterface $header
  * @return bool
  * @throws \Exception
  */
 public function checkHeader(BlockHeaderInterface $header)
 {
     $math = $this->math;
     $target = $this->difficulty->getTarget($header->getBits());
     if ($math->cmp($target, 0) == 0 || $math->cmp($target, $this->limit()) > 0) {
         throw new \Exception('nBits below minimum work');
     }
     $hashInt = $math->hexDec($header->getBlockHash());
     if ($math->cmp($hashInt, $target) > 0) {
         throw new \Exception("Hash doesn't match nBits");
     }
     return true;
 }
Ejemplo n.º 5
0
 /**
  * @param BlockHeaderInterface $header
  * @return Chain
  */
 public function findTipForNext(BlockHeaderInterface $header)
 {
     foreach ($this->states as $state) {
         $tTip = $state->getChain();
         $tipHash = $tTip->getIndex()->getHash();
         if ($header->getPrevBlock() == $tipHash) {
             $tip = $tTip;
         }
     }
     if (!isset($tip)) {
         throw new \RuntimeException('No tip found for this Header');
     }
     return $tip;
 }
Ejemplo n.º 6
0
 /**
  * @param BlockHeaderInterface $header
  * @return $this
  */
 public function delete(BlockHeaderInterface $header)
 {
     $hash = $header->getBlockHash();
     $this->hash()->delete($this->height()->fetch($hash));
     $this->height()->delete($hash);
     return $this;
 }
Ejemplo n.º 7
0
 /**
  * Process a block against the given state of the chain.
  * @param BlockHeaderInterface $header
  * @return bool
  */
 public function process(BlockHeaderInterface $header)
 {
     // Ignore the genesis block
     $hash = $header->getBlockHash();
     if ($hash === $this->genesis->getBlockHash()) {
         return true;
     }
     if ($this->index()->height()->contains($hash)) {
         return true;
     }
     try {
         // Attempt to add it to the chain
         $this->add($header);
         $this->pow->checkHeader($header);
         $result = true;
     } catch (BlockPrevNotFound $e) {
         // If it fails because it doesn't elongate the chain, process it as an orphan.
         // Result will be determined
         $result = $this->processOrphan($header);
     } catch (BlockPowError $e) {
         $result = false;
         // Invalid block.
     }
     return $result;
 }
Ejemplo n.º 8
0
 /**
  * @param TransactionInterface|null $coinbaseTx
  * @return Block
  * @throws \BitWasp\Bitcoin\Exceptions\MerkleTreeEmpty
  */
 public function run(TransactionInterface $coinbaseTx = null)
 {
     $nonce = '0';
     $maxNonce = $this->math->pow(2, 32);
     // Allow user supplied transactions
     if ($coinbaseTx == null) {
         $coinbaseTx = new Transaction();
         $coinbaseTx->getInputs()->addInput(new TransactionInput('0000000000000000000000000000000000000000000000000000000000000000', 4294967295.0));
         $coinbaseTx->getOutputs()->addOutput(new TransactionOutput(5000000000.0, $this->script));
     }
     $inputs = $coinbaseTx->getInputs();
     $found = false;
     $usingDiff = $this->lastBlockHeader->getBits();
     $diff = new Difficulty($this->math);
     $target = $diff->getTarget($usingDiff);
     while (false === $found) {
         // Set coinbase script, and build Merkle tree & block header.
         $inputs->getInput(0)->setScript($this->getCoinbaseScriptBuf());
         $transactions = new TransactionCollection(array_merge(array($coinbaseTx), $this->transactions->getTransactions()));
         $merkleRoot = new MerkleRoot($this->math, $transactions);
         $merkleHash = $merkleRoot->calculateHash();
         $header = new BlockHeader($this->version, $this->lastBlockHeader->getBlockHash(), $merkleHash, $this->timestamp, $usingDiff, '0');
         $t = microtime(true);
         // Loop through all nonces (up to 2^32). Restart after modifying extranonce.
         while ($this->math->cmp($header->getNonce(), $maxNonce) <= 0) {
             $header->setNonce($this->math->add($header->getNonce(), '1'));
             $hash = (new Parser())->writeBytes(32, Hash::sha256d($header->getBuffer()), true)->getBuffer();
             if ($this->math->cmp($hash->getInt(), $target) <= 0) {
                 $block = new Block($this->math, $header, $transactions);
                 return $block;
             }
             if ($this->report && $this->math->cmp($this->math->mod($header->getNonce(), 100000), '0') == 0) {
                 $time = microtime(true) - $t;
                 $khash = $nonce / $time / 1000;
                 echo "extraNonce[{$this->extraNonce}] nonce[{$nonce}] time[{$time}] khash/s[{$khash}] \n";
             }
         }
         // Whenever we exceed 2^32, increment extraNonce and reset $nonce
         $this->extraNonce++;
         $nonce = '0';
     }
 }
Ejemplo n.º 9
0
 /**
  * @param BlockHeaderInterface $header
  * @return bool
  * @throws \Exception
  */
 public function checkHeader(BlockHeaderInterface $header)
 {
     return $this->check($header->getHash(), $header->getBits()->getInt());
 }
Ejemplo n.º 10
0
 /**
  * @param BlockIndex $prevIndex
  * @param BlockHeaderInterface $header
  * @return BlockIndex
  */
 public function makeIndex(BlockIndex $prevIndex, BlockHeaderInterface $header)
 {
     return new BlockIndex($header->getHash()->getHex(), $this->math->add($prevIndex->getHeight(), 1), $this->math->add($this->pow->getWork($header->getBits()), $prevIndex->getWork()), $header);
 }
Ejemplo n.º 11
0
 /**
  * @param BlockHeaderInterface $header
  * @return BlockIndexInterface|bool
  */
 public function hasBlockTip(BlockHeaderInterface $header)
 {
     echo "CheckHashBlockTip - " . count($this->segments) . PHP_EOL;
     foreach ($this->segments as $segment) {
         /** @var BlockIndexInterface $segBlock */
         $segBlock = $this->segmentBlock->offsetGet($segment);
         if ($header->getPrevBlock()->equals($segBlock->getHash())) {
             return $segBlock;
         }
     }
     return false;
 }
Ejemplo n.º 12
0
 /**
  * @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 BlockHeaderInterface $header
  * @return \BitWasp\Buffertools\Buffer
  */
 public function serialize(BlockHeaderInterface $header)
 {
     return $this->getTemplate()->write([$header->getVersion(), Buffer::hex($header->getPrevBlock()), Buffer::hex($header->getMerkleRoot()), $header->getTimestamp(), $header->getBits(), $header->getNonce()]);
 }
Ejemplo n.º 14
0
 /**
  * @param Index\Blocks $blocks
  * @param int $currentHeight
  * @param BlockHeaderInterface $header
  * @return bool
  */
 public function scriptVerifyDerSig(Index\Blocks $blocks, $currentHeight, BlockHeaderInterface $header)
 {
     if ($this->math->cmp($header->getVersion(), 3) && $this->isSuperMajority(3, $currentHeight - 1, $blocks, $this->params->majorityEnforceBlockUpgrade())) {
         return true;
     }
     return false;
 }
Ejemplo n.º 15
0
 /**
  * Creates the Genesis block index
  * @param BlockHeaderInterface $header
  * @return bool
  */
 public function createIndexGenesis(BlockHeaderInterface $header)
 {
     $stmtHeader = $this->dbh->prepare('INSERT INTO headerIndex (
         hash, segment, height, work, version, prevBlock, merkleRoot, nBits, nTimestamp, nNonce
       ) VALUES (
         :hash, :segment, :height, :work, :version, :prevBlock, :merkleRoot, :nBits, :nTimestamp, :nNonce
       )
     ');
     if ($stmtHeader->execute(array('hash' => $header->getHash()->getBinary(), 'segment' => 0, 'height' => 0, 'work' => 0, 'version' => $header->getVersion(), 'prevBlock' => $header->getPrevBlock()->getBinary(), 'merkleRoot' => $header->getMerkleRoot()->getBinary(), 'nBits' => $header->getBits(), 'nTimestamp' => $header->getTimestamp(), 'nNonce' => $header->getNonce()))) {
         return true;
     }
     throw new \RuntimeException('Failed to update insert Genesis block index!');
 }
Ejemplo n.º 16
0
 /**
  * @param BlockHeaderInterface $header
  * @return string
  */
 private function cacheIndexHeader(BlockHeaderInterface $header)
 {
     return "blkheight_" . $header->getBlockHash();
 }
Ejemplo n.º 17
0
 /**
  * @param $timeFirstBlock
  * @param BlockHeaderInterface $header
  * @return mixed
  */
 public function calculateWorkTimespan($timeFirstBlock, BlockHeaderInterface $header)
 {
     $timespan = $header->getTimestamp() - $timeFirstBlock;
     $lowest = $this->params->powTargetTimespan() / 4;
     $highest = $this->params->powTargetTimespan() * 4;
     if ($timespan < $lowest) {
         $timespan = $lowest;
     }
     if ($timespan > $highest) {
         $timespan = $highest;
     }
     return $timespan;
 }
Ejemplo n.º 18
0
 /**
  * @param BlockHeaderInterface $blk
  * @return string
  */
 private function cacheIndexBlk(BlockHeaderInterface $blk)
 {
     return $this->cacheIndex($blk->getBlockHash());
 }