Пример #1
0
        private async Task RegisterOutputAsync(CcjClientRound ongoingRound)
        {
            IEnumerable <TxoRef> registeredInputs = ongoingRound.Registration.CoinsRegistered.Select(x => x.GetTxoRef());

            var shuffledOutputs = ongoingRound.Registration.ActiveOutputs.ToList();

            shuffledOutputs.Shuffle();
            foreach (var activeOutput in shuffledOutputs)
            {
                using (var bobClient = new BobClient(CcjHostUriAction, TorSocks5EndPoint))
                {
                    if (!await bobClient.PostOutputAsync(ongoingRound.RoundId, activeOutput))
                    {
                        Logger.LogWarning <AliceClient>($"Round ({ongoingRound.State.RoundId}) Bobs did not have enough time to post outputs before timeout. If you see this message, contact nopara73, so he can optimize the phase timeout periods to the worst Internet/Tor connections, which may be yours.)");
                        break;
                    }

                    // Unblind our exposed links.
                    foreach (TxoRef input in registeredInputs)
                    {
                        if (ExposedLinks.ContainsKey(input))                         // Should never not contain, but oh well, let's not disrupt the round for this.
                        {
                            var found = ExposedLinks[input].FirstOrDefault(x => x.Key.GetP2wpkhAddress(Network) == activeOutput.Address);
                            if (found != default)
                            {
                                found.IsBlinded = false;
                            }
                            else
                            {
                                // Should never happen, but oh well we can autocorrect it so why not.
                                ExposedLinks[input] = ExposedLinks[input].Append(new HdPubKeyBlindedPair(KeyManager.GetKeyForScriptPubKey(activeOutput.Address.ScriptPubKey), false));
                            }
                        }
                    }
                }
            }

            ongoingRound.Registration.SetPhaseCompleted(CcjRoundPhase.OutputRegistration);
            Logger.LogInfo <AliceClient>($"Round ({ongoingRound.State.RoundId}) Bob Posted outputs: {ongoingRound.Registration.ActiveOutputs.Count()}.");
        }
Пример #2
0
        private (HdPubKey change, IEnumerable <HdPubKey> active) GetOutputsToRegister(Money baseDenomination, int mixingLevelCount, IEnumerable <TxoRef> coinsToRegister)
        {
            // Figure out how many mixing level we need to register active outputs.
            Money inputSum = Money.Zero;

            foreach (TxoRef coinReference in coinsToRegister)
            {
                SmartCoin coin = State.GetSingleOrDefaultFromWaitingList(coinReference);
                inputSum += coin.Amount;
            }

            int maximumMixingLevelCount = 1;
            var denominations           = new List <Money>
            {
                baseDenomination
            };

            for (int i = 1; i < mixingLevelCount; i++)
            {
                Money denom = denominations.Last() * 2;
                denominations.Add(denom);
                if (inputSum > denom)
                {
                    maximumMixingLevelCount = i + 1;
                }
            }

            string changeLabel = "ZeroLink Change";
            string activeLabel = "ZeroLink Mixed Coin";

            var keysToSurelyRegister = ExposedLinks.Where(x => coinsToRegister.Contains(x.Key)).SelectMany(x => x.Value).Select(x => x.Key).ToArray();
            var keysTryNotToRegister = ExposedLinks.SelectMany(x => x.Value).Select(x => x.Key).Except(keysToSurelyRegister).ToArray();

            // Get all locked internal keys we have and assert we have enough.
            KeyManager.AssertLockedInternalKeysIndexed(howMany: maximumMixingLevelCount + 1);
            IEnumerable <HdPubKey> allLockedInternalKeys = KeyManager.GetKeys(x => x.IsInternal && x.KeyState == KeyState.Locked && !keysTryNotToRegister.Contains(x));

            // If any of our inputs have exposed address relationship then prefer that.
            allLockedInternalKeys = keysToSurelyRegister.Concat(allLockedInternalKeys).Distinct();

            // Prefer not to bloat the wallet:
            if (allLockedInternalKeys.Count() <= maximumMixingLevelCount)
            {
                allLockedInternalKeys = allLockedInternalKeys.Concat(keysTryNotToRegister).Distinct();
            }

            var newKeys = new List <HdPubKey>();

            for (int i = allLockedInternalKeys.Count(); i <= maximumMixingLevelCount + 1; i++)
            {
                HdPubKey k = KeyManager.GenerateNewKey("", KeyState.Locked, isInternal: true, toFile: false);
                newKeys.Add(k);
            }
            allLockedInternalKeys = allLockedInternalKeys.Concat(newKeys);

            // Select the change and active keys to register and label them accordingly.
            HdPubKey change = allLockedInternalKeys.First();

            change.SetLabel(changeLabel);

            var actives = new List <HdPubKey>();

            foreach (HdPubKey active in allLockedInternalKeys.Skip(1).Take(maximumMixingLevelCount))
            {
                actives.Add(active);
                active.SetLabel(activeLabel);
            }

            // Remember which links we are exposing.
            var outLinks = new List <HdPubKeyBlindedPair>
            {
                new HdPubKeyBlindedPair(change, isBlinded: false)
            };

            foreach (var active in actives)
            {
                outLinks.Add(new HdPubKeyBlindedPair(active, isBlinded: true));
            }
            foreach (TxoRef coin in coinsToRegister)
            {
                if (!ExposedLinks.TryAdd(coin, outLinks))
                {
                    var newOutLinks = new List <HdPubKeyBlindedPair>();
                    foreach (HdPubKeyBlindedPair link in ExposedLinks[coin])
                    {
                        newOutLinks.Add(link);
                    }
                    foreach (HdPubKeyBlindedPair link in outLinks)
                    {
                        HdPubKeyBlindedPair found = newOutLinks.FirstOrDefault(x => x == link);

                        if (found == default)
                        {
                            newOutLinks.Add(link);
                        }
                        else                         // If already in it then update the blinded value if it's getting exposed just now. (eg. the change)
                        {
                            if (found.IsBlinded)
                            {
                                found.IsBlinded = link.IsBlinded;
                            }
                        }
                    }

                    ExposedLinks[coin] = newOutLinks;
                }
            }

            // Save our modifications in the keymanager before we give back the selected keys.
            KeyManager.ToFile();
            return(change, actives);
        }