Exemplo n.º 1
0
        internal static void AdvanceTip(DBConnection conn, HDWallet wallet, ChainedHeader newTip, uint256 prevTipHash)
        {
            uint256 lastBlockSyncedHash   = newTip?.HashBlock ?? uint256.Zero;
            int     lastBlockSyncedHeight = newTip?.Height ?? -1;
            string  blockLocator          = "";

            if (newTip != null)
            {
                blockLocator = string.Join(",", newTip?.GetLocator().Blocks);
            }

            conn.Execute($@"
                    UPDATE HDWallet
                    SET    LastBlockSyncedHash = ?,
                           LastBlockSyncedHeight = ?,
                           BlockLocator = ?
                    WHERE  LastBlockSyncedHash = ? {
                    // Respect the wallet name if provided.
                    ((wallet?.Name != null) ? $@"
                    AND    Name = {DBParameter.Create(wallet?.Name)}" : "")}",
                         lastBlockSyncedHash.ToString(),
                         lastBlockSyncedHeight,
                         blockLocator,
                         prevTipHash.ToString());
        }
Exemplo n.º 2
0
        /// <summary>
        /// Initializes a new instance of the wallet.
        /// </summary>
        public Wallet(string name, string encryptedSeed = null, byte[] chainCode = null, DateTimeOffset?creationTime = null, ChainedHeader lastBlockSynced = null, IWalletRepository walletRepository = null)
            : this(walletRepository)
        {
            this.Name          = name;
            this.EncryptedSeed = encryptedSeed;
            this.ChainCode     = chainCode;

            if (walletRepository != null)
            {
                Wallet repoWallet;

                HashHeightPair lastBlock        = (lastBlockSynced == null) ? null : new HashHeightPair(lastBlockSynced);
                BlockLocator   blockLocator     = lastBlockSynced?.GetLocator();
                uint?          unixCreationTime = (creationTime == null || lastBlockSynced?.Header == null) ? (uint?)null : (lastBlockSynced.Header.Time + 1);
                if (lastBlockSynced != null && unixCreationTime == null)
                {
                    unixCreationTime = lastBlockSynced.Header.Time + 1;
                }

                repoWallet = walletRepository?.CreateWallet(name, encryptedSeed, chainCode, lastBlock, blockLocator, unixCreationTime);

                this.BlockLocator = repoWallet.BlockLocator;
                this.CreationTime = repoWallet.CreationTime;
                this.AccountsRoot = repoWallet.AccountsRoot;
                this.Network      = repoWallet.Network;
            }
        }
        /// <summary>Creates <see cref="GetHeadersPayload"/>.</summary>
        /// <param name="header">Header which is used to create a locator.</param>
        public GetHeadersPayload CreateGetHeadersPayload(ChainedHeader header, uint256 hashStop = null)
        {
            var headersPayload = new GetHeadersPayload()
            {
                BlockLocator = header.GetLocator(),
                HashStop     = hashStop
            };

            return(headersPayload);
        }
Exemplo n.º 4
0
        /// <inheritdoc />
        public Task SaveAsync(ChainIndexer chainIndexer)
        {
            Guard.NotNull(chainIndexer, nameof(chainIndexer));

            Task task = Task.Run(() =>
            {
                using (DBreeze.Transactions.Transaction transaction = this.dbreeze.GetTransaction())
                {
                    ChainedHeader fork   = this.locator == null ? null : chainIndexer.FindFork(this.locator);
                    ChainedHeader tip    = chainIndexer.Tip;
                    ChainedHeader toSave = tip;

                    var headers = new List <ChainedHeader>();
                    while (toSave != fork)
                    {
                        headers.Add(toSave);
                        toSave = toSave.Previous;
                    }

                    // DBreeze is faster on ordered insert.
                    IOrderedEnumerable <ChainedHeader> orderedChainedHeaders = headers.OrderBy(b => b.Height);
                    foreach (ChainedHeader block in orderedChainedHeaders)
                    {
                        BlockHeader header = block.Header;
                        if (header is ProvenBlockHeader)
                        {
                            // copy the header parameters, untill we dont make PH a normal header we store it in its own repo.
                            BlockHeader newHeader    = chainIndexer.Network.Consensus.ConsensusFactory.CreateBlockHeader();
                            newHeader.Bits           = header.Bits;
                            newHeader.Time           = header.Time;
                            newHeader.Nonce          = header.Nonce;
                            newHeader.Version        = header.Version;
                            newHeader.HashMerkleRoot = header.HashMerkleRoot;
                            newHeader.HashPrevBlock  = header.HashPrevBlock;

                            header = newHeader;
                        }

                        transaction.Insert("Chain", block.Height, this.dBreezeSerializer.Serialize(header));
                    }

                    this.locator = tip.GetLocator();
                    transaction.Commit();
                }
            });

            return(task);
        }
Exemplo n.º 5
0
        /// <inheritdoc />
        public void UpdateLastBlockSyncedHeight(ChainedHeader chainedHeader)
        {
            Guard.NotNull(chainedHeader, nameof(chainedHeader));
            this.logger.LogTrace("({0}:'{1}')", nameof(chainedHeader), chainedHeader);

            lock (this.lockObject)
            {
                // The block locator will help when the wallet
                // needs to rewind this will be used to find the fork.
                this.Wallet.BlockLocator = chainedHeader.GetLocator().Blocks;

                // Update the wallets with the last processed block height.
                this.Wallet.LastBlockSyncedHeight = chainedHeader.Height;
                this.Wallet.LastBlockSyncedHash   = chainedHeader.HashBlock;
            }

            this.logger.LogTrace("(-)");

            this.WalletTipHash = chainedHeader.HashBlock;
            this.logger.LogTrace("(-)");
        }
Exemplo n.º 6
0
        /*
         * internal static HeightHashPair GreatestBlockHeightBeforeOrAt(SQLiteConnection conn, int walletId, int height)
         * {
         *  return conn.FindWithQuery<HeightHashPair>($@"
         *      SELECT  OutputBlockHeight BlockHeight
         *      ,       OutputBlockHash BlockHash
         *      FROM    HDTransactionData
         *      WHERE   WalletId = { walletId }
         *      AND     OutputBlockHeight <= { height }
         *      UNION   ALL
         *      SELECT  SpendBlockHeight BlockHeight
         *      ,       SpendBlockHash BlockHash
         *      FROM    HDTransactionData
         *      WHERE   WalletId = { walletId }
         *      AND     SpendBlockHeight <= { height }
         *      ORDER   BY BlockHeight desc
         *      LIMIT   1");
         * }
         */

        internal static void AdvanceTip(SQLiteConnection conn, HDWallet wallet, ChainedHeader newTip, uint256 prevTipHash)
        {
            uint256 lastBlockSyncedHash   = newTip?.HashBlock ?? uint256.Zero;
            int     lastBlockSyncedHeight = newTip?.Height ?? -1;
            string  blockLocator          = "";

            if (newTip != null)
            {
                blockLocator = string.Join(",", newTip?.GetLocator().Blocks);
            }

            conn.Execute($@"
                    UPDATE HDWallet
                    SET    LastBlockSyncedHash = '{lastBlockSyncedHash}',
                           LastBlockSyncedHeight = {lastBlockSyncedHeight},
                           BlockLocator = '{blockLocator}'
                    WHERE  LastBlockSyncedHash = '{prevTipHash}' {
                    // Respect the wallet name if provided.
                    ((wallet?.Name != null) ? $@"
                    AND    Name = '{wallet?.Name}'" : "")}");
        }
Exemplo n.º 7
0
        public IEnumerable <ChainedHeader> GetHeadersFromFork(INetworkPeer peer, ChainedHeader currentTip, uint256 hashStop = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            this.AssertStateAsync(peer, NetworkPeerState.HandShaked, cancellationToken).GetAwaiter().GetResult();

            using (var listener = new NetworkPeerListener(peer))
            {
                int acceptMaxReorgDepth = 0;
                while (true)
                {
                    // Get before last so, at the end, we should only receive 1 header equals to this one (so we will not have race problems with concurrent GetChains).
                    BlockLocator awaited = currentTip.Previous == null?currentTip.GetLocator() : currentTip.Previous.GetLocator();

                    peer.SendMessageAsync(new GetHeadersPayload()
                    {
                        BlockLocator = awaited,
                        HashStop     = hashStop
                    }, cancellationToken).GetAwaiter().GetResult();

                    while (true)
                    {
                        bool           isOurs  = false;
                        HeadersPayload headers = null;

                        using (CancellationTokenSource headersCancel = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
                        {
                            headersCancel.CancelAfter(TimeSpan.FromMinutes(1.0));
                            try
                            {
                                headers = listener.ReceivePayloadAsync <HeadersPayload>(headersCancel.Token).GetAwaiter().GetResult();
                            }
                            catch (OperationCanceledException)
                            {
                                acceptMaxReorgDepth += 6;
                                if (cancellationToken.IsCancellationRequested)
                                {
                                    throw;
                                }

                                // Send a new GetHeaders.
                                break;
                            }
                        }

                        // In the special case where the remote node is at height 0 as well as us, then the headers count will be 0.
                        if ((headers.Headers.Count == 0) && (peer.PeerVersion.StartHeight == 0) && (currentTip.HashBlock == peer.Network.GenesisHash))
                        {
                            yield break;
                        }

                        if ((headers.Headers.Count == 1) && (headers.Headers[0].GetHash() == currentTip.HashBlock))
                        {
                            yield break;
                        }

                        foreach (BlockHeader header in headers.Headers)
                        {
                            uint256 hash = header.GetHash();
                            if (hash == currentTip.HashBlock)
                            {
                                continue;
                            }

                            // The previous headers request timeout, this can arrive in case of big reorg.
                            if (header.HashPrevBlock != currentTip.HashBlock)
                            {
                                int           reorgDepth     = 0;
                                ChainedHeader tempCurrentTip = currentTip;
                                while (reorgDepth != acceptMaxReorgDepth && tempCurrentTip != null && header.HashPrevBlock != tempCurrentTip.HashBlock)
                                {
                                    reorgDepth++;
                                    tempCurrentTip = tempCurrentTip.Previous;
                                }

                                if (reorgDepth != acceptMaxReorgDepth && tempCurrentTip != null)
                                {
                                    currentTip = tempCurrentTip;
                                }
                            }

                            if (header.HashPrevBlock == currentTip.HashBlock)
                            {
                                isOurs     = true;
                                currentTip = new ChainedHeader(header, hash, currentTip);

                                yield return(currentTip);

                                if (currentTip.HashBlock == hashStop)
                                {
                                    yield break;
                                }
                            }
                            else
                            {
                                break;  // Not our headers, continue receive.
                            }
                        }

                        if (isOurs)
                        {
                            break;  //Go ask for next header.
                        }
                    }
                }
            }
        }
Exemplo n.º 8
0
 internal void SetLastBlockSynced(ChainedHeader lastBlockSynced, Network network)
 {
     SetLastBlockSynced((lastBlockSynced == null) ? null : new HashHeightPair(lastBlockSynced), lastBlockSynced?.GetLocator(), network);
 }