コード例 #1
0
        /// <summary>
        /// Called as part of connecting a block when the new block results in a different chain having higher total work.
        /// </summary>
        /// <exception cref="BlockStoreException"/>
        /// <exception cref="VerificationException"/>
        private void HandleNewBestChain(StoredBlock newChainHead)
        {
            // This chain has overtaken the one we currently believe is best. Reorganize is required.
            //
            // Firstly, calculate the block at which the chain diverged. We only need to examine the
            // chain from beyond this block to find differences.
            var splitPoint = FindSplit(newChainHead, _chainHead);

            _log.InfoFormat("Re-organize after split at height {0}", splitPoint.Height);
            _log.InfoFormat("Old chain head: {0}", _chainHead.Header.HashAsString);
            _log.InfoFormat("New chain head: {0}", newChainHead.Header.HashAsString);
            _log.InfoFormat("Split at block: {0}", splitPoint.Header.HashAsString);
            // Then build a list of all blocks in the old part of the chain and the new part.
            var oldBlocks = GetPartialChain(_chainHead, splitPoint);
            var newBlocks = GetPartialChain(newChainHead, splitPoint);

            // Now inform the wallet. This is necessary so the set of currently active transactions (that we can spend)
            // can be updated to take into account the re-organize. We might also have received new coins we didn't have
            // before and our previous spends might have been undone.
            foreach (var wallet in _wallets)
            {
                wallet.Reorganize(oldBlocks, newBlocks);
            }
            // Update the pointer to the best known block.
            ChainHead = newChainHead;
        }
コード例 #2
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 private void CreateNewStore(NetworkParameters @params, FileInfo file)
 {
     // Create a new block store if the file wasn't found or anything went wrong whilst reading.
     _blockCache.Clear();
     try
     {
         if (_channel != null)
         {
             _channel.Dispose();
             _channel = null;
         }
         file.Delete();
         _channel = file.Create(); // Create fresh.
         _channel.Write(_fileFormatVersion);
     }
     catch (IOException e1)
     {
         // We could not load a block store nor could we create a new one!
         throw new BlockStoreException(e1);
     }
     try
     {
         // Set up the genesis block. When we start out fresh, it is by definition the top of the chain.
         var genesis       = @params.GenesisBlock.CloneAsHeader();
         var storedGenesis = new StoredBlock(genesis, genesis.GetWork(), 0);
         _chainHead = new Sha256Hash(storedGenesis.Header.Hash);
         _channel.Write(_chainHead.Hash);
         Put(storedGenesis);
     }
     catch (IOException e)
     {
         throw new BlockStoreException(e);
     }
 }
コード例 #3
0
        /// <summary>
        /// Locates the point in the chain at which newStoredBlock and chainHead diverge. Returns null if no split point was
        /// found (ie they are part of the same chain).
        /// </summary>
        /// <exception cref="BitCoinSharp.BlockStoreException" />
        private StoredBlock FindSplit(StoredBlock newChainHead, StoredBlock chainHead)
        {
            var currentChainCursor = chainHead;
            var newChainCursor     = newChainHead;

            // Loop until we find the block both chains have in common. Example:
            //
            //    A -> B -> C -> D
            //         \--> E -> F -> G
            //
            // findSplit will return block B. chainHead = D and newChainHead = G.
            while (!currentChainCursor.Equals(newChainCursor))
            {
                if (currentChainCursor.Height > newChainCursor.Height)
                {
                    currentChainCursor = currentChainCursor.GetPrev(_blockStore);
                    Debug.Assert(newChainCursor != null, "Attempt to follow an orphan chain");
                }
                else
                {
                    newChainCursor = newChainCursor.GetPrev(_blockStore);
                    Debug.Assert(currentChainCursor != null, "Attempt to follow an orphan chain");
                }
            }
            return(currentChainCursor);
        }
コード例 #4
0
 /// <summary>
 /// Constructs a BlockChain connected to the given wallet and store. To obtain a <see cref="Wallet">Wallet</see> you can construct
 /// one from scratch, or you can deserialize a saved wallet from disk using <see cref="Wallet.LoadFromFile(System.IO.FileInfo)">Wallet.LoadFromFile(System.IO.FileInfo)</see><p />
 /// </summary>
 /// <remarks>
 /// For the store you can use a <see cref="MemoryBlockStore">MemoryBlockStore</see> if you don't care about saving the downloaded data, or a
 /// <see cref="BoundedOverheadBlockStore">BoundedOverheadBlockStore</see> if you'd like to ensure fast start-up the next time you run the program.
 /// </remarks>
 public BlockChain(NetworkParameters @params, Wallet wallet, IBlockStore blockStore)
 {
     _blockStore = blockStore;
     _chainHead  = blockStore.GetChainHead();
     _log.InfoFormat("chain head is:{0}{1}", Environment.NewLine, _chainHead.Header);
     _params = @params;
     _wallet = wallet;
 }
