public BlockChainInfo(IRpcMultiClient rpcMultiClient, ILogger <BlockChainInfo> logger, IEventBus eventBus, IClock clock)
     : base(logger, eventBus)
 {
     this.rpcMultiClient = rpcMultiClient ?? throw new ArgumentNullException(nameof(rpcMultiClient));
     this.clock          = clock ?? throw new ArgumentNullException(nameof(clock));
     lastRefreshedAt     = clock.UtcNow();
 }
 public BlockParser(IRpcMultiClient rpcMultiClient, ITxRepository txRepository, ILogger <BlockParser> logger,
                    IEventBus eventBus, IOptions <AppSettings> options, IClock clock)
     : base(logger, eventBus)
 {
     this.rpcMultiClient = rpcMultiClient ?? throw new ArgumentNullException(nameof(rpcMultiClient));
     this.txRepository   = txRepository ?? throw new ArgumentNullException(nameof(txRepository));
     this.clock          = clock ?? throw new ArgumentNullException(nameof(clock));
     appSettings         = options.Value;
 }
Esempio n. 3
0
 public Mapi(IRpcMultiClient rpcMultiClient, IFeeQuoteRepository feeQuoteRepository, IBlockChainInfo blockChainInfo, IMinerId minerId, ITxRepository txRepository, ILogger <Mapi> logger, IClock clock)
 {
     this.rpcMultiClient     = rpcMultiClient ?? throw new ArgumentNullException(nameof(rpcMultiClient));
     this.feeQuoteRepository = feeQuoteRepository ?? throw new ArgumentNullException(nameof(feeQuoteRepository));
     this.blockChainInfo     = blockChainInfo ?? throw new ArgumentNullException(nameof(blockChainInfo));
     this.minerId            = minerId ?? throw new ArgumentException(nameof(minerId));
     this.txRepository       = txRepository ?? throw new ArgumentException(nameof(txRepository));
     this.logger             = logger ?? throw new ArgumentException(nameof(logger));
     this.clock = clock ?? throw new ArgumentNullException(nameof(clock));
 }
Esempio n. 4
0
 public DsntController(ITxRepository txRepository, IRpcMultiClient rpcMultiClient, ITransactionRequestsCheck transactionRequestsCheck, IHostBanList banList,
                       IClock clock, IOptions <AppSettings> options, IEventBus eventBus, ILogger <DsntController> logger)
 {
     this.txRepository             = txRepository ?? throw new ArgumentNullException(nameof(txRepository));
     this.rpcMultiClient           = rpcMultiClient ?? throw new ArgumentNullException(nameof(rpcMultiClient));
     this.clock                    = clock ?? throw new ArgumentNullException(nameof(clock));
     this.transactionRequestsCheck = transactionRequestsCheck ?? throw new ArgumentNullException(nameof(transactionRequestsCheck));
     this.banList                  = banList ?? throw new ArgumentNullException(nameof(banList));
     this.eventBus                 = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
     this.logger                   = logger ?? throw new ArgumentNullException(nameof(logger));
     appSettings                   = options.Value;
 }
Esempio n. 5
0
        public NotificationsHandler(ILogger <NotificationsHandler> logger, INotificationServiceHttpClientFactory httpClientFactory, IOptions <AppSettings> options,
                                    ITxRepository txRepository, IRpcMultiClient rpcMultiClient, IMinerId minerId, IClock clock)
        {
            this.logger            = logger ?? throw new ArgumentNullException(nameof(logger));
            this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
            this.txRepository      = txRepository ?? throw new ArgumentNullException(nameof(txRepository));
            this.rpcMultiClient    = rpcMultiClient ?? throw new ArgumentNullException(nameof(rpcMultiClient));
            this.minerId           = minerId ?? throw new ArgumentNullException(nameof(minerId));
            notificationSettings   = options.Value.Notification;
            var maxNumberOfSlowNotifications = notificationSettings.InstantNotificationsQueueSize.Value * notificationSettings.InstantNotificationsSlowTaskPercentage / 100;

            notificationScheduler = new NotificationScheduler(logger, maxNumberOfSlowNotifications, notificationSettings.InstantNotificationsQueueSize.Value,
                                                              notificationSettings.MaxNotificationsInBatch.Value, notificationSettings.NoOfSavedExecutionTimes.Value,
                                                              notificationSettings.SlowHostThresholdInMs.Value);
            this.clock = clock ?? throw new ArgumentNullException(nameof(clock));
        }
