예제 #1
0
 /// <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;
 }
예제 #2
0
 /// <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;
 }
예제 #3
0
 public TransactionOutput(NetworkParameters networkParameters, Transaction parentTransaction, ulong value,
     Address to)
     : base(networkParameters)
 {
     Value = value;
     _scriptBytes = Script.CreateOutputScript(to);
     ParentTransaction = parentTransaction;
     _availableForSpending = true;
 }
예제 #4
0
 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;
 }
예제 #5
0
 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;
     }
 }
예제 #6
0
 /// <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;
 }
예제 #7
0
 /// <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;
 }
예제 #8
0
        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;
 }
예제 #10
0
        /// <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;
            }
        }
예제 #11
0
 /// <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;
     }
 }
예제 #12
0
 /// <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;
 }
예제 #13
0
 /// <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;
 }
예제 #14
0
        /// <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()));
                    }
                }
            }
        }
예제 #15
0
 /// <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;
     }
 }
예제 #16
0
 /// <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;
         }
     }
 }
예제 #17
0
 /// <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);
     }
 }
예제 #18
0
        /// <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;
            }
        }
예제 #19
0
 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));
 }
예제 #20
0
 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;
 }
예제 #22
0
 /// <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;
 }
예제 #23
0
 /// <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");
         }
     }
 }
예제 #24
0
 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());
 }
예제 #25
0
 /// <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);
 }
예제 #26
0
 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));
 }
예제 #27
0
        /// <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;
        }