예제 #1
0
        public override void OnBlocksDownloaded(Peer peer, Block block, int blocksLeft)
        {
            if (blocksLeft == 0)
            {
                DoneDownload();
                _done.Release();
            }

            if (blocksLeft < 0 || _originalBlocksLeft <= 0)
                return;

            var pct = 100.0 - (100.0*(blocksLeft/(double) _originalBlocksLeft));
            if ((int) pct != _lastPercent)
            {
                Progress(pct, UnixTime.FromUnixTime(block.TimeSeconds*1000));
                _lastPercent = (int) pct;
            }
        }
예제 #2
0
 /// <summary>
 /// Creates a new StoredBlock, calculating the additional fields by adding to the values in this block.
 /// </summary>
 /// <exception cref="VerificationException"/>
 public StoredBlock Build(Block block)
 {
     // Stored blocks track total work done in this chain, because the canonical chain is the one that represents
     // the largest amount of work done not the tallest.
     var chainWork = _chainWork.Add(block.GetWork());
     var height = _height + 1;
     return new StoredBlock(block.CloneAsHeader(), chainWork, height);
 }
예제 #3
0
 public StoredBlock(Block header, BigInteger chainWork, uint height)
 {
     _header = header;
     _chainWork = chainWork;
     _height = height;
 }
예제 #4
0
 /// <summary>
 /// Called by the wallet when the tx appears on the best chain and a new block is added to the top.
 /// Updates the internal counter that tracks how deeply buried the block is.
 /// Work is the value of block.getWork().
 /// </summary>
 //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
 //ORIGINAL LINE: public synchronized void notifyWorkDone(Block block) throws VerificationException
 public virtual void notifyWorkDone(Block block)
 {
     if (ConfidenceLevel == ConfidenceType.BUILDING)
     {
         this.depth++;
         this.workDone = this.workDone.Add(block.GetWork());
         OnConfidenceChanged();
     }
 }
예제 #5
0
파일: Peer.cs 프로젝트: Virus-X/CoinSharp
        /// <exception cref="IOException"/>
        private void ProcessBlock(Block m)
        {
            // This should called in the network loop thread for this peer
            try
            {
                // Was this block requested by getblock?
                lock (_pendingGetBlockFutures)
                {
                    for (var i = 0; i < _pendingGetBlockFutures.Count; i++)
                    {
                        var f = _pendingGetBlockFutures[i];
                        if (f.Item.Hash.Equals(m.Hash))
                        {
                            // Yes, it was. So pass it through the future.
                            f.SetResult(m);
                            // Blocks explicitly requested don't get sent to the block chain.
                            _pendingGetBlockFutures.RemoveAt(i);
                            return;
                        }
                    }
                }
                // Otherwise it's a block sent to us because the peer thought we needed it, so add it to the block chain.
                // This call will synchronize on blockChain.
                if (_blockChain.Add(m))
                {
                    // The block was successfully linked into the chain. Notify the user of our progress.
                    if (BlocksDownloaded != null)
                    {
                        BlocksDownloaded(this, new BlocksDownloadedEventArgs(m, GetPeerBlocksToGet()));
                    }
                }
                else
                {
                    // This block is unconnected - we don't know how to get from it back to the genesis block yet. That
                    // must mean that there are blocks we are missing, so do another getblocks with a new block locator
                    // to ask the peer to send them to us. This can happen during the initial block chain download where
                    // the peer will only send us 500 at a time and then sends us the head block expecting us to request
                    // the others.

                    // TODO: Should actually request root of orphan chain here.
                    BlockChainDownload(m.Hash);
                }
            }
            catch (VerificationException e)
            {
                // We don't want verification failures to kill the thread.
                Log.Warn("Block verification failed", e);
            }
            catch (ScriptException e)
            {
                // We don't want script failures to kill the thread.
                Log.Warn("Script exception", e);
            }
        }
