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; }
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)); }
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()); }
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; }
/// <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; }
/// <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); }
/// <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; } }