Пример #1
0
        public void DustInputsNotAddedToMultiSigWallet()
        {
            var transactionData1 = new TransactionData()
            {
                Id              = 1,
                Amount          = Money.Coins(1),
                Index           = 1,
                BlockHeight     = null,
                SpendingDetails = null
            };

            var transactionData2 = new TransactionData()
            {
                Id              = 2,
                Amount          = Money.Coins(0.0001m),
                Index           = 0,
                BlockHeight     = null,
                SpendingDetails = null
            };

            var transactions = new MultiSigTransactions
            {
                transactionData2,
                transactionData1
            };

            Assert.Equal(2, transactions.Count);
            Assert.Single(transactions.GetUnspentTransactions());
        }
Пример #2
0
        public void CanChangeHeightOfSpendableTransaction()
        {
            var transactionData1 = new TransactionData()
            {
                Id              = 1,
                Amount          = Money.Coins(1),
                Index           = 1,
                BlockHeight     = null,
                SpendingDetails = null
            };

            var transactionData2 = new TransactionData()
            {
                Id              = 2,
                Amount          = Money.Coins(1),
                Index           = 0,
                BlockHeight     = null,
                SpendingDetails = null
            };

            var transactions = new MultiSigTransactions
            {
                transactionData2,
                transactionData1
            };

            transactionData2.BlockHeight = 1;

            transactions.Remove(transactionData2);

            transactionData2.BlockHeight = null;

            transactions.Add(transactionData2);
        }
Пример #3
0
        private IEnumerable <Transaction> CompletedTransactions(IEnumerable <Transaction> transactionsToCheck)
        {
            FederationWallet     wallet    = this.federationWalletManager.GetWallet();
            MultiSigTransactions walletTxs = wallet.MultiSigAddress.Transactions;

            HashSet <uint256> spendingTransactions = walletTxs
                                                     .Where(t => t.SpendingDetails?.BlockHeight > 0)
                                                     .Select(t => t.SpendingDetails?.TransactionId)
                                                     .ToHashSet();

            foreach (Transaction tx in transactionsToCheck)
            {
                uint256 hash = tx.GetHash();

                // If there is a spendable output for this tx and it has a block height then the tx is in completed state.
                if (walletTxs.TryGetTransaction(hash, 0, out TransactionData tData) && tData.BlockHeight > 0)
                {
                    yield return(tx);
                }
                // If this is a confirmed spending transaction then it is in completed state.
                else if (spendingTransactions.Contains(hash))
                {
                    yield return(tx);
                }
                // If the tx has an input that is consumed by another confirmed transaction then it should be removed.
                else
                {
                    bool bDone = false;

                    foreach (TxIn txIn in tx.Inputs)
                    {
                        // Find the input's UTXO.
                        if (walletTxs.TryGetTransaction(txIn.PrevOut.Hash, (int)txIn.PrevOut.N, out TransactionData tData2))
                        {
                            // Check if the input's UTXO is being spent by another confirmed transaction.
                            if (tData2.SpendingDetails?.BlockHeight > 0 && tData2.SpendingDetails?.TransactionId != hash)
                            {
                                bDone = true;
                                break;
                            }
                        }
                    }

                    if (bDone)
                    {
                        yield return(tx);
                    }
                }
            }
        }