コード例 #5
0
 /// <summary>
 /// Constructs a BlockChain connected to the given list of wallets and a store.
 /// </summary>
 /// <exception cref="BlockStoreException"/>
 public BlockChain(NetworkParameters @params, IEnumerable <Wallet> wallets, IBlockStore blockStore)
 {
     _blockStore = blockStore;
     _chainHead  = blockStore.GetChainHead();
     _log.InfoFormat("chain head is:{0}{1}", Environment.NewLine, _chainHead.Header);
     _params  = @params;
     _wallets = new List <Wallet>(wallets);
 }
コード例 #6
0
ファイル: Transaction.cs プロジェクト: mavrol/bitcoinsharpev
 /// <summary>
 /// Adds the given block to the internal serializable set of blocks in which this transaction appears. This is
 /// used by the wallet to ensure transactions that appear on side chains are recorded properly even though the
 /// block stores do not save the transaction data at all.
 /// </summary>
 internal void AddBlockAppearance(StoredBlock block)
 {
     if (AppearsIn == null)
     {
         AppearsIn = new HashSet <StoredBlock>();
     }
     AppearsIn.Add(block);
 }
コード例 #7
0
 public MemoryBlockStore(NetworkParameters @params)
 {
     _blockMap = new Dictionary<ByteBuffer, byte[]>();
     // Insert the genesis block.
     var genesisHeader = @params.GenesisBlock.CloneAsHeader();
     var storedGenesis = new StoredBlock(genesisHeader, genesisHeader.GetWork(), 0);
     Put(storedGenesis);
     SetChainHead(storedGenesis);
 }
コード例 #8
0
        public MemoryBlockStore(NetworkParameters @params)
        {
            _blockMap = new Dictionary <ByteBuffer, byte[]>();
            // Insert the genesis block.
            var genesisHeader = @params.GenesisBlock.CloneAsHeader();
            var storedGenesis = new StoredBlock(genesisHeader, genesisHeader.GetWork(), 0);

            Put(storedGenesis);
            SetChainHead(storedGenesis);
        }
コード例 #9
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public void Put(StoredBlock block)
 {
     lock (this)
     {
         var hash = block.Header.Hash;
         using (var bos = new MemoryStream())
         {
             var oos = new BinaryFormatter();
             oos.Serialize(bos, block);
             _blockMap[ByteBuffer.Wrap(hash)] = bos.ToArray();
         }
     }
 }
コード例 #10
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public BoundedOverheadBlockStore(NetworkParameters @params, FileInfo file)
 {
     _params = @params;
     _notFoundMarker = new StoredBlock(null, null, uint.MaxValue);
     try
     {
         Load(file);
     }
     catch (IOException e)
     {
         _log.Error("failed to load block store from file", e);
         CreateNewStore(@params, file);
     }
 }
コード例 #11
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public BoundedOverheadBlockStore(NetworkParameters @params, FileInfo file)
 {
     _params         = @params;
     _notFoundMarker = new StoredBlock(null, null, uint.MaxValue);
     try
     {
         Load(file);
     }
     catch (IOException e)
     {
         _log.Error("failed to load block store from file", e);
         CreateNewStore(@params, file);
     }
 }
コード例 #12
0
        /// <exception cref="BitCoinSharp.BlockStoreException" />
        public StoredBlock Get(byte[] hashBytes)
        {
            lock (this)
            {
                // Check the memory cache first.
                var         hash = new Sha256Hash(hashBytes);
                StoredBlock fromMem;
                if (_blockCache.TryGetValue(hash, out fromMem))
                {
                    return(fromMem);
                }
                if (_notFoundCache.TryGetValue(hash, out fromMem) && fromMem == _notFoundMarker)
                {
                    return(null);
                }

                try
                {
                    var         fromDisk = GetRecord(hash);
                    StoredBlock block    = null;
                    if (fromDisk == null)
                    {
                        _notFoundCache[hash] = _notFoundMarker;
                        while (_notFoundCache.Count > 100)
                        {
                            _notFoundCache.RemoveAt(0);
                        }
                    }
                    else
                    {
                        block             = fromDisk.ToStoredBlock(_params);
                        _blockCache[hash] = block;
                        while (_blockCache.Count > 100)
                        {
                            _blockCache.RemoveAt(0);
                        }
                    }
                    return(block);
                }
                catch (IOException e)
                {
                    throw new BlockStoreException(e);
                }
                catch (ProtocolException e)
                {
                    throw new BlockStoreException(e);
                }
            }
        }
