public function services($int) { $math = Bitcoin::getMath(); $hex = $math->decHex($int); $buffer = Buffer::hex($hex, 8); return $buffer; }
/** * @param InputInterface $input * @param OutputInterface $output * @return int */ protected function execute(InputInterface $input, OutputInterface $output) { $config = (new ConfigLoader())->load(); // Create the child process // All the code after pcntl_fork () will be performed by two processes: parent and child if ($config->getItem('config', 'daemon', false)) { $child_pid = pcntl_fork(); if ($child_pid) { // Exit from the parent process that is bound to the console exit; } // Make the child as the main process. posix_setsid(); } $math = Bitcoin::getMath(); $params = new Params($math); $loop = \React\EventLoop\Factory::create(); $db = new DebugDb(Db::create($config)); $node = new BitcoinNode($config, $params, $db); $container = new Container(); $container['debug'] = function (Container $c) use($node) { $context = $c['zmq']; return new ZmqDebug($node, $context); }; $this->setupServices($container, $node, $loop, $config, $db); $loop->run(); return 0; }
/** * @param $string * @param Math $math * @return TransactionSignatureInterface */ public static function fromHex($string, Math $math = null) { $math = $math ?: Bitcoin::getMath(); $serializer = new TransactionSignatureSerializer(new DerSignatureSerializer($math)); $signature = $serializer->parse($string); return $signature; }
public function __construct(NodeInterface $node, Container $container) { $this->db = $container['db']; $this->retargetDb = new RetargetDb($this->db->getPdo()); $this->math = Bitcoin::getMath(); $this->consensus = new Consensus(Bitcoin::getMath(), new Params(Bitcoin::getMath())); $node->chains()->on('retarget', [$this, 'onRetarget']); }
/** * Calculate the hash of the current transaction, when you are looking to * spend $txOut, and are signing $inputToSign. The SigHashType defaults to * SIGHASH_ALL, though SIGHASH_SINGLE, SIGHASH_NONE, SIGHASH_ANYONECANPAY * can be used. * * @param ScriptInterface $txOutScript * @param $inputToSign * @param int $sighashType * @return Buffer * @throws \Exception */ public function calculate(ScriptInterface $txOutScript, $inputToSign, $sighashType = SignatureHashInterface::SIGHASH_ALL) { $copy = $this->transaction->makeCopy(); $inputs = $copy->getInputs(); $outputs = $copy->getOutputs(); if ($inputToSign > count($inputs)) { throw new \Exception('Input does not exist'); } // Default SIGHASH_ALL procedure: null all input scripts $inputCount = count($inputs); for ($i = 0; $i < $inputCount; $i++) { $inputs->getInput($i)->setScript(new Script()); } $inputs->getInput($inputToSign)->setScript($txOutScript); $math = Bitcoin::getMath(); if ($math->bitwiseAnd($sighashType, 31) == SignatureHashInterface::SIGHASH_NONE) { // Set outputs to empty vector, and set sequence number of inputs to 0. $copy->setOutputs(new TransactionOutputCollection()); // Let the others update at will. Set sequence of inputs we're not signing to 0. $inputCount = count($inputs); for ($i = 0; $i < $inputCount; $i++) { if ($math->cmp($i, $inputToSign) !== 0) { $inputs->getInput($i)->setSequence(0); } } } elseif ($math->bitwiseAnd($sighashType, 31) == SignatureHashInterface::SIGHASH_SINGLE) { // Resize output array to $inputToSign + 1, set remaining scripts to null, // and set sequence's to zero. $nOutput = $inputToSign; if ($math->cmp($nOutput, count($outputs)) >= 0) { return Buffer::hex('0100000000000000000000000000000000000000000000000000000000000000'); } // Resize.. $outputs = $outputs->slice(0, $nOutput + 1)->getOutputs(); // Set to null for ($i = 0; $i < $nOutput; $i++) { $outputs[$i] = new TransactionOutput($math->getBinaryMath()->getTwosComplement(-1, 64), new Script()); } $copy->setOutputs(new TransactionOutputCollection($outputs)); // Let the others update at will. Set sequence of inputs we're not signing to 0. $inputCount = count($inputs); for ($i = 0; $i < $inputCount; $i++) { if ($math->cmp($i, $inputToSign) != 0) { $inputs->getInput($i)->setSequence(0); } } } // This can happen regardless of whether it's ALL, NONE, or SINGLE if ($math->bitwiseAnd($sighashType, SignatureHashInterface::SIGHASH_ANYONECANPAY)) { $input = $inputs->getInput($inputToSign); $copy->setInputs(new TransactionInputCollection([$input])); } // Serialize the TxCopy and append the 4 byte hashtype (little endian); $txParser = new Parser($copy->getBuffer()); $txParser->writeInt(4, $sighashType, true); return Hash::sha256d($txParser->getBuffer()); }
/** * @param InputInterface $input * @param OutputInterface $output * @return int */ protected function execute(InputInterface $input, OutputInterface $output) { $math = Bitcoin::getMath(); $params = new Params($math); $loop = \React\EventLoop\Factory::create(); $app = new BitcoinNode($params, $loop); $app->start(); $loop->run(); return 0; }
public function testGetValueIn() { $utxo1 = new Utxo(new OutPoint(new Buffer('a', 32), 0), new TransactionOutput(2, new Script())); $utxo2 = new Utxo(new OutPoint(new Buffer('a', 32), 1), new TransactionOutput(4, new Script())); $utxo3 = new Utxo(new OutPoint(new Buffer('b', 32), 0), new TransactionOutput(1, new Script())); $view = new UtxoView([$utxo1, $utxo2, $utxo3]); $transaction = TransactionFactory::build()->spendOutPoint($utxo1->getOutPoint())->spendOutPoint($utxo2->getOutPoint())->spendOutPoint($utxo3->getOutPoint())->output(5, new Script())->get(); $this->assertEquals(7, $view->getValueIn(Bitcoin::getMath(), $transaction)); $this->assertEquals(2, $view->getFeePaid(Bitcoin::getMath(), $transaction)); }
/** * Forks constructor. * @param ParamsInterface $params * @param BlockIndexInterface $index * @param array[] $versions */ public function __construct(ParamsInterface $params, BlockIndexInterface $index, array $versions) { $this->versionCount = ['v1' => 0, 'v2' => 0, 'v3' => 0, 'v4' => 0, 'v5' => 0]; foreach ($versions as $value) { $this->updateCount($value); } $this->math = Bitcoin::getMath(); $this->params = $params; $this->index = $index; $this->versions = $versions; $this->update(); }
/** * @param array $bits * @return array */ private function bitsToBuffers(array $bits) { $math = Bitcoin::getMath(); $vBuffers = str_split(str_pad('', (count($bits) + 7) / 8, '0', STR_PAD_LEFT)); $nBits = count($bits); for ($p = 0; $p < $nBits; $p++) { $index = (int) floor($p / 8); $vBuffers[$index] |= $bits[$p] << $p % 8; } foreach ($vBuffers as &$value) { $value = Buffer::int($value, null, $math); } unset($value); return $vBuffers; }
/** * Calculate the hash of the current transaction, when you are looking to * spend $txOut, and are signing $inputToSign. The SigHashType defaults to * SIGHASH_ALL, though SIGHASH_SINGLE, SIGHASH_NONE, SIGHASH_ANYONECANPAY * can be used. * * @param ScriptInterface $txOutScript * @param int $inputToSign * @param int $sighashType * @return BufferInterface * @throws \Exception */ public function calculate(ScriptInterface $txOutScript, $inputToSign, $sighashType = SigHash::ALL) { $math = Bitcoin::getMath(); $tx = new TxMutator($this->transaction); $inputs = $tx->inputsMutator(); $outputs = $tx->outputsMutator(); // Default SIGHASH_ALL procedure: null all input scripts foreach ($inputs as $input) { $input->script(new Script()); } $inputs[$inputToSign]->script($txOutScript); if ($math->cmp($math->bitwiseAnd($sighashType, 31), SigHash::NONE) === 0) { // Set outputs to empty vector, and set sequence number of inputs to 0. $outputs->null(); // Let the others update at will. Set sequence of inputs we're not signing to 0. foreach ($inputs as $i => $input) { if ($i !== $inputToSign) { $input->sequence(0); } } } elseif ($math->cmp($math->bitwiseAnd($sighashType, 31), SigHash::SINGLE) === 0) { // Resize output array to $inputToSign + 1, set remaining scripts to null, // and set sequence's to zero. $nOutput = $inputToSign; if ($nOutput >= $this->nOutputs) { return Buffer::hex('0100000000000000000000000000000000000000000000000000000000000000', 32, $math); } // Resize, set to null $outputs->slice(0, $nOutput + 1); for ($i = 0; $i < $nOutput; $i++) { $outputs[$i]->null(); } // Let the others update at will. Set sequence of inputs we're not signing to 0 foreach ($inputs as $i => $input) { if ($i !== $inputToSign) { $input->sequence(0); } } } // This can happen regardless of whether it's ALL, NONE, or SINGLE if ($math->cmp($math->bitwiseAnd($sighashType, SigHash::ANYONECANPAY), 0) > 0) { $input = $inputs[$inputToSign]->done(); $inputs->null()->add($input); } return Hash::sha256d(Buffertools::concat($tx->done()->getBuffer(), Buffertools::flipBytes(Buffer::int($sighashType, 4, $math)))); }
/** * Decode a base58 string * * @param string $base58 * @return BufferInterface */ public static function decode($base58) { $math = Bitcoin::getMath(); if ($base58 === '') { return new Buffer('', 0, $math); } $original = $base58; $length = strlen($base58); $return = '0'; for ($i = 0; $i < $length; $i++) { $return = $math->add($math->mul($return, 58), strpos(self::$base58chars, $base58[$i])); } $binary = $math->cmp($return, '0') === 0 ? '' : hex2bin($math->decHex($return)); for ($i = 0; $i < $length && $original[$i] === '1'; $i++) { $binary = "" . $binary; } return new Buffer($binary); }
/** * Decode a base58 string * * @param $base58 * @return Buffer */ public static function decode($base58) { if (strlen($base58) == 0) { return new Buffer(); } $original = $base58; $strlen = strlen($base58); $return = '0'; $math = Bitcoin::getMath(); for ($i = 0; $i < $strlen; $i++) { $return = $math->add($math->mul($return, 58), strpos(self::$base58chars, $base58[$i])); } $hex = $return == '0' ? '' : $math->decHex($return); for ($i = 0; $i < $strlen && $original[$i] == "1"; $i++) { $hex = "00" . $hex; } $buffer = Buffer::hex($hex); return $buffer; }
/** * @param BufferInterface $vch * @param bool $fRequireMinimal * @param int $maxNumSize * @param Math|null $math * @return self */ public static function buffer(BufferInterface $vch, $fRequireMinimal, $maxNumSize = self::MAX_NUM_SIZE, Math $math = null) { $size = $vch->getSize(); if ($size > $maxNumSize) { throw new \RuntimeException('Script number overflow'); } if ($fRequireMinimal && $size > 0) { $binary = $vch->getBinary(); if (ord($binary[$size - 1]) & 0x7f === 0) { if ($size <= 1 || ord($binary[$size - 2]) & 0x80 === 0) { throw new \RuntimeException('Non-minimally encoded script number'); } } } $math = $math ?: Bitcoin::getMath(); $number = new self(0, $math); $number->number = $number->parseBuffer($vch); return $number; }
public function __construct() { $this->haveTx = []; $this->math = Bitcoin::getMath(); $this->generator = Bitcoin::getGenerator(); $this->adapter = EcAdapterFactory::getPhpEcc($this->math, $this->generator); $this->order = $this->adapter->getGenerator()->getOrder(); $this->loop = \React\EventLoop\Factory::create(); $factory = new \BitWasp\Bitcoin\Networking\Factory($this->loop); $dns = $factory->getDns(); $peerFactory = $factory->getPeerFactory($dns); $locator = $peerFactory->getLocator(); $server = new ReactServer($this->loop); $listener = $peerFactory->getListener($server); $this->manager = $peerFactory->getManager(true); $this->manager->registerListener($listener); $this->manager->on('outbound', function (Peer $peer) { $this->setupPeer($peer); }); $this->manager->on('inbound', function (Peer $peer) { $this->setupPeer($peer); }); $locator->queryDnsSeeds()->then(function (Locator $locator) { $this->manager->connectToPeers($locator, 5); $this->loop->addPeriodicTimer(30, function () { echo "Have seen " . $this->inputs . " inputs and " . $this->counter . " high-S signatures \n"; echo "There are " . count($this->violators) . " violators \n"; $largest = 0; $worstPeer = null; foreach ($this->violators as $ip => $v) { if ($v > $largest) { $worstPeer = $ip; $largest = $v; } } if (!is_null($worstPeer)) { echo "Worst peer: {$worstPeer} ({$largest})\n"; } }); echo "Connecting..\n"; }); }
/** * @param BlockInterface $genesisBlock */ public function init(BlockInterface $genesisBlock) { $hash = $genesisBlock->getHeader()->getHash(); $index = $this->db->fetchIndex($hash); try { $this->db->fetchBlock($hash); } catch (\Exception $e) { echo $e->getMessage() . PHP_EOL; $this->db->insertBlock($index->getHash(), $genesisBlock, new BlockSerializer(Bitcoin::getMath(), new BlockHeaderSerializer(), new TransactionSerializer())); } }
public function hasBlockchain() { $math = Bitcoin::getMath(); return $math->cmp($math->bitwiseAnd($this->services->getInt(), self::NODE_NETWORK), self::NODE_NETWORK) == 0; }
/** * @return \BitWasp\Buffertools\Buffer */ public function getBuffer() { $serializer = new CompactSignatureSerializer(Bitcoin::getMath()); return $serializer->serialize($this); }
/** * Query for headers/blocks chain state - populates Chains. * * @param Headers $headers * @return ChainState[] */ public function fetchChainState(Headers $headers) { if ($this->debug) { echo "db: called fetchChainState \n"; } $stmt = $this->dbh->prepare(' SELECT * FROM ( SELECT parent.hash as last_hash, parent.work as last_work, parent.height as last_height , parent.version as last_version, parent.prevBlock as last_prevBlock, parent.merkleRoot as last_merkleRoot , parent.nBits as last_nBits, parent.nTimestamp as last_nTimestamp, parent.nNonce as last_nNonce , tip.hash as tip_hash, tip.height as tip_height, tip.work as tip_work , tip.version as tip_version, tip.prevBlock tip_prevBlock, tip.merkleRoot as tip_merkleRoot , tip.nBits as tip_nBits, tip.nTimestamp as tip_nTimestamp, tip.nNonce as tip_nNonce FROM headerIndex AS tip, headerIndex AS parent LEFT JOIN headerIndex AS next ON next.prevBlock = parent.hash LEFT JOIN blockIndex AS b ON b.hash = next.hash WHERE tip.rgt = tip.lft + 1 and b.hash IS NULL ) as r GROUP BY r.tip_hash;'); if ($stmt->execute()) { $chainPathStmt = $this->dbh->prepare("\n SELECT node.hash, parent.hash\n FROM headerIndex AS node,\n headerIndex AS parent\n WHERE node.rgt = node.lft + 1\n AND node.lft BETWEEN parent.lft AND parent.rgt\n "); $chainPathStmt->execute(); $fetch = $chainPathStmt->fetchAll(\PDO::FETCH_GROUP | \PDO::FETCH_COLUMN); $states = []; $math = Bitcoin::getMath(); foreach ($stmt->fetchAll(\PDO::FETCH_ASSOC) as $row) { $map = $fetch[$row['tip_hash']]; foreach ($map as &$m) { $m = hex2bin($m); } unset($m); $bestHeader = new BlockIndex($row['tip_hash'], $row['tip_height'], $row['tip_work'], new BlockHeader($row['tip_version'], $row['tip_prevBlock'], $row['tip_merkleRoot'], $row['tip_nTimestamp'], Buffer::int($row['tip_nBits'], 4), $row['tip_nNonce'])); $lastBlock = new BlockIndex($row['last_hash'], $row['last_height'], $row['last_work'], new BlockHeader($row['last_version'], $row['last_prevBlock'], $row['last_merkleRoot'], $row['last_nTimestamp'], Buffer::int($row['last_nBits'], 4), $row['last_nNonce'])); $states[] = new ChainState($math, new Chain($map, $bestHeader, $headers, $math), $lastBlock); } return $states; } throw new \RuntimeException('Failed to fetch block progress'); }
/** * @param $string * @param Math $math * @return Block */ public static function fromHex($string, Math $math = null) { $serializer = new HexBlockSerializer($math ?: Bitcoin::getMath(), new HexBlockHeaderSerializer(), new TransactionSerializer()); return $serializer->parse($string); }
/** * @param Parser $parser * @return BloomFilter */ public function fromParser(Parser $parser) { list($vData, $numHashFuncs, $nTweak, $flags) = $this->getTemplate()->parse($parser); return new BloomFilter(Bitcoin::getMath(), $vData, $numHashFuncs, $nTweak, $flags); }
/** * @return bool */ public function isFinal() { $math = Bitcoin::getMath(); return $math->cmp($this->getSequence(), self::SEQUENCE_FINAL) === 0; }
/** * @param ParamsInterface $params * @param LoopInterface $loop */ public function __construct(ParamsInterface $params, LoopInterface $loop) { echo ' [App] start ' . PHP_EOL; $start = microtime(true); $math = Bitcoin::getMath(); $adapter = Bitcoin::getEcAdapter($math); $zmq = new ZMQContext($loop); $this->initControl($zmq)->initConfig(); $this->loop = $loop; $this->params = $params; $this->adapter = $adapter; $this->chains = new Chains($adapter); $this->inventory = new KnownInventory(); $this->peerState = new PeerStateCollection(); $this->peersInbound = new Peers(); $this->peersOutbound = new Peers(); $this->netFactory = new NetworkingFactory($loop); $this->db = new Db($this->config, false); $consensus = new Consensus($math, $params); $zmqScript = new ZmqScriptCheck(new \ZMQContext()); $this->headers = new Index\Headers($this->db, $consensus, $math, new HeaderCheck($consensus, $adapter, new ProofOfWork($math, $params))); $this->blocks = new Index\Blocks($this->db, $adapter, $consensus, new BlockCheck($consensus, $adapter, $zmqScript)); $genesis = $params->getGenesisBlock(); $this->headers->init($genesis->getHeader()); $this->blocks->init($genesis); $this->initChainState(); $this->utxo = new Index\UtxoIdx($this->chains, $this->db); $this->blockDownload = new BlockDownloader($this->chains, $this->peerState, $this->peersOutbound); $this->on('blocks.syncing', function () { echo ' [App] ... BLOCKS: syncing' . PHP_EOL; }); $this->on('headers.syncing', function () { echo ' [App] ... HEADERS: syncing' . PHP_EOL; }); $this->on('headers.synced', function () { echo ' [App] ... HEADERS: synced!' . PHP_EOL; }); echo ' [App] Startup took: ' . (microtime(true) - $start) . ' seconds ' . PHP_EOL; }
private function updateGreatestWork() { $segments = $this->segments; if (count($this->segments) > 1) { usort($segments, new ChainWorkComparator(Bitcoin::getMath())); } $best = end($segments); if (is_null($this->best) || $this->best instanceof ChainSegment && $this->best->getLast() !== $best->getLast()) { $this->best = $best; } }
/** * @param NetworkInterface $network */ public function __construct(NetworkInterface $network) { $this->math = Bitcoin::getMath(); $this->network = $network; $this->txSerializer = new TransactionSerializer(); $this->headerSerializer = new BlockHeaderSerializer(); $this->blockSerializer = new BlockSerializer($this->math, $this->headerSerializer, $this->txSerializer); $this->filteredBlockSerializer = new FilteredBlockSerializer($this->headerSerializer, new PartialMerkleTreeSerializer()); $this->headersSerializer = new HeadersSerializer($this->headerSerializer); $this->filterAddSerializer = new FilterAddSerializer(); $this->filterLoadSerializer = new FilterLoadSerializer(new BloomFilterSerializer()); $this->merkleBlockSerializer = new MerkleBlockSerializer($this->filteredBlockSerializer); $this->pingSerializer = new PingSerializer(); $this->pongSerializer = new PongSerializer(); $this->alertSerializer = new AlertSerializer(new AlertDetailSerializer()); $this->inventorySerializer = new InventorySerializer(); $this->getDataSerializer = new GetDataSerializer($this->inventorySerializer); $this->invSerializer = new InvSerializer($this->inventorySerializer); $this->notFoundSerializer = new NotFoundSerializer($this->inventorySerializer); $this->rejectSerializer = new RejectSerializer(); $this->blockLocatorSerializer = new BlockLocatorSerializer(); $this->getBlocksSerializer = new GetBlocksSerializer($this->blockLocatorSerializer); $this->getHeadersSerializer = new GetHeadersSerializer($this->blockLocatorSerializer); $this->versionSerializer = new VersionSerializer(new NetworkAddressSerializer()); $this->addrSerializer = new AddrSerializer(new NetworkAddressTimestampSerializer()); }
/** * @return int|string */ public function getValueOut() { $math = Bitcoin::getMath(); $value = 0; foreach ($this->outputs as $output) { $value = $math->add($value, $output->getValue()); } return $value; }
<?php require "../vendor/autoload.php"; use BitWasp\Bitcoin\Bitcoin; use BitWasp\Bitcoin\MessageSigner\MessageSigner; use BitWasp\Bitcoin\Serializer\MessageSigner\SignedMessageSerializer; use BitWasp\Bitcoin\Serializer\Signature\CompactSignatureSerializer; Bitcoin::setNetwork(\BitWasp\Bitcoin\Network\NetworkFactory::bitcoinTestnet()); $address = 'n2Z2DFCxG6vktyX1MFkKAQPQFsrmniGKj5'; $sig = '-----BEGIN BITCOIN SIGNED MESSAGE----- hi -----BEGIN SIGNATURE----- IBpGR29vEbbl4kmpK0fcDsT75GPeH2dg5O199D3iIkS3VcDoQahJMGJEDozXot8JGULWjN9Llq79aF+FogOoz/M= -----END BITCOIN SIGNED MESSAGE-----'; $ec = Bitcoin::getEcAdapter(); $addr = \BitWasp\Bitcoin\Address\AddressFactory::fromString($address); $serializer = new SignedMessageSerializer(new CompactSignatureSerializer(Bitcoin::getMath())); $signedMessage = $serializer->parse($sig); $signer = new MessageSigner($ec); if ($signer->verify($signedMessage, $addr)) { echo "Signature verified!\n"; } else { echo "Failed to verify signature!\n"; }
/** * @return \BitWasp\Buffertools\Buffer */ public function getBuffer() { $txSigSerializer = new TransactionSignatureSerializer(new DerSignatureSerializer(Bitcoin::getMath())); return $txSigSerializer->serialize($this); }
/** * @param TransactionInterface $transaction * @return BufferInterface */ public function serialize(TransactionInterface $transaction) { $math = Bitcoin::getMath(); $int8le = new Int8($math, ByteOrder::LE); $int32le = new Int32($math, ByteOrder::LE); $uint32le = new Uint32($math, ByteOrder::LE); $varint = new VarInt($math, ByteOrder::LE); $vector = new Vector($varint, function () { }); $binary = $int32le->write($transaction->getVersion()); $flags = 0; if (!$transaction->getWitnesses()->isNull()) { $flags |= 1; } if ($flags) { $binary .= $int8le->write(0); $binary .= $int8le->write($flags); } $binary .= $vector->write($transaction->getInputs()->all()); $binary .= $vector->write($transaction->getOutputs()->all()); if ($flags & 1) { foreach ($transaction->getWitnesses() as $witness) { $binary .= $witness->getBuffer()->getBinary(); } } $binary .= $uint32le->write($transaction->getLockTime()); return new Buffer($binary); }
protected function discover_wallet_addrs_single($x_pub_key) { $params = $this->get_params(); $math = Bitcoin::getMath(); $network = Bitcoin::getNetwork(); //$x_pub_key = '1LSedCD6AFWJaZXF2qR8jZobaGx3jN6akv'; $master = HierarchicalKeyFactory::fromExtended($x_pub_key, $network); /* echo "Master Public Key (m)\n"; echo " " . $master->toExtendedPublicKey($network) . "\n"; echo " Address: " . $master->getPublicKey()->getAddress()->getAddress() . "\n"; echo sprintf( " depth: %s, sequence: %s\n\n", $master->getDepth(), $master->getSequence() ); */ return $this->discover_addrs($master); }
<?php use BitWasp\Bitcoin\Bitcoin; use BitWasp\Bitcoin\Address; use BitWasp\Bitcoin\Key\Deterministic\HierarchicalKeyFactory; require __DIR__ . "/../vendor/autoload.php"; $math = Bitcoin::getMath(); $network = Bitcoin::getNetwork(); $master = HierarchicalKeyFactory::generateMasterKey(); echo "Master key (m)\n"; echo " " . $master->toExtendedPrivateKey($network) . "\n"; echo " Address: " . $master->getPublicKey()->getAddress()->getAddress() . "\n\n"; echo "Derive sequential keys:\n"; $key1 = $master->deriveChild(0); echo " - m/0' " . $key1->toExtendedPrivateKey($network) . "\n"; echo " Address: " . $key1->getPublicKey()->getAddress()->getAddress() . "\n\n"; $key2 = $key1->deriveChild(999999); echo " - m/0'/999999 " . $key2->toExtendedPublicKey($network) . "\n"; echo " Address: " . $key2->getPublicKey()->getAddress()->getAddress() . "\n\n"; echo "Directly derive path\n"; $sameKey2 = $master->derivePath("0'/999999"); echo " - m/0'/999999 " . $sameKey2->toExtendedPublicKey() . "\n"; echo " Address: " . $sameKey2->getPublicKey()->getAddress()->getAddress() . "\n\n";