Пример #4
0
        public void TransactionDataAddedToMultiSigTransactionsExistsInExpectedLookups(bool hasBlockHeight, bool hasSpendingDetails, bool hasWithdrawalDetails, bool flipBlockHeight, bool flipSpendingDetails, bool flipWithdrawalDetails)
        {
            uint256 transactionId         = 1;
            int     transactionIndex      = 2;
            uint256 spendingTransactionId = 2;
            uint256 spendingDepositId     = 3;

            SpendingDetails spendingDetails()
            {
                if (!hasSpendingDetails)
                {
                    return(null);
                }

                return(new SpendingDetails()
                {
                    WithdrawalDetails = hasWithdrawalDetails ? new WithdrawalDetails()
                    {
                        MatchingDepositId = spendingDepositId
                    } : null,
                    BlockHeight = spendingBlockHeight(),
                    TransactionId = spendingTransactionId
                });
            }

            int?blockHeight()
            {
                return(hasBlockHeight ? 3 : (int?)null);
            }

            int?spendingBlockHeight()
            {
                return(hasBlockHeight ? 4 : (int?)null);
            }

            var transactionData = new TransactionData()
            {
                Id              = transactionId,
                Amount          = Money.Coins(1),
                Index           = transactionIndex,
                BlockHeight     = blockHeight(),
                SpendingDetails = spendingDetails()
            };

            var transactions = new MultiSigTransactions();

            transactions.Add(transactionData);

            Assert.Contains(transactionData, transactions);

            void Validate()
            {
                if (hasBlockHeight && hasSpendingDetails)
                {
                    Assert.Single(transactions.SpentTransactionsBeforeHeight(int.MaxValue), x => x.Item1 == spendingBlockHeight());
                }
                else
                {
                    Assert.Empty(transactions.SpentTransactionsBeforeHeight(int.MaxValue));
                }

                if (hasSpendingDetails && hasWithdrawalDetails)
                {
                    Assert.Single(transactions.GetSpendingTransactionsByDepositId(spendingDepositId).First().txList);
                }
                else
                {
                    Assert.Empty(transactions.GetSpendingTransactionsByDepositId(spendingDepositId).First().txList);
                }

                if (hasSpendingDetails)
                {
                    Assert.Empty(transactions.GetUnspentTransactions());
                }
                else
                {
                    Assert.Single(transactions.GetUnspentTransactions(), x => x.BlockHeight == blockHeight());
                }
            }

            Validate();

            hasBlockHeight       ^= flipBlockHeight;
            hasSpendingDetails   ^= flipSpendingDetails;
            hasWithdrawalDetails ^= flipWithdrawalDetails;

            transactionData.BlockHeight     = blockHeight();
            transactionData.SpendingDetails = spendingDetails();

            Validate();

            transactions.Remove(transactionData);

            Assert.Empty(transactions);
            Assert.Empty(transactions.SpentTransactionsBeforeHeight(int.MaxValue));
            Assert.Empty(transactions.GetUnspentTransactions());
            Assert.Empty(transactions.GetSpendingTransactionsByDepositId(spendingDepositId).Single().txList);
        }
        public void TransactionsByDepositDictCantContainNullWithdrawals()
        {
            var multiSigTransactions = new MultiSigTransactions();

            // Add the transaction to the collection.
            var spendingDetails1 = new SpendingDetails()
            {
                WithdrawalDetails = new WithdrawalDetails()
                {
                    Amount            = Money.Zero,
                    MatchingDepositId = 2
                }
            };

            var spendingDetails2 = new SpendingDetails()
            {
                WithdrawalDetails = new WithdrawalDetails()
                {
                    Amount            = Money.Zero,
                    MatchingDepositId = 2
                }
            };

            TransactionData txData1Fact() => new TransactionData()
            {
                Amount          = Money.Zero,
                Id              = 1,
                Index           = 0,
                SpendingDetails = spendingDetails1
            };

            TransactionData txData2Fact() => new TransactionData()
            {
                Amount          = Money.Zero,
                Id              = 2,
                Index           = 0,
                SpendingDetails = spendingDetails2
            };

            TransactionData txData1 = txData1Fact();
            TransactionData txData2 = txData2Fact();

            multiSigTransactions.Add(txData1);
            multiSigTransactions.Add(txData2);

            // Retrieve the transaction.
            List <TransactionData> txDataMatch = multiSigTransactions.GetSpendingTransactionsByDepositId(2).Single().txList;

            Assert.Contains(txDataMatch, txDataMatch => txData1.Id == txDataMatch.Id && txData1.Index == txDataMatch.Index);
            Assert.Contains(txDataMatch, txDataMatch => txData2.Id == txDataMatch.Id && txData2.Index == txDataMatch.Index);

            multiSigTransactions.Remove(txData1Fact());
            multiSigTransactions.Remove(txData2Fact());

            multiSigTransactions.Add(txData1);
            multiSigTransactions.Add(txData2);

            // Replace the SpendingDetails with one containing WithdrawalDetails set to null.
            var spendingDetails3 = new SpendingDetails()
            {
                WithdrawalDetails = null
            };

            var spendingDetails4 = new SpendingDetails()
            {
                WithdrawalDetails = null
            };

            // Remove and restore one.
            txData2.SpendingDetails = spendingDetails4;
            Assert.Single(multiSigTransactions.GetSpendingTransactionsByDepositId(2).Single().txList);
            txData2.SpendingDetails = spendingDetails2;

            // Retrieve the transaction again.
            List <TransactionData> txDataMatch2 = multiSigTransactions.GetSpendingTransactionsByDepositId(2).Single().txList;

            Assert.Contains(txDataMatch2, txDataMatch => txData1.Id == txDataMatch.Id && txData1.Index == txDataMatch.Index);
            Assert.Contains(txDataMatch2, txDataMatch => txData2.Id == txDataMatch.Id && txData2.Index == txDataMatch.Index);

            // Remove and restore one.
            txData1.SpendingDetails = spendingDetails3;
            Assert.Single(multiSigTransactions.GetSpendingTransactionsByDepositId(2).Single().txList);
            txData1.SpendingDetails = spendingDetails1;

            // Retrieve the transaction again.
            List <TransactionData> txDataMatch3 = multiSigTransactions.GetSpendingTransactionsByDepositId(2).Single().txList;

            Assert.Contains(txDataMatch3, txDataMatch => txData1.Id == txDataMatch.Id && txData1.Index == txDataMatch.Index);
            Assert.Contains(txDataMatch3, txDataMatch => txData2.Id == txDataMatch.Id && txData2.Index == txDataMatch.Index);

            // Remove and restore both.
            txData1.SpendingDetails = spendingDetails3;
            txData2.SpendingDetails = spendingDetails4;
            Assert.Empty(multiSigTransactions.GetSpendingTransactionsByDepositId(2).Single().txList);
            txData1.SpendingDetails = spendingDetails1;
            txData2.SpendingDetails = spendingDetails2;

            // Retrieve the transaction again.
            List <TransactionData> txDataMatch4 = multiSigTransactions.GetSpendingTransactionsByDepositId(2).Single().txList;

            Assert.Contains(txDataMatch4, txDataMatch => txData1.Id == txDataMatch.Id && txData1.Index == txDataMatch.Index);
            Assert.Contains(txDataMatch4, txDataMatch => txData2.Id == txDataMatch.Id && txData2.Index == txDataMatch.Index);
        }