Maintain a number of connections to peers.
PeerGroup tries to maintain a constant number of connections to a set of distinct peers. Each peer runs a network listener in its own thread. When a connection is lost, a new peer will be tried after a delay as long as the number of connections less than the maximum.

Connections are made to addresses from a provided list. When that list is exhausted, we start again from the head of the list.

The PeerGroup can broadcast a transaction to the currently connected set of peers. It can also handle download of the block chain from peers, restarting the process when peers die. @author [email protected] (Miron Cuperman a.k.a devrandom)

        /// <summary>
        /// Sends coins to the given address, via the given <see cref="PeerGroup"/>.
        /// Change is returned to the first key in the wallet.
        /// </summary>
        /// <param name="peerGroup">The peer group to send via.</param>
        /// <param name="to">Which address to send coins to.</param>
        /// <param name="nanocoins">How many nanocoins to send. You can use Utils.toNanoCoins() to calculate this.</param>
        /// <returns>
        /// The <see cref="Transaction"/> that was created or null if there was insufficient balance to send the coins.
        /// </returns>
        /// <exception cref="IOException">If there was a problem broadcasting the transaction.</exception>
        public Transaction SendCoins(PeerGroup peerGroup, Address to, ulong nanocoins)
        {
            lock (this)
            {
                var tx = CreateSend(to, nanocoins);
                if (tx == null) // Not enough money! :-(
                    return null;
                if (!peerGroup.BroadcastTransaction(tx))
                {
                    throw new IOException("Failed to broadcast tx to all connected peers");
                }

                // TODO - retry logic
                ConfirmSend(tx);
                return tx;
            }
        }