예제 #1
0
 /**
  * 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());
 }