/**
  * Serializes the transaction for use in a signature
  *
  * @param index Current transaction index
  * @param sigHashType Signature hash type
  * @param subScriptBytes Replacement script for the current input
  * @param outBuffer Output buffer
  * @throws ScriptException Transaction index out-of-range
  */
 public final void serializeForSignature(
     int index, int sigHashType, byte[] subScriptBytes, SerializedBuffer outBuffer)
     throws ScriptException {
   int hashType;
   boolean anyoneCanPay;
   //
   // The transaction input must be within range
   //
   if (index < 0 || index >= txInputs.size())
     throw new ScriptException("Transaction input index is not valid");
   //
   // Check for a valid hash type
   //
   // Note that SIGHASH_ANYONE_CAN_PAY is or'ed with one of the other hash types.  So we need
   // to remove it when checking for a valid signature.
   //
   // SIGHASH_ALL:    This is the default. It indicates that everything about the transaction is
   // signed
   //                 except for the input scripts. Signing the input scripts as well would
   // obviously make
   //                 it impossible to construct a transaction.
   // SIGHASH_NONE:   The outputs are not signed and can be anything. This mode allows others to
   // update
   //                 the transaction by changing their inputs sequence numbers.  This means that
   // all
   //                 input sequence numbers are set to 0 except for the current input.
   // SIGHASH_SINGLE: Outputs up to and including the current input index number are included.
   // Outputs
   //                 before the current index have a -1 value and an empty script.  All input
   // sequence
   //                 numbers are set to 0 except for the current input.
   //
   // The SIGHASH_ANYONE_CAN_PAY modifier can be combined with the above three modes. When set,
   // only that
   // input is signed and the other inputs can be anything.
   //
   // In all cases, the script for the current input is replaced with the script from the connected
   // output.  All other input scripts are set to an empty script.
   //
   // The reference client accepts an invalid hash types and treats it as SIGHASH_ALL.  So we need
   // to
   // do the same.
   //
   anyoneCanPay = ((sigHashType & ScriptOpCodes.SIGHASH_ANYONE_CAN_PAY) != 0);
   hashType = sigHashType & (255 - ScriptOpCodes.SIGHASH_ANYONE_CAN_PAY);
   if (hashType != ScriptOpCodes.SIGHASH_ALL
       && hashType != ScriptOpCodes.SIGHASH_NONE
       && hashType != ScriptOpCodes.SIGHASH_SINGLE) hashType = ScriptOpCodes.SIGHASH_ALL;
   //
   // Serialize the version
   //
   outBuffer.putInt(txVersion);
   //
   // Serialize the inputs
   //
   // For SIGHASH_ANYONE_CAN_PAY, only the current input is included in the signature.
   // Otherwise, all inputs are included.
   //
   List<TransactionInput> sigInputs;
   if (anyoneCanPay) {
     sigInputs = new ArrayList<>(1);
     sigInputs.add(txInputs.get(index));
   } else {
     sigInputs = txInputs;
   }
   outBuffer.putVarInt(sigInputs.size());
   byte[] emptyScriptBytes = new byte[0];
   for (TransactionInput txInput : sigInputs)
     txInput.serializeForSignature(
         index,
         hashType,
         (txInput.getIndex() == index ? subScriptBytes : emptyScriptBytes),
         outBuffer);
   //
   // Serialize the outputs
   //
   if (hashType == ScriptOpCodes.SIGHASH_NONE) {
     //
     // There are no outputs for SIGHASH_NONE
     //
     outBuffer.putVarInt(0);
   } else if (hashType == ScriptOpCodes.SIGHASH_SINGLE) {
     //
     // The output list is resized to the input index+1
     //
     if (txOutputs.size() <= index)
       throw new ScriptException("Input index out-of-range for SIGHASH_SINGLE");
     outBuffer.putVarInt(index + 1);
     for (TransactionOutput txOutput : txOutputs) {
       if (txOutput.getIndex() > index) break;
       txOutput.serializeForSignature(index, hashType, outBuffer);
     }
   } else {
     //
     // All outputs are serialized for SIGHASH_ALL
     //
     outBuffer.putVarInt(txOutputs.size());
     for (TransactionOutput txOutput : txOutputs)
       txOutput.serializeForSignature(index, hashType, outBuffer);
   }
   //
   // Serialize the lock time
   //
   outBuffer.putUnsignedInt(txLockTime);
 }