src/Stratis.FederatedPeg.Features.FederationGateway/TargetChain/CrossChainTransferStore.cs
/// <summary>
/// Uses the information contained in our chain's blocks to update the store.
/// Sets the <see cref="CrossChainTransferStatus.SeenInBlock"/> status for transfers
/// identified in the blocks.
/// </summary>
/// <param name="blocks">The blocks used to update the store. Must be sorted by ascending height leading up to the new tip.</param>
Uses the information contained in our chain's blocks to update the store.
Sets the  status for transfers
identified in the blocks.
Uses the information contained in our chain ' s blocks to update the store . Sets the status for transfers identified in the blocks .
private void Put(List<Block> blocks)
        {
            if (blocks.Count == 0)
                this.logger.LogTrace("(-)[NO_BLOCKS]:0");
            Dictionary<uint256, ICrossChainTransfer> transferLookup;
            Dictionary<uint256, IWithdrawal[]> allWithdrawals;
            int blockHeight = this.TipHashAndHeight.Height + 1;
            var allDepositIds = new HashSet<uint256>();
            allWithdrawals = new Dictionary<uint256, IWithdrawal[]>();
            foreach (Block block in blocks)
            {
                IReadOnlyList<IWithdrawal> blockWithdrawals = this.withdrawalExtractor.ExtractWithdrawalsFromBlock(block, blockHeight++);
                allDepositIds.UnionWith(blockWithdrawals.Select(d => d.DepositId).ToArray());
                allWithdrawals[block.GetHash()] = blockWithdrawals.ToArray();
            }
            if (allDepositIds.Count == 0)
            {
                this.TipHashAndHeight = this.chain.GetBlock(blocks.Last().GetHash());
                this.logger.LogTrace("(-)[NO_DEPOSIT_IDS]");
                return;
            }
            uint256[] uniqueDepositIds = allDepositIds.ToArray();
            ICrossChainTransfer[] uniqueTransfers = this.Get(uniqueDepositIds);
            transferLookup = new Dictionary<uint256, ICrossChainTransfer>();
            for (int i = 0; i < uniqueDepositIds.Length; i++)
                transferLookup[uniqueDepositIds[i]] = uniqueTransfers[i];
            using (DBreeze.Transactions.Transaction dbreezeTransaction = this.DBreeze.GetTransaction())
            {
                dbreezeTransaction.SynchronizeTables(transferTableName, commonTableName);
                ChainedHeader prevTip = this.TipHashAndHeight;
                try
                {
                    var tracker = new StatusChangeTracker();
                    foreach (Block block in blocks)
                    {
                        IWithdrawal[] withdrawals = allWithdrawals[block.GetHash()].ToArray();
                        ICrossChainTransfer[] crossChainTransfers = withdrawals.Select(d => transferLookup[d.DepositId]).ToArray();
                        for (int i = 0; i < crossChainTransfers.Length; i++)
                        {
                            IWithdrawal withdrawal = withdrawals[i];
                            Transaction transaction = block.Transactions.Single(t => t.GetHash() == withdrawal.Id);
                            this.federationWalletManager.ProcessTransaction(transaction, withdrawal.BlockNumber, block);
                            if (crossChainTransfers[i] == null)
                            {
                                Script scriptPubKey = BitcoinAddress.Create(withdrawal.TargetAddress, this.network).ScriptPubKey;
                                crossChainTransfers[i] = new CrossChainTransfer(CrossChainTransferStatus.SeenInBlock, withdrawal.DepositId,
                                    scriptPubKey, withdrawal.Amount, null, transaction, withdrawal.BlockHash, withdrawal.BlockNumber);
                                tracker.SetTransferStatus(crossChainTransfers[i]);
                            }
                            else
                            {
                                crossChainTransfers[i].SetPartialTransaction(transaction);
                                tracker.SetTransferStatus(crossChainTransfers[i],
                                    CrossChainTransferStatus.SeenInBlock, withdrawal.BlockHash, withdrawal.BlockNumber);
                            }
                        }
                    }
                    this.PutTransfers(dbreezeTransaction, tracker.Keys.ToArray());
                    ChainedHeader newTip = this.chain.GetBlock(blocks.Last().GetHash());
                    this.SaveTipHashAndHeight(dbreezeTransaction, newTip);
                    dbreezeTransaction.Commit();
                    this.UpdateLookups(tracker);
                }
                catch (Exception err)
                {
                    this.TipHashAndHeight = prevTip;
                    this.RollbackAndThrowTransactionError(dbreezeTransaction, err, "PUT_ERROR");
                }
            }
        }
