Exemplo n.º 1
0
        public static bool CheckExpectedHash(string filePath, string sourceFolderPath)
        {
            var fileHash = GetHashFile(filePath);

            try
            {
                var digests = File.ReadAllLines(Path.Combine(sourceFolderPath, "digests.txt"));
                foreach (var digest in digests)
                {
                    var expectedHash = ByteHelpers.FromHex(digest);
                    if (ByteHelpers.CompareFastUnsafe(fileHash, expectedHash))
                    {
                        return(true);
                    }
                }
                return(false);
            }
            catch (Exception)
            {
                return(false);
            }
        }
Exemplo n.º 2
0
        public static bool TryGetMasterFingerprintFromFile(string filePath, out HDFingerprint masterFingerprint)
        {
            masterFingerprint = default;
            filePath          = Guard.NotNullOrEmptyOrWhitespace(nameof(filePath), filePath);

            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException($"Wallet file not found at: `{filePath}`.");
            }

            // Example text to handle: "ExtPubKey": "03BF8271268000000013B9013C881FE456DDF524764F6322F611B03CF6".
            var masterFpLine = File.ReadLines(filePath) // Enumerated read.
                               .Take(21)                // Limit reads to x lines.
                               .FirstOrDefault(line => line.Contains("\"MasterFingerprint\": \"", StringComparison.OrdinalIgnoreCase));

            if (string.IsNullOrEmpty(masterFpLine))
            {
                return(false);
            }

            var parts = masterFpLine.Split("\"MasterFingerprint\": \"");

            if (parts.Length != 2)
            {
                throw new FormatException($"Could not split line: {masterFpLine}");
            }

            var hex = parts[1].TrimEnd(',', '"');

            if (string.IsNullOrEmpty(hex) || hex.Equals("null", StringComparison.OrdinalIgnoreCase))
            {
                return(false);
            }

            var mfp = new HDFingerprint(ByteHelpers.FromHex(hex));

            masterFingerprint = mfp;
            return(true);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Transmits one tpdu and sends the NAK or ACK
        /// </summary>
        /// <param name="tpduData"></param>
        /// <returns></returns>
        private void SafeTransmit(byte[] tpduData)
        {
            int  transmitCounter  = 0;
            bool transmitSucceded = false;

            while (transmitCounter <= MAX_BLOCKREPEATS && !transmitSucceded)
            {
                _log.Debug("Sending transmitCounter={1}: {0}", ByteHelpers.ByteToString(tpduData), transmitCounter);
                //Write Data to the serial port
                _serialPort.SendData(tpduData, 0, tpduData.Length);

                //Read NAK or ACK or something else ;)
                var statusByte = _buffer.WaitForByte(RECEIVE_RESPONSE_TIMEOUT, true);

                if (statusByte != null && statusByte == ACK)
                {
                    transmitSucceded = true;
                    return;
                }
                else
                {
                    _log.Debug("TPDU transmission failed, increasing transmitCounter to '{0}'", transmitCounter + 1);
                    transmitCounter++;
                }
            }

            if (transmitSucceded == false)
            {
                _log.Debug("TPDU transmission failed {0}-times, reporting error to application layer", transmitCounter);
                throw new RS232TransportException($"TPDU transmission failed {transmitCounter}-times, reporting error to application layer");
            }
            else
            {
                //Should never get here
                Debug.Assert(false);
                throw new InvalidOperationException("Transmission succeeded but no data");
            }
        }
        private static KeyManager GetKeyManagerByColdcardJson(WalletManager manager, JObject jsonWallet, string walletFullPath)
        {
            var xpubString = jsonWallet["ExtPubKey"].ToString();
            var mfpString  = jsonWallet["MasterFingerprint"].ToString();

            // https://github.com/zkSNACKs/WalletWasabi/pull/1663#issuecomment-508073066
            // Coldcard 2.1.0 improperly implemented Wasabi skeleton fingerprint at first, so we must reverse byte order.
            // The solution was to add a ColdCardFirmwareVersion json field from 2.1.1 and correct the one generated by 2.1.0.
            var coldCardVersionString = jsonWallet["ColdCardFirmwareVersion"]?.ToString();
            var reverseByteOrder      = false;

            if (coldCardVersionString is null)
            {
                reverseByteOrder = true;
            }
            else
            {
                Version coldCardVersion = new(coldCardVersionString);

                if (coldCardVersion == new Version("2.1.0"))                 // Should never happen though.
                {
                    reverseByteOrder = true;
                }
            }

            var           bytes = ByteHelpers.FromHex(Guard.NotNullOrEmptyOrWhitespace(nameof(mfpString), mfpString, trim: true));
            HDFingerprint mfp   = reverseByteOrder ? new HDFingerprint(bytes.Reverse().ToArray()) : new HDFingerprint(bytes);

            if (manager.WalletExists(mfp))
            {
                throw new InvalidOperationException(WalletExistsErrorMessage);
            }

            ExtPubKey extPubKey = NBitcoinHelpers.BetterParseExtPubKey(xpubString);

            return(KeyManager.CreateNewHardwareWalletWatchOnly(mfp, extPubKey, walletFullPath));
        }
