public IActionResult GetHistoryFilter([FromQuery] WalletHistoryFilterRequest request)
        {
            Guard.NotNull(request, nameof(request));

            if (!this.ModelState.IsValid)
            {
                return(ModelStateErrors.BuildErrorResponse(this.ModelState));
            }

            try
            {
                WalletHistoryFilterModel model = HistoryModelBuilder.GetHistoryFilter(this.chain, this.walletManager, this.blockRepository, this.txMempool, this.network, request);

                return(this.Json(model));
            }
            catch (Exception e)
            {
                this.logger.LogError("Exception occurred: {0}", e.ToString());
                return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString()));
            }
        }
예제 #2
0
        public static WalletHistoryFilterModel GetHistoryFilter(ChainIndexer chain, IWalletManager walletManager, IBlockRepository blockRepository, ITxMempool txMempool, Network network, WalletHistoryFilterRequest request)
        {
            bool isAddressFilter = request.Address == null ? false : true;

            var model = new WalletHistoryFilterModel();

            // Get a list of all the transactions found in an account (or in a wallet if no account is specified), with the addresses associated with them.
            IEnumerable <HistoryFilter> historyFilters = walletManager.GetHistoryFilter(request.WalletName, request.Address, request.AccountName, request.FromDate);


            foreach (HistoryFilter historyFilter in historyFilters)
            {
                var transactionItems = new List <TransactionHistoryItemModel>();

                foreach (FlatHistorySlim item in historyFilter.History)
                {
                    var isConfirmed = item.Transaction.BlockHeight.HasValue;

                    Transaction tx = new Transaction();
                    if (isConfirmed)
                    {
                        if (chain.Height == walletManager.WalletTipHeight)
                        {
                            tx = blockRepository.GetTransactionById(new uint256(item.Transaction.IsSent ? item.Transaction.SentTo : item.Transaction.OutPoint.Hash));
                        }
                    }
                    else
                    {
                        tx = txMempool.Get(new uint256(item.Transaction.IsSent ? item.Transaction.SentTo : item.Transaction.OutPoint.Hash));
                    }

                    if (tx == null)
                    {
                        continue;
                    }
                    bool isOutputContained = false;
                    bool isInputContained  = false;
                    if (isAddressFilter)
                    {
                        if (item.Transaction.IsSent)
                        {
                            if (item.Transaction.IsCoinStake.HasValue && item.Transaction.IsCoinStake.Value == true)
                            {
                                // We don't show in history transactions that are outputs of staking transactions.
                                continue;
                            }
                            foreach (TxOut outp in tx.Outputs)
                            {
                                if (!isOutputContained)
                                {
                                    if (outp.ScriptPubKey.IsUnspendable)
                                    {
                                        continue;
                                    }
                                    if (outp.ScriptPubKey.GetDestinationAddress(network).ToString() != (request.Address))
                                    {
                                        continue;
                                    }
                                    isOutputContained = true;
                                }
                            }
                        }
                        else
                        {
                            foreach (TxOut txOut in tx.Outputs)
                            {
                                if (!isOutputContained && !tx.IsCoinStake)
                                {
                                    if (!txOut.ScriptPubKey.IsUnspendable)
                                    {
                                        if (txOut.ScriptPubKey.GetDestinationAddress(network).ToString() != request.Address)
                                        {
                                            continue;
                                        }
                                        isOutputContained = true;
                                    }
                                }
                            }
                        }
                    }

                    var modelItem = new TransactionHistoryItemModel
                    {
                        Type             = item.Transaction.IsSent ? TransactionItemType.Send : TransactionItemType.Received,
                        Amount           = item.Transaction.IsSent == false ? item.Transaction.Amount : Money.Zero,
                        Id               = item.Transaction.IsSent ? item.Transaction.SentTo : item.Transaction.OutPoint.Hash,
                        Timestamp        = item.Transaction.CreationTime,
                        ConfirmedInBlock = item.Transaction.BlockHeight,
                        BlockIndex       = item.Transaction.BlockIndex
                    };


                    int n = 0;
                    modelItem.Outputs.AddRange(tx.Outputs.Select(x => new Vout(n++, x, network)).Where(y => y.ScriptPubKey.Type == "nulldata"));

                    if (item.Transaction.IsSent == true) // handle send entries
                    {
                        // First we look for staking transaction as they require special attention.
                        // A staking transaction spends one of our inputs into 2 outputs or more, paid to the same address.
                        if ((item.Transaction.IsCoinStake ?? false == true))
                        {
                            if (item.Transaction.IsSent == true)
                            {
                                modelItem.Type = TransactionItemType.Staked;
                                var amount = item.Transaction.SentPayments.Sum(p => p.Amount);
                                modelItem.Amount = amount - item.Transaction.Amount;
                            }
                            else
                            {
                                // We don't show in history transactions that are outputs of staking transactions.
                                continue;
                            }
                        }
                        else
                        {
                            if (item.Transaction.SentPayments.All(a => a.PayToSelf == true))
                            {
                                // if all outputs are to ourself
                                // we don't show that in history
                                continue;
                            }

                            modelItem.Amount = item.Transaction.SentPayments.Where(x => x.PayToSelf == false).Sum(p => p.Amount);

                            foreach (TxIn input in tx.Inputs)
                            {
                                InputHistoryDetailModel inputHistoryDetail = new InputHistoryDetailModel()
                                {
                                    ScriptSig = input.ScriptSig,
                                    Sequence  = input.Sequence,
                                    TxId      = input.PrevOut.Hash.ToString(),
                                    VOut      = input.PrevOut.N,
                                };

                                if (input.ScriptSig.GetSigner(network) == null)
                                {
                                    TxOut  prevOutTx = blockRepository.GetTransactionById(input.PrevOut.Hash).Outputs[input.PrevOut.N];
                                    string address   = prevOutTx.ScriptPubKey.GetDestinationPublicKeys(network).FirstOrDefault().GetAddress(network).ToString();
                                    inputHistoryDetail.Address = address;
                                }
                                else
                                {
                                    inputHistoryDetail.Address = input.ScriptSig.GetSignerAddress(network).ToString();
                                }

                                modelItem.Inputs.Add(inputHistoryDetail);
                            }


                            foreach (WalletHistoryPaymentData payment in item.Transaction.SentPayments)
                            {
                                if (payment.PayToSelf == false)
                                {
                                    PaymentHistoryDetailModel paymentDetail = new PaymentHistoryDetailModel()
                                    {
                                        Amount             = payment.Amount,
                                        DestinationAddress = payment.DestinationAddress,
                                        PayToSelf          = payment.PayToSelf
                                    };

                                    modelItem.Payments.Add(paymentDetail);
                                }
                            }
                        }
                    }
                    else // handle receive entries
                    {
                        if (item.Address.IsChangeAddress())
                        {
                            // we don't display transactions sent to self
                            continue;
                        }

                        if (item.Transaction.IsCoinStake.HasValue && item.Transaction.IsCoinStake.Value == true)
                        {
                            // We don't show in history transactions that are outputs of staking transactions.
                            continue;
                        }

                        PaymentHistoryDetailModel paymentDetail = new PaymentHistoryDetailModel()
                        {
                            Amount             = item.Transaction.Amount,
                            DestinationAddress = item.Transaction.Address,
                            PayToSelf          = true
                        };
                        modelItem.Payments.Add(paymentDetail);

                        foreach (TxIn input in tx.Inputs)
                        {
                            InputHistoryDetailModel inputHistoryDetail = new InputHistoryDetailModel()
                            {
                                ScriptSig = input.ScriptSig,
                                Sequence  = input.Sequence,
                                TxId      = input.PrevOut.Hash.ToString(),
                                VOut      = input.PrevOut.N,
                            };

                            if (input.ScriptSig.GetSigner(network) == null)
                            {
                                TxOut  prevOutTx = blockRepository.GetTransactionById(input.PrevOut.Hash).Outputs[input.PrevOut.N];
                                string address   = prevOutTx.ScriptPubKey.GetDestinationPublicKeys(network).FirstOrDefault().GetAddress(network).ToString();
                                inputHistoryDetail.Address = address;
                            }
                            else
                            {
                                inputHistoryDetail.Address = input.ScriptSig.GetSignerAddress(network).ToString();
                            }

                            if (isAddressFilter)
                            {
                                if (!isOutputContained)
                                {
                                    if (!inputHistoryDetail.Address.Contains(request.Address))
                                    {
                                        continue;
                                    }
                                    isInputContained = true;
                                }
                            }

                            modelItem.Inputs.Add(inputHistoryDetail);
                        }
                    }

                    if (isAddressFilter == true && isInputContained == false && isOutputContained == false)
                    {
                        continue;
                    }
                    transactionItems.Add(modelItem);
                }

                model.AccountsHistoryModel.Add(new HistoryFilterModel
                {
                    TransactionsHistory = transactionItems,
                    Name     = historyFilter.Account.Name,
                    CoinType = network.Consensus.CoinType,
                    HdPath   = historyFilter.Account.HdPath
                });
            }

            return(model);
        }