Beispiel #1
0
        public UtxoReferee(Network network, string folderPath, RPCClient rpc, CcjRoundConfig roundConfig)
        {
            Network     = Guard.NotNull(nameof(network), network);
            FolderPath  = Guard.NotNullOrEmptyOrWhitespace(nameof(folderPath), folderPath, trim: true);
            RpcClient   = Guard.NotNull(nameof(rpc), rpc);
            RoundConfig = Guard.NotNull(nameof(roundConfig), roundConfig);

            BannedUtxos = new ConcurrentDictionary <OutPoint, BannedUtxoRecord>();

            Directory.CreateDirectory(FolderPath);

            if (File.Exists(BannedUtxosFilePath))
            {
                try
                {
                    var      toRemove = new List <string>();               // what's been confirmed
                    string[] allLines = File.ReadAllLines(BannedUtxosFilePath);
                    foreach (string line in allLines)
                    {
                        var bannedRecord = BannedUtxoRecord.FromString(line);

                        GetTxOutResponse getTxOutResponse = RpcClient.GetTxOut(bannedRecord.Utxo.Hash, (int)bannedRecord.Utxo.N, includeMempool: true);

                        // Check if inputs are unspent.
                        if (getTxOutResponse is null)
                        {
                            toRemove.Add(line);
                        }
                        else
                        {
                            BannedUtxos.TryAdd(bannedRecord.Utxo, bannedRecord);
                        }
                    }

                    if (toRemove.Count != 0)                     // a little performance boost, often it'll be empty
                    {
                        var newAllLines = allLines.Where(x => !toRemove.Contains(x));
                        File.WriteAllLines(BannedUtxosFilePath, newAllLines);
                    }

                    Logger.LogInfo($"{allLines.Length} banned UTXOs are loaded from {BannedUtxosFilePath}.");
                }
                catch (Exception ex)
                {
                    Logger.LogWarning($"Banned UTXO file got corrupted. Deleting {BannedUtxosFilePath}. {ex.GetType()}: {ex.Message}");
                    File.Delete(BannedUtxosFilePath);
                }
            }
            else
            {
                Logger.LogInfo($"No banned UTXOs are loaded from {BannedUtxosFilePath}.");
            }
        }
Beispiel #2
0
        public void UtxoRefereeSerialization()
        {
            var record = BannedUtxoRecord.FromString("2018-11-23 15-23-14:1:44:2716e680f47d74c1bc6f031da22331564dd4c6641d7216576aad1b846c85d492:True:195");

            Assert.Equal(new DateTimeOffset(2018, 11, 23, 15, 23, 14, TimeSpan.Zero), record.TimeOfBan);
            Assert.Equal(1, record.Severity);
            Assert.Equal(44u, record.Utxo.N);
            Assert.Equal(new uint256("2716e680f47d74c1bc6f031da22331564dd4c6641d7216576aad1b846c85d492"), record.Utxo.Hash);
            Assert.True(record.IsNoted);
            Assert.Equal(195, record.BannedForRound);

            DateTimeOffset dateTime    = DateTimeOffset.UtcNow;
            DateTimeOffset now         = new DateTimeOffset(dateTime.Ticks - (dateTime.Ticks % TimeSpan.TicksPerSecond), TimeSpan.Zero);
            var            record2Init = new BannedUtxoRecord(record.Utxo, 3, now, false, 99);
            string         record2Line = record2Init.ToString();
            var            record2     = BannedUtxoRecord.FromString(record2Line);

            Assert.Equal(now, record2.TimeOfBan);
            Assert.Equal(3, record2.Severity);
            Assert.Equal(44u, record2.Utxo.N);
            Assert.Equal(new uint256("2716e680f47d74c1bc6f031da22331564dd4c6641d7216576aad1b846c85d492"), record2.Utxo.Hash);
            Assert.False(record2.IsNoted);
            Assert.Equal(99, record2.BannedForRound);
        }
Beispiel #3
0
        public async Task BanUtxosAsync(int severity, DateTimeOffset timeOfBan, bool forceNoted, long bannedForRound, params OutPoint[] toBan)
        {
            if (RoundConfig.DosSeverity == 0)
            {
                return;
            }

            var lines   = new List <string>();
            var updated = false;

            foreach (var utxo in toBan)
            {
                BannedUtxoRecord foundElem = null;
                if (BannedUtxos.TryGetValue(utxo, out BannedUtxoRecord fe))
                {
                    foundElem = fe;
                    bool bannedForTheSameRound = foundElem.BannedForRound == bannedForRound;
                    if (bannedForTheSameRound && (!forceNoted || foundElem.IsNoted))
                    {
                        continue;                         // We would be simply duplicating this ban.
                    }
                }

                var isNoted = true;
                if (!forceNoted)
                {
                    if (RoundConfig.DosNoteBeforeBan)
                    {
                        if (foundElem != null)
                        {
                            isNoted = false;
                        }
                    }
                    else
                    {
                        isNoted = false;
                    }
                }

                var newElem = new BannedUtxoRecord(utxo, severity, timeOfBan, isNoted, bannedForRound);
                if (BannedUtxos.TryAdd(newElem.Utxo, newElem))
                {
                    string line = newElem.ToString();
                    lines.Add(line);
                }
                else
                {
                    var elem = BannedUtxos[utxo];
                    if (elem.IsNoted != isNoted || elem.BannedForRound != bannedForRound)
                    {
                        BannedUtxos[utxo] = new BannedUtxoRecord(elem.Utxo, elem.Severity, elem.TimeOfBan, isNoted, bannedForRound);
                        updated           = true;
                    }
                }

                Logger.LogInfo($"UTXO {(isNoted ? "noted" : "banned")} with severity: {severity}. UTXO: {utxo.N}:{utxo.Hash} for disrupting Round {bannedForRound}.");
            }

            if (updated)             // If at any time we set updated then we must update the whole thing.
            {
                var allLines = BannedUtxos.Select(x => x.Value.ToString());
                await File.WriteAllLinesAsync(BannedUtxosFilePath, allLines);
            }
            else if (lines.Count != 0)             // If we do not have to update the whole thing, we must check if we added a line and so only append.
            {
                await File.AppendAllLinesAsync(BannedUtxosFilePath, lines);
            }
        }