Esempio n. 1
0
        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;
        }
Esempio n. 2
0
        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;
        }