public IndexBuilderService(RPCClient rpc, TrustedNodeNotifyingBehavior trustedNodeNotifyingBehavior, string indexFilePath, string bech32UtxoSetFilePath) { RpcClient = Guard.NotNull(nameof(rpc), rpc); TrustedNodeNotifyingBehavior = Guard.NotNull(nameof(trustedNodeNotifyingBehavior), trustedNodeNotifyingBehavior); IndexFilePath = Guard.NotNullOrEmptyOrWhitespace(nameof(indexFilePath), indexFilePath); Bech32UtxoSetFilePath = Guard.NotNullOrEmptyOrWhitespace(nameof(bech32UtxoSetFilePath), bech32UtxoSetFilePath); Bech32UtxoSet = new Dictionary <OutPoint, Script>(); Bech32UtxoSetHistory = new List <ActionHistoryHelper>(capacity: 100); Index = new List <FilterModel>(); IndexLock = new AsyncLock(); StartingFilter = StartingFilters.GetStartingFilter(RpcClient.Network); StartingHeight = StartingFilters.GetStartingHeight(RpcClient.Network); _running = 0; IoHelpers.EnsureContainingDirectoryExists(IndexFilePath); if (File.Exists(IndexFilePath)) { if (RpcClient.Network == Network.RegTest) { File.Delete(IndexFilePath); // RegTest is not a global ledger, better to delete it. } else { var height = StartingHeight; foreach (var line in File.ReadAllLines(IndexFilePath)) { var filter = FilterModel.FromHeightlessLine(line, height); height++; Index.Add(filter); } } } IoHelpers.EnsureContainingDirectoryExists(bech32UtxoSetFilePath); if (File.Exists(bech32UtxoSetFilePath)) { if (RpcClient.Network == Network.RegTest) { File.Delete(bech32UtxoSetFilePath); // RegTest is not a global ledger, better to delete it. } else { foreach (var line in File.ReadAllLines(Bech32UtxoSetFilePath)) { var parts = line.Split(':'); var txHash = new uint256(parts[0]); var nIn = int.Parse(parts[1]); var script = new Script(ByteHelpers.FromHex(parts[2]), true); Bech32UtxoSet.Add(new OutPoint(txHash, nIn), script); } } } TrustedNodeNotifyingBehavior.BlockInv += TrustedNodeNotifyingBehavior_BlockInv; }
public CcjCoordinator(Network network, TrustedNodeNotifyingBehavior trustedNodeNotifyingBehavior, string folderPath, RPCClient rpc, CcjRoundConfig roundConfig) { Network = Guard.NotNull(nameof(network), network); TrustedNodeNotifyingBehavior = Guard.NotNull(nameof(trustedNodeNotifyingBehavior), trustedNodeNotifyingBehavior); FolderPath = Guard.NotNullOrEmptyOrWhitespace(nameof(folderPath), folderPath, trim: true); RpcClient = Guard.NotNull(nameof(rpc), rpc); RoundConfig = Guard.NotNull(nameof(roundConfig), roundConfig); Rounds = new List <CcjRound>(); RoundsListLock = new AsyncLock(); CoinJoins = new List <uint256>(); CoinJoinsLock = new AsyncLock(); Directory.CreateDirectory(FolderPath); UtxoReferee = new UtxoReferee(Network, FolderPath, RpcClient, RoundConfig); if (File.Exists(CoinJoinsFilePath)) { try { var toRemove = new List <string>(); string[] allLines = File.ReadAllLines(CoinJoinsFilePath); foreach (string line in allLines) { try { uint256 txHash = new uint256(line); RPCResponse getRawTransactionResponse = RpcClient.SendCommand(RPCOperations.getrawtransaction, txHash.ToString(), true); CoinJoins.Add(txHash); } catch (Exception ex) { toRemove.Add(line); var logEntry = ex is RPCException rpce && rpce.RPCCode == RPCErrorCode.RPC_INVALID_ADDRESS_OR_KEY ? $"CoinJoins file contains invalid transaction ID {line}" : $"CoinJoins file got corrupted. Deleting offending line \"{line.Substring(0, 20)}\"."; Logger.LogWarning <CcjCoordinator>($"{logEntry}. {ex.GetType()}: {ex.Message}"); } } if (toRemove.Count != 0) // a little performance boost, it'll be empty almost always { var newAllLines = allLines.Where(x => !toRemove.Contains(x)); File.WriteAllLines(CoinJoinsFilePath, newAllLines); } } catch (Exception ex) { Logger.LogWarning <CcjCoordinator>($"CoinJoins file got corrupted. Deleting {CoinJoinsFilePath}. {ex.GetType()}: {ex.Message}"); File.Delete(CoinJoinsFilePath); } } try { string roundCountFilePath = Path.Combine(folderPath, "RoundCount.txt"); if (File.Exists(roundCountFilePath)) { string roundCount = File.ReadAllText(roundCountFilePath); CcjRound.RoundCount = long.Parse(roundCount); } else { // First time initializes (so the first constructor will increment it and we'll start from 1.) CcjRound.RoundCount = 0; } } catch (Exception ex) { CcjRound.RoundCount = 0; Logger.LogInfo <CcjCoordinator>($"{nameof(CcjRound.RoundCount)} file was corrupt. Resetting to 0."); Logger.LogDebug <CcjCoordinator>(ex); } TrustedNodeNotifyingBehavior.Block += TrustedNodeNotifyingBehavior_BlockAsync; }