public ColoredTransaction GetFromCache(uint256 txId)
 {
     using (_lock.LockRead())
     {
         return(_ColoredTransactions.TryGet(txId));
     }
 }
        Task <T> Request <T>(string key, Func <Task <T> > wrapped)
        {
            Task <T> task = null;

            using (@lock.LockRead())
            {
                task = _Tasks.TryGet(key) as Task <T>;
            }
            if (task != null)
            {
                return(task);
            }
            using (@lock.LockWrite())
            {
                task = _Tasks.TryGet(key) as Task <T>;
                if (task != null)
                {
                    return(task);
                }
                task = wrapped();
                _Tasks.Add(key, task);
            }
            task.ContinueWith((_) =>
            {
                using (@lock.LockWrite())
                {
                    _Tasks.Remove(key);
                }
            });
            return(task);
        }
        public override Task <FetchCoinsResponse> FetchCoinsAsync(uint256[] txIds)
        {
            Guard.NotNull(txIds, nameof(txIds));

            using (lockobj.LockRead())
            {
                UnspentOutputs[] result = new UnspentOutputs[txIds.Length];
                for (int i = 0; i < txIds.Length; i++)
                {
                    result[i] = unspents.TryGet(txIds[i]);
                    if (result[i] != null)
                    {
                        result[i] = result[i].Clone();
                    }
                }
                return(Task.FromResult(new FetchCoinsResponse(result, blockHash)));
            }
        }