コード例 #13
0
 /// <exception cref="BitCoinSharp.VerificationException" />
 private void SendTransactionsToWallet(StoredBlock block, NewBlockType blockType, IEnumerable <Transaction> newTransactions)
 {
     // Scan the transactions to find out if any mention addresses we own.
     foreach (var tx in newTransactions)
     {
         try
         {
             ScanTransaction(block, tx, blockType);
         }
         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.WarnFormat("Failed to parse a script: {0}", e);
         }
     }
 }
コード例 #14
0
        /// <summary>
        /// Returns the set of contiguous blocks between 'higher' and 'lower'. Higher is included, lower is not.
        /// </summary>
        /// <exception cref="BitCoinSharp.BlockStoreException" />
        private IList <StoredBlock> GetPartialChain(StoredBlock higher, StoredBlock lower)
        {
            Debug.Assert(higher.Height > lower.Height);
            var results = new LinkedList <StoredBlock>();
            var cursor  = higher;

            while (true)
            {
                results.AddLast(cursor);
                cursor = cursor.GetPrev(_blockStore);
                Debug.Assert(cursor != null, "Ran off the end of the chain");
                if (cursor.Equals(lower))
                {
                    break;
                }
            }
            return(results.ToList());
        }
コード例 #15
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public void SetChainHead(StoredBlock chainHead)
 {
     lock (this)
     {
         try
         {
             var hash = chainHead.Header.Hash;
             _chainHead = new Sha256Hash(hash);
             // Write out new hash to the first 32 bytes of the file past one (first byte is version number).
             _stream.Seek(1, SeekOrigin.Begin);
             _stream.Write(hash, 0, hash.Length);
         }
         catch (IOException e)
         {
             throw new BlockStoreException(e);
         }
     }
 }
コード例 #16
0
        /// <exception cref="BitCoinSharp.BlockStoreException" />
        /// <exception cref="BitCoinSharp.VerificationException" />
        private void ConnectBlock(StoredBlock newStoredBlock, StoredBlock storedPrev, IEnumerable <Transaction> newTransactions)
        {
            if (storedPrev.Equals(_chainHead))
            {
                // This block connects to the best known block, it is a normal continuation of the system.
                ChainHead = newStoredBlock;
                _log.DebugFormat("Chain is now {0} blocks high", _chainHead.Height);
                if (newTransactions != null)
                {
                    SendTransactionsToWallet(newStoredBlock, NewBlockType.BestChain, newTransactions);
                }
            }
            else
            {
                // This block connects to somewhere other than the top of the best known chain. We treat these differently.
                //
                // Note that we send the transactions to the wallet FIRST, even if we're about to re-organize this block
                // to become the new best chain head. This simplifies handling of the re-org in the Wallet class.
                var haveNewBestChain = newStoredBlock.MoreWorkThan(_chainHead);
                if (haveNewBestChain)
                {
                    _log.Info("Block is causing a re-organize");
                }
                else
                {
                    var splitPoint     = FindSplit(newStoredBlock, _chainHead);
                    var splitPointHash = splitPoint != null ? splitPoint.Header.HashAsString : "?";
                    _log.InfoFormat("Block forks the chain at {0}, but it did not cause a reorganize:{1}{2}",
                                    splitPointHash, Environment.NewLine, newStoredBlock);
                }

                // We may not have any transactions if we received only a header. That never happens today but will in
                // future when GetHeaders is used as an optimization.
                if (newTransactions != null)
                {
                    SendTransactionsToWallet(newStoredBlock, NewBlockType.SideChain, newTransactions);
                }

                if (haveNewBestChain)
                {
                    HandleNewBestChain(newStoredBlock);
                }
            }
        }
コード例 #17
0
 /// <exception cref="VerificationException"/>
 private static void SendTransactionsToWallet(StoredBlock block, NewBlockType blockType, IEnumerable <KeyValuePair <Wallet, List <Transaction> > > newTransactions)
 {
     foreach (var item in newTransactions)
     {
         try
         {
             foreach (var tx in item.Value)
             {
                 item.Key.Receive(tx, block, blockType);
             }
         }
         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.WarnFormat("Failed to parse a script: {0}", e);
         }
     }
 }
コード例 #18
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public void Put(StoredBlock block)
 {
     lock (this)
     {
         try
         {
             var hash = new Sha256Hash(block.Header.Hash);
             Debug.Assert(!_blockMap.ContainsKey(hash), "Attempt to insert duplicate");
             // Append to the end of the file. The other fields in StoredBlock will be recalculated when it's reloaded.
             var bytes = block.Header.BitcoinSerialize();
             _stream.Write(bytes);
             _stream.Flush();
             _blockMap[hash] = block;
         }
         catch (IOException e)
         {
             throw new BlockStoreException(e);
         }
     }
 }
