Esempio n. 1
0
        public static ISegWitAddress Match(this ISegWitAddress segWitAddress, string address = null, AddressType addressType = AddressType.MatchAll)
        {
            if (segWitAddress == null)  // no op
            {
                return(null);
            }

            if (address != null) // filter by address
            {
                if (segWitAddress.Address == address)
                {
                    if (addressType == AddressType.MatchAll || addressType == segWitAddress.AddressType)
                    {
                        return(segWitAddress);
                    }
                    return(null);
                }
                return(null);
            }

            // do not filter by address
            if (addressType == AddressType.MatchAll)
            {
                return(segWitAddress);
            }

            if (addressType == segWitAddress.AddressType)
            {
                return(segWitAddress);
            }

            return(null);
        }
Esempio n. 2
0
 public SegWitCoin(ISegWitAddress segWitAddress, uint256 utxoTxHash, int utxoTxN, long utxoValue)
 {
     this.SegWitAddress = segWitAddress;
     this.UtxoTxHash    = utxoTxHash;
     this.UtxoTxN       = utxoTxN;
     this.UtxoValue     = utxoValue;
 }
Esempio n. 3
0
        public static ISegWitAddress GetOrAddAddress(string bech32, int blockHeight, X1WalletFile x1WalletFile)
        {
            ISegWitAddress existing = null;

            if (x1WalletFile.PubKeyHashAddresses.TryGetValue(bech32, out var pubKeyHashAddress))
            {
                existing = pubKeyHashAddress;
            }
            else if (x1WalletFile.ColdStakingAddresses.TryGetValue(bech32, out var coldStakingAddress))
            {
                existing = coldStakingAddress;
            }
            else if (x1WalletFile.MultiSigAddresses.TryGetValue(bech32, out var multiSigAddress))
            {
                existing = multiSigAddress;
            }
            if (existing != null)
            {
                existing.LastSeenHeight = blockHeight;
                x1WalletFile.SaveX1WalletFile(x1WalletFile.CurrentPath);
                return(existing);
            }

            if (x1WalletFile.LookAhead.TryGetValue(bech32, out var gapAddress))
            {
                gapAddress.LastSeenHeight = blockHeight;
                x1WalletFile.PubKeyHashAddresses[gapAddress.Address] = gapAddress;
                x1WalletFile.LookAhead.TryRemove(gapAddress.Address, out var _);
                x1WalletFile.SaveX1WalletFile(x1WalletFile.CurrentPath);
                return(gapAddress);
            }
            return(null);
        }
Esempio n. 4
0
        static Dictionary <string, UtxoMetadata> ExtractIncomingFunds(Transaction transaction, int blockHeight, bool didSpend, Func <string, int, ISegWitAddress> addressReader, out long amountReceived, out Dictionary <string, UtxoMetadata> destinations)
        {
            Dictionary <string, UtxoMetadata> received    = null;
            Dictionary <string, UtxoMetadata> notInWallet = null;
            long sum   = 0;
            int  index = 0;

            foreach (var output in transaction.Outputs)
            {
                ISegWitAddress ownAddress = null;

                if (!output.IsProtocolOutput(transaction))
                {
                    ownAddress = addressReader(output.ScriptPubKey.GetAddressFromScriptPubKey(), blockHeight);
                }

                if (ownAddress != null)
                {
                    NotNull(ref received, transaction.Outputs.Count);

                    var item = new UtxoMetadata
                    {
                        Address  = ownAddress.Address,
                        HashTx   = transaction.GetHash(),
                        Satoshis = output.Value.Satoshi,
                        Index    = index
                    };
                    received.Add(item.GetKey(), item);
                    sum += item.Satoshis;
                }
                else
                {   // For protocol tx, we are not interested in the other outputs.
                    // If we spent, the save the destinations, because the wallet wants to show where we sent coins to.
                    // if we did not spent, we do not save the destinations, because they are the other parties change address
                    // and we only received coins.
                    if (!transaction.IsCoinBase && !transaction.IsCoinStake && didSpend)
                    {
                        NotNull(ref notInWallet, transaction.Outputs.Count);
                        var dest = new UtxoMetadata
                        {
                            Address  = output.ScriptPubKey.GetAddressFromScriptPubKey(),
                            HashTx   = transaction.GetHash(),
                            Satoshis = output.Value != null ? output.Value.Satoshi : 0,
                            Index    = index
                        };
                        notInWallet.Add(dest.GetKey(), dest);
                    }
                }
                index++;
            }

            destinations = received != null
                ? notInWallet
                : null;

            amountReceived = sum;
            return(received);
        }
Esempio n. 5
0
 static bool IsAddressUsedInConfirmedTransactions(ISegWitAddress address, IReadOnlyCollection <BlockMetadata> blocks)
 {
     // slow version
     foreach (BlockMetadata block in blocks)
     {
         foreach (TransactionMetadata tx in block.Transactions)
         {
             foreach (var utxo in tx.Received.Values)
             {
                 if (utxo.Address == address.Address)
                 {
                     return(true);
                 }
             }
         }
     }
     return(false);
 }
