/** * @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; }
/** * Given an ancestor height, and a list of hashes in the fork, use this * information to compare the work, and if necessary, commit a reorg. * * @param int $ancestorHeight * @param array $forkBlockHashes * @return bool * @throws \Exception */ public function processFork($ancestorHeight, array $forkBlockHashes) { $blocks = $this->blocks(); $index = $this->index(); /** @var \BitWasp\Bitcoin\Block\BlockHeaderInterface[] $chainHeaders */ $chainHeaders = []; $chainHeight = $index->height()->height(); for ($i = $ancestorHeight; $i < $chainHeight; $i++) { $chainHeaders[] = $blocks->fetch($index->hash()->fetch($i))->getHeader(); } /** @var \BitWasp\Bitcoin\Block\BlockHeaderInterface[] $forkBlocks */ $forkBlocks = []; $forkHeaders = []; foreach ($forkBlockHashes as $hash) { $block = $blocks->fetch($hash); $forkBlocks[] = $block; $forkHeaders[] = $block->getHeader(); } // Only recalculate BlockIndex values if fork has greater work than chain blocks since ancestor if ($this->difficulty->compareWork($forkHeaders, $chainHeaders) > 0) { $index->reorg($ancestorHeight, $forkHeaders); return true; } return false; }
/** * @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'; } }
<?php require_once __DIR__ . "/../vendor/autoload.php"; use BitWasp\Bitcoin\Address\AddressFactory; use BitWasp\Bitcoin\Rpc\RpcFactory; use BitWasp\Bitcoin\Chain\Difficulty; use BitWasp\Bitcoin\Math\Math; use BitWasp\Bitcoin\Network\NetworkFactory; use BitWasp\Bitcoin\Bitcoin; use BitWasp\Bitcoin\Script\OutputScriptFactory; use BitWasp\Bitcoin\Script\ScriptFactory; use BitWasp\Buffertools\Buffer; use willgriffin\MariaInterface\MariaInterface; $configFile = count($argv) > 1 ? $argv[1] : false; $x = count($argv) > 2 ? intval($argv[2]) : 1; $math = new Math(); $difficulty = new Difficulty($math); if (file_exists($configFile)) { $config = (object) parse_ini_file($configFile); //$currency = Main::getCurrency($currencyName); $db = new MariaInterface(["host" => $config->dbhost, "user" => $config->dbuser, "pass" => $config->dbpass, "port" => $config->dbport, "name" => $config->dbname]); $bitcoind = RpcFactory::bitcoind($config->rpchost, $config->rpcport, $config->rpcuser, $config->rpcpass); $network = NetworkFactory::create($config->magic_byte, $config->magic_p2sh_byte, $config->private_key_byte)->setHDPubByte($config->hd_pub_byte)->setHDPrivByte($config->hd_priv_byte)->setNetMagicBytes($config->net_magic_bytes); Bitcoin::setNetwork($network); $nextBlockHash = $bitcoind->getblockhash($x); do { echo "Block {$x}\n"; $blockhash = $nextBlockHash; $block = $bitcoind->getblock($blockhash); $blockHeader = $block->getHeader(); $blockBits = $blockHeader->getBits(); $blockTime = $blockHeader->getTimestamp();