/// <summary> /// Deserializes a transaction output message. This is usually part of a transaction message. /// </summary> /// <exception cref="ProtocolException"/> public TransactionOutput(NetworkParameters networkParameters, Transaction parentTransaction, byte[] payload, int offset) : base(networkParameters, payload, offset) { ParentTransaction = parentTransaction; _availableForSpending = true; }
/// <summary> /// Used only in creation of the genesis block. /// </summary> internal TransactionInput(NetworkParameters networkParameters, Transaction parentTransaction, byte[] scriptBytes) : base(networkParameters) { ScriptBytes = scriptBytes; Outpoint = new TransactionOutPoint(networkParameters, -1, null); _sequence = uint.MaxValue; ParentTransaction = parentTransaction; }
public TransactionOutput(NetworkParameters networkParameters, Transaction parentTransaction, ulong value, Address to) : base(networkParameters) { Value = value; _scriptBytes = Script.CreateOutputScript(to); ParentTransaction = parentTransaction; _availableForSpending = true; }
public static Transaction CreateFakeTx(NetworkParameters @params, ulong nanocoins, Address to) { var t = new Transaction(@params); var o1 = new TransactionOutput(@params, t, nanocoins, to); t.AddOutput(o1); // Make a previous tx simply to send us sufficient coins. This prev tx is not really valid but it doesn't // matter for our purposes. var prevTx = new Transaction(@params); var prevOut = new TransactionOutput(@params, prevTx, nanocoins, to); prevTx.AddOutput(prevOut); // Connect it. t.AddInput(prevOut); return t; }
internal TransactionOutPoint(NetworkParameters networkParameters, int index, Transaction fromTransaction) : base(networkParameters) { Index = index; if (fromTransaction != null) { Hash = fromTransaction.Hash; FromTransaction = fromTransaction; } else { // This happens when constructing the genesis block. Hash = Sha256Hash.ZeroHash; } }
/// <summary> /// Used only in creation of the genesis blocks and in unit tests. /// </summary> public TransactionOutput(NetworkParameters networkParameters, Transaction parentTransaction, byte[] scriptBytes) : base(networkParameters) { _scriptBytes = scriptBytes; Value = Utils.ToNanoCoins(50, 0); ParentTransaction = parentTransaction; _availableForSpending = true; }
/// <summary> /// Broadcast a transaction to all connected peers. /// </summary> /// <returns>Whether we sent to at least one peer.</returns> public bool BroadcastTransaction(Transaction tx) { bool success = false; lock (_peers) { foreach (Peer peer in _peers) { try { peer.BroadcastTransaction(tx); success = true; } catch (IOException e) { Log.Error("failed to broadcast to " + peer, e); } } } return success; }
private void ReprocessTransactionAfterReorg(IDictionary<Sha256Hash, Transaction> pool, Transaction transaction) { Log.InfoFormat(" TX {0}", transaction.HashAsString); var numInputs = transaction.TransactionInputs.Count; var noSuchTransaction = 0; var success = 0; var isDead = false; foreach (var transactionInput in transaction.TransactionInputs) { if (transactionInput.IsCoinBase) { // Input is not in our wallet so there is "no such input tx", bit of an abuse. noSuchTransaction++; continue; } var result = transactionInput.Connect(pool, false); if (result == TransactionInput.ConnectionResult.Success) { success++; } else if (result == TransactionInput.ConnectionResult.NoSuchTx) { noSuchTransaction++; } else if (result == TransactionInput.ConnectionResult.AlreadySpent) { isDead = true; // This transaction was replaced by a double spend on the new chain. Did you just reverse // your own transaction? I hope not!! Log.Info(" ->dead, will not confirm now unless there's another re-org"); var doubleSpent = transactionInput.GetConnectedOutput(pool); var replacement = doubleSpent.SpentBy.ParentTransaction; _dead[transaction.Hash] = transaction; Pending.Remove(transaction.Hash); // Inform the event listeners of the newly dead tx. if (DeadTransaction != null) { lock (DeadTransaction) { DeadTransaction(this, new WalletDeadTransactionEventArgs(transaction, replacement)); } } break; } } if (isDead) return; if (noSuchTransaction == numInputs) { Log.Info(" ->inactive"); _inactive[transaction.Hash] = transaction; } else if (success == numInputs - noSuchTransaction) { // All inputs are either valid for spending or don't come from us. Miners are trying to re-include it. Log.Info(" ->pending"); Pending[transaction.Hash] = transaction; _dead.Remove(transaction.Hash); } }
/// <param name="deadTransaction">The transaction that is newly dead.</param> /// <param name="replacementTransaction">The transaction that killed it.</param> public WalletDeadTransactionEventArgs(Transaction deadTransaction, Transaction replacementTransaction) { DeadTransaction = deadTransaction; ReplacementTransaction = replacementTransaction; }
/// <exception cref="ProtocolException" /> protected override void Parse() { _version = ReadUint32(); _previousBlockHash = ReadHash(); _merkleRoot = ReadHash(); _time = ReadUint32(); _targetDifficulty = ReadUint32(); _nonce = ReadUint32(); _hash = new Sha256Hash(Utils.ReverseBytes(Utils.DoubleDigest(Bytes, 0, Cursor))); if (Cursor == Bytes.Length) { // This message is just a header, it has no transactions. return; } var numTransactions = (int) ReadVarInt(); Transactions = new List<Transaction>(numTransactions); for (var i = 0; i < numTransactions; i++) { var transaction = new Transaction(NetworkParameters, Bytes, Cursor); Transactions.Add(transaction); Cursor += transaction.MessageSize; } }
/// <summary> /// Call this when we have successfully transmitted the send tx to the network, to update the wallet. /// </summary> public void ConfirmSend(Transaction transaction) { lock (this) { Debug.Assert(!Pending.ContainsKey(transaction.Hash), "confirmSend called on the same transaction twice"); Log.InfoFormat("confirmSend of {0}", transaction.HashAsString); // Mark the outputs of the used transactions as spent, so we don't try and spend it again. foreach (var transactionInput in transaction.TransactionInputs) { var connectedOutput = transactionInput.Outpoint.ConnectedOutput; var connectedParentTransaction = connectedOutput.ParentTransaction; connectedOutput.MarkAsSpent(transactionInput); MaybeMoveTransactionToSpent(connectedParentTransaction, "spent tx"); } // Add to the pending WalletPool. It'll be moved out once we receive this transaction on the best chain. Pending[transaction.Hash] = transaction; } }
/// <summary> /// Deserializes an input message. This is usually part of a transaction message. /// </summary> /// <exception cref="ProtocolException"/> public TransactionInput(NetworkParameters networkParameters, Transaction parentTransaction, byte[] payload, int offset) : base(networkParameters, payload, offset) { ParentTransaction = parentTransaction; }
/// <summary> /// Creates an UNSIGNED input that links to the given output /// </summary> internal TransactionInput(NetworkParameters networkParameters, Transaction parentTransaction, TransactionOutput output) : base(networkParameters) { var outputIndex = output.Index; Outpoint = new TransactionOutPoint(networkParameters, outputIndex, output.ParentTransaction); ScriptBytes = EmptyArray; _sequence = uint.MaxValue; ParentTransaction = parentTransaction; }
/// <exception cref="BitcoinSharp.Core.Exceptions.VerificationException"/> /// <exception cref="BitcoinSharp.Core.Exceptions.ScriptException"/> private void Receive(Transaction transaction, StoredBlock storedBlock, BlockChain.NewBlockType blockType, bool reorg) { lock (this) { // Runs in a peer thread. var previousBalance = GetBalance(); var transactionHash = transaction.Hash; var bestChain = blockType == BlockChain.NewBlockType.BestChain; var sideChain = blockType == BlockChain.NewBlockType.SideChain; var valueSentFromMe = transaction.GetValueSentFromMe(this); var valueSentToMe = transaction.GetValueSentToMe(this); var valueDifference = (long) (valueSentToMe - valueSentFromMe); if (!reorg) { Log.InfoFormat("Received tx{0} for {1} BTC: {2}", sideChain ? " on a side chain" : "", Utils.BitcoinValueToFriendlyString(valueDifference), transaction.HashAsString); } // If this transaction is already in the wallet we may need to move it into a different WalletPool. At the very // least we need to ensure we're manipulating the canonical object rather than a duplicate. Transaction walletTransaction; if (Pending.TryGetValue(transactionHash, out walletTransaction)) { Pending.Remove(transactionHash); Log.Info(" <-pending"); // A transaction we created appeared in a block. Probably this is a spend we broadcast that has been // accepted by the network. // // Mark the tx as appearing in this block so we can find it later after a re-org. walletTransaction.AddBlockAppearance(storedBlock); if (bestChain) { if (valueSentToMe.Equals(0)) { // There were no change transactions so this tx is fully spent. Log.Info(" ->spent"); Debug.Assert(!Spent.ContainsKey(walletTransaction.Hash), "TX in both pending and spent pools"); Spent[walletTransaction.Hash] = walletTransaction; } else { // There was change back to us, or this tx was purely a spend back to ourselves (perhaps for // anonymization purposes). Log.Info(" ->unspent"); Debug.Assert(!Unspent.ContainsKey(walletTransaction.Hash), "TX in both pending and unspent pools"); Unspent[walletTransaction.Hash] = walletTransaction; } } else if (sideChain) { // The transaction was accepted on an inactive side chain, but not yet by the best chain. Log.Info(" ->inactive"); // It's OK for this to already be in the inactive WalletPool because there can be multiple independent side // chains in which it appears: // // b1 --> b2 // \-> b3 // \-> b4 (at this point it's already present in 'inactive' if (_inactive.ContainsKey(walletTransaction.Hash)) Log.Info("Saw a transaction be incorporated into multiple independent side chains"); _inactive[walletTransaction.Hash] = walletTransaction; // Put it back into the pending WalletPool, because 'pending' means 'waiting to be included in best chain'. Pending[walletTransaction.Hash] = walletTransaction; } } else { if (!reorg) { // Mark the tx as appearing in this block so we can find it later after a re-org. transaction.AddBlockAppearance(storedBlock); } // This TX didn't originate with us. It could be sending us coins and also spending our own coins if keys // are being shared between different wallets. if (sideChain) { Log.Info(" ->inactive"); _inactive[transaction.Hash] = transaction; } else if (bestChain) { ProcessTransactionFromBestChain(transaction); } } Log.InfoFormat("Balance is now: {0}", Utils.BitcoinValueToFriendlyString(GetBalance())); // Inform anyone interested that we have new coins. Note: we may be re-entered by the event listener, // so we must not make assumptions about our state after this loop returns! For example, // the balance we just received might already be spent! if (!reorg && bestChain && valueDifference > 0 && CoinsReceived != null) { lock (CoinsReceived) { CoinsReceived(this, new WalletCoinsReceivedEventArgs(transaction, previousBalance, GetBalance())); } } } }
/// <summary> /// Handle when a transaction becomes newly active on the best chain, either due to receiving a new block or a /// re-org making inactive transactions active. /// </summary> /// <exception cref="BitcoinSharp.Core.Exceptions.VerificationException"/> private void ProcessTransactionFromBestChain(Transaction transaction) { // This TX may spend our existing outputs even though it was not pending. This can happen in unit // tests and if keys are moved between wallets. UpdateForSpends(transaction); if (!transaction.GetValueSentToMe(this).Equals(0)) { // It's sending us coins. Log.Info(" new tx ->unspent"); Debug.Assert(!Unspent.ContainsKey(transaction.Hash), "TX was received twice"); Unspent[transaction.Hash] = transaction; } else { // It spent some of our coins and did not send us any. Log.Info(" new tx ->spent"); Debug.Assert(!Spent.ContainsKey(transaction.Hash), "TX was received twice"); Spent[transaction.Hash] = transaction; } }
/// <summary> /// If the transactions outputs are all marked as spent, and it's in the unspent map, move it. /// </summary> private void MaybeMoveTransactionToSpent(Transaction transaction, String context) { if (transaction.IsEveryOutputSpent()) { // There's nothing left I can spend in this transaction. if (Unspent.Remove(transaction.Hash)) { if (Log.IsInfoEnabled) { Log.Info(" " + context + " <-unspent"); Log.Info(" " + context + " ->spent"); } Spent[transaction.Hash] = transaction; } } }
/// <summary> /// Called by the <see cref="BitcoinSharp.Core.BlockChain"/> when we receive a new block that sends coins to one of our addresses or /// spends coins from one of our addresses (note that a single transaction can do both). /// </summary> /// <remarks> /// This is necessary for the internal book-keeping Wallet does. When a transaction is received that sends us /// coins it is added to a WalletPool so we can use it later to create spends. When a transaction is received that /// consumes outputs they are marked as spent so they won't be used in future.<p/> /// A transaction that spends our own coins can be received either because a spend we created was accepted by the /// network and thus made it into a block, or because our keys are being shared between multiple instances and /// some other node spent the coins instead. We still have to know about that to avoid accidentally trying to /// double spend.<p/> /// A transaction may be received multiple times if is included into blocks in parallel chains. The blockType /// parameter describes whether the containing block is on the main/best chain or whether it's on a presently /// inactive side chain. We must still record these transactions and the blocks they appear in because a future /// block might change which chain is best causing a reorganize. A re-org can totally change our balance! /// </remarks> /// <exception cref="BitcoinSharp.Core.Exceptions.VerificationException"/> /// <exception cref="BitcoinSharp.Core.Exceptions.ScriptException"/> public void Receive(Transaction transaction, StoredBlock storedBlock, BlockChain.NewBlockType blockType) { lock (this) { Receive(transaction, storedBlock, blockType, false); } }
/// <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="BitcoinSharp.Core.Messages.Transaction"/> or null if we cannot afford this send. /// </returns> public 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 transaction in Unspent.Values) { foreach (var transactionOutput in transaction.TransactionOutputs) { if (!transactionOutput.IsAvailableForSpending) continue; if (!transactionOutput.IsMine(this)) continue; gathered.AddLast(transactionOutput); valueGathered += transactionOutput.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 sendTransaction = new Transaction(_networkParameters); sendTransaction.AddOutput(new TransactionOutput(_networkParameters, sendTransaction, 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"); sendTransaction.AddOutput(new TransactionOutput(_networkParameters, sendTransaction, (ulong) change, changeAddress)); } foreach (var output in gathered) { sendTransaction.AddInput(output); } // Now sign the inputs, thus proving that we are entitled to redeem the connected outputs. sendTransaction.SignInputs(Transaction.SigHash.All, this); Log.InfoFormat(" created {0}", sendTransaction.HashAsString); return sendTransaction; } }
public void Transactions() { // This test covers a _bug in which Transaction.getValueSentFromMe was calculating incorrectly. var tx = TestUtils.CreateFakeTx(Params, Utils.ToNanoCoins(1, 0), _myAddress); // Now add another output (ie, change) that goes to some other address. var someOtherGuy = new EcKey().ToAddress(Params); var output = new TransactionOutput(Params, tx, Utils.ToNanoCoins(0, 5), someOtherGuy); tx.AddOutput(output); // Note that tx is no longer valid: it spends more than it imports. However checking transactions balance // correctly isn't possible in SPV mode because value is a property of outputs not inputs. Without all // transactions you can't check they add up. _defaultWallet.Receive(tx, null, BlockChain.NewBlockType.BestChain); // Now the other guy creates a transaction which spends that change. var tx2 = new Transaction(Params); tx2.AddInput(output); tx2.AddOutput(new TransactionOutput(Params, tx2, Utils.ToNanoCoins(0, 5), _myAddress)); // tx2 doesn't send any coins from us, even though the output is in the wallet. Assert.AreEqual(Utils.ToNanoCoins(0, 0), tx2.GetValueSentFromMe(_defaultWallet)); }
private static Block CreateGenesis(NetworkParameters networkParameters) { var genesisBlock = new Block(networkParameters); var transaction = new Transaction(networkParameters); // 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"); transaction.AddInput(new TransactionInput(networkParameters, transaction, bytes)); using (var scriptPubKeyBytes = new MemoryStream()) { Script.WriteBytes(scriptPubKeyBytes,Hex.Decode("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f")); scriptPubKeyBytes.Write(Script.OpCheckSig); transaction.AddOutput(new TransactionOutput(networkParameters, transaction, scriptPubKeyBytes.ToArray())); } genesisBlock.AddTransaction(transaction); return genesisBlock; }
/// <param name="transaction">The transaction which sent us the coins.</param> /// <param name="previousBalance">Balance before the coins were received.</param> /// <param name="newBalance">Current balance of the wallet.</param> public WalletCoinsReceivedEventArgs(Transaction transaction, ulong previousBalance, ulong newBalance) { Transaction = transaction; PreviousBalance = previousBalance; NewBalance = newBalance; }
/// <summary> /// Adds a transaction to this block. /// </summary> public void AddTransaction(Transaction transaction) { if (Transactions == null) { Transactions = new List<Transaction>(); } Transactions.Add(transaction); // Force a recalculation next time the values are needed. _merkleRoot = null; _hash = null; }
/// <summary> /// Updates the wallet by checking if this TX spends any of our outputs. This is not used normally because /// when we receive our own spends, we've already marked the outputs as spent previously (during tx creation) so /// there's no need to go through and do it again. /// </summary> /// <exception cref="BitcoinSharp.Core.Exceptions.VerificationException"/> private void UpdateForSpends(Transaction transaction) { // tx is on the best chain by this point. foreach (var transactionInput in transaction.TransactionInputs) { var result = transactionInput.Connect(Unspent, false); if (result == TransactionInput.ConnectionResult.NoSuchTx) { // Not found in the unspent map. Try again with the spent map. result = transactionInput.Connect(Spent, false); if (result == TransactionInput.ConnectionResult.NoSuchTx) { // Doesn't spend any of our outputs or is coinbase. continue; } } if (result == TransactionInput.ConnectionResult.AlreadySpent) { // Double spend! This must have overridden a pending tx, or the block is bad (contains transactions // that illegally double spend: should never occur if we are connected to an honest node). // // Work backwards like so: // // A -> spent by B [pending] // \-> spent by C [chain] var doubleSpent = transactionInput.Outpoint.FromTransaction; // == A Debug.Assert(doubleSpent != null); var index = transactionInput.Outpoint.Index; var output = doubleSpent.TransactionOutputs[index]; var spentBy = output.SpentBy; Debug.Assert(spentBy != null); var connected = spentBy.ParentTransaction; Debug.Assert(connected != null); if (Pending.Remove(connected.Hash)) { Log.InfoFormat("Saw double spend from chain override pending tx {0}", connected.HashAsString); Log.Info(" <-pending ->dead"); _dead[connected.Hash] = connected; // Now forcibly change the connection. transactionInput.Connect(Unspent, true); // Inform the event listeners of the newly dead tx. if (DeadTransaction != null) { lock (DeadTransaction) { DeadTransaction(this, new WalletDeadTransactionEventArgs(connected, transaction)); } } } } else if (result == TransactionInput.ConnectionResult.Success) { // Otherwise we saw a transaction spend our coins, but we didn't try and spend them ourselves yet. // The outputs are already marked as spent by the connect call above, so check if there are any more for // us to use. Move if not. var connected = transactionInput.Outpoint.FromTransaction; MaybeMoveTransactionToSpent(connected, "prevtx"); } } }
public void Bounce() { // This test covers _bug 64 (False double spends). Check that if we create a spend and it's immediately sent // back to us, this isn't considered as a double spend. var coin1 = Utils.ToNanoCoins(1, 0); var coinHalf = Utils.ToNanoCoins(0, 50); // Start by giving us 1 coin. var inbound1 = TestUtils.CreateFakeTx(Params, coin1, _myAddress); _defaultWallet.Receive(inbound1, null, BlockChain.NewBlockType.BestChain); // Send half to some other guy. Sending only half then waiting for a confirm is important to ensure the tx is // in the unspent pool, not pending or spent. Assert.AreEqual(1, _defaultWallet.GetPoolSize(WalletPool.Unspent)); Assert.AreEqual(1, _defaultWallet.GetPoolSize(WalletPool.All)); var someOtherGuy = new EcKey().ToAddress(Params); var outbound1 = _defaultWallet.CreateSend(someOtherGuy, coinHalf); _defaultWallet.ConfirmSend(outbound1); _defaultWallet.Receive(outbound1, null, BlockChain.NewBlockType.BestChain); // That other guy gives us the coins right back. var inbound2 = new Transaction(Params); inbound2.AddOutput(new TransactionOutput(Params, inbound2, coinHalf, _myAddress)); inbound2.AddInput(outbound1.TransactionOutputs[0]); _defaultWallet.Receive(inbound2, null, BlockChain.NewBlockType.BestChain); Assert.AreEqual(coin1, _defaultWallet.GetBalance()); }
/// <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(NetworkParameters); // 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(NetworkParameters, coinbase, new[] {(byte) _transactionCounter++})); coinbase.AddOutput(new TransactionOutput(NetworkParameters, coinbase, Script.CreateOutputScript(pubKeyTo))); Transactions.Add(coinbase); }
public void Balances() { var nanos = Utils.ToNanoCoins(1, 0); var tx1 = TestUtils.CreateFakeTx(Params, nanos, _myAddress); _defaultWallet.Receive(tx1, null, BlockChain.NewBlockType.BestChain); Assert.AreEqual(nanos, tx1.GetValueSentToMe(_defaultWallet, true)); // Send 0.10 to somebody else. var send1 = _defaultWallet.CreateSend(new EcKey().ToAddress(Params), Utils.ToNanoCoins(0, 10), _myAddress); // Re-serialize. var send2 = new Transaction(Params, send1.BitcoinSerialize()); Assert.AreEqual(nanos, send2.GetValueSentFromMe(_defaultWallet)); }
/// <summary> /// Returns a solved block that builds on top of this one. This exists for unit tests. /// </summary> internal Block CreateNextBlock(Address toAddress, uint time) { var block = new Block(NetworkParameters) {TargetDifficulty = _targetDifficulty}; block.AddCoinbaseTransaction(EmptyBytes); // Add a transaction paying 50 coins to the "to" address. var transaction = new Transaction(NetworkParameters); transaction.AddOutput(new TransactionOutput(NetworkParameters, transaction, Utils.ToNanoCoins(50, 0), toAddress)); // The input does not really need to be a valid signature, as long as it has the right general form. var input = new TransactionInput(NetworkParameters, transaction, 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) _transactionCounter++; input.Outpoint.Hash = new Sha256Hash(counter); transaction.AddInput(input); block.AddTransaction(transaction); block.PreviousBlockHash = Hash; block.TimeSeconds = time; block.Solve(); block.VerifyHeader(); return block; }