/// <summary>
/// Once a transaction has some inputs and outputs added, the signatures in the inputs can be calculated. The
/// signature is over the transaction itself, to prove the redeemer actually created that transaction,
/// so we have to do this step last.
/// </summary>
/// <remarks>
/// This method is similar to SignatureHash in script.cpp
/// </remarks>
/// <param name="hashType">This should always be set to SigHash.ALL currently. Other types are unused. </param>
/// <param name="wallet">A wallet is required to fetch the keys needed for signing.</param>
/// <exception cref="ScriptException"/>
public void SignInputs(SigHash hashType, Wallet wallet)
{
Debug.Assert(_inputs.Count > 0);
Debug.Assert(_outputs.Count > 0);
// I don't currently have an easy way to test other modes work, as the official client does not use them.
Debug.Assert(hashType == SigHash.All);
// The transaction is signed with the input scripts empty except for the input we are signing. In the case
// where addInput has been used to set up a new transaction, they are already all empty. The input being signed
// has to have the connected OUTPUT program in it when the hash is calculated!
//
// Note that each input may be claiming an output sent to a different key. So we have to look at the outputs
// to figure out which key to sign with.
var signatures = new byte[_inputs.Count][];
var signingKeys = new EcKey[_inputs.Count];
for (var i = 0; i < _inputs.Count; i++)
{
var input = _inputs[i];
Debug.Assert(input.ScriptBytes.Length == 0, "Attempting to sign a non-fresh transaction");
// Set the input to the script of its output.
input.ScriptBytes = input.Outpoint.ConnectedPubKeyScript;
// Find the signing key we'll need to use.
var connectedPubKeyHash = input.Outpoint.ConnectedPubKeyHash;
var key = wallet.FindKeyFromPubHash(connectedPubKeyHash);
// This assert should never fire. If it does, it means the wallet is inconsistent.
Debug.Assert(key != null, "Transaction exists in wallet that we cannot redeem: " + Utils.BytesToHexString(connectedPubKeyHash));
// Keep the key around for the script creation step below.
signingKeys[i] = key;
// The anyoneCanPay feature isn't used at the moment.
const bool anyoneCanPay = false;
var hash = HashTransactionForSignature(hashType, anyoneCanPay);
// Set the script to empty again for the next input.
input.ScriptBytes = TransactionInput.EmptyArray;
// Now sign for the output so we can redeem it. We use the keypair to sign the hash,
// and then put the resulting signature in the script along with the public key (below).
using (var bos = new MemoryStream())
{
bos.Write(key.Sign(hash));
bos.Write((byte) (((int) hashType + 1) | (anyoneCanPay ? 0x80 : 0)));
signatures[i] = bos.ToArray();
}
}
// Now we have calculated each signature, go through and create the scripts. Reminder: the script consists of
// a signature (over a hash of the transaction) and the complete public key needed to sign for the connected
// output.
for (var i = 0; i < _inputs.Count; i++)
{
var input = _inputs[i];
Debug.Assert(input.ScriptBytes.Length == 0);
var key = signingKeys[i];
input.ScriptBytes = Script.CreateInputScript(signatures[i], key.PubKey);
}
// Every input is now complete.
}