/** * @param NetworkInterface|null $network * @return string */ public function getAddress(NetworkInterface $network = null) { $network = $network ?: Bitcoin::getNetwork(); $witnessByte = dechex($this->witnessVersion); $witnessByte = strlen($witnessByte) % 2 == 0 ? $witnessByte : '0' . $witnessByte; $payload = Buffer::hex($this->getPrefixByte($network) . $witnessByte . "00" . $this->getHash()); return Base58::encodeCheck($payload); }
public function test() { $network = Bitcoin::getNetwork(); $verack = new VerAck(); $expected = 'f9beb4d976657261636b000000000000000000005df6e0e2'; $this->assertEquals($expected, $verack->getNetworkMessage($network)->getHex()); $this->assertSame('verack', $verack->getNetworkCommand()); }
/** * @param ScriptInterface $script * @param NetworkInterface $network * @return String * @throws \RuntimeException */ public static function getAssociatedAddress(ScriptInterface $script, NetworkInterface $network = null) { $classifier = new OutputClassifier($script); $network = $network ?: Bitcoin::getNetwork(); try { $address = $classifier->isPayToPublicKey() ? PublicKeyFactory::fromHex($script->getScriptParser()->parse()[0]->getHex())->getAddress() : self::fromOutputScript($script); return Base58::encodeCheck(Buffer::hex($network->getAddressByte() . $address->getHash())); } catch (\Exception $e) { throw new \RuntimeException('No address associated with this script type'); } }
/** * P2P constructor. * @param Container $container */ public function __construct(Container $container) { $this->loop = $container['loop']; $this->config = $container['config']; $this->peerStates = $container['p2p.states']; /** @var ConnectionParams $params */ $params = $container['p2p.params']; $factory = new Factory($this->loop, Bitcoin::getNetwork()); $dns = $factory->getDns(); $messages = $factory->getMessages(); if ((bool) $this->config->getItem('config', 'tor', false)) { $socks = new Client('127.0.0.1:9050', $this->loop); $socks->setResolveLocal(false); $this->connector = new Connector($messages, $params, $this->loop, $dns, $socks->createConnector()); } else { $this->connector = new Connector($messages, $params, $this->loop, $dns); } $this->manager = new Manager($this->connector); $this->locator = new Locator($dns); // Setup listener if required if ($this->config->getItem('config', 'listen', '0')) { $listener = new Listener($params, $messages, new Server($this->loop), $this->loop); $this->manager->registerListener($listener); } /** * @var Peers $peersInbound * @var Peers $peersOutbound * @var DebugInterface $debug */ $debug = $container['debug']; $peersInbound = $container['p2p.inbound']; $peersOutbound = $container['p2p.outbound']; $this->manager->on('outbound', function (Peer $peer) use($peersOutbound, $debug) { $addr = $peer->getRemoteAddress(); $debug->log('p2p.outbound', ['peer' => ['ip' => $addr->getIp(), 'port' => $addr->getPort(), 'services' => $this->decodeServices($addr->getServices())]]); $this->setupPeer($peer); $peersOutbound->add($peer); $peer->on('close', [$this, 'onPeerClose']); }); $this->manager->on('inbound', function (Peer $peer) use($peersInbound, $debug) { $addr = $peer->getRemoteAddress(); $debug->log('p2p.inbound', ['peer' => ['ip' => $addr->getIp(), 'port' => $addr->getPort()]]); $this->setupPeer($peer); $peersInbound->add($peer); }); $this->manager->on('outbound', [$this, 'onOutBoundPeer']); $this->manager->on('inbound', [$this, 'onInboundPeer']); }
/** * @param NetworkInterface $network * @return string */ public function getPrefixByte(NetworkInterface $network = null) { $network = $network ?: Bitcoin::getNetwork(); return $network->getP2shByte(); }
/** * * @param NetworkInterface $network * @return string */ public function toExtendedKey(NetworkInterface $network = null) { $network = $network ?: Bitcoin::getNetwork(); $extendedSerializer = new ExtendedKeySerializer(new HexExtendedKeySerializer($this->ecAdapter, $network)); $extended = $extendedSerializer->serialize($this); return $extended; }
protected function discover_addrs($xpub) { $master = $xpub; $params = $this->get_params(); $addrs = array(); // filtered addrs. $gap_limit = $params['gap-limit']; $include_unused = $params['include-unused']; $network = Bitcoin::getNetwork(); $gen_only = @$params['gen-only']; list($relpath_base, $abspath_base) = $this->get_derivation_paths($params['derivation']); $types = self::addrtypes(); $apis = $params['api'] == 'roundrobin' ? blockchain_api_factory::instance_all() : [blockchain_api_factory::instance($params['api'])]; $tmap = array('receive' => self::receive_idx, 'change' => self::change_idx); foreach (range(self::receive_idx, self::change_idx) as $type) { if ($params['type'] != 'both' && $tmap[$params['type']] != $type) { continue; } $gap = 0; // reset gap! $batchnum = 1; while (1) { $api = next($apis) ?: reset($apis); $batch = []; $typename = $types[$type]; $msg = sprintf("-- %s Addresses. Start of batch %s. --", $typename, $batchnum); mylogger()->log($msg, mylogger::info); // Goal: reduce number of API calls and increase performance. // if the api supports multiaddr lookups then we set batchsize to double the gap limit. // note: doubling is disabled until secp256kp1 extension passes all test cases. // because key generation is so slooooow without it. // otherwise, set it to 1 to minimize total API calls. // warning: if secp256k1 extension not installed, addr generation will be slowest factor. // todo: check if extension installed, adjust batch size for multiaddr. if ($params['batch-size'] == 'auto') { $batchsize = $api->service_supports_multiaddr() ? $gap_limit * 2 : 1; if ($params['api'] == 'roundrobin') { $batchsize = 1; } } else { $batchsize = $params['batch-size']; } // gen-only mode uses a single batch. if ($gen_only) { $batchsize = $gen_only; } $end = $batchnum * $batchsize; $start = $end - ($batchsize - 1); mylogger()->log("Generating {$typename} public keys", mylogger::info); for ($i = $start - 1; $i < $end; $i++) { if ($i && $i % 5 == 0) { mylogger()->log("Generated {$i} public keys ({$typename})", mylogger::info); } $relpath = $relpath_base . (strlen($relpath_base) ? '/' : '') . "{$type}/{$i}"; $abspath = strlen($abspath_base) ? $abspath_base . "/{$type}/{$i}" : ''; $key = $master->derivePath($relpath); // fixme: hack for copay/multisig. maybe should use a callback? if (method_exists($key, 'getPublicKey')) { // bip32 path $address = $key->getPublicKey()->getAddress()->getAddress(); $xpub = $key->toExtendedPublicKey($network); } else { // copay/multisig path $address = $key->getAddress()->getAddress(); $xpubs = array(); foreach ($key->getKeys() as $key) { $xpubs[] = $key->toExtendedKey(); } // note: encoding multiple xpub as csv string in same field. $xpub = implode(',', $xpubs); } $batch[$address] = array('relpath' => $relpath, 'abspath' => $abspath, 'xpub' => $xpub, 'index' => $i); } if ($gen_only) { foreach ($batch as $addr => $batchinfo) { $r = ['addr' => $addr, 'total_received' => null, 'total_sent' => null, 'balance' => null, 'type' => $typename, 'relpath' => $batchinfo['relpath'], 'abspath' => $batchinfo['abspath'], 'xpub' => $batchinfo['xpub']]; $addrs[] = $r; } break; } else { mylogger()->log(sprintf("Querying addresses %s to %s...", $start, $end), mylogger::info); $response = $api->get_addresses_info(array_keys($batch), $params); foreach ($response as $r) { if ($r['total_received'] == 0) { $gap++; if ($gap > $gap_limit) { break 2; } } else { $gap = 0; } $r['type'] = $typename; $batchinfo = $batch[$r['addr']]; $r['relpath'] = $batchinfo['relpath']; $r['abspath'] = $batchinfo['abspath']; $r['xpub'] = $batchinfo['xpub']; if ($r['total_received'] > 0 || $include_unused) { $addrs[] = $r; } } } $batchnum++; } } return $addrs; }
/** * @param NetworkInterface $network * @param LoopInterface $loop */ public function __construct(LoopInterface $loop, NetworkInterface $network = null) { $this->loop = $loop; $this->network = $network ?: Bitcoin::getNetwork(); }
/** * @param NetworkInterface|null $network * @return string */ public function getAddress(NetworkInterface $network = null) { $network = $network ?: Bitcoin::getNetwork(); $payload = Buffer::hex($this->getPrefixByte($network) . $this->getHash()); return Base58::encodeCheck($payload); }
/** * @param NetworkInterface $network * @return string */ public function toWif(NetworkInterface $network = null) { $network = $network ?: Bitcoin::getNetwork(); $wifSerializer = new WifPrivateKeySerializer($this->ecAdapter->getMath(), new PrivateKeySerializer($this->ecAdapter)); return $wifSerializer->serialize($network, $this); }
/** * @param NetworkInterface $network * @return NetworkMessage */ public function getNetworkMessage(NetworkInterface $network = null) { return new NetworkMessage($network ?: Bitcoin::getNetwork(), $this); }
<?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";