/** * @dataProvider generateSet */ public function testPing(Ping $ping) { $this->assertInternalType('string', $ping->getNonce()); $this->assertEquals('ping', $ping->getNetworkCommand()); $math = new Math(); $this->assertEquals(str_pad($math->decHex($ping->getNonce()), 16, '0', STR_PAD_LEFT), $ping->getHex()); }
/** * @param callable|null $hashFunction * @return Buffer * @throws MerkleTreeEmpty */ public function calculateHash(callable $hashFunction = null) { $hashFxn = $hashFunction ?: function ($value) { return hash('sha256', hash('sha256', $value, true), true); }; $txCount = count($this->transactions); if ($txCount === 0) { // TODO: Probably necessary. Should always have a coinbase at least. throw new MerkleTreeEmpty('Cannot compute Merkle root of an empty tree'); } if ($txCount === 1) { $binary = $hashFxn($this->transactions[0]->getBinary()); } else { // Create a fixed size Merkle Tree $tree = new FixedSizeTree($txCount + $txCount % 2, $hashFxn); // Compute hash of each transaction $last = ''; foreach ($this->transactions as $i => $transaction) { $last = $transaction->getBinary(); $tree->set($i, $last); } // Check if we need to repeat the last hash (odd number of transactions) if (!$this->math->isEven($txCount)) { $tree->set($txCount, $last); } $binary = $tree->hash(); } $this->setLastHash((new Buffer($binary))->flip()); return $this->getLastHash(); }
/** * Given a sequence, get the human readable node. Ie, 0 -> 0, 0x80000000 -> 0h * @param $sequence * @return string */ public function getNode($sequence) { if ($this->isHardened($sequence)) { $sequence = $this->math->sub($sequence, self::START_HARDENED) . 'h'; } return $sequence; }
/** * @param int $ptr * @return Operation */ private function doNext($ptr) { if ($this->math->cmp($this->position, $this->end) >= 0) { throw new \RuntimeException('Position exceeds end of script!'); } $opCode = ord($this->data[$this->position++]); $pushData = $this->empty; $dataSize = 0; if ($opCode <= Opcodes::OP_PUSHDATA4) { if ($opCode < Opcodes::OP_PUSHDATA1) { $dataSize = $opCode; } else { if ($opCode === Opcodes::OP_PUSHDATA1) { $dataSize = $this->unpackSize('C', 1); } else { if ($opCode === Opcodes::OP_PUSHDATA2) { $dataSize = $this->unpackSize('v', 2); } else { $dataSize = $this->unpackSize('V', 4); } } } $delta = $this->end - $this->position; if ($dataSize === false || $delta < 0 || $delta < $dataSize) { throw new \RuntimeException('Failed to unpack data from Script'); } if ($dataSize > 0) { $pushData = new Buffer(substr($this->data, $this->position, $dataSize), $dataSize, $this->math); } $this->position += $dataSize; } $this->array[$ptr] = new Operation($opCode, $pushData, $dataSize); return $this->array[$ptr]; }
/** * @dataProvider generateSet */ public function testPong(Ping $ping) { $pong = new Pong($ping->getNonce()); $this->assertEquals('pong', $pong->getNetworkCommand()); $this->assertTrue($ping->getNonce() == $pong->getNonce()); $math = new Math(); $this->assertEquals(str_pad($math->decHex($ping->getNonce()), 16, '0', STR_PAD_LEFT), $pong->getHex()); }
/** * @param Math $math * @param TransactionInterface $transaction * @return int|string */ public function getValueIn(Math $math, TransactionInterface $transaction) { $value = 0; foreach ($transaction->getInputs() as $input) { $value = $math->add($value, $this->fetchByInput($input)->getOutput()->getValue()); } return $value; }
/** * @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 BlockIndexInterface $prevIndex * @param int $timeFirstBlock * @return int */ public function calculateNextWorkRequired(BlockIndexInterface $prevIndex, $timeFirstBlock) { $header = $prevIndex->getHeader(); $math = $this->math; $timespan = $this->calculateWorkTimespan($timeFirstBlock, $header); $negative = false; $overflow = false; $target = $math->decodeCompact($header->getBits(), $negative, $overflow); $limit = $this->math->decodeCompact($this->params->powBitsLimit(), $negative, $overflow); $new = gmp_init(bcdiv(bcmul($target, $timespan), $this->params->powTargetTimespan()), 10); if ($math->cmp($new, $limit) > 0) { $new = $limit; } return gmp_strval($math->encodeCompact($new, false), 10); }
/** * @param UtxoView $view * @param TransactionInterface $tx * @param int $spendHeight * @return $this */ public function checkContextualInputs(UtxoView $view, TransactionInterface $tx, $spendHeight) { $valueIn = gmp_init(0); for ($i = 0, $nInputs = count($tx->getInputs()); $i < $nInputs; $i++) { /*if ($out->isCoinbase()) { // todo: cb / height if ($spendHeight - $out->getHeight() < $this->params->coinbaseMaturityAge()) { return false; } }*/ $value = gmp_init($view->fetchByInput($tx->getInput($i))->getOutput()->getValue(), 10); $valueIn = $this->math->add($valueIn, $value); $this->consensus->checkAmount($valueIn); } $valueOut = gmp_init(0); foreach ($tx->getOutputs() as $output) { $valueOut = $this->math->add($valueOut, gmp_init($output->getValue(), 10)); $this->consensus->checkAmount($valueOut); } if ($this->math->cmp($valueIn, $valueOut) < 0) { throw new \RuntimeException('Value-in is less than value-out'); } $fee = $this->math->sub($valueIn, $valueOut); $this->consensus->checkAmount($fee); return $this; }
/** * @return $this * @throws \Exception */ private function checkOpcodeCount() { if ($this->math->cmp($this->opCount, 201) > 0) { throw new \RuntimeException('Error: Script op code count'); } return $this; }
/** * @param Parser $parser * @return CompactSignature * @throws ParserOutOfRange */ public function fromParser(Parser &$parser) { try { list($byte, $r, $s) = $this->getTemplate()->parse($parser); $recoveryFlags = $this->math->sub($byte, 27); if ($recoveryFlags < 0 || $recoveryFlags > 7) { throw new \InvalidArgumentException('invalid signature type'); } $isCompressed = $this->math->bitwiseAnd($recoveryFlags, 4) != 0; $recoveryId = $recoveryFlags - ($isCompressed ? 4 : 0); } catch (ParserOutOfRange $e) { throw new ParserOutOfRange('Failed to extract full signature from parser'); } $signature = new CompactSignature($r, $s, $recoveryId, $isCompressed); return $signature; }
/** * @param $opCode * @param Buffer $pushData * @return bool */ public function next(&$opCode, &$pushData) { $opcodes = $this->script->getOpcodes(); $opCode = $opcodes->getOpByName('OP_INVALIDOPCODE'); if ($this->math->cmp($this->getPosition(), $this->getEndPos()) >= 0) { return false; } $opCode = $this->getNextOp(); if ($opcodes->cmp($opCode, 'OP_PUSHDATA4') <= 0) { if ($opcodes->cmp($opCode, 'OP_PUSHDATA1') < 0) { $size = $opCode; } else { if ($opcodes->isOp($opCode, 'OP_PUSHDATA1')) { $size = $this->unpackSize("C", 1); } else { if ($opcodes->isOp($opCode, 'OP_PUSHDATA2')) { $size = $this->unpackSize("v", 2); } else { $size = $this->unpackSize("V", 4); } } } if ($size === false || $this->validateSize($size) === false) { return false; } $pushData = new Buffer(substr($this->scriptRaw, $this->ptr, $size), $size); $this->ptr += $size; } return true; }
/** * Convert locktime to block height tx is locked to. Doesn't convert anything * really, but does check the bounds of the supplied locktime. * * @param int|string $lockTime * @return int|string * @throws \Exception */ public function toBlockHeight($lockTime) { if ($this->math->cmp($lockTime, self::BLOCK_MAX) > 0) { throw new \Exception('This locktime is out of range for a block height'); } return $lockTime; }
/** * @param $height * @return \React\Promise\Promise */ public function blockGetHeader($height) { return $this->client->request('blockchain.block.get_header', [$height])->then(function (\BitWasp\Stratum\Request\Response $response) { $content = $response->getResult(); return new \BitWasp\Bitcoin\Block\BlockHeader($content['version'], @$content['prev_block_hash'], $content['merkle_root'], $content['timestamp'], Buffer::hex($this->math->decHex($content['bits'])), $content['nonce']); }); }
/** * @return $this */ private function updateProofOfWork() { if ($this->math->cmp(0, $this->math->mod($this->currentHeight(), 2016)) == 0) { $this->chainDiff = $this->difficulty->getDifficulty($this->chainTip()->getHeader()->getBits()); $this->pow = new ProofOfWork($this->math, $this->difficulty, $this->chainDiff); } return $this; }
/** * @param int $minVersion * @param int $startHeight * @param int $nRequired * @param Index\Blocks $blocks * @return bool */ public function isSuperMajority($minVersion, $startHeight, Index\Blocks $blocks, $nRequired) { $nFound = 0; $window = $this->params->majorityWindow(); for ($i = 0; $i < $window && $nFound < $nRequired && ($index = $blocks->fetchByHeight($startHeight - $i)); $i++) { if ($this->math->cmp($index->getHeader()->getVersion(), $minVersion)) { $nFound++; } } return $nFound >= $nRequired; }
/** * @return int */ public function getInt() { if ($this->math->cmp($this->number, self::MAX) > 0) { return self::MAX; } else { if ($this->math->cmp($this->number, self::MIN) < 0) { return self::MIN; } } return $this->number; }
/** * @param \BitWasp\Bitcoin\Script\Interpreter\Number $sequence * @return bool */ private function checkSequence(Number $sequence) { $txSequence = $this->transaction->getInput($this->inputToSign)->getSequence(); if ($this->transaction->getVersion() < 2) { return false; } if ($this->math->cmp($this->math->bitwiseAnd($txSequence, TransactionInputInterface::SEQUENCE_LOCKTIME_DISABLE_FLAG), 0) !== 0) { return 0; } $mask = $this->math->bitwiseOr(TransactionInputInterface::SEQUENCE_LOCKTIME_TYPE_FLAG, TransactionInputInterface::SEQUENCE_LOCKTIME_MASK); return $this->verifyLockTime($this->math->bitwiseAnd($txSequence, $mask), TransactionInputInterface::SEQUENCE_LOCKTIME_TYPE_FLAG, Number::int($this->math->bitwiseAnd($sequence->getInt(), $mask))); }
/** * @param Peer $sender * @param TransactionSignatureInterface $txSig * @return TransactionSignatureInterface */ public function fixSig(Peer $sender, TransactionSignatureInterface $txSig, &$wasMalleated = false) { $sig = $txSig->getSignature(); if (!$this->adapter->validateSignatureElement($sig->getS(), true)) { $ip = $sender->getRemoteAddr()->getIp(); if (!isset($this->violators[$ip])) { $this->violators[$sender->getRemoteAddr()->getIp()] = 1; } else { $this->violators[$sender->getRemoteAddr()->getIp()]++; } $wasMalleated = true; $this->counter++; $txSig = new TransactionSignature($this->adapter, new Signature($this->adapter, $sig->getR(), $this->math->sub($this->order, $sig->getS())), $txSig->getHashType()); if (!$this->adapter->validateSignatureElement($txSig->getSignature()->getS(), true)) { die('failed to produce a low-s signature'); } } return $txSig; }
/** * @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'; } }
/** * @param ChainState $state * @param BlockInterface $block * @param Headers $headers * @param UtxoIdx $utxoIdx * @return BlockIndex */ public function accept(ChainState $state, BlockInterface $block, Headers $headers, UtxoIdx $utxoIdx) { $bestBlock = $state->getLastBlock(); if ($bestBlock->getHash() !== $block->getHeader()->getPrevBlock()) { throw new \RuntimeException('Blocks:accept() Block does not extend this chain!'); } $index = $headers->accept($state, $block->getHeader()); $this->blockCheck->check($block)->checkContextual($block, $bestBlock); //$view = $utxoIdx->fetchView($state, $block); $view = $this->db->fetchUtxoView($block); $flagP2sh = $this->consensus->scriptVerifyPayToScriptHash($bestBlock->getHeader()->getTimestamp()); $flags = new Flags($flagP2sh ? InterpreterInterface::VERIFY_P2SH : InterpreterInterface::VERIFY_NONE); $nInputs = 0; $nFees = 0; $nSigOps = 0; $txs = $block->getTransactions(); foreach ($block->getTransactions() as $tx) { $nInputs += count($tx->getInputs()); $nSigOps += $this->blockCheck->getLegacySigOps($tx); if ($nSigOps > $this->consensus->getParams()->getMaxBlockSigOps()) { throw new \RuntimeException('Blocks::accept() - too many sigops'); } if (!$tx->isCoinbase()) { if ($flagP2sh) { $nSigOps = $this->blockCheck->getP2shSigOps($view, $tx); if ($nSigOps > $this->consensus->getParams()->getMaxBlockSigOps()) { throw new \RuntimeException('Blocks::accept() - too many sigops'); } } $fee = $this->math->sub($view->getValueIn($this->math, $tx), $tx->getValueOut()); $nFees = $this->math->add($nFees, $fee); $this->blockCheck->checkInputs($view, $tx, $index->getHeight(), $flags); } } $this->blockCheck->checkCoinbaseSubsidy($txs[0], $nFees, $index->getHeight()); $this->db->insertBlock($block); $state->updateLastBlock($index); return $index; }
/** * @param UtxoView $view * @param TransactionInterface $tx * @param $spendHeight * @return bool */ public function checkContextualInputs(UtxoView $view, TransactionInterface $tx, $spendHeight) { $valueIn = 0; for ($i = 0; $i < count($tx->getInputs()); $i++) { $utxo = $view->fetchByInput($tx->getInput($i)); /*if ($out->isCoinbase()) { // todo: cb / height if ($spendHeight - $out->getHeight() < $this->params->coinbaseMaturityAge()) { return false; } }*/ $value = $utxo->getOutput()->getValue(); $valueIn = $this->math->add($value, $valueIn); if (!$this->consensus->checkAmount($valueIn) || !$this->consensus->checkAmount($value)) { throw new \RuntimeException('CheckAmount failed for inputs value'); } } $valueOut = 0; foreach ($tx->getOutputs() as $output) { $valueOut = $this->math->add($output->getValue(), $valueOut); if (!$this->consensus->checkAmount($valueOut) || !$this->consensus->checkAmount($output->getValue())) { throw new \RuntimeException('CheckAmount failed for outputs value'); } } if ($this->math->cmp($valueIn, $valueOut) < 0) { throw new \RuntimeException('Value-in is less than value out'); } $fee = $this->math->sub($valueIn, $valueOut); if ($this->math->cmp($fee, 0) < 0) { throw new \RuntimeException('Fee is less than zero'); } if (!$this->consensus->checkAmount($fee)) { throw new \RuntimeException('CheckAmount failed for fee'); } return true; }
/** * @param BlockInterface $block * @param BlockData $blockData * @param bool $checkSignatures * @param bool $flags * @param $height */ public function checkBlockData(BlockInterface $block, BlockData $blockData, $checkSignatures, $flags, $height) { $validation = new ScriptValidation($checkSignatures, $flags); foreach ($block->getTransactions() as $tx) { $blockData->nSigOps += $this->blockCheck->getLegacySigOps($tx); if ($blockData->nSigOps > $this->consensus->getParams()->getMaxBlockSigOps()) { throw new \RuntimeException('Blocks::accept() - too many sigops'); } if (!$tx->isCoinbase()) { if ($flags & InterpreterInterface::VERIFY_P2SH) { $blockData->nSigOps += $this->blockCheck->getP2shSigOps($blockData->utxoView, $tx); if ($blockData->nSigOps > $this->consensus->getParams()->getMaxBlockSigOps()) { throw new \RuntimeException('Blocks::accept() - too many sigops'); } } $blockData->nFees = $this->math->add($blockData->nFees, $blockData->utxoView->getFeePaid($this->math, $tx)); $this->blockCheck->checkInputs($blockData->utxoView, $tx, $height, $flags, $validation); } } if ($validation->active() && !$validation->result()) { throw new \RuntimeException('ScriptValidation failed!'); } $this->blockCheck->checkCoinbaseSubsidy($block->getTransaction(0), $blockData->nFees, $height); }
/** * @param int $nHashNum * @param BufferInterface $data * @return string */ public function hash($nHashNum, BufferInterface $data) { return $this->math->mod(Hash::murmur3($data, $nHashNum * self::TWEAK_START + $this->nTweak & 0xffffffff)->getInt(), count($this->vFilter) * 8); }
/** * @param $opCode * @param ScriptStack $mainStack * @param ScriptStack $altStack * @throws \BitWasp\Bitcoin\Exceptions\ScriptStackException * @throws \Exception */ public function op($opCode, ScriptStack $mainStack, ScriptStack $altStack) { $opCodes = $this->opCodes; $opName = $this->opCodes->getOp($opCode); $castToBool = $this->castToBool; if ($opName == 'OP_TOALTSTACK') { if ($mainStack->size() < 1) { throw new \Exception('Invalid stack operation OP_TOALTSTACK'); } $altStack->push($mainStack->pop()); return; } else { if ($opName == 'OP_FROMALTSTACK') { if ($altStack->size() < 1) { throw new \Exception('Invalid alt-stack operation OP_FROMALTSTACK'); } $mainStack->push($altStack->pop()); return; } else { if ($opName == 'OP_IFDUP') { // If top value not zero, duplicate it. if ($mainStack->size() < 1) { throw new \Exception('Invalid stack operation OP_IFDUP'); } $vch = $mainStack->top(-1); if ($castToBool($vch)) { $mainStack->push($vch); } return; } else { if ($opName == 'OP_DEPTH') { $num = $mainStack->size(); $bin = Buffer::hex($this->math->decHex($num)); $mainStack->push($bin); return; } else { if ($opName == 'OP_DROP') { if ($mainStack->size() < 1) { throw new \Exception('Invalid stack operation OP_DROP'); } $mainStack->pop(); return; } else { if ($opName == 'OP_DUP') { if ($mainStack->size() < 1) { throw new \Exception('Invalid stack operation OP_DUP'); } $vch = $mainStack->top(-1); $mainStack->push($vch); return; } else { if ($opName == 'OP_NIP') { if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_NIP'); } $mainStack->erase(-2); return; } else { if ($opName == 'OP_OVER') { if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_OVER'); } $vch = $mainStack->top(-2); $mainStack->push($vch); return; } else { if (in_array($opName, ['OP_PICK', 'OP_ROLL'])) { // cscriptnum if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_PICK'); } $n = $mainStack->top(-1)->getInt(); $mainStack->pop(); if ($this->math->cmp($n, 0) < 0 || $this->math->cmp($n, $mainStack->size()) >= 0) { throw new \Exception('Invalid stack operation OP_PICK'); } $pos = $this->math->sub($this->math->sub(0, $n), 1); $vch = $mainStack->top($pos); if ($opCodes->isOp($opCode, 'OP_ROLL')) { $mainStack->erase($pos); } $mainStack->push($vch); return; } else { if ($opName == 'OP_ROT') { if ($mainStack->size() < 3) { throw new \Exception('Invalid stack operation OP_ROT'); } $mainStack->swap(-3, -2); $mainStack->swap(-2, -1); return; } else { if ($opName == 'OP_SWAP') { if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_SWAP'); } $mainStack->swap(-2, -1); return; } else { if ($opName == 'OP_TUCK') { if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_TUCK'); } $vch = $mainStack->top(-1); $mainStack->insert($mainStack->end() - 2, $vch); return; } else { if ($opName == 'OP_2DROP') { if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_2DROP'); } $mainStack->pop(); $mainStack->pop(); return; } else { if ($opName == 'OP_2DUP') { if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_2DUP'); } $string1 = $mainStack->top(-2); $string2 = $mainStack->top(-1); $mainStack->push($string1); $mainStack->push($string2); return; } else { if ($opName == 'OP_3DUP') { if ($mainStack->size() < 3) { throw new \Exception('Invalid stack operation OP_3DUP'); } $string1 = $mainStack->top(-3); $string2 = $mainStack->top(-2); $string3 = $mainStack->top(-1); $mainStack->push($string1); $mainStack->push($string2); $mainStack->push($string3); return; } else { if ($opName == 'OP_2OVER') { if ($mainStack->size() < 4) { throw new \Exception('Invalid stack operation OP_2OVER'); } $string1 = $mainStack->top(-4); $string2 = $mainStack->top(-3); $mainStack->push($string1); $mainStack->push($string2); return; } else { if ($opName == 'OP_2ROT') { if ($mainStack->size() < 6) { throw new \Exception('Invalid stack operation OP_2ROT'); } $string1 = $mainStack->top(-6); $string2 = $mainStack->top(-5); $mainStack->erase(-6); $mainStack->erase(-5); $mainStack->push($string1); $mainStack->push($string2); return; } else { if ($opName == 'OP_2SWAP') { if ($mainStack->size() < 4) { throw new \Exception('Invalid stack operation OP_2SWAP'); } $mainStack->swap(-3, -1); $mainStack->swap(-4, -2); return; } } } } } } } } } } } } } } } } } } throw new \Exception('Opcode not found'); }
/** * @param Math $math * @param TransactionInterface $tx * @return \GMP */ public function getFeePaid(Math $math, TransactionInterface $tx) { return $math->sub($this->getValueIn($math, $tx), gmp_init($tx->getValueOut())); }
/** * @param Buffer $bits * @return int|string */ public function getWork(Buffer $bits) { return bcdiv($this->math->pow(2, 256), $this->getTarget($bits)); }
#!/usr/bin/php <?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();
/** * @return int|string */ public function getMaxTxSigOps() { return $this->math->div($this->getMaxBlockSigOps(), 5); }
/** * @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); }