/// <summary> /// Creates a transaction that sends $coins.$cents BTC to the given address. /// </summary> /// <remarks> /// IMPORTANT: This method does NOT update the wallet. If you call createSend again you may get two transactions /// that spend the same coins. You have to call confirmSend on the created transaction to prevent this, /// but that should only occur once the transaction has been accepted by the network. This implies you cannot have /// more than one outstanding sending tx at once. /// </remarks> /// <param name="address">The BitCoin address to send the money to.</param> /// <param name="nanocoins">How much currency to send, in nanocoins.</param> /// <param name="changeAddress"> /// Which address to send the change to, in case we can't make exactly the right value from /// our coins. This should be an address we own (is in the keychain). /// </param> /// <returns> /// A new <see cref="Transaction"/> or null if we cannot afford this send. /// </returns> 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; } }
/// <summary> /// Adds a coinbase transaction to the block. This exists for unit tests. /// </summary> internal void AddCoinbaseTransaction(byte[] pubKeyTo) { Transactions = new List<Transaction>(); var coinbase = new Transaction(Params); // A real coinbase transaction has some stuff in the scriptSig like the extraNonce and difficulty. The // transactions are distinguished by every TX output going to a different key. // // Here we will do things a bit differently so a new address isn't needed every time. We'll put a simple // counter in the scriptSig so every transaction has a different hash. coinbase.AddInput(new TransactionInput(Params, coinbase, new[] {(byte) _txCounter++})); coinbase.AddOutput(new TransactionOutput(Params, coinbase, Script.CreateOutputScript(pubKeyTo))); Transactions.Add(coinbase); }
/// <summary> /// Returns a solved block that builds on top of this one. This exists for unit tests. /// </summary> internal Block CreateNextBlock(Address to, uint time) { var b = new Block(Params); b.DifficultyTarget = _difficultyTarget; b.AddCoinbaseTransaction(_emptyBytes); // Add a transaction paying 50 coins to the "to" address. var t = new Transaction(Params); t.AddOutput(new TransactionOutput(Params, t, Utils.ToNanoCoins(50, 0), to)); // The input does not really need to be a valid signature, as long as it has the right general form. var input = new TransactionInput(Params, t, Script.CreateInputScript(_emptyBytes, _emptyBytes)); // Importantly the outpoint hash cannot be zero as that's how we detect a coinbase transaction in isolation // but it must be unique to avoid 'different' transactions looking the same. var counter = new byte[32]; counter[0] = (byte) _txCounter++; input.Outpoint.Hash = new Sha256Hash(counter); t.AddInput(input); b.AddTransaction(t); b.PrevBlockHash = Hash; b.TimeSeconds = time; b.Solve(); b.VerifyHeader(); return b; }
private static Block CreateGenesis(NetworkParameters n) { var genesisBlock = new Block(n); var t = new Transaction(n); // A script containing the difficulty bits and the following message: // // "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks" var bytes = Hex.Decode("04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73"); t.AddInput(new TransactionInput(n, t, bytes)); using (var scriptPubKeyBytes = new MemoryStream()) { Script.WriteBytes(scriptPubKeyBytes, Hex.Decode("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f")); scriptPubKeyBytes.Write(Script.OpCheckSig); t.AddOutput(new TransactionOutput(n, t, scriptPubKeyBytes.ToArray())); } genesisBlock.AddTransaction(t); return genesisBlock; }