Beispiel #4
0
        void node_MessageReceived(Node node, IncomingMessage message)
        {
            if (_KnownInvs.Count == 1000)
            {
                _KnownInvs.Clear();
            }
            if (message.Message.Payload is InvPayload)
            {
                var inv = (InvPayload)message.Message.Payload;
                foreach (var inventory in inv.Inventory)
                {
                    Transaction tx;
                    if (_Broadcasting.TryRemove(inventory.Hash, out tx))
                    {
                        ListenerTrace.Info("Broadcasted reached mempool " + inventory);
                    }
                }
                var getdata = new GetDataPayload(inv.Inventory.Where(i => i.Type == InventoryType.MSG_TX && _KnownInvs.TryAdd(i.Hash, i.Hash)).ToArray());
                foreach (var data in getdata.Inventory)
                {
                    data.Type = node.AddSupportedOptions(InventoryType.MSG_TX);
                }
                if (getdata.Inventory.Count > 0)
                {
                    node.SendMessageAsync(getdata);
                }
            }
            if (message.Message.Payload is TxPayload)
            {
                var tx = ((TxPayload)message.Message.Payload).Object;
                ListenerTrace.Verbose("Received Transaction " + tx.GetHash());
                _Indexer.IndexAsync(new TransactionEntry.Entity(tx.GetHash(), tx, null))
                .ContinueWith(HandleException);
                _Indexer.IndexOrderedBalanceAsync(tx)
                .ContinueWith(HandleException);
                Async(() =>
                {
                    var txId = tx.GetHash();
                    List <OrderedBalanceChange> balances;
                    using (_WalletsSlimLock.LockRead())
                    {
                        balances =
                            OrderedBalanceChange
                            .ExtractWalletBalances(txId, tx, null, null, int.MaxValue, _Wallets)
                            .AsEnumerable()
                            .ToList();
                    }
                    UpdateHDState(balances);

                    _Indexer.IndexAsync(balances)
                    .ContinueWith(HandleException);


                    Task notify = null;
                    using (_SubscriptionSlimLock.LockRead())
                    {
                        var topic = Configuration.Topics.SendNotifications;

                        notify = Task.WhenAll(_Subscriptions
                                              .GetNewTransactions()
                                              .Select(t => topic.AddAsync(new Notify()
                        {
                            SendAndForget = true,
                            Notification  = new Notification()
                            {
                                Subscription = t,
                                Data         = new NewTransactionNotificationData()
                                {
                                    TransactionId = txId
                                }
                            }
                        })).ToArray());
                    }
                    notify.Wait();
                });
                var unused = Configuration.Topics.NewTransactions.AddAsync(tx)
                             .ContinueWith(HandleException);
            }

            if (message.Message.Payload is BlockPayload)
            {
                var block   = ((BlockPayload)message.Message.Payload).Object;
                var blockId = block.GetHash();

                List <OrderedBalanceChange> balances = null;
                using (_WalletsSlimLock.LockRead())
                {
                    balances = block.Transactions.SelectMany(tx => OrderedBalanceChange.ExtractWalletBalances(null, tx, null, null, 0, _Wallets)).ToList();
                }
                UpdateHDState(balances);
            }

            if (message.Message.Payload is HeadersPayload)
            {
                if (_Chain.Tip.HashBlock != _LastChainTip)
                {
                    var header = _Chain.Tip.Header;
                    _LastChainTip = _Chain.Tip.HashBlock;

                    Configuration.Indexer.CreateIndexer().IndexChain(_Chain);

                    Async(() =>
                    {
                        CancellationTokenSource cancel = new CancellationTokenSource(TimeSpan.FromMinutes(30));
                        var repo = new CacheBlocksRepository(new NodeBlocksRepository(node));
                        TryLock(_LockBlocks, () =>
                        {
                            new IndexBlocksTask(Configuration.Indexer)
                            {
                                EnsureIsSetup = false,
                            }.Index(new BlockFetcher(_Indexer.GetCheckpoint(IndexerCheckpoints.Blocks), repo, _Chain)
                            {
                                CancellationToken = cancel.Token
                            }, _Indexer.TaskScheduler);
                        });
                        TryLock(_LockTransactions, () =>
                        {
                            new IndexTransactionsTask(Configuration.Indexer)
                            {
                                EnsureIsSetup = false
                            }
                            .Index(new BlockFetcher(_Indexer.GetCheckpoint(IndexerCheckpoints.Transactions), repo, _Chain)
                            {
                                CancellationToken = cancel.Token
                            }, _Indexer.TaskScheduler);
                        });
                        TryLock(_LockWallets, () =>
                        {
                            using (_WalletsSlimLock.LockRead())
                            {
                                new IndexBalanceTask(Configuration.Indexer, _Wallets)
                                {
                                    EnsureIsSetup = false
                                }
                                .Index(new BlockFetcher(_Indexer.GetCheckpoint(IndexerCheckpoints.Wallets), repo, _Chain)
                                {
                                    CancellationToken = cancel.Token
                                }, _Indexer.TaskScheduler);
                            }
                        });
                        TryLock(_LockBalance, () =>
                        {
                            new IndexBalanceTask(Configuration.Indexer, null)
                            {
                                EnsureIsSetup = false
                            }.Index(new BlockFetcher(_Indexer.GetCheckpoint(IndexerCheckpoints.Balances), repo, _Chain)
                            {
                                CancellationToken = cancel.Token
                            }, _Indexer.TaskScheduler);
                        });
                        TryLock(_LockSubscriptions, () =>
                        {
                            using (_SubscriptionSlimLock.LockRead())
                            {
                                new IndexNotificationsTask(Configuration, _Subscriptions)
                                {
                                    EnsureIsSetup = false,
                                }
                                .Index(new BlockFetcher(_Indexer.GetCheckpointRepository().GetCheckpoint("subscriptions"), repo, _Chain)
                                {
                                    CancellationToken = cancel.Token
                                }, _Indexer.TaskScheduler);
                            }
                        });
                        cancel.Dispose();
                        var unused = _Configuration.Topics.NewBlocks.AddAsync(header);
                    });
                }
            }
            if (message.Message.Payload is GetDataPayload)
            {
                var getData = (GetDataPayload)message.Message.Payload;
                foreach (var data in getData.Inventory)
                {
                    Transaction tx = null;
                    if (data.Type == InventoryType.MSG_TX && _Broadcasting.TryGetValue(data.Hash, out tx))
                    {
                        var payload = new TxPayload(tx);
                        node.SendMessageAsync(payload);
                        ListenerTrace.Info("Broadcasted " + data.Hash);
                    }
                }
            }
            if (message.Message.Payload is RejectPayload)
            {
                var     reject = (RejectPayload)message.Message.Payload;
                uint256 txId   = reject.Hash;
                if (txId != null)
                {
                    ListenerTrace.Info("Broadcasted transaction rejected (" + reject.Code + ") " + txId);
                    if (reject.Code != RejectCode.DUPLICATE)
                    {
                        Configuration.GetRejectTable().Create(txId.ToString(), reject);
                    }
                    Transaction tx;
                    _Broadcasting.TryRemove(txId, out tx);
                }
            }
        }
        public override async Task <FetchCoinsResponse> FetchCoinsAsync(uint256[] txIds)
        {
            Guard.NotNull(txIds, nameof(txIds));

            FetchCoinsResponse result         = null;
            uint256            innerBlockHash = null;

            UnspentOutputs[] outputs     = new UnspentOutputs[txIds.Length];
            List <int>       miss        = new List <int>();
            List <uint256>   missedTxIds = new List <uint256>();

            using (_Lock.LockRead())
            {
                WaitOngoingTasks();
                for (int i = 0; i < txIds.Length; i++)
                {
                    CacheItem cache;
                    if (!_Unspents.TryGetValue(txIds[i], out cache))
                    {
                        miss.Add(i);
                        missedTxIds.Add(txIds[i]);
                    }
                    else
                    {
                        outputs[i] = cache.UnspentOutputs == null ? null :
                                     cache.UnspentOutputs.IsPrunable ? null :
                                     cache.UnspentOutputs.Clone();
                    }
                }
                PerformanceCounter.AddMissCount(miss.Count);
                PerformanceCounter.AddHitCount(txIds.Length - miss.Count);
            }
            var fetchedCoins = await Inner.FetchCoinsAsync(missedTxIds.ToArray()).ConfigureAwait(false);

            using (_Lock.LockWrite())
            {
                _Flushing.Wait();
                innerBlockHash = fetchedCoins.BlockHash;
                if (_BlockHash == null)
                {
                    Debug.Assert(_Unspents.Count == 0);
                    _InnerBlockHash = innerBlockHash;
                    _BlockHash      = innerBlockHash;
                }
                for (int i = 0; i < miss.Count; i++)
                {
                    var index   = miss[i];
                    var unspent = fetchedCoins.UnspentOutputs[i];
                    outputs[index] = unspent;
                    CacheItem cache = new CacheItem();
                    cache.ExistInInner    = unspent != null;
                    cache.IsDirty         = false;
                    cache.UnspentOutputs  = unspent;
                    cache.OriginalOutputs = unspent?._Outputs.ToArray();
                    _Unspents.TryAdd(txIds[index], cache);
                }
                result = new FetchCoinsResponse(outputs, _BlockHash);
            }

            if (CacheEntryCount > MaxItems)
            {
                Evict();
                if (CacheEntryCount > MaxItems)
                {
                    await FlushAsync().ConfigureAwait(false);

                    Evict();
                }
            }

            return(result);
        }