public bool SaveTransaction(Transaction tx) { Coin[] changeset; lock (contracts) lock (coins) { if (tx.Inputs.Any(p => !coins.Contains(p) || coins[p].State.HasFlag(CoinState.Spent) || !coins[p].State.HasFlag(CoinState.Confirmed))) { return(false); } foreach (CoinReference input in tx.Inputs) { coins[input].State |= CoinState.Spent; coins[input].State &= ~CoinState.Confirmed; } for (ushort i = 0; i < tx.Outputs.Length; i++) { AddressState state = CheckAddressState(tx.Outputs[i].ScriptHash); if (state.HasFlag(AddressState.InWallet)) { Coin coin = new Coin { Reference = new CoinReference { PrevHash = tx.Hash, PrevIndex = i }, Output = tx.Outputs[i], State = CoinState.Unconfirmed }; if (state.HasFlag(AddressState.WatchOnly)) { coin.State |= CoinState.WatchOnly; } coins.Add(coin); } } if (tx is ClaimTransaction) { foreach (CoinReference claim in ((ClaimTransaction)tx).Claims) { coins[claim].State |= CoinState.Claimed; coins[claim].State &= ~CoinState.Confirmed; } } changeset = coins.GetChangeSet(); OnSaveTransaction(tx, changeset.Where(p => ((ITrackable <CoinReference>)p).TrackState == TrackState.Added), changeset.Where(p => ((ITrackable <CoinReference>)p).TrackState == TrackState.Changed)); coins.Commit(); } if (changeset.Length > 0) { BalanceChanged?.Invoke(this, EventArgs.Empty); } return(true); }
private void ProcessNewBlock(Block block) { Coin[] changeset; lock (contracts) lock (coins) { foreach (Transaction tx in block.Transactions) { for (ushort index = 0; index < tx.Outputs.Length; index++) { TransactionOutput output = tx.Outputs[index]; AddressState state = CheckAddressState(output.ScriptHash); if (state.HasFlag(AddressState.InWallet)) { CoinReference key = new CoinReference { PrevHash = tx.Hash, PrevIndex = index }; if (coins.Contains(key)) { coins[key].State |= CoinState.Confirmed; } else { coins.Add(new Coin { Reference = key, Output = output, State = CoinState.Confirmed }); } if (state.HasFlag(AddressState.WatchOnly)) { coins[key].State |= CoinState.WatchOnly; } } } } foreach (Transaction tx in block.Transactions) { foreach (CoinReference input in tx.Inputs) { if (coins.Contains(input)) { if (coins[input].Output.AssetId.Equals(Blockchain.SystemShare.Hash)) { coins[input].State |= CoinState.Spent | CoinState.Confirmed; } else { coins.Remove(input); } } } } foreach (ClaimTransaction tx in block.Transactions.OfType <ClaimTransaction>()) { foreach (CoinReference claim in tx.Claims) { if (coins.Contains(claim)) { coins.Remove(claim); } } } current_height++; changeset = coins.GetChangeSet(); OnProcessNewBlock(block, changeset.Where(p => ((ITrackable <CoinReference>)p).TrackState == TrackState.Added), changeset.Where(p => ((ITrackable <CoinReference>)p).TrackState == TrackState.Changed), changeset.Where(p => ((ITrackable <CoinReference>)p).TrackState == TrackState.Deleted)); coins.Commit(); } if (changeset.Length > 0) { BalanceChanged?.Invoke(this, EventArgs.Empty); } }