コード例 #19
0
 // This should be static but the language does not allow for it.
 /// <exception cref="System.IO.IOException" />
 public void Write(Stream channel, StoredBlock block)
 {
     using (var buf = ByteBuffer.Allocate(Size))
     {
         buf.PutInt((int)block.Height);
         var chainWorkBytes = block.ChainWork.ToByteArray();
         Debug.Assert(chainWorkBytes.Length <= _chainWorkBytes, "Ran out of space to store chain work!");
         if (chainWorkBytes.Length < _chainWorkBytes)
         {
             // Pad to the right size.
             buf.Put(_emptyBytes, 0, _chainWorkBytes - chainWorkBytes.Length);
         }
         buf.Put(chainWorkBytes);
         buf.Put(block.Header.BitcoinSerialize());
         buf.Position     = 0;
         channel.Position = channel.Length;
         channel.Write(buf.ToArray());
         channel.Position = channel.Length - Size;
     }
 }
コード例 #20
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public void SetChainHead(StoredBlock chainHead)
 {
     lock (this)
     {
         try
         {
             var hash = chainHead.Header.Hash;
             _chainHead = new Sha256Hash(hash);
             // Write out new hash to the first 32 bytes of the file past one (first byte is version number).
             var originalPos = _channel.Position;
             _channel.Position = 1;
             _channel.Write(hash, 0, hash.Length);
             _channel.Position = originalPos;
         }
         catch (IOException e)
         {
             throw new BlockStoreException(e);
         }
     }
 }
コード例 #21
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public void Put(StoredBlock block)
 {
     lock (this)
     {
         try
         {
             var hash = new Sha256Hash(block.Header.Hash);
             // Append to the end of the file.
             _dummyRecord.Write(_channel, block);
             _blockCache[hash] = block;
             while (_blockCache.Count > 100)
             {
                 _blockCache.RemoveAt(0);
             }
         }
         catch (IOException e)
         {
             throw new BlockStoreException(e);
         }
     }
 }
コード例 #22
0
        /// <exception cref="BitCoinSharp.ScriptException" />
        /// <exception cref="BitCoinSharp.VerificationException" />
        private void ScanTransaction(StoredBlock block, Transaction tx, NewBlockType blockType)
        {
            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)
                {
                    return;
                }
                // This is not thread safe as a key could be removed between the call to isMine and receive.
                if (output.IsMine(_wallet))
                {
                    shouldReceive = true;
                }
            }

            // Coinbase transactions don't have anything useful in their inputs (as they create coins out of thin air).
            if (!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)
            {
                _wallet.Receive(tx, block, blockType);
            }
        }
コード例 #23
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public void Put(StoredBlock block)
 {
     lock (this)
     {
         try
         {
             var hash = new Sha256Hash(block.Header.Hash);
             Debug.Assert(!_blockMap.ContainsKey(hash), "Attempt to insert duplicate");
             // Append to the end of the file. The other fields in StoredBlock will be recalculated when it's reloaded.
             var bytes = block.Header.BitcoinSerialize();
             _stream.Write(bytes);
             _stream.Flush();
             _blockMap[hash] = block;
         }
         catch (IOException e)
         {
             throw new BlockStoreException(e);
         }
     }
 }
コード例 #24
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public void SetChainHead(StoredBlock chainHead)
 {
     _chainHead = chainHead;
 }
コード例 #25
0
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
 /// <summary>
 /// Constructs a BlockChain connected to the given list of wallets and a store.
 /// </summary>
 /// <exception cref="BlockStoreException"/>
 public BlockChain(NetworkParameters @params, IEnumerable<Wallet> wallets, IBlockStore blockStore)
 {
     _blockStore = blockStore;
     _chainHead = blockStore.GetChainHead();
     _log.InfoFormat("chain head is:{0}{1}", Environment.NewLine, _chainHead.Header);
     _params = @params;
     _wallets = new List<Wallet>(wallets);
 }
コード例 #26
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);
     }
 }
コード例 #27
0
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
        /// <exception cref="BitCoinSharp.ScriptException" />
        /// <exception cref="BitCoinSharp.VerificationException" />
        private void ScanTransaction(StoredBlock block, Transaction tx, NewBlockType blockType)
        {
            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) return;
                // This is not thread safe as a key could be removed between the call to isMine and receive.
                if (output.IsMine(_wallet))
                {
                    shouldReceive = true;
                }
            }

            // Coinbase transactions don't have anything useful in their inputs (as they create coins out of thin air).
            if (!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)
                _wallet.Receive(tx, block, blockType);
        }
