Ejemplo n.º 1
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()));
                    }
                }
            }
        }
Ejemplo n.º 2
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;
     }
 }