/// <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); }
/// <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); } }
/// <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); } }
/// <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; }
/// <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; } }