Exemplo n.º 5
0
        public static BitcoinExtPubKey BetterParseExtPubKey(string extPubKeyString, Network network, bool ignoreInvalidNetwork)
        {
            extPubKeyString = Guard.NotNullOrEmptyOrWhitespace(nameof(extPubKeyString), extPubKeyString, trim: true);

            ExtPubKey epk;

            try
            {
                epk = ExtPubKey.Parse(extPubKeyString, network); // Starts with "ExtPubKey": "xpub...
            }
            catch
            {
                try
                {
                    // Try hex, Old wallet format was like this.
                    epk = new ExtPubKey(ByteHelpers.FromHex(extPubKeyString)); // Starts with "ExtPubKey": "hexbytes...
                }
                catch when(ignoreInvalidNetwork)
                {
                    // Let's replace the version prefix
                    var data         = Encoders.Base58Check.DecodeData(extPubKeyString);
                    var versionBytes = network.GetVersionBytes(Base58Type.EXT_PUBLIC_KEY, true);

                    if (versionBytes.Length > data.Length)
                    {
                        throw;
                    }
                    for (int i = 0; i < versionBytes.Length; i++)
                    {
                        data[i] = versionBytes[i];
                    }
                    extPubKeyString = Encoders.Base58Check.EncodeData(data);
                    epk             = ExtPubKey.Parse(extPubKeyString, network);
                }
            }
            return(epk.GetWif(network));
        }
        private static bool ConfirmationPassword(PasswordEntry passwordEntry)
        {
            using (var passwordEntry2 = new PasswordEntry())
            {
                passwordEntry2.LabelText = "Please confirm your session password(s).";

                if (passwordEntry2.ShowDialog() != DialogResult.OK)
                {
                    return(false);
                }

                bool password1Match = ByteHelpers.ByteArrayCompare(passwordEntry.Password.Password1, passwordEntry2.Password.Password1);
                bool password2Match = ByteHelpers.ByteArrayCompare(passwordEntry.Password.Password2, passwordEntry2.Password.Password2);

                if ((password1Match == false) || (password2Match == false))
                {
                    MessageBox.Show(Resources.TextShredderMainForm_ConfirmationPassword_The_passwords_do_not_match_, Resources.TextShredderMainForm_ConfirmationPassword_The_passwords_do_not_match_, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

                    return(false);
                }

                return(true);
            }
        }
Exemplo n.º 7
0
        public async Task PostOutputAsync(string roundHash, Script activeOutput, byte[] unblindedSignature)
        {
            var request = new OutputRequest()
            {
                OutputScript = activeOutput.ToString(), SignatureHex = ByteHelpers.ToHex(unblindedSignature)
            };

            using (var response = await TorClient.SendAsync(HttpMethod.Post, $"/api/v1/btc/chaumiancoinjoin/output?roundHash={roundHash}", request.ToHttpStringContent()))
            {
                if (response.StatusCode != HttpStatusCode.NoContent)
                {
                    string error = await response.Content.ReadAsJsonAsync <string>();

                    if (error == null)
                    {
                        throw new HttpRequestException(response.StatusCode.ToReasonString());
                    }
                    else
                    {
                        throw new HttpRequestException($"{response.StatusCode.ToReasonString()}\n{error}");
                    }
                }
            }
        }
Exemplo n.º 8
0
		private async Task ReorgOneAsync()
		{
			// 1. Rollback index
			using (await IndexLock.LockAsync())
			{
				Logger.LogInfo($"REORG invalid block: {Index.Last().BlockHash}");
				Index.RemoveLast();
			}

			// 2. Serialize Index. (Remove last line.)
			var lines = await File.ReadAllLinesAsync(IndexFilePath);
			await File.WriteAllLinesAsync(IndexFilePath, lines.Take(lines.Length - 1).ToArray());

			// 3. Rollback Bech32UtxoSet
			if (Bech32UtxoSetHistory.Count != 0)
			{
				Bech32UtxoSetHistory.Last().Rollback(Bech32UtxoSet); // The Bech32UtxoSet MUST be recovered to its previous state.
				Bech32UtxoSetHistory.RemoveLast();

				// 4. Serialize Bech32UtxoSet.
				await File.WriteAllLinesAsync(Bech32UtxoSetFilePath, Bech32UtxoSet
					.Select(entry => entry.Key.Hash + ":" + entry.Key.N + ":" + ByteHelpers.ToHex(entry.Value.ToCompressedBytes())));
			}
		}
Exemplo n.º 9
0
        private static void CreateDigests()
        {
            var tempDir = "DigestTempDir";

            IoHelpers.DeleteRecursivelyWithMagicDustAsync(tempDir).GetAwaiter().GetResult();
            Directory.CreateDirectory(tempDir);

            var    torDaemonsDir = Path.Combine(LibraryProjectDirectory, "TorDaemons");
            string torWinZip     = Path.Combine(torDaemonsDir, "tor-win32.zip");

            IoHelpers.BetterExtractZipToDirectoryAsync(torWinZip, tempDir).GetAwaiter().GetResult();
            File.Move(Path.Combine(tempDir, "Tor", "tor.exe"), Path.Combine(tempDir, "TorWin"));

            string torLinuxZip = Path.Combine(torDaemonsDir, "tor-linux64.zip");

            IoHelpers.BetterExtractZipToDirectoryAsync(torLinuxZip, tempDir).GetAwaiter().GetResult();
            File.Move(Path.Combine(tempDir, "Tor", "tor"), Path.Combine(tempDir, "TorLin"));

            string torOsxZip = Path.Combine(torDaemonsDir, "tor-osx64.zip");

            IoHelpers.BetterExtractZipToDirectoryAsync(torOsxZip, tempDir).GetAwaiter().GetResult();
            File.Move(Path.Combine(tempDir, "Tor", "tor"), Path.Combine(tempDir, "TorOsx"));

            var tempDirInfo = new DirectoryInfo(tempDir);
            var binaries    = tempDirInfo.GetFiles();

            Console.WriteLine("Digests:");
            foreach (var file in binaries)
            {
                var filePath = file.FullName;
                var hash     = ByteHelpers.ToHex(IoHelpers.GetHashFile(filePath)).ToLowerInvariant();
                Console.WriteLine($"{file.Name}: {hash}");
            }

            IoHelpers.DeleteRecursivelyWithMagicDustAsync(tempDir).GetAwaiter().GetResult();
        }
 public static bool operator ==(ByteArraySerializableBase x, byte[] y) => ByteHelpers.CompareFastUnsafe(x?.ToBytes(), y);
 public override byte[] ToBytes() => ByteHelpers.Combine(new byte[] { Ver.ToByte(), Rep.ToByte(), Rsv.ToByte(), Atyp.ToByte() }, BndAddr.ToBytes(), BndPort.ToBytes());
 public bool Equals(byte[] other) => ByteHelpers.CompareFastUnsafe(ToBytes(), other);
 public static bool operator ==(byte[] x, ByteArraySerializableBase y) => ByteHelpers.CompareFastUnsafe(x, y?.ToBytes());
Exemplo n.º 14
0
 public void CreateSpecialByteArrayThrowsInvalidOperationExceptionIfLengthIsZero()
 {
     ByteHelpers.CreateSpecialByteArray(0);
 }
Exemplo n.º 15
0
        private async Task TryRegisterCoinsAsync(CcjClientRound inputRegistrableRound)
        {
            try
            {
                List <(uint256 txid, uint index)> registrableCoins = State.GetRegistrableCoins(
                    inputRegistrableRound.State.MaximumInputCountPerPeer,
                    inputRegistrableRound.State.Denomination,
                    inputRegistrableRound.State.FeePerInputs,
                    inputRegistrableRound.State.FeePerOutputs).ToList();

                if (registrableCoins.Any())
                {
                    BitcoinAddress changeAddress = null;
                    BitcoinAddress activeAddress = null;
                    lock (CustomChangeAddressesLock)
                    {
                        if (CustomChangeAddresses.Count > 0)
                        {
                            changeAddress = CustomChangeAddresses.First();
                            CustomChangeAddresses.RemoveFirst();
                        }
                    }
                    lock (CustomActiveAddressesLock)
                    {
                        if (CustomActiveAddresses.Count > 0)
                        {
                            activeAddress = CustomActiveAddresses.First();
                            CustomActiveAddresses.RemoveFirst();
                        }
                    }

                    if (changeAddress is null || activeAddress is null)
                    {
                        IEnumerable <HdPubKey> allUnusedInternalKeys = KeyManager.GetKeys(keyState: null, isInternal: true).Where(x => x.KeyState != KeyState.Used);

                        if (changeAddress is null)
                        {
                            string changeLabel = "ZeroLink Change";
                            IEnumerable <HdPubKey> allChangeKeys = allUnusedInternalKeys.Where(x => x.Label == changeLabel);
                            HdPubKey changeKey = null;

                            KeyManager.AssertLockedInternalKeysIndexed(14);
                            IEnumerable <HdPubKey> internalNotCachedLockedKeys = KeyManager.GetKeys(KeyState.Locked, isInternal: true).Except(AccessCache.Keys);

                            if (allChangeKeys.Count() >= 7 || !internalNotCachedLockedKeys.Any())                             // Then don't generate new keys, because it'd bloat the wallet.
                            {
                                // Find the first one that we did not try to register in the current session.
                                changeKey = allChangeKeys.FirstOrDefault(x => !AccessCache.ContainsKey(x));
                                // If there is no such a key, then use the oldest.
                                if (changeKey == default)
                                {
                                    changeKey = AccessCache.Where(x => allChangeKeys.Contains(x.Key)).OrderBy(x => x.Value).First().Key;
                                }
                                changeKey.SetLabel(changeLabel);
                                changeKey.SetKeyState(KeyState.Locked);
                            }
                            else
                            {
                                changeKey = internalNotCachedLockedKeys.RandomElement();
                                changeKey.SetLabel(changeLabel);
                            }
                            changeAddress = changeKey.GetP2wpkhAddress(Network);
                            AccessCache.AddOrReplace(changeKey, DateTimeOffset.UtcNow);
                        }

                        if (activeAddress is null)
                        {
                            string activeLabel = "ZeroLink Mixed Coin";
                            IEnumerable <HdPubKey> allActiveKeys = allUnusedInternalKeys.Where(x => x.Label == activeLabel);
                            HdPubKey activeKey = null;

                            KeyManager.AssertLockedInternalKeysIndexed(14);
                            IEnumerable <HdPubKey> internalNotCachedLockedKeys = KeyManager.GetKeys(KeyState.Locked, isInternal: true).Except(AccessCache.Keys);

                            if (allActiveKeys.Count() >= 7 || !internalNotCachedLockedKeys.Any())                             // Then don't generate new keys, because it'd bloat the wallet.
                            {
                                // Find the first one that we did not try to register in the current session.
                                activeKey = allActiveKeys.FirstOrDefault(x => !AccessCache.ContainsKey(x));
                                // If there is no such a key, then use the oldest.
                                if (activeKey == default)
                                {
                                    activeKey = AccessCache.Where(x => allActiveKeys.Contains(x.Key)).OrderBy(x => x.Value).First().Key;
                                }
                                activeKey.SetLabel(activeLabel);
                                activeKey.SetKeyState(KeyState.Locked);
                                activeAddress = activeKey.GetP2wpkhAddress(Network);
                            }
                            else
                            {
                                activeKey = internalNotCachedLockedKeys.RandomElement();
                                activeKey.SetLabel(activeLabel);
                            }
                            activeAddress = activeKey.GetP2wpkhAddress(Network);
                            AccessCache.AddOrReplace(activeKey, DateTimeOffset.UtcNow);
                        }
                    }

                    KeyManager.ToFile();

                    var blind = CoordinatorPubKey.Blind(activeAddress.ScriptPubKey.ToBytes());

                    var inputProofs = new List <InputProofModel>();
                    foreach ((uint256 txid, uint index)coinReference in registrableCoins)
                    {
                        SmartCoin coin = State.GetSingleOrDefaultFromWaitingList(coinReference);
                        if (coin is null)
                        {
                            throw new NotSupportedException("This is impossible.");
                        }
                        coin.Secret = coin.Secret ?? KeyManager.GetSecrets(OnePiece, coin.ScriptPubKey).Single();
                        var inputProof = new InputProofModel
                        {
                            Input = coin.GetTxoRef(),
                            Proof = coin.Secret.PrivateKey.SignMessage(ByteHelpers.ToHex(blind.BlindedData))
                        };
                        inputProofs.Add(inputProof);
                    }
                    AliceClient aliceClient = await AliceClient.CreateNewAsync(Network, changeAddress, blind.BlindedData, inputProofs, CcjHostUri, TorSocks5EndPoint);

                    byte[] unblindedSignature = CoordinatorPubKey.UnblindSignature(aliceClient.BlindedOutputSignature, blind.BlindingFactor);

                    if (!CoordinatorPubKey.Verify(unblindedSignature, activeAddress.ScriptPubKey.ToBytes()))
                    {
                        throw new NotSupportedException("Coordinator did not sign the blinded output properly.");
                    }

                    CcjClientRound roundRegistered = State.GetSingleOrDefaultRound(aliceClient.RoundId);
                    if (roundRegistered is null)
                    {
                        // If our SatoshiClient doesn't yet know about the round because of the dealy create it.
                        // Make its state as it'd be the same as our assumed round was, except the roundId and registeredPeerCount, it'll be updated later.
                        roundRegistered = new CcjClientRound(CcjRunningRoundState.CloneExcept(inputRegistrableRound.State, aliceClient.RoundId, registeredPeerCount: 1));
                        State.AddOrReplaceRound(roundRegistered);
                    }

                    foreach ((uint256 txid, uint index)coinReference in registrableCoins)
                    {
                        var coin = State.GetSingleOrDefaultFromWaitingList(coinReference);
                        if (coin is null)
                        {
                            throw new NotSupportedException("This is impossible.");
                        }
                        roundRegistered.CoinsRegistered.Add(coin);
                        State.RemoveCoinFromWaitingList(coin);
                    }
                    roundRegistered.ActiveOutputAddress = activeAddress;
                    roundRegistered.ChangeOutputAddress = changeAddress;
                    roundRegistered.UnblindedSignature  = unblindedSignature;
                    roundRegistered.AliceClient         = aliceClient;
                }
            }
            catch (Exception ex)
            {
                Logger.LogError <CcjClient>(ex);
            }
        }
Exemplo n.º 16
0
 public static void FromHex(this IBitcoinSerializable me, string hex)
 {
     Guard.NotNullOrEmptyOrWhitespace(nameof(hex), hex);
     me.FromBytes(ByteHelpers.FromHex(hex));
 }
Exemplo n.º 17
0
 public void GetStringThrowsArgumentNullExceptionIsInputArrayIsNull()
 {
     ByteHelpers.GetString(null);
 }
Exemplo n.º 18
0
 public override byte[] ToBytes() => ByteHelpers.Combine(new byte[] { Ver.ToByte(), Cmd.ToByte(), Rsv.ToByte(), Atyp.ToByte() }, DstAddr.ToBytes(), DstPort.ToBytes());
Exemplo n.º 19
0
 public void ByteArrayCompareThrowsArgumentNullExceptionIfFirstParameterIsNull()
 {
     ByteHelpers.ByteArrayCompare(null, null);
 }
Exemplo n.º 20
0
        public void CombineThrowsArgumentNullExceptionIfSecondParameterIsNull()
        {
            var test = new byte[5];

            ByteHelpers.Combine(test, null);
        }
Exemplo n.º 21
0
 public void CombineThrowsArgumentNullExceptionIfFirstParameterIsNull()
 {
     ByteHelpers.Combine(null, null);
 }
Exemplo n.º 22
0
 public void CreateSpecialByteArrayCreateArayOfSize10()
 {
     byte[] array = ByteHelpers.CreateSpecialByteArray(10);
     Assert.AreEqual(10, array.Length);
 }
Exemplo n.º 23
0
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var value = (string)reader.Value;

        return(OwnershipProof.FromBytes(ByteHelpers.FromHex(value)));
    }