Esempio n. 6
0
        /// <summary>
        /// Collect previous outputs being spent by tx. Two sources are consulted
        ///  - batch of incoming transactions - outputs wil be found there in case of chained transactions
        ///  - node
        /// Exception is thrown if output can not be found or is already spent on node side
        /// This function does not check for single output that is spent multiple times inside additionalTx.
        /// This will be detected by the node itself and one of the transactions spending the output will be rejected
        /// </summary>
        /// <param name="tx"></param>
        /// <param name="additionalTxs">optional </param>
        /// <param name="rpcMultiClient"></param>
        /// <returns>
        ///   sum of al outputs being spent
        ///   array of all outputs sorted in the same order as tx.inputs
        /// </returns>
        public static async Task <(Money sumPrevOuputs, PrevOut[] prevOuts)> CollectPreviousOuputs(Transaction tx,
                                                                                                   IReadOnlyDictionary <uint256, byte[]> additionalTxs, IRpcMultiClient rpcMultiClient)
        {
            var parentTransactionsFromBatch = new Dictionary <uint256, Transaction>();
            var prevOutsNotInBatch          = new List <OutPoint>(tx.Inputs.Count);

            foreach (var input in tx.Inputs)
            {
                var prevOut = input.PrevOut;
                if (parentTransactionsFromBatch.ContainsKey(prevOut.Hash))
                {
                    continue;
                }

                // First try to find the output in batch of transactions  we are submitting
                if (additionalTxs != null && additionalTxs.TryGetValue(prevOut.Hash, out var txRaw))
                {
                    if (TryParseTransaction(txRaw, out var t))
                    {
                        parentTransactionsFromBatch.TryAdd(prevOut.Hash, t);
                        continue;
                    }
                    else
                    {
                        // Ignore parse errors. We might be able to get it from node.
                    }
                }
                prevOutsNotInBatch.Add(prevOut);
            }

            Dictionary <OutPoint, PrevOut> prevOutsFromNode = null;

            // Fetch missing outputs from node
            if (prevOutsNotInBatch.Any())
            {
                var missing = prevOutsNotInBatch.Select(x => (txId: x.Hash.ToString(), N: (long)x.N)).ToArray();
                var prevOutsFromNodeResult = await rpcMultiClient.GetTxOutsAsync(missing, getTxOutFields);

                if (missing.Length != prevOutsFromNodeResult.TxOuts.Length)
                {
                    throw new Exception(
                              $"Internal error. Gettxouts RPC call should return exactly {missing.Length} elements, but it returned {prevOutsFromNodeResult.TxOuts.Length}");
                }

                // Convert results to dictionary for faster lookup.
                // Responses are returned in same order as requests were passed in, so we can use Zip() to merge them
                prevOutsFromNode = new Dictionary <OutPoint, PrevOut>(
                    prevOutsNotInBatch.Zip(
                        prevOutsFromNodeResult.TxOuts,
                        (K, V) => new KeyValuePair <OutPoint, PrevOut>(K, V))
                    );
            }

            Money sumPrevOuputs  = Money.Zero;
            var   resultPrevOuts = new List <PrevOut>(tx.Inputs.Count);

            foreach (var input in tx.Inputs)
            {
                var     outPoint = input.PrevOut;
                PrevOut prevOut;

                // Check if UTXO is present in batch of incoming transactions
                if (parentTransactionsFromBatch.TryGetValue(outPoint.Hash, out var txFromBatch))
                {
                    // we have found the input in input batch
                    var outputs = txFromBatch.Outputs;


                    if (outPoint.N > outputs.Count - 1)
                    {
                        prevOut = new PrevOut
                        {
                            Error = "Missing inputs - invalid output index"
                        };
                    }
                    else
                    {
                        var output = outputs[outPoint.N];

                        prevOut =
                            new PrevOut
                        {
                            Error = null,
                            // ScriptPubKey = null, // We do not use ScriptPUbKey
                            ScriptPubKeyLength = output.ScriptPubKey.Length,
                            Value         = output.Value.ToDecimal(MoneyUnit.BTC),
                            IsStandard    = true,
                            Confirmations = 0
                        };
                    }
                }
                else // ask the node for previous output
                {
                    if (prevOutsFromNode == null || !prevOutsFromNode.TryGetValue(outPoint, out prevOut))
                    {
                        // This indicates internal error in node or mAPI
                        throw new Exception($"Node did not return output {outPoint} that we have asked for");
                    }
                }

                if (string.IsNullOrEmpty(prevOut.Error))
                {
                    sumPrevOuputs += new Money((long)(prevOut.Value * Money.COIN));
                }

                resultPrevOuts.Add(prevOut);
            }

            return(sumPrevOuputs, resultPrevOuts.ToArray());
        }