/// <summary> /// Remove old spent & confirmed TrackedOutpoint, old unconf operations, and old forked operations /// </summary> /// <param name="chain"></param> internal List <object> Prune(ConcurrentChain chain, int blockExpiration = 2000, TimeSpan?timeExpiration = null) { List <object> removed = new List <object>(); timeExpiration = timeExpiration ?? TimeSpan.FromDays(7.0); foreach (var op in _Operations) { if (op.Value.BlockId != null) { var chained = chain.GetBlock(op.Value.BlockId); var isForked = chained == null; if (!isForked) { bool isOldConfirmed = chain.Height - chained.Height + 1 > blockExpiration; if (isOldConfirmed) { foreach (var spent in op.Value.SpentCoins) //Stop tracking the outpoints { TrackedOutpoint unused; if (_TrackedOutpoints.TryRemove(TrackedOutpoint.GetId(spent.Item1.Outpoint), out unused)) { removed.Add(unused); } } } } else { var isOldFork = chain.Height - op.Value.Height + 1 > blockExpiration; if (isOldFork) //clear any operation belonging to an old fork { Operation unused; if (_Operations.TryRemove(op.Key, out unused)) { removed.Add(unused); } } } } else { var isOldUnconf = (DateTimeOffset.UtcNow - op.Value.AddedDate) > timeExpiration; if (isOldUnconf) //clear any old unconfirmed { Operation unused; if (_Operations.TryRemove(op.Key, out unused)) { removed.Add(unused); } } } } return(removed); }
public bool NotifyTransaction(Transaction transaction, ChainedBlock chainedBlock, MerkleBlock proof) { if (chainedBlock != null) { if (proof == null) { throw new ArgumentNullException("proof"); } if (proof.Header.GetHash() != chainedBlock.Header.GetHash()) { throw new InvalidOperationException("The chained block and the merkle block are different blocks"); } if (!proof.PartialMerkleTree.Check(chainedBlock.Header.HashMerkleRoot)) { throw new InvalidOperationException("The MerkleBlock does not have the expected merkle root"); } if (!proof.PartialMerkleTree.GetMatchedTransactions().Contains(transaction.GetHash())) { throw new InvalidOperationException("The MerkleBlock does not contains the input transaction"); } } var interesting = false; lock (cs) { foreach (var txin in transaction.Inputs.AsIndexedInputs()) { var key = TrackedOutpoint.GetId(txin.PrevOut); TrackedOutpoint match; if (_TrackedOutpoints.TryGetValue(key, out match)) { TrackedScript parentMetadata; if (_TrackedScripts.TryGetValue(match.TrackedScriptId, out parentMetadata)) { interesting = true; Spent(parentMetadata, txin, match.Coin, chainedBlock, proof); } } } foreach (var txout in transaction.Outputs.AsIndexedOutputs()) { var key = TrackedScript.GetId(txout.TxOut.ScriptPubKey); TrackedScript match; if (_TrackedScripts.TryGetValue(key, out match)) { interesting = true; Received(match, txout, chainedBlock, proof); } } } return(interesting); }
private void Received(TrackedScript match, IndexedTxOut txout, ChainedBlock block, MerkleBlock proof) { var operation = new Operation(txout.Transaction, block, proof); SetUnconfirmedSeenIfPossible(txout.Transaction, block, operation); var coin = new Coin(txout); operation.ReceivedCoins.Add(Tuple.Create(coin, match.GetId())); _Operations.AddOrUpdate(operation.GetId(), operation, (k, old) => old.Merge(operation)); var trackedOutpoint = new TrackedOutpoint() { Coin = coin, TrackedScriptId = match.GetId(), Filter = match.Filter }; _TrackedOutpoints.TryAdd(trackedOutpoint.GetId(), trackedOutpoint); }
private Operation Received(TrackedScript match, IndexedTxOut txout, ChainedBlock block, MerkleBlock proof) { var operation = new Operation(txout.Transaction, block, proof, _TrackedScripts); SetUnconfirmedSeenIfPossible(txout.Transaction, block, operation); var coin = new Coin(txout); operation.ReceivedCoins.Add(Tuple.Create(coin, match.GetId())); bool merged = false; var returned = _Operations.AddOrUpdate(operation.GetId(), operation, (k, old) => old.Merge(operation, out merged)); var trackedOutpoint = new TrackedOutpoint() { Coin = coin, TrackedScriptId = match.GetId(), Filter = match.Filter }; _TrackedOutpoints.TryAdd(trackedOutpoint.GetId(), trackedOutpoint); return((operation == returned || merged) ? operation : null); }
private Operation Received(TrackedScript match, IndexedTxOut txout, ChainedBlock block, MerkleBlock proof) { var operation = new Operation(txout.Transaction, block, proof, _TrackedScripts); SetUnconfirmedSeenIfPossible(txout.Transaction, block, operation); var coin = new Coin(txout); operation.ReceivedCoins.Add(Tuple.Create(coin, match.GetId())); bool merged = false; var returned = _Operations.AddOrUpdate(operation.GetId(), operation, (k, old) => old.Merge(operation, out merged)); var trackedOutpoint = new TrackedOutpoint() { Coin = coin, TrackedScriptId = match.GetId(), Filter = match.Filter }; _TrackedOutpoints.TryAdd(trackedOutpoint.GetId(), trackedOutpoint); return (operation == returned || merged) ? operation : null; }