Exemplo n.º 24
0
 public void GeneratorsArentChanged()
 {
     Assert.Equal("0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", ByteHelpers.ToHex(Generators.G.ToBytes()));
     Assert.Equal("03AB8F46084B4FA0FC8261328A5A71AF267B1D1F8FE229C63C751D02A2E996E0EC", ByteHelpers.ToHex(Generators.Ga.ToBytes()));
     Assert.Equal("02FB8868ACD9CBBD68964BAA1CFA6B893A6269E01569183474E6C1C4242A0071A9", ByteHelpers.ToHex(Generators.Gg.ToBytes()));
     Assert.Equal("023D11E10CE7A8C17671ED777886FC2B84E65A532FA0C411ABBE96E1206F9DFF80", ByteHelpers.ToHex(Generators.Gh.ToBytes()));
     Assert.Equal("031E7775ED62B79E9E83366198CFE69DFE7408AFF10C331CEE3B2C7F7A5F2EB0C8", ByteHelpers.ToHex(Generators.Gs.ToBytes()));
     Assert.Equal("03665E9B8468DCEDA16ED3E315FBD0A0E597F4AA3B4C6F2146437F53F3AF204C2C", ByteHelpers.ToHex(Generators.GV.ToBytes()));
     Assert.Equal("02B4DF49B623A8A0B245CCF2867134A5DAC12FE39ECEC08B3D361801D2C79DDC14", ByteHelpers.ToHex(Generators.Gw.ToBytes()));
     Assert.Equal("03F50265578FCE5E977162E662ED75D7224AE720FA79B72CF2B6FB86B2136E3B48", ByteHelpers.ToHex(Generators.Gwp.ToBytes()));
     Assert.Equal("02E33C9F3CBE6388A2D3C3ECB12153DB73499928541905D86AAA4FFC01F2763B54", ByteHelpers.ToHex(Generators.Gx0.ToBytes()));
     Assert.Equal("0246253CC926AAB789BAA278AB9A54EDEF455CA2014038E9F84DE312C05A8121CC", ByteHelpers.ToHex(Generators.Gx1.ToBytes()));
 }
