/** * 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) { $sighashType = (int) $sighashType; $hashPrevOuts = $this->hashPrevOuts($sighashType); $hashSequence = $this->hashSequences($sighashType); $hashOutputs = $this->hashOutputs($sighashType, $inputToSign); $input = $this->transaction->getInput($inputToSign); return Hash::sha256d(new Buffer(pack("V", $this->transaction->getVersion()) . $hashPrevOuts->getBinary() . $hashSequence->getBinary() . $input->getOutPoint()->getBinary() . ScriptFactory::create()->push($txOutScript->getBuffer())->getScript()->getBinary() . Buffer::int($this->amount, 8)->flip()->getBinary() . pack("V", $input->getSequence()) . $hashOutputs->getBinary() . pack("V", $this->transaction->getLockTime()) . pack("V", $sighashType))); }
/** * @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 \BitWasp\Bitcoin\Script\Interpreter\Number $sequence * @return bool */ public function checkSequence(\BitWasp\Bitcoin\Script\Interpreter\Number $sequence) { $math = $this->adapter->getMath(); $txSequence = $this->transaction->getInput($this->nInput)->getSequence(); if ($this->transaction->getVersion() < 2) { return false; } if ($math->cmp($math->bitwiseAnd($txSequence, TransactionInputInterface::SEQUENCE_LOCKTIME_DISABLE_FLAG), 0) !== 0) { return 0; } $mask = $math->bitwiseOr(TransactionInputInterface::SEQUENCE_LOCKTIME_TYPE_FLAG, TransactionInputInterface::SEQUENCE_LOCKTIME_MASK); return $this->verifyLockTime($math->bitwiseAnd($txSequence, $mask), TransactionInputInterface::SEQUENCE_LOCKTIME_TYPE_FLAG, Number::int($math->bitwiseAnd($sequence->getInt(), $mask))); }
/** * @param TransactionInterface $transaction * @return string */ public function serialize(TransactionInterface $transaction) { return $this->getTemplate()->write([$transaction->getVersion(), $transaction->getInputs()->getInputs(), $transaction->getOutputs()->getOutputs(), $transaction->getLockTime()]); }
/** * @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); }
/** * @param TransactionInterface $transaction * @return array */ public function convertTransactionToArray(TransactionInterface $transaction) { $inputs = []; foreach ($transaction->getInputs() as $input) { $inputs[] = $this->convertTxinToArray($input); } $outputs = []; foreach ($transaction->getOutputs() as $output) { $outputs[] = $this->convertTxoutToArray($output); } $buf = $transaction->getBuffer()->getBinary(); return ['hash' => $transaction->getTxId()->getHex(), 'version' => $transaction->getVersion(), 'inputs' => $inputs, 'outputs' => $outputs, 'locktime' => $transaction->getLockTime(), 'raw' => bin2hex($buf), 'size' => strlen($buf)]; }
/** * @param TransactionInterface $tx * @return Transaction */ public function fixTransaction(Peer $sender, TransactionInterface $tx, &$wasMalleated = false) { $c = count($tx->getInputs()); $new = new TransactionInputCollection(); for ($i = 0; $i < $c; $i++) { $input = $tx->getInput($i); $script = $input->getScript(); $classify = ScriptFactory::scriptSig()->classify($input->getScript()); $this->inputs++; if ($classify->isPayToPublicKeyHash()) { $parsed = $input->getScript()->getScriptParser()->parse(); $txSig = TransactionSignatureFactory::fromHex($parsed[0]); $txSig = $this->fixSig($sender, $txSig, $wasMalleated); $script = ScriptFactory::create()->push($txSig->getBuffer())->push($parsed[1])->getScript(); } $new->addInput(new TransactionInput($input->getTransactionId(), $input->getVout(), $script, $input->getSequence())); } return new Transaction($tx->getVersion(), $new, $tx->getOutputs(), $tx->getLockTime()); }
/** * @param array $array * @return $this */ private function replace(array $array = []) { $this->transaction = new Transaction(array_key_exists('version', $array) ? $array['version'] : $this->transaction->getVersion(), array_key_exists('inputs', $array) ? $array['inputs'] : $this->transaction->getInputs(), array_key_exists('outputs', $array) ? $array['outputs'] : $this->transaction->getOutputs(), array_key_exists('witness', $array) ? $array['witness'] : $this->transaction->getWitnesses(), array_key_exists('nLockTime', $array) ? $array['nLockTime'] : $this->transaction->getLockTime()); return $this; }