Example #1
0
        public IEnumerable <Coin> GetUnclaimedCoins()
        {
            IEnumerable <UInt160> accounts = GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash);
            IEnumerable <Coin>    coins    = GetCoins(accounts);

            coins = coins.Where(p => p.Output.AssetId.Equals(BlockchainBase.GetStaticAttr().GoverningToken.Hash));
            coins = coins.Where(p => p.State.HasFlag(CoinState.Confirmed) && p.State.HasFlag(CoinState.Spent));
            coins = coins.Where(p => !p.State.HasFlag(CoinState.Claimed) && !p.State.HasFlag(CoinState.Frozen));
            return(coins);
        }
Example #2
0
        public T MakeTransaction <T>(T tx, UInt160 from = null, UInt160 change_address = null, Fixed8 fee = default(Fixed8)) where T : Transaction
        {
            if (tx.Outputs == null)
            {
                tx.Outputs = new TransactionOutput[0];
            }
            if (tx.Attributes == null)
            {
                tx.Attributes = new TransactionAttribute[0];
            }
            fee += tx.SystemFee;
            var pay_total = (typeof(T) == typeof(IssueTransaction) ? new TransactionOutput[0] : tx.Outputs).GroupBy(p => p.AssetId, (k, g) => new
            {
                AssetId = k,
                Value   = g.Sum(p => p.Value)
            }).ToDictionary(p => p.AssetId);

            if (fee > Fixed8.Zero)
            {
                if (pay_total.ContainsKey(BlockchainBase.GetStaticAttr().UtilityToken.Hash))
                {
                    pay_total[BlockchainBase.GetStaticAttr().UtilityToken.Hash] = new
                    {
                        AssetId = BlockchainBase.GetStaticAttr().UtilityToken.Hash,
                        Value   = pay_total[BlockchainBase.GetStaticAttr().UtilityToken.Hash].Value + fee
                    };
                }
                else
                {
                    pay_total.Add(BlockchainBase.GetStaticAttr().UtilityToken.Hash, new
                    {
                        AssetId = BlockchainBase.GetStaticAttr().UtilityToken.Hash,
                        Value   = fee
                    });
                }
            }
            var pay_coins = pay_total.Select(p => new
            {
                AssetId  = p.Key,
                Unspents = from == null ? FindUnspentCoins(p.Key, p.Value.Value) : FindUnspentCoins(p.Key, p.Value.Value, from)
            }).ToDictionary(p => p.AssetId);

            if (pay_coins.Any(p => p.Value.Unspents == null))
            {
                return(null);
            }
            var input_sum = pay_coins.Values.ToDictionary(p => p.AssetId, p => new
            {
                p.AssetId,
                Value = p.Unspents.Sum(q => q.Output.Value)
            });

            if (change_address == null)
            {
                change_address = GetChangeAddress();
            }
            List <TransactionOutput> outputs_new = new List <TransactionOutput>(tx.Outputs);

            foreach (UInt256 asset_id in input_sum.Keys)
            {
                if (input_sum[asset_id].Value > pay_total[asset_id].Value)
                {
                    outputs_new.Add(new TransactionOutput
                    {
                        AssetId    = asset_id,
                        Value      = input_sum[asset_id].Value - pay_total[asset_id].Value,
                        ScriptHash = change_address
                    });
                }
            }
            tx.Inputs  = pay_coins.Values.SelectMany(p => p.Unspents).Select(p => p.Reference).ToArray();
            tx.Outputs = outputs_new.ToArray();
            return(tx);
        }
Example #3
0
 private static void ProcessBlock(Block block, HashSet <UInt160> accounts, WriteBatch batch)
 {
     foreach (Transaction tx in block.Transactions)
     {
         HashSet <UInt160> accounts_changed = new HashSet <UInt160>();
         for (ushort index = 0; index < tx.Outputs.Length; index++)
         {
             TransactionOutput output = tx.Outputs[index];
             if (accounts_tracked.ContainsKey(output.ScriptHash))
             {
                 CoinReference reference = new CoinReference
                 {
                     PrevHash  = tx.Hash,
                     PrevIndex = index
                 };
                 if (coins_tracked.TryGetValue(reference, out Coin coin))
                 {
                     coin.State |= CoinState.Confirmed;
                 }
                 else
                 {
                     accounts_tracked[output.ScriptHash].Add(reference);
                     coins_tracked.Add(reference, coin = new Coin
                     {
                         Reference = reference,
                         Output    = output,
                         State     = CoinState.Confirmed
                     });
                 }
                 batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_Coin).Add(reference), SliceBuilder.Begin().Add(output).Add((byte)coin.State));
                 accounts_changed.Add(output.ScriptHash);
             }
         }
         foreach (CoinReference input in tx.Inputs)
         {
             if (coins_tracked.TryGetValue(input, out Coin coin))
             {
                 if (coin.Output.AssetId.Equals(BlockchainBase.GetStaticAttr().GoverningToken.Hash))
                 {
                     coin.State |= CoinState.Spent | CoinState.Confirmed;
                     batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_Coin).Add(input), SliceBuilder.Begin().Add(coin.Output).Add((byte)coin.State));
                 }
                 else
                 {
                     accounts_tracked[coin.Output.ScriptHash].Remove(input);
                     coins_tracked.Remove(input);
                     batch.Delete(DataEntryPrefix.ST_Coin, input);
                 }
                 accounts_changed.Add(coin.Output.ScriptHash);
             }
         }
         if (tx is ClaimTransaction ctx)
         {
             foreach (CoinReference claim in ctx.Claims)
             {
                 if (coins_tracked.TryGetValue(claim, out Coin coin))
                 {
                     accounts_tracked[coin.Output.ScriptHash].Remove(claim);
                     coins_tracked.Remove(claim);
                     batch.Delete(DataEntryPrefix.ST_Coin, claim);
                     accounts_changed.Add(coin.Output.ScriptHash);
                 }
             }
         }
         if (accounts_changed.Count > 0)
         {
             foreach (UInt160 account in accounts_changed)
             {
                 batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_Transaction).Add(account).Add(tx.Hash), false);
             }
             BalanceChanged?.Invoke(null, new BalanceEventArgs
             {
                 Transaction     = tx,
                 RelatedAccounts = accounts_changed.ToArray(),
                 Height          = block.Index,
                 Time            = block.Timestamp
             });
         }
     }
 }