예제 #6
0
파일: Peer.cs 프로젝트: Virus-X/CoinSharp
 public BlocksDownloadedEventArgs(Block block, int blocksLeft)
 {
     Block = block;
     BlocksLeft = blocksLeft;
 }
예제 #7
0
        /// <summary>
        /// For the transactions in the given block, update the txToWalletMap such that each wallet maps to a list of
        /// transactions for which it is relevant.
        /// </summary>
        /// <exception cref="VerificationException"/>
        private void ScanTransactions(Block block, IDictionary<Wallet, List<Transaction>> walletToTxMap)
        {
            foreach (var tx in block.Transactions)
            {
                try
                {
                    foreach (var wallet in _wallets)
                    {
                        var shouldReceive = false;
                        foreach (var output in tx.Outputs)
                        {
                            // TODO: Handle more types of outputs, not just regular to address outputs.
                            if (output.ScriptPubKey.IsSentToIp) continue;
                            // This is not thread safe as a key could be removed between the call to isMine and receive.
                            if (output.IsMine(wallet))
                            {
                                shouldReceive = true;
                                break;
                            }
                        }

                        // Coinbase transactions don't have anything useful in their inputs (as they create coins out of thin air).
                        if (!shouldReceive && !tx.IsCoinBase)
                        {
                            foreach (var i in tx.Inputs)
                            {
                                var pubkey = i.ScriptSig.PubKey;
                                // This is not thread safe as a key could be removed between the call to isPubKeyMine and receive.
                                if (wallet.IsPubKeyMine(pubkey))
                                {
                                    shouldReceive = true;
                                }
                            }
                        }

                        if (!shouldReceive) continue;
                        List<Transaction> txList;
                        if (!walletToTxMap.TryGetValue(wallet, out txList))
                        {
                            txList = new List<Transaction>();
                            walletToTxMap[wallet] = txList;
                        }
                        txList.Add(tx);
                    }
                }
                catch (ScriptException e)
                {
                    // We don't want scripts we don't understand to break the block chain so just note that this tx was
                    // not scanned here and continue.
                    Log.Warn("Failed to parse a script: " + e);
                }
            }
        }
예제 #8
0
        /// <exception cref="BlockStoreException"/>
        /// <exception cref="VerificationException"/>
        /// <exception cref="ScriptException"/>
        private bool Add(Block block, bool tryConnecting)
        {
            lock (this)
            {
                if (Environment.TickCount - _statsLastTime > 1000)
                {
                    // More than a second passed since last stats logging.
                    Log.InfoFormat("{0} blocks per second", _statsBlocksAdded);
                    _statsLastTime = Environment.TickCount;
                    _statsBlocksAdded = 0;
                }
                // We check only the chain head for double adds here to avoid potentially expensive block chain misses.
                if (block.Equals(_chainHead.Header))
                {
                    // Duplicate add of the block at the top of the chain, can be a natural artifact of the download process.
                    return true;
                }

                // Does this block contain any transactions we might care about? Check this up front before verifying the
                // blocks validity so we can skip the merkle root verification if the contents aren't interesting. This saves
                // a lot of time for big blocks.
                var contentsImportant = false;
                var walletToTxMap = new Dictionary<Wallet, List<Transaction>>();
                if (block.Transactions != null)
                {
                    ScanTransactions(block, walletToTxMap);
                    contentsImportant = walletToTxMap.Count > 0;
                }

                // Prove the block is internally valid: hash is lower than target, etc. This only checks the block contents
                // if there is a tx sending or receiving coins using an address in one of our wallets. And those transactions
                // are only lightly verified: presence in a valid connecting block is taken as proof of validity. See the
                // article here for more details: http://code.google.com/p/bitcoinj/wiki/SecurityModel
                try
                {
                    block.VerifyHeader();
                    if (contentsImportant)
                        block.VerifyTransactions();
                }
                catch (VerificationException e)
                {
                    Log.Error("Failed to verify block:", e);
                    Log.Error(block.HashAsString);
                    throw;
                }

                // Try linking it to a place in the currently known blocks.
                var storedPrev = _blockStore.Get(block.PrevBlockHash);

                if (storedPrev == null)
                {
                    // We can't find the previous block. Probably we are still in the process of downloading the chain and a
                    // block was solved whilst we were doing it. We put it to one side and try to connect it later when we
                    // have more blocks.
                    Log.WarnFormat("Block does not connect: {0}", block.HashAsString);
                    _unconnectedBlocks.Add(block);
                    return false;
                }
                // It connects to somewhere on the chain. Not necessarily the top of the best known chain.
                //
                // Create a new StoredBlock from this block. It will throw away the transaction data so when block goes
                // out of scope we will reclaim the used memory.
                var newStoredBlock = storedPrev.Build(block);
                CheckDifficultyTransitions(storedPrev, newStoredBlock);
                _blockStore.Put(newStoredBlock);
                ConnectBlock(newStoredBlock, storedPrev, walletToTxMap);

                if (tryConnecting)
                    TryConnectingUnconnected();

                _statsBlocksAdded++;
                return true;
            }
        }