コード例 #28
0
        /// <summary>
        /// Throws an exception if the blocks difficulty is not correct.
        /// </summary>
        /// <exception cref="BitCoinSharp.BlockStoreException" />
        /// <exception cref="BitCoinSharp.VerificationException" />
        private void CheckDifficultyTransitions(StoredBlock storedPrev, StoredBlock storedNext)
        {
            var prev = storedPrev.Header;
            var next = storedNext.Header;

            // Is this supposed to be a difficulty transition point?
            if ((storedPrev.Height + 1) % _params.Interval != 0)
            {
                // No ... so check the difficulty didn't actually change.
                if (next.DifficultyTarget != prev.DifficultyTarget)
                {
                    throw new VerificationException("Unexpected change in difficulty at height " + storedPrev.Height +
                                                    ": " + next.DifficultyTarget.ToString("x") + " vs " +
                                                    prev.DifficultyTarget.ToString("x"));
                }
                return;
            }

            // We need to find a block far back in the chain. It's OK that this is expensive because it only occurs every
            // two weeks after the initial block chain download.
            var now    = Environment.TickCount;
            var cursor = _blockStore.Get(prev.Hash);

            for (var i = 0; i < _params.Interval - 1; i++)
            {
                if (cursor == null)
                {
                    // This should never happen. If it does, it means we are following an incorrect or busted chain.
                    throw new VerificationException(
                              "Difficulty transition point but we did not find a way back to the genesis block.");
                }
                cursor = _blockStore.Get(cursor.Header.PrevBlockHash);
            }
            _log.InfoFormat("Difficulty transition traversal took {0}ms", Environment.TickCount - now);

            var blockIntervalAgo = cursor.Header;
            var timespan         = (int)(prev.Time - blockIntervalAgo.Time);

            // Limit the adjustment step.
            if (timespan < _params.TargetTimespan / 4)
            {
                timespan = _params.TargetTimespan / 4;
            }
            if (timespan > _params.TargetTimespan * 4)
            {
                timespan = _params.TargetTimespan * 4;
            }

            var newDifficulty = Utils.DecodeCompactBits(blockIntervalAgo.DifficultyTarget);

            newDifficulty = newDifficulty.Multiply(BigInteger.ValueOf(timespan));
            newDifficulty = newDifficulty.Divide(BigInteger.ValueOf(_params.TargetTimespan));

            if (newDifficulty.CompareTo(_params.ProofOfWorkLimit) > 0)
            {
                _log.WarnFormat("Difficulty hit proof of work limit: {0}", newDifficulty.ToString(16));
                newDifficulty = _params.ProofOfWorkLimit;
            }

            var accuracyBytes      = (int)(next.DifficultyTarget >> 24) - 3;
            var receivedDifficulty = next.GetDifficultyTargetAsInteger();

            // The calculated difficulty is to a higher precision than received, so reduce here.
            var mask = BigInteger.ValueOf(0xFFFFFF).ShiftLeft(accuracyBytes * 8);

            newDifficulty = newDifficulty.And(mask);

            if (newDifficulty.CompareTo(receivedDifficulty) != 0)
            {
                throw new VerificationException("Network provided difficulty bits do not match what was calculated: " +
                                                receivedDifficulty.ToString(16) + " vs " + newDifficulty.ToString(16));
            }
        }
コード例 #29
0
ファイル: Wallet.cs プロジェクト: bitspill/Gridcoin-master
 /// <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);
     }
 }
コード例 #30
0
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
 /// <exception cref="BitCoinSharp.VerificationException" />
 private void SendTransactionsToWallet(StoredBlock block, NewBlockType blockType, IEnumerable<Transaction> newTransactions)
 {
     // Scan the transactions to find out if any mention addresses we own.
     foreach (var tx in newTransactions)
     {
         try
         {
             ScanTransaction(block, tx, blockType);
         }
         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.WarnFormat("Failed to parse a script: {0}", e);
         }
     }
 }
コード例 #31
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public void SetChainHead(StoredBlock chainHead)
 {
     lock (this)
     {
         try
         {
             var hash = chainHead.Header.Hash;
             _chainHead = new Sha256Hash(hash);
             // Write out new hash to the first 32 bytes of the file past one (first byte is version number).
             _stream.Seek(1, SeekOrigin.Begin);
             _stream.Write(hash, 0, hash.Length);
         }
         catch (IOException e)
         {
             throw new BlockStoreException(e);
         }
     }
 }
コード例 #32
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public void Put(StoredBlock block)
 {
     lock (this)
     {
         var hash = block.Header.Hash;
         using (var bos = new MemoryStream())
         {
             var oos = new BinaryFormatter();
             oos.Serialize(bos, block);
             _blockMap[ByteBuffer.Wrap(hash)] = bos.ToArray();
         }
     }
 }
