Esempio n. 1
0
        public static bool TryGetHeader(Height height, out ChainedBlock creationHeader)
        {
            creationHeader = null;
            try
            {
                if (_connectionParameters == null)
                {
                    return(false);
                }

                creationHeader = HeaderChain.GetBlock(height);

                if (creationHeader == null)
                {
                    return(false);
                }
                else
                {
                    return(true);
                }
            }
            catch
            {
                return(false);
            }
        }
Esempio n. 2
0
 private static void SaveHeaderChain()
 {
     using (var fs = File.Open(_headerChainFilePath, FileMode.Create))
     {
         HeaderChain.WriteTo(fs);
     }
 }
Esempio n. 3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="account">if null then default safe, if doesn't contain, then exception</param>
        /// <returns></returns>
        public IEnumerable <SafeHistoryRecord> GetSafeHistory(SafeAccount account = null)
        {
            AssertAccount(account);

            var safeHistory = new HashSet <SafeHistoryRecord>();

            var transactions  = GetAllChainAndMemPoolTransactionsBySafeAccount(account);
            var scriptPubKeys = GetTrackedScriptPubKeysBySafeAccount(account);

            foreach (SmartTransaction transaction in transactions)
            {
                SafeHistoryRecord record = new SafeHistoryRecord();
                record.TransactionId = transaction.GetHash();
                record.BlockHeight   = transaction.Height;
                // todo: the mempool could note when it seen the transaction the first time
                record.TimeStamp = !transaction.Confirmed
                                        ? DateTimeOffset.UtcNow
                                        : HeaderChain.GetBlock(transaction.Height).Header.BlockTime;

                record.Amount = Money.Zero;                 //for now

                // how much came to our scriptpubkeys
                foreach (var output in transaction.Transaction.Outputs)
                {
                    if (scriptPubKeys.Contains(output.ScriptPubKey))
                    {
                        record.Amount += output.Value;
                    }
                }

                foreach (var input in transaction.Transaction.Inputs)
                {
                    // do we have the input?
                    SmartTransaction inputTransaction = transactions.FirstOrDefault(x => x.GetHash() == input.PrevOut.Hash);
                    if (default(SmartTransaction) != inputTransaction)
                    {
                        // if yes then deduct from amount (bitcoin output cannot be partially spent)
                        var prevOutput = inputTransaction.Transaction.Outputs[input.PrevOut.N];
                        if (scriptPubKeys.Contains(prevOutput.ScriptPubKey))
                        {
                            record.Amount -= prevOutput.Value;
                        }
                    }
                    // if no then whatever
                }

                safeHistory.Add(record);
            }

            return(safeHistory.ToList().OrderBy(x => x.TimeStamp));
        }
Esempio n. 4
0
 private void Reorg()
 {
     HeaderChain.SetTip(HeaderChain.Tip.Previous);
     Tracker.ReorgOne();
 }
Esempio n. 5
0
        private async Task BlockPullerJobAsync(CancellationToken ctsToken)
        {
            const int currTimeoutDownSec = 360;

            MemPoolJob.Enabled = false;
            while (true)
            {
                try
                {
                    if (ctsToken.IsCancellationRequested)
                    {
                        return;
                    }

                    // the headerchain didn't catch up to the creationheight yet
                    if (CreationHeight == Height.Unknown || HeaderChain.Height < CreationHeight)
                    {
                        State = WalletState.SyncingHeaders;
                        await Task.Delay(100, ctsToken).ContinueWith(tsk => { }).ConfigureAwait(false);

                        continue;
                    }

                    Height height;
                    if (Tracker.BlockCount == 0)
                    {
                        height = CreationHeight;
                    }
                    else
                    {
                        int    headerChainHeight          = HeaderChain.Height;
                        Height trackerBestHeight          = Tracker.BestHeight;
                        Height unprocessedBlockBestHeight = Tracker.UnprocessedBlockBuffer.BestHeight;
                        // if no blocks to download (or process) start syncing mempool
                        if (headerChainHeight <= trackerBestHeight)
                        {
                            State = MemPoolJob.SyncedOnce ? WalletState.Synced : WalletState.SyncingMemPool;
                            MemPoolJob.Enabled = true;
                            await Task.Delay(100, ctsToken).ContinueWith(tsk => { }).ConfigureAwait(false);

                            continue;
                        }
                        // else sync blocks
                        else
                        {
                            MemPoolJob.Enabled = false;
                            State = WalletState.SyncingBlocks;
                            // if unprocessed buffer hit the headerchain height
                            // or unprocessed buffer is full
                            // wait until they get processed
                            if ((
                                    unprocessedBlockBestHeight.Type == HeightType.Chain &&
                                    (headerChainHeight <= unprocessedBlockBestHeight)
                                    ) ||
                                Tracker.UnprocessedBlockBuffer.Full)
                            {
                                await Task.Delay(100, ctsToken).ContinueWith(tsk => { }).ConfigureAwait(false);

                                continue;
                            }
                            // else figure out the next block's height to download
                            else
                            {
                                int relevant = unprocessedBlockBestHeight.Type == HeightType.Chain
                                                                        ? unprocessedBlockBestHeight.Value
                                                                        : 0;

                                // should not happen at this point, but better to check
                                if (trackerBestHeight.Type != HeightType.Chain)
                                {
                                    await Task.Delay(100, ctsToken).ContinueWith(tsk => { }).ConfigureAwait(false);

                                    continue;
                                }

                                height = new Height(
                                    Math.Max(trackerBestHeight.Value, relevant)
                                    + 1);
                            }
                        }
                    }

                    var chainedBlock = HeaderChain.GetBlock(height);
                    BlockPuller.SetLocation(new ChainedBlock(chainedBlock.Previous.Header, chainedBlock.Previous.Height));
                    Block block = null;
                    CancellationTokenSource ctsBlockDownload = CancellationTokenSource.CreateLinkedTokenSource(
                        new CancellationTokenSource(TimeSpan.FromSeconds(currTimeoutDownSec)).Token,
                        ctsToken);
                    var blockDownloadTask = Task.Run(() => BlockPuller.NextBlock(ctsBlockDownload.Token));
                    block = await blockDownloadTask.ContinueWith(t =>
                    {
                        if (ctsToken.IsCancellationRequested)
                        {
                            return(null);
                        }
                        if (t.IsCanceled || t.IsFaulted)
                        {
                            Nodes.Purge("no reason");
                            Debug.WriteLine(
                                $"Purging nodes, reason: couldn't download block in {currTimeoutDownSec} seconds.");
                            return(null);
                        }
                        return(t.Result);
                    }).ConfigureAwait(false);

                    if (ctsToken.IsCancellationRequested)
                    {
                        return;
                    }
                    if (blockDownloadTask.IsCanceled || blockDownloadTask.IsFaulted)
                    {
                        continue;
                    }

                    if (block == null)                // then reorg happened
                    {
                        Reorg();
                        continue;
                    }

                    Tracker.AddOrReplaceBlock(new Height(chainedBlock.Height), block);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"Ignoring {nameof(BlockPullerJobAsync)} exception:");
                    Debug.WriteLine(ex);
                }
            }
        }
