/// <summary> /// Connects this input to the relevant output of the referenced transaction if it's in the given map. /// Connecting means updating the internal pointers and spent flags. /// </summary> /// <param name="transactions">Map of txhash->transaction.</param> /// <param name="disconnect">Whether to abort if there's a pre-existing connection or not.</param> /// <returns>True if connection took place, false if the referenced transaction was not in the list.</returns> internal ConnectionResult Connect(IDictionary <Sha256Hash, Transaction> transactions, bool disconnect) { var h = new Sha256Hash(Outpoint.Hash); Transaction tx; if (!transactions.TryGetValue(h, out tx)) { return(ConnectionResult.NoSuchTx); } var @out = tx.Outputs[Outpoint.Index]; if ([email protected]) { if (disconnect) { @out.MarkAsUnspent(); } else { return(ConnectionResult.AlreadySpent); } } Outpoint.FromTx = tx; @out.MarkAsSpent(this); return(ConnectionResult.Success); }
/// <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); } }
/// <exception cref="System.IO.IOException" /> /// <exception cref="BitCoinSharp.BlockStoreException" /> private void Load(FileInfo file) { _log.InfoFormat("Reading block store from {0}", file); if (_channel != null) { _channel.Dispose(); } _channel = file.OpenRead(); // Read a version byte. var version = _channel.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 != _fileFormatVersion) { throw new BlockStoreException("Bad version number: " + version); } // Chain head pointer is the first thing in the file. var chainHeadHash = new byte[32]; _channel.Read(chainHeadHash); _chainHead = new Sha256Hash(chainHeadHash); _log.InfoFormat("Read chain head from disk: {0}", _chainHead); _channel.Position = _channel.Length - Record.Size; }
/// <exception cref="ProtocolException"/> protected override void Parse() { _version = ReadUint32(); _prevBlockHash = ReadHash(); _merkleRoot = ReadHash(); _time = ReadUint32(); _difficultyTarget = ReadUint32(); _nonce = ReadUint32(); _hash = new Sha256Hash(Utils.ReverseBytes(Utils.DoubleDigest(Bytes, 0, Cursor))); if (Cursor == Bytes.Length) { // This message is just a header, it has no transactions. return; } var numTransactions = (int)ReadVarInt(); Transactions = new List <Transaction>(numTransactions); for (var i = 0; i < numTransactions; i++) { var tx = new Transaction(Params, Bytes, Cursor); Transactions.Add(tx); Cursor += tx.MessageSize; } }
/// <exception cref="BitCoinSharp.ProtocolException" /> protected override void Parse() { _version = ReadUint32(); // First come the inputs. var numInputs = ReadVarInt(); _inputs = new List <TransactionInput>((int)numInputs); for (var i = 0UL; i < numInputs; i++) { var input = new TransactionInput(Params, this, Bytes, Cursor); _inputs.Add(input); Cursor += input.MessageSize; } // Now the outputs var numOutputs = ReadVarInt(); _outputs = new List <TransactionOutput>((int)numOutputs); for (var i = 0UL; i < numOutputs; i++) { var output = new TransactionOutput(Params, this, Bytes, Cursor); _outputs.Add(output); Cursor += output.MessageSize; } _lockTime = ReadUint32(); // Store a hash, it may come in useful later (want to avoid re-serialization costs). _hash = new Sha256Hash(Utils.ReverseBytes(Utils.DoubleDigest(Bytes, Offset, Cursor - Offset))); }
/// <summary> /// Special case constructor, used for the genesis node, cloneAsHeader and unit tests. /// </summary> internal Block(NetworkParameters @params) : base(@params) { // Set up a few basic things. We are not complete after this though. _version = 1; _difficultyTarget = 0x1d07fff8; _time = (uint)UnixTime.ToUnixTime(DateTime.UtcNow); _prevBlockHash = Sha256Hash.ZeroHash; }
/// <summary> /// Adds a transaction to this block. /// </summary> internal void AddTransaction(Transaction t) { if (Transactions == null) { Transactions = new List <Transaction>(); } Transactions.Add(t); // Force a recalculation next time the values are needed. _merkleRoot = null; _hash = null; }
// TODO: Clean all this up once TransactionOutPoint disappears. /// <summary> /// Locates the referenced output from the given pool of transactions. /// </summary> /// <returns>The TransactionOutput or null if the transactions map doesn't contain the referenced tx.</returns> internal TransactionOutput GetConnectedOutput(IDictionary <Sha256Hash, Transaction> transactions) { var h = new Sha256Hash(Outpoint.Hash); Transaction tx; if (!transactions.TryGetValue(h, out tx)) { return(null); } var @out = tx.Outputs[Outpoint.Index]; return(@out); }
/// <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); } } }
/// <exception cref="IOException"/> private void BlockChainDownload(Sha256Hash toHash) { // This may run in ANY thread. // The block chain download process is a bit complicated. Basically, we start with zero or more blocks in a // chain that we have from a previous session. We want to catch up to the head of the chain BUT we don't know // where that chain is up to or even if the top block we have is even still in the chain - we // might have got ourselves onto a fork that was later resolved by the network. // // To solve this, we send the peer a block locator which is just a list of block hashes. It contains the // blocks we know about, but not all of them, just enough of them so the peer can figure out if we did end up // on a fork and if so, what the earliest still valid block we know about is likely to be. // // Once it has decided which blocks we need, it will send us an inv with up to 500 block messages. We may // have some of them already if we already have a block chain and just need to catch up. Once we request the // last block, if there are still more to come it sends us an "inv" containing only the hash of the head // block. // // That causes us to download the head block but then we find (in processBlock) that we can't connect // it to the chain yet because we don't have the intermediate blocks. So we rerun this function building a // new block locator describing where we're up to. // // The getblocks with the new locator gets us another inv with another bunch of blocks. We download them once // again. This time when the peer sends us an inv with the head block, we already have it so we won't download // it again - but we recognize this case as special and call back into blockChainDownload to continue the // process. // // So this is a complicated process but it has the advantage that we can download a chain of enormous length // in a relatively stateless manner and with constant/bounded memory usage. _log.InfoFormat("blockChainDownload({0})", toHash); // TODO: Block locators should be abstracted out rather than special cased here. var blockLocator = new LinkedList <Sha256Hash>(); // We don't do the exponential thinning here, so if we get onto a fork of the chain we will end up // re-downloading the whole thing again. blockLocator.AddLast(_params.GenesisBlock.Hash); var topBlock = _blockChain.ChainHead.Header; if (!topBlock.Equals(_params.GenesisBlock)) { blockLocator.AddFirst(topBlock.Hash); } var message = new GetBlocksMessage(_params, blockLocator.ToList(), toHash); _conn.WriteMessage(message); }
/// <summary> /// Asks the connected peer for the block of the given hash, and returns a Future representing the answer. /// If you want the block right away and don't mind waiting for it, just call .get() on the result. Your thread /// will block until the peer answers. You can also use the Future object to wait with a timeout, or just check /// whether it's done later. /// </summary> /// <param name="blockHash">Hash of the block you were requesting.</param> /// <exception cref="IOException"/> public IAsyncResult BeginGetBlock(Sha256Hash blockHash, AsyncCallback callback, object state) { var getdata = new GetDataMessage(_params); var inventoryItem = new InventoryItem(InventoryItem.ItemType.Block, blockHash); getdata.AddItem(inventoryItem); var future = new GetDataFuture <Block>(inventoryItem, callback, state); // Add to the list of things we're waiting for. It's important this come before the network send to avoid // race conditions. lock (_pendingGetBlockFutures) { _pendingGetBlockFutures.Add(future); } _conn.WriteMessage(getdata); return(future); }
/// <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); } } }
/// <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); } } }
/// <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); } } }
/// <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); } } }
/// <exception cref="BitCoinSharp.BlockStoreException" /> /// <exception cref="System.IO.IOException" /> /// <exception cref="BitCoinSharp.ProtocolException" /> private Record GetRecord(Sha256Hash hash) { var startPos = _channel.Position; // Use our own file pointer within the tight loop as updating channel positions is really expensive. var pos = startPos; var record = new Record(); do { if (!record.Read(_channel, pos, _buf)) { throw new IOException("Failed to read buffer"); } if (record.GetHeader(_params).Hash.SequenceEqual(hash.Hash)) { // Found it. Update file position for next time. _channel.Position = pos; return(record); } // Did not find it. if (pos == 1 + 32) { // At the start so wrap around to the end. pos = _channel.Length - Record.Size; } else { // Move backwards. pos = pos - Record.Size; Debug.Assert(pos >= 1 + 32, pos.ToString()); } } while (pos != startPos); // Was never stored. _channel.Position = pos; return(null); }
/// <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); } } }
/// <exception cref="ProtocolException"/> protected override void Parse() { _version = ReadUint32(); _prevBlockHash = ReadHash(); _merkleRoot = ReadHash(); _time = ReadUint32(); _difficultyTarget = ReadUint32(); _nonce = ReadUint32(); _hash = new Sha256Hash(Utils.ReverseBytes(Utils.DoubleDigest(Bytes, 0, Cursor))); if (Cursor == Bytes.Length) { // This message is just a header, it has no transactions. return; } var numTransactions = (int) ReadVarInt(); Transactions = new List<Transaction>(numTransactions); for (var i = 0; i < numTransactions; i++) { var tx = new Transaction(Params, Bytes, Cursor); Transactions.Add(tx); Cursor += tx.MessageSize; } }
/// <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); } }
public GetBlocksMessage(NetworkParameters @params, IList<Sha256Hash> locator, Sha256Hash stopHash) : base(@params) { _locator = locator; _stopHash = stopHash; }
public IList<Sha256Hash> Locator { get { return _locator; } } public Sha256Hash StopHash
/// <exception cref="BitCoinSharp.BlockStoreException" /> /// <exception cref="System.IO.IOException" /> /// <exception cref="BitCoinSharp.ProtocolException" /> private Record GetRecord(Sha256Hash hash) { var startPos = _channel.Position; // Use our own file pointer within the tight loop as updating channel positions is really expensive. var pos = startPos; var record = new Record(); do { if (!record.Read(_channel, pos, _buf)) throw new IOException("Failed to read buffer"); if (record.GetHeader(_params).Hash.SequenceEqual(hash.Hash)) { // Found it. Update file position for next time. _channel.Position = pos; return record; } // Did not find it. if (pos == 1 + 32) { // At the start so wrap around to the end. pos = _channel.Length - Record.Size; } else { // Move backwards. pos = pos - Record.Size; Debug.Assert(pos >= 1 + 32, pos.ToString()); } } while (pos != startPos); // Was never stored. _channel.Position = pos; return null; }
/// <exception cref="System.IO.IOException" /> /// <exception cref="BitCoinSharp.BlockStoreException" /> private void Load(FileInfo file) { _log.InfoFormat("Reading block store from {0}", file); if (_channel != null) { _channel.Dispose(); } _channel = file.OpenRead(); // Read a version byte. var version = _channel.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 != _fileFormatVersion) { throw new BlockStoreException("Bad version number: " + version); } // Chain head pointer is the first thing in the file. var chainHeadHash = new byte[32]; _channel.Read(chainHeadHash); _chainHead = new Sha256Hash(chainHeadHash); _log.InfoFormat("Read chain head from disk: {0}", _chainHead); _channel.Position = _channel.Length - Record.Size; }
/// <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); } } }
/// <summary> /// Adds a transaction to this block. /// </summary> internal void AddTransaction(Transaction t) { if (Transactions == null) { Transactions = new List<Transaction>(); } Transactions.Add(t); // Force a recalculation next time the values are needed. _merkleRoot = null; _hash = null; }
/// <summary> /// Special case constructor, used for the genesis node, cloneAsHeader and unit tests. /// </summary> internal Block(NetworkParameters @params) : base(@params) { // Set up a few basic things. We are not complete after this though. _version = 1; _difficultyTarget = 0x1d07fff8; _time = (uint) UnixTime.ToUnixTime(DateTime.UtcNow); _prevBlockHash = Sha256Hash.ZeroHash; }
/// <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> /// Connects this input to the relevant output of the referenced transaction if it's in the given map. /// Connecting means updating the internal pointers and spent flags. /// </summary> /// <param name="transactions">Map of txhash->transaction.</param> /// <param name="disconnect">Whether to abort if there's a pre-existing connection or not.</param> /// <returns>True if connection took place, false if the referenced transaction was not in the list.</returns> internal ConnectionResult Connect(IDictionary<Sha256Hash, Transaction> transactions, bool disconnect) { var h = new Sha256Hash(Outpoint.Hash); Transaction tx; if (!transactions.TryGetValue(h, out tx)) return ConnectionResult.NoSuchTx; var @out = tx.Outputs[Outpoint.Index]; if ([email protected]) { if (disconnect) @out.MarkAsUnspent(); else return ConnectionResult.AlreadySpent; } Outpoint.FromTx = tx; @out.MarkAsSpent(this); return ConnectionResult.Success; }
/// <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); } } }
/// <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); } }
/// <exception cref="BitCoinSharp.ProtocolException" /> protected override void Parse() { _version = ReadUint32(); // First come the inputs. var numInputs = ReadVarInt(); _inputs = new List<TransactionInput>((int) numInputs); for (var i = 0UL; i < numInputs; i++) { var input = new TransactionInput(Params, this, Bytes, Cursor); _inputs.Add(input); Cursor += input.MessageSize; } // Now the outputs var numOutputs = ReadVarInt(); _outputs = new List<TransactionOutput>((int) numOutputs); for (var i = 0UL; i < numOutputs; i++) { var output = new TransactionOutput(Params, this, Bytes, Cursor); _outputs.Add(output); Cursor += output.MessageSize; } _lockTime = ReadUint32(); // Store a hash, it may come in useful later (want to avoid re-serialization costs). _hash = new Sha256Hash(Utils.ReverseBytes(Utils.DoubleDigest(Bytes, Offset, Cursor - Offset))); }
/// <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); } } }
// TODO: Clean all this up once TransactionOutPoint disappears. /// <summary> /// Locates the referenced output from the given pool of transactions. /// </summary> /// <returns>The TransactionOutput or null if the transactions map doesn't contain the referenced tx.</returns> internal TransactionOutput GetConnectedOutput(IDictionary<Sha256Hash, Transaction> transactions) { var h = new Sha256Hash(Outpoint.Hash); Transaction tx; if (!transactions.TryGetValue(h, out tx)) return null; var @out = tx.Outputs[Outpoint.Index]; return @out; }
/// <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); } } }