Beispiel #1
0
        void GetStatus(StatusOptions options)
        {
            options.Query = options?.Query?.Trim() ?? String.Empty;
            if (!string.IsNullOrWhiteSpace(options.Query))
            {
                bool parsed = false;
                try
                {
                    options.CycleId = int.Parse(options.Query);
                    parsed          = true;
                }
                catch { }
                try
                {
                    options.TxId = new uint256(options.Query).ToString();
                    parsed       = true;
                }
                catch { }
                try
                {
                    options.Address = BitcoinAddress.Create(options.Query, Runtime.Network).ToString();
                    parsed          = true;
                }
                catch { }
                if (!parsed)
                {
                    throw new FormatException();
                }
            }

            if (options.CycleId != null)
            {
                CycleParameters cycle = null;

                try
                {
                    cycle = Runtime.TumblerParameters?.CycleGenerator?.GetCycle(options.CycleId.Value);
                }
                catch
                {
                    Console.WriteLine("Invalid cycle");
                    return;
                }
                var records       = Runtime.Tracker.GetRecords(options.CycleId.Value);
                var currentHeight = Runtime.Services.BlockExplorerService.GetCurrentHeight();

                var phases = new[]
                {
                    CyclePhase.Registration,
                    CyclePhase.ClientChannelEstablishment,
                    CyclePhase.TumblerChannelEstablishment,
                    CyclePhase.PaymentPhase,
                    CyclePhase.TumblerCashoutPhase,
                    CyclePhase.ClientCashoutPhase
                };

                if (cycle != null)
                {
                    Console.WriteLine("Phases:");
                    Console.WriteLine(cycle.ToString(currentHeight));
                    var periods = cycle.GetPeriods();
                    foreach (var phase in phases)
                    {
                        var period = periods.GetPeriod(phase);
                        if (period.IsInPeriod(currentHeight))
                        {
                            Console.WriteLine($"In phase: {phase.ToString()}  ({(period.End - currentHeight)} blocks left)");
                        }
                    }
                    Console.WriteLine();
                }

                Console.WriteLine("Records:");
                foreach (var correlationGroup in records.GroupBy(r => r.Correlation))
                {
                    Console.WriteLine("========");
                    foreach (var group in correlationGroup.GroupBy(r => r.TransactionType).OrderBy(r => (int)r.Key))
                    {
                        var builder = new StringBuilder();
                        builder.AppendLine(group.Key.ToString());
                        foreach (var data in group.OrderBy(g => g.RecordType))
                        {
                            builder.Append("\t" + data.RecordType.ToString());
                            if (data.ScriptPubKey != null)
                            {
                                builder.AppendLine(" " + data.ScriptPubKey.GetDestinationAddress(Runtime.Network));
                            }
                            if (data.TransactionId != null)
                            {
                                builder.AppendLine(" " + data.TransactionId);
                            }
                        }
                        Console.WriteLine(builder.ToString());
                    }
                    Console.WriteLine("========");
                }
            }

            if (options.TxId != null)
            {
                var currentHeight = Runtime.Services.BlockExplorerService.GetCurrentHeight();
                var txId          = new uint256(options.TxId);
                var result        = Runtime.Tracker.Search(txId);
                foreach (var record in result)
                {
                    Console.WriteLine("Cycle " + record.Cycle);
                    Console.WriteLine("Type " + record.TransactionType);
                }

                var         knownTransaction = Runtime.Services.TrustedBroadcastService.GetKnownTransaction(txId);
                Transaction tx = knownTransaction?.Transaction;
                if (knownTransaction != null)
                {
                    if (knownTransaction.BroadcastableHeight != 0)
                    {
                        var blockLeft = (knownTransaction.BroadcastableHeight - currentHeight);
                        Console.Write("Planned for " + knownTransaction.BroadcastableHeight.ToString());
                        if (blockLeft > 0)
                        {
                            Console.WriteLine($" ({blockLeft} blocks left)");
                        }
                        else
                        {
                            Console.WriteLine($" ({-blockLeft} blocks ago)");
                        }
                    }
                }
                if (tx == null)
                {
                    tx = Runtime.Services.BroadcastService.GetKnownTransaction(txId);
                }
                var txInfo = Runtime.Services.BlockExplorerService.GetTransaction(txId);
                if (tx == null)
                {
                    tx = txInfo?.Transaction;
                }
                if (txInfo != null)
                {
                    if (txInfo.Confirmations != 0)
                    {
                        Console.WriteLine(txInfo.Confirmations + " Confirmations");
                    }
                    else
                    {
                        Console.WriteLine("Unconfirmed");
                    }
                }

                if (tx != null)
                {
                    Console.WriteLine("Hex " + tx.ToHex());
                }
                //TODO ask to other objects for more info
            }

            if (options.Address != null)
            {
                var address = BitcoinAddress.Create(options.Address, Runtime.TumblerParameters.Network);
                var result  = Runtime.Tracker.Search(address.ScriptPubKey);
                foreach (var record in result)
                {
                    Console.WriteLine("Cycle " + record.Cycle);
                    Console.WriteLine("Type " + record.TransactionType);
                }
                if (Runtime.DestinationWallet != null)
                {
                    var keyPath = Runtime.DestinationWallet.GetKeyPath(address.ScriptPubKey);
                    if (keyPath != null)
                    {
                        Console.WriteLine("KeyPath: " + keyPath.ToString());
                    }
                }
            }
        }
        //https://medium.com/@nicolasdorier/tumblebit-tumbler-mode-ea44e9a2a2ec#.a4wgwa86u
        public void CanCalculatePhase()
        {
            var parameter = new CycleParameters
            {
                Start = 100,
                RegistrationDuration = 10,
                ClientChannelEstablishmentDuration  = 11,
                TumblerChannelEstablishmentDuration = 12,
                TumblerCashoutDuration = 10,
                ClientCashoutDuration  = 13,
                PaymentPhaseDuration   = 3,
                SafetyPeriodDuration   = 2,
            };

            Assert.Equal("{[..o.......]..[...........]..[............]..[[...].......][.............]..}", parameter.ToString(102));
            //              0          10 12          23 25           37  39  42       49            62

            Assert.True(parameter.IsInPhase(CyclePhase.Registration, 100));
            Assert.True(parameter.IsInPhase(CyclePhase.Registration, 109));
            Assert.False(parameter.IsInPhase(CyclePhase.Registration, 110));

            Assert.True(parameter.IsInPhase(CyclePhase.ClientChannelEstablishment, 112));

            Assert.True(parameter.IsInPhase(CyclePhase.TumblerChannelEstablishment, 125));

            Assert.True(parameter.IsInPhase(CyclePhase.TumblerCashoutPhase, 139));

            Assert.True(parameter.IsInPhase(CyclePhase.PaymentPhase, 139));

            Assert.True(parameter.IsInPhase(CyclePhase.ClientCashoutPhase, 149));

            Assert.Equal(149 + 2, parameter.GetClientLockTime().Height);


            var total = parameter.GetPeriods().Total;

            Assert.Equal(100, total.Start);
            Assert.Equal(162 + 2, total.End);

            Assert.Equal(162 + 2, parameter.GetTumblerLockTime().Height);

            var cycleGenerator = new OverlappedCycleGenerator();

            cycleGenerator.FirstCycle          = parameter;
            cycleGenerator.RegistrationOverlap = 3;
            Assert.Equal(100, cycleGenerator.GetRegistratingCycle(100).Start);
            Assert.Equal(100, cycleGenerator.GetRegistratingCycle(106).Start);
            Assert.Equal(107, cycleGenerator.GetRegistratingCycle(107).Start);
        }