Esempio n. 6
0
 private void Reorg()
 {
     HeaderChain.SetTip(HeaderChain.Tip.Previous);
     Tracker.ReorgOne();
     SaveAllChangedAsync().Wait();
 }
Esempio n. 7
0
        private async Task BlockDownloadingJobAsync(CancellationToken ctsToken)
        {
            MemPoolJob.Enabled = false;
            while (true)
            {
                try
                {
                    if (ctsToken.IsCancellationRequested)
                    {
                        return;
                    }

                    // the headerchain didn't catch up to the creationheight yet
                    if (Nodes.ConnectedNodes.Count < 3 ||                     // at this condition it might catched up already, neverthless don't progress further
                        CreationHeight == Height.Unknown || HeaderChain.Height < CreationHeight)
                    {
                        State = WalletState.SyncingHeaders;
                        await Task.Delay(100, ctsToken).ContinueWith(tsk => { }).ConfigureAwait(false);

                        continue;
                    }

                    Height height;
                    if (Tracker.BlockCount == 0)
                    {
                        height = CreationHeight;
                    }
                    else
                    {
                        int    headerChainHeight          = HeaderChain.Height;
                        Height trackerBestHeight          = Tracker.BestHeight;
                        Height unprocessedBlockBestHeight = Tracker.UnprocessedBlockBuffer.BestHeight;
                        // if no blocks to download (or process) start syncing mempool
                        if (headerChainHeight <= trackerBestHeight)
                        {
                            State = MemPoolJob.SyncedOnce ? WalletState.Synced : WalletState.SyncingMemPool;
                            MemPoolJob.Enabled = true;
                            await Task.Delay(100, ctsToken).ContinueWith(tsk => { }).ConfigureAwait(false);

                            continue;
                        }
                        // else sync blocks
                        else
                        {
                            MemPoolJob.Enabled = false;
                            State = WalletState.SyncingBlocks;
                            // if unprocessed buffer hit the headerchain height
                            // or unprocessed buffer is full
                            // wait until they get processed
                            if ((
                                    unprocessedBlockBestHeight.Type == HeightType.Chain &&
                                    (headerChainHeight <= unprocessedBlockBestHeight)
                                    ) ||
                                Tracker.UnprocessedBlockBuffer.Full)
                            {
                                await Task.Delay(100, ctsToken).ContinueWith(tsk => { }).ConfigureAwait(false);

                                continue;
                            }
                            // else figure out the next block's height to download
                            else
                            {
                                int relevant = unprocessedBlockBestHeight.Type == HeightType.Chain
                                                                        ? unprocessedBlockBestHeight.Value
                                                                        : 0;

                                // should not happen at this point, but better to check
                                if (trackerBestHeight.Type != HeightType.Chain)
                                {
                                    await Task.Delay(100, ctsToken).ContinueWith(tsk => { }).ConfigureAwait(false);

                                    continue;
                                }

                                height = new Height(
                                    Math.Max(trackerBestHeight.Value, relevant)
                                    + 1);
                            }
                        }
                    }

                    var blockFeature = new BlockFeature(height.Value);

                    Task <GetBlockResponse> getBlockTask = _noTorQBitClient.GetBlock(blockFeature, headerOnly: false, extended: false);

                    var getBlockRespone = await getBlockTask.ConfigureAwait(false);

                    if (getBlockRespone == null)
                    {
                        // probably our local headerchain is in front of qbit server
                        await Task.Delay(1000).ConfigureAwait(false);

                        continue;
                    }

                    var block = getBlockRespone.Block;
                    if (block == null)
                    {
                        // should not happen
                        await Task.Delay(1000).ConfigureAwait(false);

                        continue;
                    }

                    if (ctsToken.IsCancellationRequested)
                    {
                        return;
                    }

                    // if the hash of the downloaded block is not the same as the header's
                    // if the proof of work and merkle root isn't valid
                    if (HeaderChain.GetBlock(height).HashBlock != block.GetHash() ||
                        !block.Check())
                    {
                        Reorg();
                        continue;
                    }

                    Tracker.AddOrReplaceBlock(height, block);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"Ignoring {nameof(BlockDownloadingJobAsync)} exception:");
                    Debug.WriteLine(ex);
                }
            }
        }