Beispiel #1
14
 /**
  * @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;
 }
Beispiel #2
0
 /**
  * @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)));
 }
Beispiel #4
0
 /**
  * @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;
 }
Beispiel #5
0
 /**
  * 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');
 }
Beispiel #6
0
 /**
  * @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);
 }
Beispiel #10
0
 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);
     });
 }
Beispiel #13
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;
     });
 }
Beispiel #14
0
 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);
 }
Beispiel #18
0
 /**
  * @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)];
 }
Beispiel #19
0
 /**
  * @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());
 }
Beispiel #27
0
 /**
  * @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)];
 }
Beispiel #28
0
 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()]);
 }