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()); }
/// <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); }
/// <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); }
/// <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("(-)"); }
/* * 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}'" : "")}"); }
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. } } } } }
internal void SetLastBlockSynced(ChainedHeader lastBlockSynced, Network network) { SetLastBlockSynced((lastBlockSynced == null) ? null : new HashHeightPair(lastBlockSynced), lastBlockSynced?.GetLocator(), network); }