Exemple #1
0
        /// <summary>
        /// Creates a PeerGroup with the given parameters. The connectionDelayMillis parameter controls how long the
        /// PeerGroup will wait between attempts to connect to nodes or read from any added peer discovery sources.
        /// </summary>
        public PeerGroup(IBlockStore blockStore, NetworkParameters networkNetworkParams, BlockChain chain)
        {
            _blockStore        = blockStore;
            this.networkParams = networkNetworkParams;
            _chain             = chain;

            peerConnectionPool = new ThreadWorkerPool(MaxPeerConnections);

            _inactives       = new ConcurrentQueue <PeerAddress>();
            _peers           = new List <Peer>();
            _peerDiscoverers = new List <IPeerDiscovery>();
            peerGroupTimer   = new SingleEntryTimer(PeerGroupTimerCallback);
        }
Exemple #2
0
 /// <summary>
 /// Construct a peer that handles the given network connection and reads/writes from the given block chain. Note that
 /// communication won't occur until you call Connect().
 /// </summary>
 /// <param name="bestHeight">Our current best chain height, to facilitate downloading.</param>
 public Peer(NetworkParameters networkParams, PeerAddress address, uint bestHeight, BlockChain blockChain)
 {
     _params = networkParams;
     _address = address;
     _bestHeight = bestHeight;
     _blockChain = blockChain;
     _pendingGetBlockFutures = new List<GetDataFuture<Block>>();
 }
Exemple #3
0
 /// <summary>
 /// Construct a peer that handles the given network connection and reads/writes from the given block chain. Note that
 /// communication won't occur until you call connect().
 /// </summary>
 public Peer(NetworkParameters networkParams, PeerAddress address, BlockChain blockChain)
     : this(networkParams, address, 0, blockChain)
 {
 }
Exemple #4
0
        /// <exception cref="VerificationException"/>
        /// <exception cref="ScriptException"/>
        private void Receive(Transaction tx, StoredBlock block, BlockChain.NewBlockType blockType, bool reorg)
        {
            lock (this)
            {
                // Runs in a peer thread.
                var prevBalance = GetBalance();

                var txHash = tx.Hash;

                var bestChain = blockType == BlockChain.NewBlockType.BestChain;
                var sideChain = blockType == BlockChain.NewBlockType.SideChain;

                var valueSentFromMe = tx.GetValueSentFromMe(this);
                var valueSentToMe = tx.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), tx.HashAsString);
                }

                // If this transaction is already in the wallet we may need to move it into a different pool. At the very
                // least we need to ensure we're manipulating the canonical object rather than a duplicate.
                Transaction wtx;
                if (Pending.TryGetValue(txHash, out wtx))
                {
                    Pending.Remove(txHash);
                    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.
                    wtx.AddBlockAppearance(block);
                    if (bestChain)
                    {
                        if (valueSentToMe.Equals(0))
                        {
                            // There were no change transactions so this tx is fully spent.
                            Log.Info("  ->spent");
                            Debug.Assert(!Spent.ContainsKey(wtx.Hash), "TX in both pending and spent pools");
                            Spent[wtx.Hash] = wtx;
                        }
                        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(wtx.Hash), "TX in both pending and unspent pools");
                            Unspent[wtx.Hash] = wtx;
                        }
                    }
                    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 pool 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(wtx.Hash))
                            Log.Info("Saw a transaction be incorporated into multiple independent side chains");
                        _inactive[wtx.Hash] = wtx;
                        // Put it back into the pending pool, because 'pending' means 'waiting to be included in best chain'.
                        Pending[wtx.Hash] = wtx;
                    }
                }
                else
                {
                    if (!reorg)
                    {
                        // Mark the tx as appearing in this block so we can find it later after a re-org.
                        tx.AddBlockAppearance(block);
                    }
                    // 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[tx.Hash] = tx;
                    }
                    else if (bestChain)
                    {
                        ProcessTxFromBestChain(tx);
                    }
                }

                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(tx, prevBalance, GetBalance()));
                    }
                }
            }
        }
Exemple #5
0
 /// <summary>
 /// Called by the <see cref="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 pool 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="VerificationException"/>
 /// <exception cref="ScriptException"/>
 internal void Receive(Transaction tx, StoredBlock block, BlockChain.NewBlockType blockType)
 {
     lock (this)
     {
         Receive(tx, block, blockType, false);
     }
 }
Exemple #6
0
 /// <summary>
 /// Construct a peer that handles the given network connection and reads/writes from the given block chain. Note that
 /// communication won't occur until you call connect().
 /// </summary>
 public Peer(NetworkParameters networkParams, PeerAddress address, BlockChain blockChain)
     : this(networkParams, address, 0, blockChain)
 {
 }
Exemple #7
0
 /// <summary>
 /// Construct a peer that handles the given network connection and reads/writes from the given block chain. Note that
 /// communication won't occur until you call Connect().
 /// </summary>
 /// <param name="bestHeight">Our current best chain height, to facilitate downloading.</param>
 public Peer(NetworkParameters networkParams, PeerAddress address, uint bestHeight, BlockChain blockChain)
 {
     _params                 = networkParams;
     _address                = address;
     _bestHeight             = bestHeight;
     _blockChain             = blockChain;
     _pendingGetBlockFutures = new List <GetDataFuture <Block> >();
 }
Exemple #8
0
        /// <summary>
        /// Creates a PeerGroup with the given parameters. The connectionDelayMillis parameter controls how long the
        /// PeerGroup will wait between attempts to connect to nodes or read from any added peer discovery sources.
        /// </summary>
        public PeerGroup(IBlockStore blockStore, NetworkParameters networkNetworkParams, BlockChain chain)
        {
            _blockStore = blockStore;
            this.networkParams = networkNetworkParams;
            _chain = chain;

            peerConnectionPool = new ThreadWorkerPool(MaxPeerConnections);

            _inactives = new ConcurrentQueue<PeerAddress>();
            _peers = new List<Peer>();
            _peerDiscoverers = new List<IPeerDiscovery>();
            peerGroupTimer = new SingleEntryTimer(PeerGroupTimerCallback);
        }