コード例 #33
0
 // This should be static but the language does not allow for it.
 /// <exception cref="System.IO.IOException" />
 public void Write(Stream channel, StoredBlock block)
 {
     using (var buf = ByteBuffer.Allocate(Size))
     {
         buf.PutInt((int) block.Height);
         var chainWorkBytes = block.ChainWork.ToByteArray();
         Debug.Assert(chainWorkBytes.Length <= _chainWorkBytes, "Ran out of space to store chain work!");
         if (chainWorkBytes.Length < _chainWorkBytes)
         {
             // Pad to the right size.
             buf.Put(_emptyBytes, 0, _chainWorkBytes - chainWorkBytes.Length);
         }
         buf.Put(chainWorkBytes);
         buf.Put(block.Header.BitcoinSerialize());
         buf.Position = 0;
         channel.Position = channel.Length;
         channel.Write(buf.ToArray());
         channel.Position = channel.Length - Size;
     }
 }
コード例 #34
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);
     }
 }
コード例 #35
0
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
 /// <summary>
 /// Called as part of connecting a block when the new block results in a different chain having higher total work.
 /// </summary>
 /// <exception cref="BlockStoreException"/>
 /// <exception cref="VerificationException"/>
 private void HandleNewBestChain(StoredBlock newChainHead)
 {
     // This chain has overtaken the one we currently believe is best. Reorganize is required.
     //
     // Firstly, calculate the block at which the chain diverged. We only need to examine the
     // chain from beyond this block to find differences.
     var splitPoint = FindSplit(newChainHead, _chainHead);
     _log.InfoFormat("Re-organize after split at height {0}", splitPoint.Height);
     _log.InfoFormat("Old chain head: {0}", _chainHead.Header.HashAsString);
     _log.InfoFormat("New chain head: {0}", newChainHead.Header.HashAsString);
     _log.InfoFormat("Split at block: {0}", splitPoint.Header.HashAsString);
     // Then build a list of all blocks in the old part of the chain and the new part.
     var oldBlocks = GetPartialChain(_chainHead, splitPoint);
     var newBlocks = GetPartialChain(newChainHead, splitPoint);
     // Now inform the wallet. This is necessary so the set of currently active transactions (that we can spend)
     // can be updated to take into account the re-organize. We might also have received new coins we didn't have
     // before and our previous spends might have been undone.
     foreach (var wallet in _wallets)
     {
         wallet.Reorganize(oldBlocks, newBlocks);
     }
     // Update the pointer to the best known block.
     ChainHead = newChainHead;
 }
コード例 #36
0
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
 /// <summary>
 /// Locates the point in the chain at which newStoredBlock and chainHead diverge. Returns null if no split point was
 /// found (ie they are part of the same chain).
 /// </summary>
 /// <exception cref="BlockStoreException"/>
 private StoredBlock FindSplit(StoredBlock newChainHead, StoredBlock chainHead)
 {
     var currentChainCursor = chainHead;
     var newChainCursor = newChainHead;
     // Loop until we find the block both chains have in common. Example:
     //
     //    A -> B -> C -> D
     //         \--> E -> F -> G
     //
     // findSplit will return block B. chainHead = D and newChainHead = G.
     while (!currentChainCursor.Equals(newChainCursor))
     {
         if (currentChainCursor.Height > newChainCursor.Height)
         {
             currentChainCursor = currentChainCursor.GetPrev(_blockStore);
             Debug.Assert(newChainCursor != null, "Attempt to follow an orphan chain");
         }
         else
         {
             newChainCursor = newChainCursor.GetPrev(_blockStore);
             Debug.Assert(currentChainCursor != null, "Attempt to follow an orphan chain");
         }
     }
     return currentChainCursor;
 }
