コード例 #1
0
ファイル: WalletJob.cs プロジェクト: dangershony/HBitcoin
        /// <summary>
        ///
        /// </summary>
        /// <param name="account">if null then default safe, if doesn't contain, then exception</param>
        /// <returns></returns>
        public IEnumerable <SafeHistoryRecord> GetSafeHistory(SafeAccount account = null)
        {
            AssertAccount(account);

            var safeHistory = new HashSet <SafeHistoryRecord>();

            var transactions  = GetAllChainAndMemPoolTransactionsBySafeAccount(account);
            var scriptPubKeys = GetTrackedScriptPubKeysBySafeAccount(account);

            foreach (SmartTransaction transaction in transactions)
            {
                SafeHistoryRecord record = new SafeHistoryRecord();
                record.TransactionId = transaction.GetHash();
                record.BlockHeight   = transaction.Height;
                // todo: the mempool could note when it seen the transaction the first time
                record.TimeStamp = !transaction.Confirmed
                                        ? DateTimeOffset.UtcNow
                                        : HeaderChain.GetBlock(transaction.Height).Header.BlockTime;

                record.Amount = Money.Zero;                 //for now

                // how much came to our scriptpubkeys
                foreach (var output in transaction.Transaction.Outputs)
                {
                    if (scriptPubKeys.Contains(output.ScriptPubKey))
                    {
                        record.Amount += output.Value;
                    }
                }

                foreach (var input in transaction.Transaction.Inputs)
                {
                    // do we have the input?
                    SmartTransaction inputTransaction = transactions.FirstOrDefault(x => x.GetHash() == input.PrevOut.Hash);
                    if (default(SmartTransaction) != inputTransaction)
                    {
                        // if yes then deduct from amount (bitcoin output cannot be partially spent)
                        var prevOutput = inputTransaction.Transaction.Outputs[input.PrevOut.N];
                        if (scriptPubKeys.Contains(prevOutput.ScriptPubKey))
                        {
                            record.Amount -= prevOutput.Value;
                        }
                    }
                    // if no then whatever
                }

                safeHistory.Add(record);
            }

            return(safeHistory.ToList().OrderBy(x => x.TimeStamp));
        }
コード例 #2
0
        public void RealHistoryTest()
        {
            // load wallet
            Network      network  = Network.TestNet;
            string       path     = Path.Combine(Helpers.CommittedWalletsFolderPath, $"HiddenWallet.json");
            const string password = "";

            // I change it because I am using a very old wallet to test
            Safe.EarliestPossibleCreationTime = DateTimeOffset.ParseExact("2016-12-18", "yyyy-MM-dd", CultureInfo.InvariantCulture);
            Safe safe = Safe.Load(password, path);

            Assert.Equal(network, safe.Network);
            Debug.WriteLine($"Unique Safe ID: {safe.UniqueId}");

            // create walletjob
            WalletJob walletJob = new WalletJob(Helpers.SocksPortHandler, Helpers.ControlPortClient, safe)
            {
                MaxCleanAddressCount = 79
            };

            // note some event
            WalletJob.ConnectedNodeCountChanged += WalletJob_ConnectedNodeCountChanged;
            _syncedOnce             = false;
            walletJob.StateChanged += WalletJob_StateChanged;

            // start syncing
            var  cts           = new CancellationTokenSource();
            var  walletJobTask = walletJob.StartAsync(cts.Token);
            Task reportTask    = Helpers.ReportAsync(cts.Token, walletJob);

            try
            {
                // wait until fully synced
                while (!_syncedOnce)
                {
                    Task.Delay(1000).Wait();
                }

                Helpers.ReportFullHistory(walletJob);

                // 0. Query all operations, grouped our used safe addresses
                int MinUnusedKeyNum = 37;
                Dictionary <BitcoinAddress, List <BalanceOperation> > operationsPerAddresses = Helpers.QueryOperationsPerSafeAddressesAsync(new QBitNinjaClient(safe.Network), safe, MinUnusedKeyNum).Result;

                Dictionary <uint256, List <BalanceOperation> > operationsPerTransactions = QBitNinjaJutsus.GetOperationsPerTransactions(operationsPerAddresses);

                // 3. Create history records from the transactions
                // History records is arbitrary data we want to show to the user
                var txHistoryRecords = new List <Tuple <DateTimeOffset, Money, int, uint256> >();
                foreach (var elem in operationsPerTransactions)
                {
                    var amount = Money.Zero;
                    foreach (var op in elem.Value)
                    {
                        amount += op.Amount;
                    }

                    var firstOp = elem.Value.First();

                    txHistoryRecords
                    .Add(new Tuple <DateTimeOffset, Money, int, uint256>(
                             firstOp.FirstSeen,
                             amount,
                             firstOp.Confirmations,
                             elem.Key));
                }

                // 4. Order the records by confirmations and time (Simply time does not work, because of a QBitNinja issue)
                var qBitHistoryRecords = txHistoryRecords
                                         .OrderByDescending(x => x.Item3) // Confirmations
                                         .ThenBy(x => x.Item1);           // FirstSeen

                var fullSpvHistoryRecords = walletJob.GetSafeHistory();

                // This won't be equal QBit doesn't show us this transaction: 2017.01.04. 16:24:49	0.00000000	True		77b10ff78aab2e41764a05794c4c464922c73f0c23356190429833ce68fd7be9
                // Assert.Equal(qBitHistoryRecords.Count(), fullSpvHistoryRecords.Count());

                HashSet <SafeHistoryRecord> qBitFoundItToo = new HashSet <SafeHistoryRecord>();
                // Assert all record found by qbit also found by spv and they are identical
                foreach (var record in qBitHistoryRecords)
                {
                    // Item2 is the Amount
                    SafeHistoryRecord found = fullSpvHistoryRecords.FirstOrDefault(x => x.TransactionId == record.Item4);
                    Assert.True(found != default(SafeHistoryRecord));
                    Assert.True(found.TimeStamp.Equals(record.Item1));
                    Assert.True(found.Confirmed.Equals(record.Item3 > 0));
                    Assert.True(found.Amount.Equals(record.Item2));
                    qBitFoundItToo.Add(found);
                }

                foreach (var record in fullSpvHistoryRecords)
                {
                    if (!qBitFoundItToo.Contains(record))
                    {
                        Assert.True(null == qBitHistoryRecords.FirstOrDefault(x => x.Item4 == record.TransactionId));
                        Debug.WriteLine($@"QBitNinja failed to find, but SPV found it: {record.TimeStamp.DateTime}	{record.Amount}	{record.Confirmed}		{record.TransactionId}");
                    }
                }
            }
            finally
            {
                cts.Cancel();
                Task.WhenAll(reportTask, walletJobTask).Wait();

                WalletJob.ConnectedNodeCountChanged -= WalletJob_ConnectedNodeCountChanged;
                walletJob.StateChanged -= WalletJob_StateChanged;
            }
        }