/** * @param int $type * @param Buffer $hash */ public function __construct($type, Buffer $hash) { if (false === $this->checkType($type)) { throw new \InvalidArgumentException('Invalid type in InventoryVector'); } if (false === (32 === $hash->getSize())) { throw new \InvalidArgumentException('Hash size must be 32 bytes'); } $this->type = $type; $this->hash = $hash; }
/** * @param int|string $version * @param Buffer $prevBlock * @param Buffer $merkleRoot * @param int|string $timestamp * @param Buffer $bits * @param int|string $nonce */ public function __construct($version, Buffer $prevBlock, Buffer $merkleRoot, $timestamp, Buffer $bits, $nonce) { if (!is_numeric($version)) { throw new \InvalidArgumentException('Block header version must be numeric'); } if ($prevBlock->getSize() !== 32) { throw new \InvalidArgumentException('Block header prevBlock must be a 32-byte Buffer'); } if ($merkleRoot->getSize() !== 32) { throw new \InvalidArgumentException('Block header prevBlock must be a 32-byte Buffer'); } if (!is_numeric($timestamp)) { throw new \InvalidArgumentException('Block header timestamp must be numeric'); } if (!is_numeric($nonce)) { throw new \InvalidArgumentException('Block header nonce must be numeric'); } $this->version = $version; $this->prevBlock = $prevBlock; $this->merkleRoot = $merkleRoot; $this->timestamp = $timestamp; $this->bits = $bits; $this->nonce = $nonce; $this->initFunctionAlias('version', 'getVersion')->initFunctionAlias('prevBlock', 'getPrevBlock')->initFunctionAlias('merkleRoot', 'getMerkleRoot')->initFunctionAlias('timestamp', 'getTimestamp')->initFunctionAlias('bits', 'getBits')->initFunctionAlias('nonce', 'getNonce'); }
/** * @param Buffer $ip * @return string * @throws \Exception */ private function parseIpBuffer(Buffer $ip) { $end = $ip->slice(12, 4); return implode(".", array_map(function ($int) { return unpack("C", $int)[1]; }, str_split($end->getBinary(), 1))); }
/** * @param Buffer $bits * @return array */ public function unpackCompact(Buffer $bits) { $bitStr = $bits->getBinary(); // Unpack and decode $sci = array_map(function ($value) { return $this->hexDec($value); }, unpack('H2exp/H6mul', $bitStr)); return $sci; }
/** * OutPoint constructor. * @param Buffer $hashPrevOutput * @param int $nPrevOutput */ public function __construct(Buffer $hashPrevOutput, $nPrevOutput) { if ($hashPrevOutput->getSize() !== 32) { throw new \InvalidArgumentException('OutPoint: hashPrevOut must be a 32-byte Buffer'); } if (!is_numeric($nPrevOutput)) { throw new \InvalidArgumentException('OutPoint: nPrevOut must be numeric'); } $this->hashPrevOutput = $hashPrevOutput; $this->nPrevOutput = $nPrevOutput; $this->initFunctionAlias('txid', 'getTxId')->initFunctionAlias('vout', 'getVout'); }
/** * @param Buffer $hash * @param int|string $nBits * @return bool */ public function check(Buffer $hash, $nBits) { $negative = false; $overflow = false; $target = $this->math->writeCompact($nBits, $negative, $overflow); if ($negative || $overflow || $this->math->cmp($target, 0) === 0 || $this->math->cmp($target, $this->getMaxTarget()) > 0) { throw new \RuntimeException('nBits below minimum work'); } if ($this->math->cmp($hash->getInt(), $target) > 0) { throw new \RuntimeException("Hash doesn't match nBits"); } return true; }
/** * Generate a master private key given a * @param Buffer $seed * @param EcAdapterInterface $ecAdapter * @return ElectrumKey */ public static function generateMasterKey(Buffer $seed, EcAdapterInterface $ecAdapter = null) { // Really weird, did electrum actually hash hex string seeds? $seed = $oldseed = $seed->getHex(); // Perform sha256 hash 5 times per iteration for ($i = 0; $i < 5 * 20000; $i++) { // Hash should return binary data $seed = hash('sha256', $seed . $oldseed, true); } // Convert binary data to hex. $str = new Buffer($seed); return self::fromSecretExponent($str->getInt(), $ecAdapter ?: Bitcoin::getEcAdapter()); }
/** * @param Buffer $entropy * @return array */ public function entropyToWords(Buffer $entropy) { $math = $this->ecAdapter->getMath(); $ENT = $entropy->getSize() * 8; $CS = $ENT / 32; $entBits = $math->baseConvert($entropy->getHex(), 16, 2); $csBits = $this->calculateChecksum($entropy, $CS); $bits = str_pad($entBits . $csBits, $ENT + $CS, '0', STR_PAD_LEFT); $result = []; foreach (str_split($bits, 11) as $bit) { $idx = $math->baseConvert($bit, 2, 10); $result[] = $this->wordList->getWord($idx); } return $result; }
/** * @param string $hex * @param bool $compressed * @param EcAdapterInterface|null $ecAdapter * @return PrivateKey */ public static function fromHex($hex, $compressed = false, EcAdapterInterface $ecAdapter = null) { $hex = Buffer::hex($hex); $ecAdapter = $ecAdapter ?: Bitcoin::getEcAdapter(); $hexSerializer = new HexPrivateKeySerializer($ecAdapter); return $hexSerializer->parse($hex)->setCompressed($compressed); }
public function testPeer() { $localhost = '127.0.0.1'; $localport = '8333'; $remotehost = '127.0.0.1'; $remoteport = '9999'; $loop = new StreamSelectLoop(); $dnsResolverFactory = new \React\Dns\Resolver\Factory(); $dns = $dnsResolverFactory->createCached('8.8.8.8', $loop); $reactServer = new Server($loop); $network = Bitcoin::getDefaultNetwork(); $client = new NetworkAddress(Buffer::hex('0000000000000001'), $localhost, $localport); $server = new NetworkAddress(Buffer::hex('0000000000000001'), $remotehost, $remoteport); $msgs = new Factory($network, new Random()); $serverReceivedConnection = false; $serverListener = new Listener($server, $msgs, $reactServer, $loop); $serverListener->on('connection', function (Peer $peer) use(&$serverReceivedConnection, &$serverListener) { $peer->close(); $serverReceivedConnection = true; }); $serverListener->listen($server->getPort()); $connector = new Connector($loop, $dns); $clientConnection = new Peer($client, $msgs, $loop); $clientConnection->connect($connector, $server)->then(function (Peer $peer) use($serverListener, &$loop) { $peer->close(); $serverListener->close(); }); $loop->run(); $this->assertTrue($serverReceivedConnection); }
/** * Composes a send transaction * @param string $asset A counterparty asset name or BTC * @param mixed $quantity Quantity of asset to send. Accepts a float or a Tokenly\CounterpartyTransactionComposer\Quantity or Tokenly\CryptoQuantity\CryptoQuantity object. Use a Quantity object for indivisible assets. * @param mixed $destination A single destination bitcoin address. For BTC sends an array of [[address, amount], [address, amount]] is also allowed. Amounts should be float values. * @param string $private_key_wif The private key in ASCII WIF format. This can be null to compose an unsigned transaction. * @param array $utxos An array of UTXOs. Each UTXO should be ['txid' => txid, 'n' => n, 'amount' => amount (in satoshis), 'script' => script hexadecimal string] * @param mixed $change_address_collection a single address string to receive all change. Or an array of [[address, amount], [address, amount], [address]]. Amounts should be float values. An address with no amount for the last entry will send the remaining change to that address. * @param float $fee A fee * @param float $btc_dust Amount of BTC dust to send with the Counterparty transaction. * @return Array returns a ComposedTransaction object */ public function composeSend($asset, $quantity, $destination, $private_key_wif, $utxos, $change_address_collection = null, $fee = null, $btc_dust = null) { if ($asset == 'BTC') { return $this->composeBTCSend($quantity, $destination, $private_key_wif, $utxos, $change_address_collection, $fee); } $fee_satoshis = $fee === null ? self::DEFAULT_FEE : intval(round($fee * self::SATOSHI)); $btc_dust_satoshis = $btc_dust === null ? self::DEFAULT_BTC_DUST : intval(round($btc_dust * self::SATOSHI)); // get total and change amount $change_amounts = $this->calculateAndValidateChange($utxos, $btc_dust_satoshis, $fee_satoshis, $change_address_collection); $tx_builder = TransactionFactory::build(); // add the UTXO inputs $transaction_outputs = $this->addInputsAndReturnPreviousOutputs($utxos, $tx_builder); // pay the btc_dust to the destination if (is_array($destination)) { throw new Exception("Multiple destinations are not supported for counterparty sends", 1); } $tx_builder->payToAddress($btc_dust_satoshis, AddressFactory::fromString($destination)); // build the OP_RETURN script $op_return_builder = new OpReturnBuilder(); $op_return = $op_return_builder->buildOpReturn($quantity, $asset, $utxos[0]['txid']); $script = ScriptFactory::create()->op('OP_RETURN')->push(Buffer::hex($op_return, 28))->getScript(); $tx_builder->output(0, $script); // pay the change to self $this->payChange($change_amounts, $tx_builder); // sign if ($private_key_wif !== null) { $signed_transaction = $this->signTx($private_key_wif, $tx_builder, $transaction_outputs); return $this->buildReturnValuesFromTransactionAndInputs($signed_transaction, $utxos, true); } return $this->buildReturnValuesFromTransactionAndInputs($tx_builder->get(), $utxos, false); }
public function __construct() { parent::__construct(function () { $consensus = new ConsensusFactory(Bitcoin::getEcAdapter()); $loop = LoopFactory::create(); $context = new ZmqContext($loop); $control = $context->getSocket(\ZMQ::SOCKET_SUB); $control->connect('tcp://127.0.0.1:5594'); $control->subscribe('control'); $control->on('messages', function ($msg) use($loop) { if ($msg[1] == 'shutdown') { $loop->stop(); } }); $results = $context->getSocket(\ZMQ::SOCKET_PUSH); $results->connect("tcp://127.0.0.1:5593"); $workers = $context->getSocket(\ZMQ::SOCKET_PULL); $workers->connect('tcp://127.0.0.1:5592'); $workers->on('message', function ($message) use($consensus, $results) { $details = json_decode($message, true); $txid = $details['txid']; $flags = $details['flags']; $vin = $details['vin']; $scriptPubKey = new Script(Buffer::hex($details['scriptPubKey'])); $tx = TransactionFactory::fromHex($details['tx']); $results->send(json_encode(['txid' => $txid, 'vin' => $vin, 'result' => $consensus->getConsensus(new Flags($flags))->verify($tx, $scriptPubKey, $vin)])); }); $loop->run(); exit(0); }); }
/** * Connect to $numSeeds DNS seeds * * @param int $numSeeds * @return \React\Promise\Promise|\React\Promise\PromiseInterface */ public function queryDnsSeeds($numSeeds = 1) { $peerList = new Deferred(); // Take $numSeeds $seedHosts = self::dnsSeedHosts(); $seeds = array_slice($seedHosts, 0, min($numSeeds, count($seedHosts))); // Connect to $numSeeds peers /** @var Peer[] $vNetAddr */ $vNetAddr = []; foreach ($seeds as $seed) { echo " [ query DNS seed: " . $seed . " ] \n"; $this->dns->resolve($seed)->then(function ($ipList) use(&$vNetAddr, $peerList, &$numSeeds) { $vNetAddr[] = $ipList; if (count($vNetAddr) == $numSeeds) { $peerList->resolve($vNetAddr); } }); } // Compile the list of lists of peers into $this->knownAddresses return $peerList->promise()->then(function (array $vPeerVAddrs) { shuffle($vPeerVAddrs); /** @var NetworkAddressInterface[] $addresses */ $addresses = []; array_map(function (array $value) use(&$addresses) { foreach ($value as $ip) { $addresses[] = new NetworkAddress(Buffer::hex('01', 8), $ip, 8333); } }, $vPeerVAddrs); $this->knownAddresses = array_merge($this->knownAddresses, $addresses); return $this; }); }
public function testMethods() { $loop = new \React\EventLoop\StreamSelectLoop(); $dns = (new \BitWasp\Bitcoin\Networking\Dns\Factory())->create('8.8.8.8', $loop); $network = Bitcoin::getDefaultNetwork(); $random = new Random(); $messages = new \BitWasp\Bitcoin\Networking\Messages\Factory($network, $random); $factory = new Factory($dns, $messages, $loop); $this->assertInstanceOf($this->peerType, $factory->getPeer()); $services = Buffer::hex('00', 8); $address = $factory->getAddress('127.0.0.1', 8332, $services); $this->assertInstanceOf($this->addrType, $address); $connector = $factory->getConnector(); $this->assertInstanceOf($this->connType, $connector); $server = $factory->getServer(); $this->assertInstanceOf($this->serverType, $server); $locator = $factory->getLocator(); $this->assertInstanceOf($this->locatorType, $locator); $listener = $factory->getListener($server); $this->assertInstanceOf($this->listenerType, $listener); $handler = $factory->getPacketHandler(); $this->assertInstanceOf($this->handlerType, $handler); $manager = $factory->getManager(); $this->assertInstanceOf($this->managerType, $manager); }
/** * @param \BitWasp\Buffertools\Buffer $sig * @return bool * @throws SignatureNotCanonical */ public static function isDERSignature(Buffer $sig) { $checkVal = function ($fieldName, $start, $length, $binaryString) { if ($length == 0) { throw new SignatureNotCanonical('Signature ' . $fieldName . ' length is zero'); } $typePrefix = ord(substr($binaryString, $start - 2, 1)); if ($typePrefix !== 0x2) { throw new SignatureNotCanonical('Signature ' . $fieldName . ' value type mismatch'); } $val = substr($binaryString, $start, $length); $vAnd = $val[0] & pack("H*", '80'); if (ord($vAnd) === 128) { throw new SignatureNotCanonical('Signature ' . $fieldName . ' value is negative'); } if ($length > 1 && ord($val[0]) == 0x0 && !ord($val[1] & pack('H*', '80'))) { throw new SignatureNotCanonical('Signature ' . $fieldName . ' value excessively padded'); } }; $bin = $sig->getBinary(); $size = $sig->getSize(); if ($size < 9) { throw new SignatureNotCanonical('Signature too short'); } if ($size > 73) { throw new SignatureNotCanonical('Signature too long'); } if (ord($bin[0]) !== 0x30) { throw new SignatureNotCanonical('Signature has wrong type'); } if (ord($bin[1]) !== $size - 3) { throw new SignatureNotCanonical('Signature has wrong length marker'); } $lenR = ord($bin[3]); $startR = 4; if (5 + $lenR >= $size) { throw new SignatureNotCanonical('Signature S length misplaced'); } $lenS = ord($bin[5 + $lenR]); $startS = 4 + $lenR + 2; if ($lenR + $lenS + 7 !== $size) { throw new SignatureNotCanonical('Signature R+S length mismatch'); } $checkVal('R', $startR, $lenR, $bin); $checkVal('S', $startS, $lenS, $bin); return true; }
/** * @param Parser $parser * @return Buffer * @throws \BitWasp\Buffertools\Exceptions\ParserOutOfRange */ public function read(Parser &$parser) { $bits = $this->readBits($parser->readBytes($this->length)); if (!$this->isBigEndian()) { $bits = $this->flipBits($bits); } return Buffer::hex(str_pad($this->getMath()->baseConvert($bits, 2, 16), $this->length * 2, '0', STR_PAD_LEFT), $this->length, $this->getMath()); }
/** * @param $hex * @return PublicKey * @throws \Exception */ public function parse($hex) { $hex = Buffer::hex($hex); if (!in_array($hex->getSize(), [PublicKey::LENGTH_COMPRESSED, PublicKey::LENGTH_UNCOMPRESSED])) { throw new \Exception('Invalid hex string, must match size of compressed or uncompressed public key'); } return $this->ecAdapter->publicKeyFromBuffer($hex); }
/** * @param NodeInterface $node * @param array $params * @return array */ public function execute(NodeInterface $node, array $params) { if (strlen($params[self::PARAM_HASH]) !== 64) { throw new \RuntimeException('Invalid hash'); } $index = $node->chain()->fetchIndex(Buffer::hex($params[self::PARAM_HASH])); return ['header' => $this->convertIndexToArray($index)]; }
/** * @return \BitWasp\Bitcoin\Block\BlockInterface */ public function getGenesisBlock() { $timestamp = new Buffer('The Times 03/Jan/2009 Chancellor on brink of second bailout for banks', null, $this->math); $publicKey = Buffer::hex('04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f', null, $this->math); $inputScript = ScriptFactory::sequence([Buffer::int('486604799', 4, $this->math)->flip(), Buffer::int('4', null, $this->math), $timestamp]); $outputScript = ScriptFactory::sequence([$publicKey, Opcodes::OP_CHECKSIG]); return new Block($this->math, $this->getGenesisBlockHeader(), new TransactionCollection([(new TxBuilder())->version('1')->input(new Buffer('', 32), 4294967295.0, $inputScript)->output(5000000000.0, $outputScript)->locktime(0)->get()])); }
/** * @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); }
/** * @param NetworkInterface $network * @param PrivateKeyInterface $privateKey * @return string */ public function serialize(NetworkInterface $network, PrivateKeyInterface $privateKey) { $serialized = Buffertools::concat(Buffer::hex($network->getPrivByte()), $this->hexSerializer->serialize($privateKey)); if ($privateKey->isCompressed()) { $serialized = Buffertools::concat($serialized, new Buffer("", 1)); } return Base58::encodeCheck($serialized); }
public function testHashIsSerializedInReverseOrder() { $buffer = Buffer::hex('0001020300010203000102030001020300010203000102030001020300010203'); $inv = Inventory::block($buffer); $results = unpack("Vtype/H64hash", $inv->getBinary()); $parsedBuffer = Buffer::hex($results['hash']); $this->assertEquals($buffer->getHex(), Buffertools::flipBytes($parsedBuffer)->getHex()); }
/** * @param BlockInterface $block * @return \BitWasp\Buffertools\BufferInterface */ public function serialize(BlockInterface $block) { $buffer = $block->getBuffer(); $size = $buffer->getSize(); $data = new Parser($this->getHeaderTemplate()->write([Buffer::hex($this->network->getNetMagicBytes()), $size])); $data->writeBytes($size, $buffer); return $data->getBuffer(); }
/** * @param TransactionSignature $txSig * @return \BitWasp\Buffertools\Buffer */ public function serialize(TransactionSignature $txSig) { $sig = $this->sigSerializer->serialize($txSig->getSignature()); $parser = new Parser($sig->getHex()); $parser->writeBytes(1, Buffer::int($txSig->getHashType(), 1)); $buffer = $parser->getBuffer(); return $buffer; }
/** * @param $opCode * @param ScriptStack $mainStack * @throws \BitWasp\Bitcoin\Exceptions\ScriptStackException * @throws \Exception */ private function twoValueCases($opCode, ScriptStack $mainStack) { if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation (greater than)'); } $num1 = $mainStack->top(-2)->getInt(); // cscriptnum $num2 = $mainStack->top(-1)->getInt(); $opCodes = $this->opCodes; $opName = $opCodes->getOp($opCode); $math = $this->math; $castToBool = $this->castToBool; if ($opName == 'OP_ADD') { $num = $math->add($num1, $num2); } elseif ($opName == 'OP_SUB') { // cscriptnum $num = $math->sub($num1, $num2); } elseif ($opName == 'OP_BOOLAND') { // cscriptnum $num = $math->cmp($num1, $this->_bn0->getInt()) !== 0 && $math->cmp($num2, $this->_bn0->getInt()) !== 0; } elseif ($opName == 'OP_BOOLOR') { $num = $math->cmp($num1, $this->_bn0->getInt()) !== 0 || $math->cmp($num2, $this->_bn0->getInt()) !== 0; } elseif ($opName == 'OP_NUMEQUAL') { // cscriptnum $num = $math->cmp($num1, $num2) == 0; } elseif ($opName == 'OP_NUMEQUALVERIFY') { // cscriptnum $num = $math->cmp($num1, $num2) == 0; } elseif ($opName == 'OP_NUMNOTEQUAL') { $num = $math->cmp($num1, $num2) !== 0; } elseif ($opName == 'OP_LESSTHAN') { // cscriptnum $num = $math->cmp($num1, $num2) < 0; } elseif ($opName == 'OP_GREATERTHAN') { $num = $math->cmp($num1, $num2) > 0; } elseif ($opName == 'OP_LESSTHANOREQUAL') { // cscriptnum $num = $math->cmp($num1, $num2) <= 0; } elseif ($opName == 'OP_GREATERTHANOREQUAL') { $num = $math->cmp($num1, $num2) >= 0; } elseif ($opName == 'OP_MIN') { $num = $math->cmp($num1, $num2) <= 0 ? $num1 : $num2; } else { // is OP_MAX $num = $math->cmp($num1, $num2) >= 0 ? $num1 : $num2; } $mainStack->pop(); $mainStack->pop(); $buffer = Buffer::hex($math->decHex($num)); $mainStack->push($buffer); if ($opCodes->isOp($opCode, 'OP_NUMEQUALVERIFY')) { if ($castToBool($mainStack->top(-1))) { $mainStack->pop(); } else { throw new \Exception('NUM EQUAL VERIFY error'); } } }
/** * 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 NodeInterface $node * @param array $params * @return array */ public function execute(NodeInterface $node, array $params) { if (strlen($params[self::PARAM_TXID]) !== 64) { throw new \RuntimeException('Invalid txid field'); } $txid = Buffer::hex($params[self::PARAM_TXID], 32); $tx = $node->chain()->fetchTransaction($node->transactions(), $txid); return ['tx' => $this->convertTransactionToArray($tx)]; }
public function testNetworkSerializer() { $net = Bitcoin::getDefaultNetwork(); $factory = new Factory($net, new Random()); $inv = $factory->inv([new Inventory(Inventory::MSG_BLOCK, Buffer::hex('4141414141414141414141414141414141414141414141414141414141414141'))]); $serialized = $inv->getNetworkMessage()->getBuffer(); $parsed = $factory->parse(new Parser($serialized))->getPayload(); $this->assertEquals($inv, $parsed); }
public function testNetworkSerializer() { $array = [new Inventory(Inventory::MSG_TX, Buffer::hex('4141414141414141414141414141414141414141414141414141414141414141')), new Inventory(Inventory::MSG_TX, Buffer::hex('4141414141414141414141414141414141414141414141414141414141414142')), new Inventory(Inventory::MSG_TX, Buffer::hex('4141414141414141414141414141414141414141414141414141414141414143'))]; $not = new NotFound($array); $serializer = new NetworkMessageSerializer(Bitcoin::getDefaultNetwork()); $serialized = $not->getNetworkMessage()->getBuffer(); $parsed = $serializer->parse($serialized)->getPayload(); $this->assertEquals($not, $parsed); }
/** * @param BloomFilter $filter * @return BufferInterface */ public function serialize(BloomFilter $filter) { $math = new Math(); $vBuf = []; foreach ($filter->getData() as $i) { $vBuf[] = Buffer::int($i, 1, $math); } return $this->getTemplate()->write([$vBuf, $filter->getNumHashFuncs(), $filter->getTweak(), (string) $filter->getFlags()]); }