コード例 #37
0
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
        /// <summary>
        /// Throws an exception if the blocks difficulty is not correct.
        /// </summary>
        /// <exception cref="BlockStoreException"/>
        /// <exception cref="VerificationException"/>
        private void CheckDifficultyTransitions(StoredBlock storedPrev, StoredBlock storedNext)
        {
            var prev = storedPrev.Header;
            var next = storedNext.Header;
            // Is this supposed to be a difficulty transition point?
            if ((storedPrev.Height + 1)%_params.Interval != 0)
            {
                // No ... so check the difficulty didn't actually change.
                if (next.DifficultyTarget != prev.DifficultyTarget)
                    throw new VerificationException("Unexpected change in difficulty at height " + storedPrev.Height +
                                                    ": " + next.DifficultyTarget.ToString("x") + " vs " +
                                                    prev.DifficultyTarget.ToString("x"));
                return;
            }

            // We need to find a block far back in the chain. It's OK that this is expensive because it only occurs every
            // two weeks after the initial block chain download.
            var now = Environment.TickCount;
            var cursor = _blockStore.Get(prev.Hash);
            for (var i = 0; i < _params.Interval - 1; i++)
            {
                if (cursor == null)
                {
                    // This should never happen. If it does, it means we are following an incorrect or busted chain.
                    throw new VerificationException(
                        "Difficulty transition point but we did not find a way back to the genesis block.");
                }
                cursor = _blockStore.Get(cursor.Header.PrevBlockHash);
            }
            _log.DebugFormat("Difficulty transition traversal took {0}ms", Environment.TickCount - now);

            var blockIntervalAgo = cursor.Header;
            var timespan = (int) (prev.TimeSeconds - blockIntervalAgo.TimeSeconds);
            // Limit the adjustment step.
            if (timespan < _params.TargetTimespan/4)
                timespan = _params.TargetTimespan/4;
            if (timespan > _params.TargetTimespan*4)
                timespan = _params.TargetTimespan*4;

            var newDifficulty = Utils.DecodeCompactBits(blockIntervalAgo.DifficultyTarget);
            newDifficulty = newDifficulty.Multiply(BigInteger.ValueOf(timespan));
            newDifficulty = newDifficulty.Divide(BigInteger.ValueOf(_params.TargetTimespan));

            if (newDifficulty.CompareTo(_params.ProofOfWorkLimit) > 0)
            {
                _log.DebugFormat("Difficulty hit proof of work limit: {0}", newDifficulty.ToString(16));
                newDifficulty = _params.ProofOfWorkLimit;
            }

            var accuracyBytes = (int) (next.DifficultyTarget >> 24) - 3;
            var receivedDifficulty = next.GetDifficultyTargetAsInteger();

            // The calculated difficulty is to a higher precision than received, so reduce here.
            var mask = BigInteger.ValueOf(0xFFFFFF).ShiftLeft(accuracyBytes*8);
            newDifficulty = newDifficulty.And(mask);

            if (newDifficulty.CompareTo(receivedDifficulty) != 0)
                throw new VerificationException("Network provided difficulty bits do not match what was calculated: " +
                                                receivedDifficulty.ToString(16) + " vs " + newDifficulty.ToString(16));
        }
コード例 #38
0
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
 /// <summary>
 /// Constructs a BlockChain connected to the given wallet and store. To obtain a <see cref="Wallet">Wallet</see> you can construct
 /// one from scratch, or you can deserialize a saved wallet from disk using <see cref="Wallet.LoadFromFile(System.IO.FileInfo)">Wallet.LoadFromFile(System.IO.FileInfo)</see><p />
 /// </summary>
 /// <remarks>
 /// For the store you can use a <see cref="MemoryBlockStore">MemoryBlockStore</see> if you don't care about saving the downloaded data, or a
 /// <see cref="BoundedOverheadBlockStore">BoundedOverheadBlockStore</see> if you'd like to ensure fast start-up the next time you run the program.
 /// </remarks>
 public BlockChain(NetworkParameters @params, Wallet wallet, IBlockStore blockStore)
 {
     _blockStore = blockStore;
     _chainHead = blockStore.GetChainHead();
     _log.InfoFormat("chain head is:{0}{1}", Environment.NewLine, _chainHead.Header);
     _params = @params;
     _wallet = wallet;
 }
コード例 #39
0
ファイル: Wallet.cs プロジェクト: bitspill/Gridcoin-master
        /// <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()));
                    }
                }
            }
        }
コード例 #40
0
ファイル: Transaction.cs プロジェクト: aklein53/bitcoinsharp
 /// <summary>
 /// Adds the given block to the internal serializable set of blocks in which this transaction appears. This is
 /// used by the wallet to ensure transactions that appear on side chains are recorded properly even though the
 /// block stores do not save the transaction data at all.
 /// </summary>
 internal void AddBlockAppearance(StoredBlock block)
 {
     if (AppearsIn == null)
     {
         AppearsIn = new HashSet<StoredBlock>();
     }
     AppearsIn.Add(block);
 }
コード例 #41
0
 /// <summary>
 /// Returns true if this objects chainWork is higher than the others.
 /// </summary>
 public bool MoreWorkThan(StoredBlock other)
 {
     return(_chainWork.CompareTo(other._chainWork) > 0);
 }
コード例 #42
0
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
 /// <exception cref="VerificationException"/>
 private static void SendTransactionsToWallet(StoredBlock block, NewBlockType blockType, IDictionary<Wallet, List<Transaction>> newTransactions)
 {
     foreach (var item in newTransactions)
     {
         try
         {
             foreach (var tx in item.Value)
             {
                 item.Key.Receive(tx, block, blockType);
             }
         }
         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.WarnFormat("Failed to parse a script: {0}", e);
         }
     }
 }
コード例 #43
0
ファイル: StoredBlock.cs プロジェクト: aklein53/bitcoinsharp
 /// <summary>
 /// Returns true if this objects chainWork is higher than the others.
 /// </summary>
 public bool MoreWorkThan(StoredBlock other)
 {
     return _chainWork.CompareTo(other._chainWork) > 0;
 }
