internal Transaction CreateSend(Address address, ulong nanocoins, Address changeAddress)
{
lock (this)
{
_log.Info("Creating send tx to " + address + " for " +
Utils.BitcoinValueToFriendlyString(nanocoins));
// To send money to somebody else, we need to do gather up transactions with unspent outputs until we have
// sufficient value. Many coin selection algorithms are possible, we use a simple but suboptimal one.
// TODO: Sort coins so we use the smallest first, to combat wallet fragmentation and reduce fees.
var valueGathered = 0UL;
var gathered = new LinkedList<TransactionOutput>();
foreach (var tx in Unspent.Values)
{
foreach (var output in tx.Outputs)
{
if (!output.IsAvailableForSpending) continue;
if (!output.IsMine(this)) continue;
gathered.AddLast(output);
valueGathered += output.Value;
}
if (valueGathered >= nanocoins) break;
}
// Can we afford this?
if (valueGathered < nanocoins)
{
_log.Info("Insufficient value in wallet for send, missing " +
Utils.BitcoinValueToFriendlyString(nanocoins - valueGathered));
// TODO: Should throw an exception here.
return null;
}
Debug.Assert(gathered.Count > 0);
var sendTx = new Transaction(_params);
sendTx.AddOutput(new TransactionOutput(_params, sendTx, nanocoins, address));
var change = (long) (valueGathered - nanocoins);
if (change > 0)
{
// The value of the inputs is greater than what we want to send. Just like in real life then,
// we need to take back some coins ... this is called "change". Add another output that sends the change
// back to us.
_log.Info(" with " + Utils.BitcoinValueToFriendlyString((ulong) change) + " coins change");
sendTx.AddOutput(new TransactionOutput(_params, sendTx, (ulong) change, changeAddress));
}
foreach (var output in gathered)
{
sendTx.AddInput(output);
}
// Now sign the inputs, thus proving that we are entitled to redeem the connected outputs.
sendTx.SignInputs(Transaction.SigHash.All, this);
_log.InfoFormat(" created {0}", sendTx.HashAsString);
return sendTx;
}
}