예제 #9
0
 /// <summary>
 /// Processes a received block and tries to add it to the chain. If there's something wrong with the block an
 /// exception is thrown. If the block is OK but cannot be connected to the chain at this time, returns false.
 /// If the block can be connected to the chain, returns true.
 /// </summary>
 /// <exception cref="VerificationException"/>
 /// <exception cref="ScriptException"/>
 public bool Add(Block block)
 {
     lock (this)
     {
         return Add(block, true);
     }
 }
예제 #10
0
파일: Block.cs 프로젝트: Virus-X/CoinSharp
        /// <summary>
        /// Returns a solved block that builds on top of this one. This exists for unit tests.
        /// </summary>
        internal Block CreateNextBlock(Address to, uint time)
        {
            var b = new Block(Params);
            b.DifficultyTarget = _difficultyTarget;
            b.AddCoinbaseTransaction(_emptyBytes);

            // Add a transaction paying 50 coins to the "to" address.
            var t = new Transaction(Params);
            t.AddOutput(new TransactionOutput(Params, t, Utils.ToNanoCoins(50, 0), to));
            // The input does not really need to be a valid signature, as long as it has the right general form.
            var input = new TransactionInput(Params, t, 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) _txCounter++;
            input.Outpoint.Hash = new Sha256Hash(counter);
            t.AddInput(input);
            b.AddTransaction(t);

            b.PrevBlockHash = Hash;
            b.TimeSeconds = time;
            b.Solve();
            b.VerifyHeader();
            return b;
        }
예제 #11
0
파일: Block.cs 프로젝트: Virus-X/CoinSharp
 /// <summary>
 /// Returns a copy of the block, but without any transactions.
 /// </summary>
 public Block CloneAsHeader()
 {
     var block = new Block(Params);
     block._nonce = _nonce;
     block._prevBlockHash = _prevBlockHash.Duplicate();
     block._merkleRoot = MerkleRoot.Duplicate();
     block._version = _version;
     block._time = _time;
     block._difficultyTarget = _difficultyTarget;
     block.Transactions = null;
     block._hash = Hash.Duplicate();
     return block;
 }
예제 #12
0
 private static Block CreateGenesis(NetworkParameters n)
 {
     var genesisBlock = new Block(n);
     var t = new Transaction(n);
     // 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");
     t.AddInput(new TransactionInput(n, t, bytes));
     using (var scriptPubKeyBytes = new MemoryStream())
     {
         Script.WriteBytes(scriptPubKeyBytes, Hex.Decode("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"));
         scriptPubKeyBytes.WriteByte((byte) OpCode.OP_CHECKSIG);
         t.AddOutput(new TransactionOutput(n, t, scriptPubKeyBytes.ToArray()));
     }
     genesisBlock.AddTransaction(t);
     return genesisBlock;
 }