コード例 #44
0
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
        /// <exception cref="BlockStoreException"/>
        /// <exception cref="VerificationException"/>
        private void ConnectBlock(StoredBlock newStoredBlock, StoredBlock storedPrev, IDictionary<Wallet, List<Transaction>> newTransactions)
        {
            if (storedPrev.Equals(_chainHead))
            {
                // This block connects to the best known block, it is a normal continuation of the system.
                ChainHead = newStoredBlock;
                _log.DebugFormat("Chain is now {0} blocks high", _chainHead.Height);
                if (newTransactions != null)
                    SendTransactionsToWallet(newStoredBlock, NewBlockType.BestChain, newTransactions);
            }
            else
            {
                // This block connects to somewhere other than the top of the best known chain. We treat these differently.
                //
                // Note that we send the transactions to the wallet FIRST, even if we're about to re-organize this block
                // to become the new best chain head. This simplifies handling of the re-org in the Wallet class.
                var haveNewBestChain = newStoredBlock.MoreWorkThan(_chainHead);
                if (haveNewBestChain)
                {
                    _log.Info("Block is causing a re-organize");
                }
                else
                {
                    var splitPoint = FindSplit(newStoredBlock, _chainHead);
                    var splitPointHash = splitPoint != null ? splitPoint.Header.HashAsString : "?";
                    _log.InfoFormat("Block forks the chain at {0}, but it did not cause a reorganize:{1}{2}",
                                    splitPointHash, Environment.NewLine, newStoredBlock);
                }

                // We may not have any transactions if we received only a header. That never happens today but will in
                // future when GetHeaders is used as an optimization.
                if (newTransactions != null)
                {
                    SendTransactionsToWallet(newStoredBlock, NewBlockType.SideChain, newTransactions);
                }

                if (haveNewBestChain)
                    HandleNewBestChain(newStoredBlock);
            }
        }
コード例 #45
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public void Put(StoredBlock block)
 {
     lock (this)
     {
         try
         {
             var hash = new Sha256Hash(block.Header.Hash);
             // Append to the end of the file.
             _dummyRecord.Write(_channel, block);
             _blockCache[hash] = block;
             while (_blockCache.Count > 100)
             {
                 _blockCache.RemoveAt(0);
             }
         }
         catch (IOException e)
         {
             throw new BlockStoreException(e);
         }
     }
 }
コード例 #46
0
ファイル: BlockChain.cs プロジェクト: aklein53/bitcoinsharp
 /// <summary>
 /// Returns the set of contiguous blocks between 'higher' and 'lower'. Higher is included, lower is not.
 /// </summary>
 /// <exception cref="BlockStoreException"/>
 private IList<StoredBlock> GetPartialChain(StoredBlock higher, StoredBlock lower)
 {
     Debug.Assert(higher.Height > lower.Height);
     var results = new LinkedList<StoredBlock>();
     var cursor = higher;
     while (true)
     {
         results.AddLast(cursor);
         cursor = cursor.GetPrev(_blockStore);
         Debug.Assert(cursor != null, "Ran off the end of the chain");
         if (cursor.Equals(lower)) break;
     }
     return results.ToList();
 }
コード例 #47
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public void SetChainHead(StoredBlock chainHead)
 {
     lock (this)
     {
         try
         {
             var hash = chainHead.Header.Hash;
             _chainHead = new Sha256Hash(hash);
             // Write out new hash to the first 32 bytes of the file past one (first byte is version number).
             var originalPos = _channel.Position;
             _channel.Position = 1;
             _channel.Write(hash, 0, hash.Length);
             _channel.Position = originalPos;
         }
         catch (IOException e)
         {
             throw new BlockStoreException(e);
         }
     }
 }
コード例 #48
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 private void CreateNewStore(NetworkParameters @params, FileInfo file)
 {
     // Create a new block store if the file wasn't found or anything went wrong whilst reading.
     _blockCache.Clear();
     try
     {
         if (_channel != null)
         {
             _channel.Dispose();
             _channel = null;
         }
         file.Delete();
         _channel = file.Create(); // Create fresh.
         _channel.Write(_fileFormatVersion);
     }
     catch (IOException e1)
     {
         // We could not load a block store nor could we create a new one!
         throw new BlockStoreException(e1);
     }
     try
     {
         // Set up the genesis block. When we start out fresh, it is by definition the top of the chain.
         var genesis = @params.GenesisBlock.CloneAsHeader();
         var storedGenesis = new StoredBlock(genesis, genesis.GetWork(), 0);
         _chainHead = new Sha256Hash(storedGenesis.Header.Hash);
         _channel.Write(_chainHead.Hash);
         Put(storedGenesis);
     }
     catch (IOException e)
     {
         throw new BlockStoreException(e);
     }
 }
コード例 #49
0
 /// <exception cref="BitCoinSharp.BlockStoreException" />
 public void SetChainHead(StoredBlock chainHead)
 {
     _chainHead = chainHead;
 }