private void CheckTumblerChannelSecured(CycleParameters cycle)
        {
            TransactionInformation tumblerTx = GetTransactionInformation(PromiseClientSession.EscrowedCoin, false);

            if (tumblerTx == null)
            {
                Logs.Client.LogInformation($"Tumbler escrow not yet broadcasted");
                return;
            }

            if (tumblerTx.Confirmations >= cycle.SafetyPeriodDuration)
            {
                var bobCount = Parameters.CountEscrows(tumblerTx.Transaction, Identity.Bob);
                Logs.Client.LogInformation($"Tumbler escrow reached {cycle.SafetyPeriodDuration} confirmations");
                Logs.Client.LogInformation($"Tumbler escrow transaction has {bobCount} users");
                Status   = PaymentStateMachineStatus.TumblerChannelSecured;
                NeedSave = true;
                return;
            }

            if (tumblerTx.Confirmations < cycle.SafetyPeriodDuration)
            {
                Logs.Client.LogInformation($"Tumbler escrow need {cycle.SafetyPeriodDuration - tumblerTx.Confirmations} more confirmation");
                return;
            }
        }
Example #2
0
        private void CheckPhase(CyclePhase expectedPhase, int height, int cycleId)
        {
            CycleParameters cycle = GetCycle(cycleId);

            if (!cycle.IsInPhase(expectedPhase, height))
            {
                throw BadRequest("invalid-phase").AsException();
            }
        }
Example #3
0
        public PaymentStateMachine.State GetPaymentStateMachineState(CycleParameters cycle)
        {
            var state = Runtime.Repository.Get <PaymentStateMachine.State>(GetPartitionKey(cycle.Start), "");

            if (state == null)
            {
                return(null);
            }
            return(state.TumblerParametersHash == _ParametersHash ? state : null);
        }
Example #4
0
        private void CheckTumblerChannelConfirmed(CycleParameters cycle)
        {
            TransactionInformation tumblerTx = GetTransactionInformation(PromiseClientSession.EscrowedCoin, false);

            if (tumblerTx != null && tumblerTx.Confirmations >= cycle.SafetyPeriodDuration)
            {
                var bobCount = Parameters.CountEscrows(tumblerTx.Transaction, Identity.Bob);
                Logs.Client.LogInformation($"Tumbler escrow reached {cycle.SafetyPeriodDuration} confirmations");
                Logs.Client.LogInformation($"Tumbler escrow transaction has {bobCount} users");
            }
            Status = PaymentStateMachineStatus.TumblerChannelConfirmed;
        }
 private bool IsConfirmed(CycleParameters cycle, TransactionType transactionType)
 {
     foreach (var tx in Tracker.GetRecords(cycle.Start).Where(t => t.RecordType == RecordType.Transaction && t.TransactionType == transactionType))
     {
         var txInfo = Services.BlockExplorerService.GetTransaction(tx.TransactionId, true);
         if (txInfo != null && txInfo.Confirmations >= cycle.SafetyPeriodDuration)
         {
             return(true);
         }
     }
     return(false);
 }
        private void MineTo(CoreNode node, CycleParameters cycle, CyclePhase phase, bool end = false, int offset = 0)
        {
            var height       = node.CreateRPCClient().GetBlockCount();
            var periodStart  = end ? cycle.GetPeriods().GetPeriod(phase).End : cycle.GetPeriods().GetPeriod(phase).Start;
            var blocksToFind = periodStart - height + offset;

            if (blocksToFind <= 0)
            {
                return;
            }

            node.FindBlock(blocksToFind);
        }
Example #7
0
        //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
            {
                FirstCycle          = parameter,
                RegistrationOverlap = 3
            };

            Assert.Equal(100, cycleGenerator.GetRegistratingCycle(100).Start);
            Assert.Equal(100, cycleGenerator.GetRegistratingCycle(106).Start);
            Assert.Equal(107, cycleGenerator.GetRegistratingCycle(107).Start);
        }
Example #8
0
 public override LockTime GetLockTime(CycleParameters cycle)
 {
     return(cycle.GetClientLockTime());
 }
Example #9
0
 public override LockTime GetLockTime(CycleParameters cycle)
 {
     return(cycle.GetTumblerLockTime());
 }
Example #10
0
 public abstract LockTime GetLockTime(CycleParameters cycle);
Example #11
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());
                    }
                }
            }
        }
Example #12
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());
                    }
                }
            }
        }
Example #13
0
        //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.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, 110));
            Assert.True(parameter.IsInPhase(CyclePhase.ClientChannelEstablishment, 120));
            Assert.False(parameter.IsInPhase(CyclePhase.ClientChannelEstablishment, 121));

            Assert.True(parameter.IsInPhase(CyclePhase.TumblerChannelEstablishment, 121));
            Assert.True(parameter.IsInPhase(CyclePhase.TumblerChannelEstablishment, 132));
            Assert.False(parameter.IsInPhase(CyclePhase.TumblerChannelEstablishment, 133));

            Assert.False(parameter.IsInPhase(CyclePhase.TumblerCashoutPhase, 133));
            Assert.False(parameter.IsInPhase(CyclePhase.TumblerCashoutPhase, 134));
            Assert.True(parameter.IsInPhase(CyclePhase.TumblerCashoutPhase, 135));
            Assert.True(parameter.IsInPhase(CyclePhase.TumblerCashoutPhase, 144));
            Assert.False(parameter.IsInPhase(CyclePhase.TumblerCashoutPhase, 145));

            Assert.False(parameter.IsInPhase(CyclePhase.PaymentPhase, 133));
            Assert.False(parameter.IsInPhase(CyclePhase.PaymentPhase, 134));
            Assert.True(parameter.IsInPhase(CyclePhase.PaymentPhase, 135));
            Assert.True(parameter.IsInPhase(CyclePhase.PaymentPhase, 137));
            Assert.False(parameter.IsInPhase(CyclePhase.PaymentPhase, 138));

            Assert.True(parameter.IsInPhase(CyclePhase.ClientCashoutPhase, 145));
            Assert.True(parameter.IsInPhase(CyclePhase.ClientCashoutPhase, 157));
            Assert.False(parameter.IsInPhase(CyclePhase.ClientCashoutPhase, 158));

            //At block 147 we will be able to broadcast refund for expected confirmation at 148
            Assert.Equal(147, parameter.GetClientLockTime().Height);


            var total = parameter.GetPeriods().Total;

            Assert.Equal(100, total.Start);
            Assert.Equal(160, total.End);

            ////At block 160 we will be able to broadcast refund for expected confirmation at 161
            Assert.Equal(160, 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);
        }