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); }
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); }
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 }); } } }