Exemplo n.º 25
0
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var bytes = ((OwnershipProof)value).ToBytes();

        writer.WriteValue(ByteHelpers.ToHex(bytes));
    }
        public async Task <IActionResult> PostInputsAsync([FromBody] InputsRequest request)
        {
            // Validate request.
            if (!ModelState.IsValid ||
                request == null ||
                string.IsNullOrWhiteSpace(request.BlindedOutputScriptHex) ||
                string.IsNullOrWhiteSpace(request.ChangeOutputScript) ||
                request.Inputs == null ||
                request.Inputs.Count() == 0 ||
                request.Inputs.Any(x => x.Input == null ||
                                   x.Input.Hash == null ||
                                   string.IsNullOrWhiteSpace(x.Proof)))
            {
                return(BadRequest("Invalid request."));
            }

            if (request.Inputs.Count() > 7)
            {
                return(BadRequest("Maximum 7 inputs can be registered."));
            }

            using (await InputsLock.LockAsync())
            {
                CcjRound round = Coordinator.GetCurrentInputRegisterableRound();

                // Do more checks.
                try
                {
                    if (round.ContainsBlindedOutputScriptHex(request.BlindedOutputScriptHex, out _))
                    {
                        return(BadRequest("Blinded output has already been registered."));
                    }

                    var changeOutput = new Script(request.ChangeOutputScript);

                    var inputs = new HashSet <(OutPoint OutPoint, TxOut Output)>();

                    var alicesToRemove = new HashSet <Guid>();

                    foreach (InputProofModel inputProof in request.Inputs)
                    {
                        if (inputs.Any(x => x.OutPoint == inputProof.Input))
                        {
                            return(BadRequest("Cannot register an input twice."));
                        }
                        if (round.ContainsInput(inputProof.Input, out List <Alice> tr))
                        {
                            alicesToRemove.UnionWith(tr.Select(x => x.UniqueId));                             // Input is already registered by this alice, remove it later if all the checks are completed fine.
                        }
                        if (Coordinator.AnyRunningRoundContainsInput(inputProof.Input, out List <Alice> tnr))
                        {
                            if (tr.Union(tnr).Count() > tr.Count())
                            {
                                return(BadRequest("Input is already registered in another round."));
                            }
                        }

                        var bannedElem = Coordinator.UtxoReferee.BannedUtxos.SingleOrDefault(x => x.Key == inputProof.Input);
                        if (bannedElem.Key != default)
                        {
                            int maxBan  = (int)TimeSpan.FromDays(30).TotalMinutes;
                            int banLeft = maxBan - (int)((DateTimeOffset.UtcNow - bannedElem.Value.timeOfBan).TotalMinutes);
                            if (banLeft > 0)
                            {
                                return(BadRequest($"Input is banned from participation for {banLeft} minutes: {inputProof.Input.N}:{inputProof.Input.Hash}."));
                            }
                            else
                            {
                                await Coordinator.UtxoReferee.UnbanAsync(bannedElem.Key);
                            }
                        }

                        GetTxOutResponse getTxOutResponse = await RpcClient.GetTxOutAsync(inputProof.Input.Hash, (int)inputProof.Input.N, includeMempool : true);

                        // Check if inputs are unspent.
                        if (getTxOutResponse == null)
                        {
                            return(BadRequest("Provided input is not unspent."));
                        }

                        // Check if unconfirmed.
                        if (getTxOutResponse.Confirmations <= 0)
                        {
                            // If it spends a CJ then it may be acceptable to register.
                            if (!Coordinator.ContainsCoinJoin(inputProof.Input.Hash))
                            {
                                return(BadRequest("Provided input is neither confirmed, nor is from an unconfirmed coinjoin."));
                            }
                            // After 24 unconfirmed cj in the mempool dont't let unconfirmed coinjoin to be registered.
                            if (await Coordinator.IsUnconfirmedCoinJoinLimitReachedAsync())
                            {
                                return(BadRequest("Provided input is from an unconfirmed coinjoin, but the maximum number of unconfirmed coinjoins is reached."));
                            }
                        }

                        // Check if immature.
                        if (getTxOutResponse.Confirmations <= 100)
                        {
                            if (getTxOutResponse.IsCoinBase)
                            {
                                return(BadRequest("Provided input is immature."));
                            }
                        }

                        // Check if inputs are native segwit.
                        if (getTxOutResponse.ScriptPubKeyType != "witness_v0_keyhash")
                        {
                            return(BadRequest("Provided input must be witness_v0_keyhash."));
                        }

                        TxOut txout = getTxOutResponse.TxOut;

                        var address = (BitcoinWitPubKeyAddress)txout.ScriptPubKey.GetDestinationAddress(Network);
                        // Check if proofs are valid.
                        bool validProof;
                        try
                        {
                            validProof = address.VerifyMessage(request.BlindedOutputScriptHex, inputProof.Proof);
                        }
                        catch (FormatException ex)
                        {
                            return(BadRequest($"Provided proof is invalid: {ex.Message}"));
                        }
                        if (!validProof)
                        {
                            return(BadRequest("Provided proof is invalid."));
                        }

                        inputs.Add((inputProof.Input, txout));
                    }

                    // Check if inputs have enough coins.
                    Money inputSum        = inputs.Sum(x => x.Output.Value);
                    Money networkFeeToPay = (inputs.Count() * round.FeePerInputs + 2 * round.FeePerOutputs);
                    Money changeAmount    = inputSum - (round.Denomination + networkFeeToPay);
                    if (changeAmount < Money.Zero)
                    {
                        return(BadRequest($"Not enough inputs are provided. Fee to pay: {networkFeeToPay.ToString(false, true)} BTC. Round denomination: {round.Denomination.ToString(false, true)} BTC. Only provided: {inputSum.ToString(false, true)} BTC."));
                    }

                    // Make sure Alice checks work.
                    var alice = new Alice(inputs, networkFeeToPay, new Script(request.ChangeOutputScript), request.BlindedOutputScriptHex);

                    foreach (Guid aliceToRemove in alicesToRemove)
                    {
                        round.RemoveAlicesBy(aliceToRemove);
                    }
                    round.AddAlice(alice);

                    // All checks are good. Sign.
                    byte[] blindedData;
                    try
                    {
                        blindedData = ByteHelpers.FromHex(request.BlindedOutputScriptHex);
                    }
                    catch
                    {
                        return(BadRequest("Invalid blinded output hex."));
                    }
                    Logger.LogDebug <ChaumianCoinJoinController>($"Blinded data hex: {request.BlindedOutputScriptHex}");
                    Logger.LogDebug <ChaumianCoinJoinController>($"Blinded data array size: {blindedData.Length}");
                    byte[] signature = RsaKey.SignBlindedData(blindedData);

                    // Check if phase changed since.
                    if (round.Status != ChaumianCoinJoin.CcjRoundStatus.Running || round.Phase != CcjRoundPhase.InputRegistration)
                    {
                        return(base.StatusCode(StatusCodes.Status503ServiceUnavailable, "The state of the round changed while handling the request. Try again."));
                    }

                    // Progress round if needed.
                    if (round.CountAlices() >= round.AnonymitySet)
                    {
                        await round.RemoveAlicesIfInputsSpentAsync();

                        if (round.CountAlices() >= round.AnonymitySet)
                        {
                            await round.ExecuteNextPhaseAsync(CcjRoundPhase.ConnectionConfirmation);
                        }
                    }

                    var resp = new InputsResponse
                    {
                        UniqueId = alice.UniqueId,
                        BlindedOutputSignature = signature,
                        RoundId = round.RoundId
                    };
                    return(Ok(resp));
                }
                catch (Exception ex)
                {
                    Logger.LogDebug <ChaumianCoinJoinController>(ex);
                    return(BadRequest(ex.Message));
                }
            }
        }