Beispiel #3
0
        void GetStatus(StatusOptions options)
        {
            options.Query = options?.Query?.Trim() ?? String.Empty;
            if (!string.IsNullOrWhiteSpace(options.Query))
            {
                bool parsed = false;

                if (options.Query.StartsWith("now", StringComparison.Ordinal))
                {
                    var blockCount = Runtime.Services.BlockExplorerService.GetCurrentHeight();
                    options.CycleId =
                        Runtime.TumblerParameters?.CycleGenerator?.GetCycles(blockCount)
                        .OrderByDescending(o => o.Start)
                        .Select(o => o.Start)
                        .FirstOrDefault();
                    parsed        = options.CycleId != 0;
                    options.Query = options.Query.Replace("now", options.CycleId.Value.ToString());
                }

                try
                {
                    var regex = System.Text.RegularExpressions.Regex.Match(options.Query, @"^(\d+)(([+|-])(\d))?$");
                    if (regex.Success)
                    {
                        options.CycleId = int.Parse(regex.Groups[1].Value);
                        if (regex.Groups[3].Success && regex.Groups[4].Success)
                        {
                            int offset = 1;
                            if (regex.Groups[3].Value.Equals("-", StringComparison.OrdinalIgnoreCase))
                            {
                                offset = -1;
                            }
                            offset = offset * int.Parse(regex.Groups[4].Value);
                            options.CycleOffset = offset;
                        }

                        parsed = true;
                    }
                }
                catch { }
                try
                {
                    options.TxId = new uint256(options.Query).ToString();
                    parsed       = true;
                }
                catch { }
                try
                {
                    options.Address = BitcoinAddress.Create(options.Query, Runtime.Network).ToString();
                    parsed          = true;
                }
                catch { }
                if (!parsed)
                {
                    throw new FormatException();
                }
            }

            Stats stats      = new Stats();
            Stats statsTotal = new Stats();

            if (options.CycleId != null)
            {
                while (options.PreviousCount > 0)
                {
                    CycleParameters cycle = null;
                    try
                    {
                        cycle = Runtime.TumblerParameters.CycleGenerator.GetCycle(options.CycleId.Value);
                        if (cycle == null)
                        {
                            throw new NullReferenceException();                             //Cleanup
                        }
                        for (int i = 0; i < Math.Abs(options.CycleOffset); i++)
                        {
                            cycle = options.CycleOffset < 0 ? Runtime.TumblerParameters.CycleGenerator.GetPreviousCycle(cycle) : Runtime.TumblerParameters.CycleGenerator.GetNextCycle(cycle);
                        }
                        options.CycleId = cycle.Start;
                    }
                    catch
                    {
                        Console.WriteLine("Invalid cycle");
                        return;
                    }
                    var state = Services.OfType <StateMachinesExecutor>().Select(e => e.GetPaymentStateMachineState(cycle)).FirstOrDefault();

                    var records       = Runtime.Tracker.GetRecords(options.CycleId.Value);
                    var currentHeight = Runtime.Services.BlockExplorerService.GetCurrentHeight();

                    bool hasData = false;

                    var phases = new[]
                    { CyclePhase.Registration,
                      CyclePhase.ClientChannelEstablishment,
                      CyclePhase.TumblerChannelEstablishment,
                      CyclePhase.PaymentPhase,
                      CyclePhase.TumblerCashoutPhase,
                      CyclePhase.ClientCashoutPhase };

                    Console.WriteLine("=====================================");
                    if (cycle != null)
                    {
                        Console.WriteLine("CycleId: " + cycle.Start);
                        if (state != null)
                        {
                            Console.WriteLine("Status: " + state.Status);
                            hasData = true;
                        }
                        Console.WriteLine("Phases:");
                        Console.WriteLine(cycle.ToString(currentHeight));
                        var periods = cycle.GetPeriods();
                        foreach (var phase in phases)
                        {
                            var period = periods.GetPeriod(phase);
                            if (period.IsInPeriod(currentHeight))
                            {
                                Console.WriteLine($"In phase: {phase.ToString()}  ({(period.End - currentHeight)} blocks left)");
                            }
                        }
                        Console.WriteLine();
                    }

                    Console.WriteLine("Records:");
                    foreach (var correlationGroup in records.GroupBy(r => r.Correlation))
                    {
                        stats.CorrelationGroupCount++;
                        hasData = true;
                        Console.WriteLine("========");

                        var transactions = correlationGroup.Where(o => o.RecordType == RecordType.Transaction).ToArray();

                        if (state == null)
                        {
                            var isBob   = transactions.Any(o => o.TransactionType == TransactionType.TumblerEscrow);
                            var isAlice = transactions.Any(o => o.TransactionType == TransactionType.ClientEscrow);
                            if (isBob)
                            {
                                stats.BobCount++;
                            }
                            if (isAlice)
                            {
                                stats.AliceCount++;
                            }

                            var isUncooperative = transactions.Any(o => o.TransactionType == TransactionType.ClientFulfill) &&
                                                  transactions.All(o => o.TransactionType != TransactionType.ClientEscape);
                            if (isUncooperative)
                            {
                                stats.UncooperativeCount++;
                            }

                            var isCashout = transactions.Any(o => (o.TransactionType == TransactionType.ClientEscape || o.TransactionType == TransactionType.ClientFulfill));
                            if (isCashout)
                            {
                                stats.CashoutCount++;
                            }
                        }
                        else
                        {
                            var isUncooperative = transactions.Any(o => (o.TransactionType == TransactionType.ClientOffer || o.TransactionType == TransactionType.ClientOfferRedeem));
                            if (isUncooperative)
                            {
                                stats.UncooperativeCount++;
                            }

                            var isCashout = transactions.Any(o => (o.TransactionType == TransactionType.TumblerCashout));
                            if (isCashout)
                            {
                                stats.CashoutCount++;
                            }
                        }


                        foreach (var group in correlationGroup.GroupBy(r => r.TransactionType).OrderBy(r => (int)r.Key))
                        {
                            var builder = new StringBuilder();
                            builder.AppendLine(group.Key.ToString());

                            foreach (var data in group.OrderBy(g => g.RecordType))
                            {
                                builder.Append("\t" + data.RecordType.ToString());
                                if (data.ScriptPubKey != null)
                                {
                                    builder.AppendLine(" " + data.ScriptPubKey.GetDestinationAddress(Runtime.Network));
                                }
                                if (data.TransactionId != null)
                                {
                                    builder.AppendLine(" " + data.TransactionId);
                                }
                            }
                            Console.WriteLine(builder.ToString());
                        }
                        Console.WriteLine("========");
                    }
                    if (!hasData)
                    {
                        Console.WriteLine("Cycle " + cycle.Start + " has no data");
                    }

                    Console.WriteLine("Status for " + cycle.Start + ":");
                    Console.Write(stats.ToString());
                    Console.WriteLine("=====================================");

                    statsTotal = statsTotal + stats;
                    stats      = new Stats();

                    options.PreviousCount--;
                    try
                    {
                        options.CycleId = Runtime.TumblerParameters.CycleGenerator.GetPreviousCycle(cycle).Start;
                    }
                    catch
                    {
                        break;
                    }
                }
                Console.WriteLine("Stats Total:");
                Console.Write(statsTotal.ToString());
            }

            if (options.TxId != null)
            {
                var currentHeight = Runtime.Services.BlockExplorerService.GetCurrentHeight();
                var txId          = new uint256(options.TxId);
                var result        = Runtime.Tracker.Search(txId);
                foreach (var record in result)
                {
                    Console.WriteLine("Cycle " + record.Cycle);
                    Console.WriteLine("Type " + record.TransactionType);
                }

                var         knownTransaction = Runtime.Services.TrustedBroadcastService.GetKnownTransaction(txId);
                Transaction tx = knownTransaction?.Transaction;
                if (knownTransaction != null)
                {
                    if (knownTransaction.BroadcastableHeight != 0)
                    {
                        var blockLeft = (knownTransaction.BroadcastableHeight - currentHeight);
                        Console.Write("Planned for " + knownTransaction.BroadcastableHeight.ToString());
                        if (blockLeft > 0)
                        {
                            Console.WriteLine($" ({blockLeft} blocks left)");
                        }
                        else
                        {
                            Console.WriteLine($" ({-blockLeft} blocks ago)");
                        }
                    }
                }
                if (tx == null)
                {
                    tx = Runtime.Services.BroadcastService.GetKnownTransaction(txId);
                }
                var txInfo = Runtime.Services.BlockExplorerService.GetTransaction(txId);
                if (tx == null)
                {
                    tx = txInfo?.Transaction;
                }
                if (txInfo != null)
                {
                    if (txInfo.Confirmations != 0)
                    {
                        Console.WriteLine(txInfo.Confirmations + " Confirmations");
                    }
                    else
                    {
                        Console.WriteLine("Unconfirmed");
                    }
                }

                if (tx != null)
                {
                    Console.WriteLine("Hex " + tx.ToHex());
                }
                //TODO ask to other objects for more info
            }

            if (options.Address != null)
            {
                var address = BitcoinAddress.Create(options.Address, Runtime.TumblerParameters.Network);
                var result  = Runtime.Tracker.Search(address.ScriptPubKey);
                foreach (var record in result)
                {
                    Console.WriteLine("Cycle " + record.Cycle);
                    Console.WriteLine("Type " + record.TransactionType);
                }
                if (Runtime.DestinationWallet != null)
                {
                    var keyPath = Runtime.DestinationWallet.GetKeyPath(address.ScriptPubKey);
                    if (keyPath != null)
                    {
                        Console.WriteLine("KeyPath: " + keyPath.ToString());
                    }
                }
            }
        }