internal TransactionOutput(NetworkParameters @params, Transaction parent, ulong value, Address to) : base(@params) { _value = value; _scriptBytes = Script.CreateOutputScript(to); ParentTransaction = parent; _availableForSpending = true; }
internal static byte[] CreateOutputScript(Address to) { using (var bits = new MemoryStream()) { // TODO: Do this by creating a Script *first* then having the script reassemble itself into bytes. bits.Write(OpDup); bits.Write(OpHash160); WriteBytes(bits, to.Hash160); bits.Write(OpEqualVerify); bits.Write(OpCheckSig); return bits.ToArray(); } }
/// <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; } }
/// <returns>A human readable version of the transaction useful for debugging.</returns> public override string ToString() { var s = new StringBuilder(); s.Append(" "); s.Append(HashAsString); s.AppendLine(); if (IsCoinBase) { string script; string script2; try { script = _inputs[0].ScriptSig.ToString(); script2 = _outputs[0].ScriptPubKey.ToString(); } catch (ScriptException) { script = "???"; script2 = "???"; } return " == COINBASE TXN (scriptSig " + script + ") (scriptPubKey " + script2 + ")"; } foreach (var @in in _inputs) { s.Append(" "); s.Append("from "); try { s.Append(@in.ScriptSig.FromAddress.ToString()); } catch (Exception e) { s.Append("[exception: ").Append(e.Message).Append("]"); throw; } s.AppendLine(); } foreach (var @out in _outputs) { s.Append(" "); s.Append("to "); try { var toAddr = new Address(Params, @out.ScriptPubKey.PubKeyHash); s.Append(toAddr.ToString()); s.Append(" "); s.Append(Utils.BitcoinValueToFriendlyString(@out.Value)); s.Append(" BTC"); } catch (Exception e) { s.Append("[exception: ").Append(e.Message).Append("]"); } s.AppendLine(); } return s.ToString(); }
/// <summary> /// Sends coins to the given address, via the given <see cref="Peer"/>. /// Change is returned to the first key in the wallet. /// </summary> /// <param name="peer">The peer to send via.</param> /// <param name="to">Which address to send coins to.</param> /// <param name="nanocoins">How many nanocoins to send. You can use Utils.ToNanoCoins() to calculate this.</param> /// <returns>The <see cref="Transaction"/> that was created or null if there was insufficient balance to send the coins.</returns> /// <exception cref="IOException">If there was a problem broadcasting the transaction.</exception> public Transaction SendCoins(Peer peer, Address to, ulong nanocoins) { lock (this) { var tx = CreateSend(to, nanocoins); if (tx == null) // Not enough money! :-( return null; peer.BroadcastTransaction(tx); ConfirmSend(tx); return tx; } }
/// <summary> /// Statelessly creates a transaction that sends the given number of nanocoins to address. The change is sent to /// the first address in the wallet, so you must have added at least one key. /// </summary> /// <remarks> /// This method is stateless in the sense that calling it twice with the same inputs will result in two /// Transaction objects which are equal. The wallet is not updated to track its pending status or to mark the /// coins as spent until confirmSend is called on the result. /// </remarks> internal Transaction CreateSend(Address address, ulong nanocoins) { lock (this) { // For now let's just pick the first key in our keychain. In future we might want to do something else to // give the user better privacy here, eg in incognito mode. Debug.Assert(Keychain.Count > 0, "Can't send value without an address to use for receiving change"); var first = Keychain[0]; return CreateSend(address, nanocoins, first.ToAddress(_params)); } }
/// <summary> /// Sends coins to the given address, via the given <see cref="PeerGroup"/>. /// Change is returned to the first key in the wallet. /// </summary> /// <param name="peerGroup">The peer group to send via.</param> /// <param name="to">Which address to send coins to.</param> /// <param name="nanocoins">How many nanocoins to send. You can use Utils.toNanoCoins() to calculate this.</param> /// <returns> /// The <see cref="Transaction"/> that was created or null if there was insufficient balance to send the coins. /// </returns> /// <exception cref="IOException">If there was a problem broadcasting the transaction.</exception> public Transaction SendCoins(PeerGroup peerGroup, Address to, ulong nanocoins) { lock (this) { var tx = CreateSend(to, nanocoins); if (tx == null) // Not enough money! :-( return null; if (!peerGroup.BroadcastTransaction(tx)) { throw new IOException("Failed to broadcast tx to all connected peers"); } // TODO - retry logic ConfirmSend(tx); return tx; } }
internal Block CreateNextBlock(Address to) { return CreateNextBlock(to, (uint) UnixTime.ToUnixTime(DateTime.UtcNow)); }
/// <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(to); b.PrevBlockHash = Hash; b.Time = time; b.Solve(); b.Verify(); return b; }
/// <summary> /// Adds a coinbase transaction to the block. This exists for unit tests. /// </summary> internal void AddCoinbaseTransaction(Address to) { 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. The output is also different. // Real coinbase transactions use <pubkey> OP_CHECKSIG rather than a send to an address though there's // nothing in the system that enforces that and both are just as valid. coinbase.AddInput(new TransactionInput(Params, coinbase, new[] {(byte) _coinbaseCounter++})); coinbase.AddOutput(new TransactionOutput(Params, coinbase, Utils.ToNanoCoins(50, 0), to)); 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; }