Exemplo n.º 27
0
        public void Synchronize()
        {
            Interlocked.Exchange(ref _running, 1);

            Task.Run(async() =>
            {
                try
                {
                    var blockCount = await RpcClient.GetBlockCountAsync();
                    var isIIB      = true;                // Initial Index Building phase

                    while (IsRunning)
                    {
                        try
                        {
                            // If stop was requested return.
                            if (IsRunning == false)
                            {
                                return;
                            }

                            var height       = StartingHeight;
                            uint256 prevHash = null;
                            using (await IndexLock.LockAsync())
                            {
                                if (Index.Count != 0)
                                {
                                    var lastIndex = Index.Last();
                                    height        = lastIndex.BlockHeight + 1;
                                    prevHash      = lastIndex.BlockHash;
                                }
                            }

                            if (blockCount - (int)height <= 100)
                            {
                                isIIB = false;
                            }

                            Block block = null;
                            try
                            {
                                block = await RpcClient.GetBlockAsync(height);
                            }
                            catch (RPCException)                             // if the block didn't come yet
                            {
                                await Task.Delay(1000);
                                continue;
                            }

                            if (prevHash != null)
                            {
                                // In case of reorg:
                                if (prevHash != block.Header.HashPrevBlock && !isIIB)                                 // There is no reorg in IIB
                                {
                                    Logger.LogInfo <IndexBuilderService>($"REORG Invalid Block: {prevHash}");
                                    // 1. Rollback index
                                    using (await IndexLock.LockAsync())
                                    {
                                        Index.RemoveLast();
                                    }

                                    // 2. Serialize Index. (Remove last line.)
                                    var lines = File.ReadAllLines(IndexFilePath);
                                    File.WriteAllLines(IndexFilePath, lines.Take(lines.Length - 1).ToArray());

                                    // 3. Rollback Bech32UtxoSet
                                    if (Bech32UtxoSetHistory.Count != 0)
                                    {
                                        Bech32UtxoSetHistory.Last().Rollback(Bech32UtxoSet);                                         // The Bech32UtxoSet MUST be recovered to its previous state.
                                        Bech32UtxoSetHistory.RemoveLast();

                                        // 4. Serialize Bech32UtxoSet.
                                        await File.WriteAllLinesAsync(Bech32UtxoSetFilePath, Bech32UtxoSet
                                                                      .Select(entry => entry.Key.Hash + ":" + entry.Key.N + ":" + ByteHelpers.ToHex(entry.Value.ToCompressedBytes())));
                                    }

                                    // 5. Skip the current block.
                                    continue;
                                }
                            }

                            if (!isIIB)
                            {
                                if (Bech32UtxoSetHistory.Count >= 100)
                                {
                                    Bech32UtxoSetHistory.RemoveFirst();
                                }
                                Bech32UtxoSetHistory.Add(new ActionHistoryHelper());
                            }

                            var scripts = new HashSet <Script>();

                            foreach (var tx in block.Transactions)
                            {
                                for (int i = 0; i < tx.Outputs.Count; i++)
                                {
                                    var output = tx.Outputs[i];
                                    if (!output.ScriptPubKey.IsPayToScriptHash && output.ScriptPubKey.IsWitness)
                                    {
                                        var outpoint = new OutPoint(tx.GetHash(), i);
                                        Bech32UtxoSet.Add(outpoint, output.ScriptPubKey);
                                        if (!isIIB)
                                        {
                                            Bech32UtxoSetHistory.Last().StoreAction(ActionHistoryHelper.Operation.Add, outpoint, output.ScriptPubKey);
                                        }
                                        scripts.Add(output.ScriptPubKey);
                                    }
                                }

                                foreach (var input in tx.Inputs)
                                {
                                    var found = Bech32UtxoSet.SingleOrDefault(x => x.Key == input.PrevOut);
                                    if (found.Key != default)
                                    {
                                        Script val = Bech32UtxoSet[input.PrevOut];
                                        Bech32UtxoSet.Remove(input.PrevOut);
                                        if (!isIIB)
                                        {
                                            Bech32UtxoSetHistory.Last().StoreAction(ActionHistoryHelper.Operation.Remove, input.PrevOut, val);
                                        }
                                        scripts.Add(found.Value);
                                    }
                                }
                            }

                            // https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki
                            // The parameter k MUST be set to the first 16 bytes of the hash of the block for which the filter
                            // is constructed.This ensures the key is deterministic while still varying from block to block.
                            var key = block.GetHash().ToBytes().Take(16).ToArray();

                            GolombRiceFilter filter = null;
                            if (scripts.Count != 0)
                            {
                                filter = GolombRiceFilter.Build(key, scripts.Select(x => x.ToCompressedBytes()));
                            }

                            var filterModel = new FilterModel
                            {
                                BlockHash   = block.GetHash(),
                                BlockHeight = height,
                                Filter      = filter
                            };

                            await File.AppendAllLinesAsync(IndexFilePath, new[] { filterModel.ToLine() });
                            using (await IndexLock.LockAsync())
                            {
                                Index.Add(filterModel);
                            }
                            if (File.Exists(Bech32UtxoSetFilePath))
                            {
                                File.Delete(Bech32UtxoSetFilePath);
                            }
                            await File.WriteAllLinesAsync(Bech32UtxoSetFilePath, Bech32UtxoSet
                                                          .Select(entry => entry.Key.Hash + ":" + entry.Key.N + ":" + ByteHelpers.ToHex(entry.Value.ToCompressedBytes())));

                            if (blockCount - height <= 3 || height % 100 == 0)                             // If not close to the tip, just log debug.
                            {
                                Logger.LogInfo <IndexBuilderService>($"Created filter for block: {height}.");
                            }
                            else
                            {
                                Logger.LogDebug <IndexBuilderService>($"Created filter for block: {height}.");
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.LogDebug <IndexBuilderService>(ex);
                        }
                    }
                }
                finally
                {
                    if (IsStopping)
                    {
                        Interlocked.Exchange(ref _running, 3);
                    }
                }
            });
        }
Exemplo n.º 28
0
        public void ByteArrayCompareThrowsArgumentNullExceptionIfSecondParameterIsNull()
        {
            var test = new byte[5];

            ByteHelpers.ByteArrayCompare(test, null);
        }
Exemplo n.º 29
0
        public void Synchronize()
        {
            Interlocked.Exchange(ref _running, 1);

            Task.Run(async() =>
            {
                try
                {
                    var blockCount = await RpcClient.GetBlockCountAsync();
                    var isIIB      = true;                // Initial Index Building phase

                    while (IsRunning)
                    {
                        try
                        {
                            // If stop was requested return.
                            if (IsRunning == false)
                            {
                                return;
                            }

                            Height height    = StartingHeight;
                            uint256 prevHash = null;
                            using (await IndexLock.LockAsync())
                            {
                                if (Index.Count != 0)
                                {
                                    var lastIndex = Index.Last();
                                    height        = lastIndex.BlockHeight + 1;
                                    prevHash      = lastIndex.BlockHash;
                                }
                            }

                            if (blockCount - height <= 100)
                            {
                                isIIB = false;
                            }

                            Block block = null;
                            try
                            {
                                block = await RpcClient.GetBlockAsync(height);
                            }
                            catch (RPCException)                             // if the block didn't come yet
                            {
                                await Task.Delay(1000);
                                continue;
                            }

                            if (blockCount - height <= 2)
                            {
                                NewBlock?.Invoke(this, block);
                            }

                            if (!(prevHash is null))
                            {
                                // In case of reorg:
                                if (prevHash != block.Header.HashPrevBlock && !isIIB)                                 // There is no reorg in IIB
                                {
                                    Logger.LogInfo <IndexBuilderService>($"REORG Invalid Block: {prevHash}");
                                    // 1. Rollback index
                                    using (await IndexLock.LockAsync())
                                    {
                                        Index.RemoveLast();
                                    }

                                    // 2. Serialize Index. (Remove last line.)
                                    var lines = File.ReadAllLines(IndexFilePath);
                                    File.WriteAllLines(IndexFilePath, lines.Take(lines.Length - 1).ToArray());

                                    // 3. Rollback Bech32UtxoSet
                                    if (Bech32UtxoSetHistory.Count != 0)
                                    {
                                        Bech32UtxoSetHistory.Last().Rollback(Bech32UtxoSet);                                         // The Bech32UtxoSet MUST be recovered to its previous state.
                                        Bech32UtxoSetHistory.RemoveLast();

                                        // 4. Serialize Bech32UtxoSet.
                                        await File.WriteAllLinesAsync(Bech32UtxoSetFilePath, Bech32UtxoSet
                                                                      .Select(entry => entry.Key.Hash + ":" + entry.Key.N + ":" + ByteHelpers.ToHex(entry.Value.ToCompressedBytes())));
                                    }

                                    // 5. Skip the current block.
                                    continue;
                                }
                            }

                            if (!isIIB)
                            {
                                if (Bech32UtxoSetHistory.Count >= 100)
                                {
                                    Bech32UtxoSetHistory.RemoveFirst();
                                }
                                Bech32UtxoSetHistory.Add(new ActionHistoryHelper());
                            }

                            var scripts = new HashSet <Script>();

                            foreach (var tx in block.Transactions)
                            {
                                // If stop was requested return.
                                // Because this tx iteration can take even minutes
                                // It doesn't need to be accessed with a thread safe fasion with Interlocked through IsRunning, this may have some performance benefit
                                if (_running != 1)
                                {
                                    return;
                                }

                                for (int i = 0; i < tx.Outputs.Count; i++)
                                {
                                    var output = tx.Outputs[i];
                                    if (!output.ScriptPubKey.IsPayToScriptHash && output.ScriptPubKey.IsWitness)
                                    {
                                        var outpoint = new OutPoint(tx.GetHash(), i);
                                        Bech32UtxoSet.Add(outpoint, output.ScriptPubKey);
                                        if (!isIIB)
                                        {
                                            Bech32UtxoSetHistory.Last().StoreAction(ActionHistoryHelper.Operation.Add, outpoint, output.ScriptPubKey);
                                        }
                                        scripts.Add(output.ScriptPubKey);
                                    }
                                }

                                foreach (var input in tx.Inputs)
                                {
                                    OutPoint prevOut = input.PrevOut;
                                    if (Bech32UtxoSet.TryGetValue(prevOut, out Script foundScript))
                                    {
                                        Bech32UtxoSet.Remove(prevOut);
                                        if (!isIIB)
                                        {
                                            Bech32UtxoSetHistory.Last().StoreAction(ActionHistoryHelper.Operation.Remove, prevOut, foundScript);
                                        }
                                        scripts.Add(foundScript);
                                    }
                                }
                            }

                            GolombRiceFilter filter = null;
                            if (scripts.Count != 0)
                            {
                                filter = new GolombRiceFilterBuilder()
                                         .SetKey(block.GetHash())
                                         .SetP(20)
                                         .SetM(1 << 20)
                                         .AddEntries(scripts.Select(x => x.ToCompressedBytes()))
                                         .Build();
                            }

                            var filterModel = new FilterModel
                            {
                                BlockHash   = block.GetHash(),
                                BlockHeight = height,
                                Filter      = filter
                            };

                            await File.AppendAllLinesAsync(IndexFilePath, new[] { filterModel.ToLine() });
                            using (await IndexLock.LockAsync())
                            {
                                Index.Add(filterModel);
                            }
                            if (File.Exists(Bech32UtxoSetFilePath))
                            {
                                File.Delete(Bech32UtxoSetFilePath);
                            }
                            await File.WriteAllLinesAsync(Bech32UtxoSetFilePath, Bech32UtxoSet
                                                          .Select(entry => entry.Key.Hash + ":" + entry.Key.N + ":" + ByteHelpers.ToHex(entry.Value.ToCompressedBytes())));

                            // If not close to the tip, just log debug.
                            // Use height.Value instead of simply height, because it cannot be negative height.
                            if (blockCount - height.Value <= 3 || height % 100 == 0)
                            {
                                Logger.LogInfo <IndexBuilderService>($"Created filter for block: {height}.");
                            }
                            else
                            {
                                Logger.LogDebug <IndexBuilderService>($"Created filter for block: {height}.");
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.LogDebug <IndexBuilderService>(ex);
                        }
                    }
                }
                finally
                {
                    if (IsStopping)
                    {
                        Interlocked.Exchange(ref _running, 3);
                    }
                }
            });
        }
Exemplo n.º 30
0
 public static string ToHex(this IBitcoinSerializable me)
 {
     return(ByteHelpers.ToHex(me.ToBytes()));
 }