private void Put ( List < Block > blocks ) { if ( blocks . Count == 0 ) this . logger . LogTrace ( " " ) ; Dictionary < uint256 , ICrossChainTransfer > transferLookup ; Dictionary < uint256 , IWithdrawal [ ] > allWithdrawals ; int blockHeight = this . TipHashAndHeight . Height + 1 ; var allDepositIds = new HashSet < uint256 > ( ) ; allWithdrawals = new Dictionary < uint256 , IWithdrawal [ ] > ( ) ; foreach ( Block block in blocks ) { IReadOnlyList < IWithdrawal > blockWithdrawals = this . withdrawalExtractor . ExtractWithdrawalsFromBlock ( block , blockHeight ++ ) ; allDepositIds . UnionWith ( blockWithdrawals . Select ( d => d . DepositId ) . ToArray ( ) ) ; allWithdrawals [ block . GetHash ( ) ] = blockWithdrawals . ToArray ( ) ; } if ( allDepositIds . Count == 0 ) { this . TipHashAndHeight = this . chain . GetBlock ( blocks . Last ( ) . GetHash ( ) ) ; this . logger . LogTrace ( " " ) ; return ; } uint256 [ ] uniqueDepositIds = allDepositIds . ToArray ( ) ; ICrossChainTransfer [ ] uniqueTransfers = this . Get ( uniqueDepositIds ) ; transferLookup = new Dictionary < uint256 , ICrossChainTransfer > ( ) ; for ( int i = 0 ; i < uniqueDepositIds . Length ; i ++ ) transferLookup [ uniqueDepositIds [ i ] ] = uniqueTransfers [ i ] ; using ( DBreeze . Transactions . Transaction dbreezeTransaction = this . DBreeze . GetTransaction ( ) ) { dbreezeTransaction . SynchronizeTables ( transferTableName , commonTableName ) ; ChainedHeader prevTip = this . TipHashAndHeight ; try { var tracker = new StatusChangeTracker ( ) ; foreach ( Block block in blocks ) { IWithdrawal [ ] withdrawals = allWithdrawals [ block . GetHash ( ) ] . ToArray ( ) ; ICrossChainTransfer [ ] crossChainTransfers = withdrawals . Select ( d => transferLookup [ d . DepositId ] ) . ToArray ( ) ; for ( int i = 0 ; i < crossChainTransfers . Length ; i ++ ) { IWithdrawal withdrawal = withdrawals [ i ] ; Transaction transaction = block . Transactions . Single ( t => t . GetHash ( ) == withdrawal . Id ) ; this . federationWalletManager . ProcessTransaction ( transaction , withdrawal . BlockNumber , block ) ; if ( crossChainTransfers [ i ] == null ) { Script scriptPubKey = BitcoinAddress . Create ( withdrawal . TargetAddress , this . network ) . ScriptPubKey ; crossChainTransfers [ i ] = new CrossChainTransfer ( CrossChainTransferStatus . SeenInBlock , withdrawal . DepositId , scriptPubKey , withdrawal . Amount , null , transaction , withdrawal . BlockHash , withdrawal . BlockNumber ) ; tracker . SetTransferStatus ( crossChainTransfers [ i ] ) ; } else { crossChainTransfers [ i ] . SetPartialTransaction ( transaction ) ; tracker . SetTransferStatus ( crossChainTransfers [ i ] , CrossChainTransferStatus . SeenInBlock , withdrawal . BlockHash , withdrawal . BlockNumber ) ; } } } this . PutTransfers ( dbreezeTransaction , tracker . Keys . ToArray ( ) ) ; ChainedHeader newTip = this . chain . GetBlock ( blocks . Last ( ) . GetHash ( ) ) ; this . SaveTipHashAndHeight ( dbreezeTransaction , newTip ) ; dbreezeTransaction . Commit ( ) ; this . UpdateLookups ( tracker ) ; } catch ( Exception err ) { this . TipHashAndHeight = prevTip ; this . RollbackAndThrowTransactionError ( dbreezeTransaction , err , " " ) ; } } }
Uses the information contained in our chain's blocks to update the store.
Uses the information contained in our chain ' s blocks to update the store .
// Nothing to do? // Exiting here and saving the tip after the sync. // Create transfer lookup by deposit Id. // Only create a transaction if there is important work to do. // Find transfer transactions in blocks // First check the database to see if we already know about these deposits. // Update the information about these deposits or record their status. // Ensure that the wallet is in step. // Write transfers. // Commit additions // Update the lookups last to ensure store integrity. // Restore expected store state in case the calling code retries / continues using the store.
blocks
List<Block>
The blocks used to update the store. Must be sorted by ascending height leading up to the new tip.
The blocks used to update the store . Must be sorted by ascending height leading up to the new tip .