コード例 #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
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
        /// <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);
                }
            }
        }
コード例 #3
0
 private static Block CreateGenesis(NetworkParameters n)
 {
     var genesisBlock = new Block(n);
     var t = new Transaction(n);
     try
     {
         // 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.Write(Script.OpCheckSig);
             t.AddOutput(new TransactionOutput(n, scriptPubKeyBytes.ToArray()));
         }
     }
     catch (Exception)
     {
     }
     genesisBlock.AddTransaction(t);
     return genesisBlock;
 }
コード例 #4
0
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
 /// <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);
     }
 }
コード例 #5
0
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
        /// <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;
            }
        }
コード例 #6
0
ファイル: StoredBlock.cs プロジェクト: aklein53/bitcoinsharp
 public StoredBlock(Block header, BigInteger chainWork, uint height)
 {
     _header = header;
     _chainWork = chainWork;
     _height = height;
 }
コード例 #7
0
ファイル: StoredBlock.cs プロジェクト: aklein53/bitcoinsharp
 /// <summary>
 /// Creates a new StoredBlock, calculating the additional fields by adding to the values in this block.
 /// </summary>
 /// <exception cref="BitCoinSharp.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);
 }
コード例 #8
0
 /// <exception cref="System.IO.IOException" />
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 private void Load(FileInfo file)
 {
     _log.InfoFormat("Reading block store from {0}", file);
     using (var input = file.OpenRead())
     {
         // Read a version byte.
         var version = input.Read();
         if (version == -1)
         {
             // No such file or the file was empty.
             throw new FileNotFoundException(file.Name + " does not exist or is empty");
         }
         if (version != 1)
         {
             throw new BlockStoreException("Bad version number: " + version);
         }
         // Chain head pointer is the first thing in the file.
         var chainHeadHash = new byte[32];
         input.Read(chainHeadHash);
         _chainHead = new Sha256Hash(chainHeadHash);
         _log.InfoFormat("Read chain head from disk: {0}", _chainHead);
         var now = Environment.TickCount;
         // Rest of file is raw block headers.
         var headerBytes = new byte[Block.HeaderSize];
         try
         {
             while (true)
             {
                 // Read a block from disk.
                 if (input.Read(headerBytes) < 80)
                 {
                     // End of file.
                     break;
                 }
                 // Parse it.
                 var b = new Block(_params, headerBytes);
                 // Look up the previous block it connects to.
                 var prev = Get(b.PrevBlockHash);
                 StoredBlock s;
                 if (prev == null)
                 {
                     // First block in the stored chain has to be treated specially.
                     if (b.Equals(_params.GenesisBlock))
                     {
                         s = new StoredBlock(_params.GenesisBlock.CloneAsHeader(), _params.GenesisBlock.GetWork(), 0);
                     }
                     else
                     {
                         throw new BlockStoreException("Could not connect " + Utils.BytesToHexString(b.Hash) + " to "
                                                       + Utils.BytesToHexString(b.PrevBlockHash));
                     }
                 }
                 else
                 {
                     // Don't try to verify the genesis block to avoid upsetting the unit tests.
                     b.Verify();
                     // Calculate its height and total chain work.
                     s = prev.Build(b);
                 }
                 // Save in memory.
                 _blockMap[new Sha256Hash(b.Hash)] = s;
             }
         }
         catch (ProtocolException e)
         {
             // Corrupted file.
             throw new BlockStoreException(e);
         }
         catch (VerificationException e)
         {
             // Should not be able to happen unless the file contains bad blocks.
             throw new BlockStoreException(e);
         }
         var elapsed = Environment.TickCount - now;
         _log.InfoFormat("Block chain read complete in {0}ms", elapsed);
     }
 }
コード例 #9
0
ファイル: Block.cs プロジェクト: aklein53/bitcoinsharp
 /// <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(to);
     b.PrevBlockHash = Hash;
     b.Time = time;
     b.Solve();
     b.Verify();
     return b;
 }
コード例 #10
0
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
        /// <exception cref="BitCoinSharp.BlockStoreException" />
        /// <exception cref="BitCoinSharp.VerificationException" />
        /// <exception cref="BitCoinSharp.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;
                }

                // Prove the block is internally valid: hash is lower than target, merkle root is correct and so on.
                try
                {
                    block.Verify();
                }
                catch (VerificationException e)
                {
                    _log.Error("Failed to verify block:", e);
                    _log.Error(block.ToString());
                    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);
                // block.transactions may be null here if we received only a header and not a full block. This does not
                // happen currently but might in future if GetHeaders is implemented.
                ConnectBlock(newStoredBlock, storedPrev, block.Transactions);

                if (tryConnecting)
                    TryConnectingUnconnected();

                _statsBlocksAdded++;
                return true;
            }
        }
コード例 #11
0
ファイル: Block.cs プロジェクト: bitspill/Gridcoin-master
        /// <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;
        }
コード例 #12
0
ファイル: Block.cs プロジェクト: bitspill/Gridcoin-master
 /// <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;
 }