Esempio n. 6
0
 public SegWitCoin(ISegWitAddress segWitAddress, uint256 utxoTxHash, int utxoTxN, long utxoValue,
                   UtxoType utxoType, uint?utxoPosV3Time) : this(segWitAddress, utxoTxHash, utxoTxN, utxoValue, utxoType)
 {
     this.UtxoPosV3Time = utxoPosV3Time;
 }
Esempio n. 7
0
 public static Script GetScriptPubKey(this ISegWitAddress address)
 {
     return(GetScriptPubKey(address.Address));
 }
Esempio n. 8
0
        public static Balance GetBalance(ConcurrentDictionary <int, BlockMetadata> blocks, int syncedHeight, HashSet <MemoryPoolEntry> memoryPoolEntries, Func <string, ISegWitAddress> getOwnAddress,
                                         string matchAddress = null, AddressType matchAddressType = AddressType.MatchAll)
        {
            var balance = new Balance();

            var spent = new Dictionary <string, UtxoMetadata>();

            // process all confirmed transactions first, oldest to newest
            foreach (var(height, block) in blocks)
            {
                foreach (var tx in block.Transactions)
                {
                    bool isImmatureForSpending = false;

                    if (tx.TxType.HasCoinbaseMaturity())
                    {
                        var confirmationsSpending = syncedHeight - height + 1;                                // if the tip is at 100 and my tx is height 90, it's 11 confirmations
                        isImmatureForSpending = confirmationsSpending < C.Network.Consensus.CoinbaseMaturity; // ok
                    }

                    var confirmationsStaking = syncedHeight - height + 1; // if the tip is at 100 and my tx is height 90, it's 11 confirmations
                    var isImmatureForStaking = confirmationsStaking < C.Network.Consensus.MaxReorgLength;

                    if (tx.Received != null)
                    {
                        foreach (UtxoMetadata utxo in tx.Received.Values)
                        {
                            for (var address = getOwnAddress(utxo.Address).Match(matchAddress, matchAddressType);
                                 address != null; address = null)
                            {
                                balance.TotalReceived += utxo.Satoshis;

                                var coin = new SegWitCoin(address, utxo.HashTx, utxo.Index, utxo.Satoshis);

                                if (!isImmatureForSpending)
                                {
                                    balance.Spendable += utxo.Satoshis;
                                    balance.SpendableCoins.AddSafe(utxo.GetKey(), coin);
                                }
                                if (!isImmatureForStaking)
                                {
                                    balance.Stakable += utxo.Satoshis;
                                    balance.StakingCoins.AddSafe(utxo.GetKey(), coin);
                                }
                            }
                        }
                    }

                    if (tx.Spent != null)
                    {
                        foreach ((string txIdN, UtxoMetadata utxo) in tx.Spent)
                        {
                            for (var address = getOwnAddress(utxo.Address).Match(matchAddress, matchAddressType);
                                 address != null;
                                 address = null)
                            {
                                balance.TotalSpent += utxo.Satoshis;
                                spent.AddSafe(txIdN, utxo);
                            }
                        }
                    }
                }
            }

            // unconfirmed transactions - add them last, ordered by time, so that they come last in coin selection
            // when unconfirmed outputs get spent, to allow the memory pool and network to recognize
            // the new unspent outputs.
            foreach (MemoryPoolEntry entry in memoryPoolEntries.OrderBy(x => x.TransactionTime))
            {
                var tx = entry.Transaction;
                if (tx.Received != null)
                {
                    foreach (UtxoMetadata utxo in tx.Received.Values)
                    {
                        ISegWitAddress address = getOwnAddress(utxo.Address);

                        balance.TotalReceivedPending += utxo.Satoshis;

                        var coin = new SegWitCoin(address, utxo.HashTx, utxo.Index, utxo.Satoshis);
                        balance.SpendableCoins.AddSafe(utxo.GetKey(), coin);
                    }
                }

                if (tx.Spent != null)
                {
                    foreach (var(txIdN, utxo) in tx.Spent)
                    {
                        for (var address = getOwnAddress(utxo.Address).Match(matchAddress, matchAddressType);
                             address != null;
                             address = null)
                        {
                            balance.TotalSpent += utxo.Satoshis;
                            spent.AddSafe(txIdN, utxo);
                        }
                    }
                }
            }

            // remove what is already spent
            foreach (var utxoId in spent)
            {
                if (balance.SpendableCoins.ContainsKey(utxoId.Key))
                {
                    balance.Spendable -= utxoId.Value.Satoshis;
                    balance.SpendableCoins.Remove(utxoId.Key);
                }
                if (balance.StakingCoins.ContainsKey(utxoId.Key))
                {
                    balance.Stakable -= utxoId.Value.Satoshis;
                    balance.StakingCoins.Remove(utxoId.Key);
                }
            }

            // last balance updates
            balance.Confirmed = balance.TotalReceived - balance.TotalSpent;
            balance.Pending   = balance.TotalReceivedPending - balance.TotalSpentPending;
            balance.Total     = balance.Confirmed + balance.Pending;

            return(balance);
        }