/// <summary> /// Saves index and current blocks to file. /// </summary> /// <returns>True if succeeds.</returns> public bool Save() { DbFile.Write(Config.GetBlockIndexFilePath(), _indexFile); foreach (var p in _blockFileByIndex) { var blockFile = p.Value; if (blockFile.IsDirty()) { BlockFile.Write(blockFile); blockFile.MarkBlocksSaved(); } } return(true); }
/// <summary> /// Loads block index from file into memory. /// </summary> /// <returns>True if succeeds.</returns> public bool Load() { _indexFile = DbFile.Read <IndexFile>(Config.GetBlockIndexFilePath()); if (_indexFile == null) { _indexFile = new IndexFile { BlockIndices = new List <BlockIndex>() }; DbFile.Write(Config.GetBlockIndexFilePath(), _indexFile); } _blockIndices = _indexFile.BlockIndices; for (int i = 0, c = _blockIndices.Count; i < c; ++i) { var idx = _blockIndices[i].Index; if (idx != i) { return(false); } var hash = Utils.HexUtils.ByteArrayFromHex(_blockIndices[i].Hash); if (!Pow.IsValidHash(hash, Pow.CalculateDifficulty(idx))) { return(false); } } _blockFileByIndex = new Dictionary <int, BlockFile>(); _blocks = new Dictionary <int, Block>(); if (_blockIndices.Count == 0) { AddBlock(Config.GetGenesisBlock()); } IsReady = true; return(true); }
/// <summary> /// Loads transaction database from persistent storage into memory. /// </summary> /// <returns>True if succeeds.</returns> public bool Load() { _indexFile = DbFile.Read <IndexFile>(Config.GetTransactionIndexFilePath()); if (_indexFile == null) { _indexFile = new IndexFile { TransactionIndices = new Dictionary <string, TransactionIndex>(), UnspentTxOuts = new List <UnspentTxOut>(), PendingTransactions = new List <PendingTransaction>(), }; DbFile.Write(Config.GetTransactionIndexFilePath(), _indexFile); } _transactionIndices = _indexFile.TransactionIndices; _unspentTxOuts = _indexFile.UnspentTxOuts; _pendingTransactions = _indexFile.PendingTransactions; _transactions = new Dictionary <string, Transaction>(); return(true); }
/// <summary> /// Adds a new block to the chain. /// </summary> /// <param name="block">The block to add.</param> /// <param name="needSave">If true, the index file and block file will be saved immediately.</param> /// <returns>Index to the new block.</returns> /// <remarks> /// In scenarios when there are multiple calls to this method, /// passing false to <paramref name="needSave"/> and then calling /// <see cref="Save"/> in the end would be a more efficient approach. /// </remarks> public BlockIndex AddBlock(Block block, bool needSave = true) { if (_blockIndices.Count > 0 && block.Index != LatestBlock.Index + 1) { throw new System.ArgumentException("Given block is not right after latest block."); } int fileIndex = block.Index / BlockFile.BlocksPerFile; if (_blockFileByIndex.ContainsKey(fileIndex)) { var blockFile = _blockFileByIndex[fileIndex]; blockFile.AddBlock(block); if (needSave) { BlockFile.Write(blockFile); } } else { var blockFile = BlockFile.Read(block.Index); if (blockFile != null) { blockFile.AddBlock(block); } else { blockFile = new BlockFile(block); } _blockFileByIndex.Add(fileIndex, blockFile); if (needSave) { BlockFile.Write(blockFile); } } if (needSave) { block.IsSaved = true; } var blockIndex = new BlockIndex { Index = block.Index, Hash = block.Hash, }; _blockIndices.Add(blockIndex); _blocks.Add(block.Index, block); if (needSave) { DbFile.Write(Config.GetBlockIndexFilePath(), _indexFile); } return(blockIndex); }
/// <summary> /// Writes transaction database into persistent storage. /// </summary> /// <returns>True if succeeds.</returns> public bool Save() { DbFile.Write(Config.GetTransactionIndexFilePath(), _indexFile); return(true); }