protected bool TryGetStorageValue(TKey key, out TValue value, bool saveInCache) { TValue valueLocal = default(TValue); var result = new MethodTimer(false && this.Name == "BlockCache").Time(() => { TValue storedValue; if (dataStorage.TryReadValue(key, out storedValue)) { // cache the retrieved value if (saveInCache) { CacheValue(key, storedValue); } // fire retrieved event var handler = this.OnRetrieved; if (handler != null) { handler(key, storedValue); } valueLocal = storedValue; return(true); } else { valueLocal = default(TValue); return(false); } }); value = valueLocal; return(result); }
private IEnumerable <Tuple <int, ChainedBlock> > ChainedBlockLookAhead(IEnumerable <Tuple <int, ChainedHeader> > chain, int lookAhead) { return(chain .Select( chainedHeaderTuple => { try { // cooperative loop this.ThrowIfCancelled(); var direction = chainedHeaderTuple.Item1; var chainedHeader = chainedHeaderTuple.Item2; var block = new MethodTimer(false).Time("GetBlock", () => this.blockCache[chainedHeader.Hash]); var chainedBlock = new ChainedBlock(chainedHeader, block); return Tuple.Create(direction, chainedBlock); } catch (MissingDataException e) { this.logger.Debug("Stalled, MissingDataException: {0}".Format2(e.Key)); throw; } }) .LookAhead(1)); }
static void Main(string[] args) { long time = MethodTimer.Run(() => File.Open(@"c:\test.txt", FileMode.CreateNew)); Console.WriteLine(time); Console.ReadLine(); }
public void SuccessRate(int iterations, double successRate) { var fickleTimes = MethodTimer.MeasureExecution(() => FickleFunc(successRate), iterations); Asserter.Against(fickleTimes) .And(Has.Property(nameof(fickleTimes.SuccessRate)).CloseTo(successRate, 0.005)) .And(Has.Property(nameof(fickleTimes.Iterations)).EqualTo(iterations)) .Invoke(); }
private void UpdateTargetChain() { try { long origChanged; lock (this.changedLock) origChanged = this.changed; var targetBlockLocal = this.targetBlock; var targetChainLocal = this.targetChain; if (targetBlockLocal != null && (targetChainLocal == null || targetBlockLocal.Hash != targetChainLocal.LastBlock.Hash)) { var newTargetChain = targetChainLocal != null ? targetChainLocal.ToBuilder() : new ChainBuilder(Chain.CreateForGenesisBlock(this.rules.GenesisChainedHeader)); var deltaBlockPath = new MethodTimer(false).Time("deltaBlockPath", () => new BlockchainWalker().GetBlockchainPath(newTargetChain.LastBlock, targetBlockLocal, blockHash => this.coreStorage.GetChainedHeader(blockHash))); foreach (var rewindBlock in deltaBlockPath.RewindBlocks) { newTargetChain.RemoveBlock(rewindBlock); } foreach (var advanceBlock in deltaBlockPath.AdvanceBlocks) { newTargetChain.AddBlock(advanceBlock); } this.logger.Debug("Winning chained block {0} at height {1}, total work: {2}".Format2(newTargetChain.LastBlock.Hash.ToHexNumberString(), newTargetChain.Height, newTargetChain.LastBlock.TotalWork.ToString("X"))); this.targetChain = newTargetChain.ToImmutable(); var handler = this.OnTargetChainChanged; if (handler != null) { handler(); } } lock (this.changedLock) { if (this.changed == origChanged) { this.updatedEvent.Set(); } else { this.NotifyWork(); } } } catch (MissingDataException) { } }
public Tuple<ECPrivateKeyParameters, ECPublicKeyParameters> CreateKeyPair() { var curve = SecNamedCurves.GetByName("secp256k1"); var domainParameters = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H, curve.GetSeed()); var generator = new ECKeyPairGenerator(); generator.Init(new ECKeyGenerationParameters(domainParameters, new SecureRandom())); var keyPair = new MethodTimer(false).Time("GenerateKeyPair", () => generator.GenerateKeyPair()); var privateKey = (ECPrivateKeyParameters)keyPair.Private; var publicKey = (ECPublicKeyParameters)keyPair.Public; //Debug.WriteLine("Private: {0}".Format2(privateKey.D.ToHexNumberStringUnsigned())); //Debug.WriteLine("Public X: {0}".Format2(publicKey.Q.X.ToBigInteger().ToHexNumberStringUnsigned())); //Debug.WriteLine("Public Y: {0}".Format2(publicKey.Q.Y.ToBigInteger().ToHexNumberStringUnsigned())); return Tuple.Create(privateKey, publicKey); }
public Tuple <ECPrivateKeyParameters, ECPublicKeyParameters> CreateKeyPair() { var curve = SecNamedCurves.GetByName("secp256k1"); var domainParameters = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H, curve.GetSeed()); var generator = new ECKeyPairGenerator(); generator.Init(new ECKeyGenerationParameters(domainParameters, new SecureRandom())); var keyPair = new MethodTimer(false).Time("GenerateKeyPair", () => generator.GenerateKeyPair()); var privateKey = (ECPrivateKeyParameters)keyPair.Private; var publicKey = (ECPublicKeyParameters)keyPair.Public; //Debug.WriteLine("Private: {0}".Format2(privateKey.D.ToHexNumberStringUnsigned())); //Debug.WriteLine("Public X: {0}".Format2(publicKey.Q.X.ToBigInteger().ToHexNumberStringUnsigned())); //Debug.WriteLine("Public Y: {0}".Format2(publicKey.Q.Y.ToBigInteger().ToHexNumberStringUnsigned())); return(Tuple.Create(privateKey, publicKey)); }
public void ListVsSet() { const int iterations = 1000; var items = MakeHugeCollection(iterations).ToArray(); var toFind = items.Random(); // Using their respecting .Contains() methods var list = items.ToList(); var set = items.ToHashSet(); var listTimes = MethodTimer.MeasureExecution(() => ListContains(list, toFind), iterations); var setTimes = MethodTimer.MeasureExecution(() => SetContains(set, toFind), iterations); Console.WriteLine($"list: {listTimes}"); Console.WriteLine($"set: {setTimes}"); // Using the extension Enumerable.Contains() list.RandomizeEntries(); set.RandomizeEntries(); var listableTimes = MethodTimer.MeasureExecution(() => EnumerableContains(list, toFind), iterations); var settableTimes = MethodTimer.MeasureExecution(() => EnumerableContains(set, toFind), iterations); Console.WriteLine($"{nameof(listableTimes)}: {listableTimes}"); Console.WriteLine($"{nameof(settableTimes)}: {settableTimes}"); // Actually doing a comparison var comparison = new AggregateExecutionComparison(listTimes, setTimes); Console.WriteLine(comparison); Asserter.Against(comparison) .And(AssertComparison(comparison.Average, 1)) .And(AssertComparison(comparison.Total, 1)) .Invoke(); }
public IEnumerable <Tuple <Block, ChainedBlock /*, ImmutableDictionary<UInt256, Transaction>*/> > BlockAndTxLookAhead(IList <UInt256> blockHashes) { var blockLookAhead = LookAheadMethods.LookAhead( () => blockHashes.Select( blockHash => { var block = new MethodTimer(false).Time("GetBlock", () => this.CacheContext.GetBlock(blockHash, saveInCache: false)); this.CacheContext.TransactionCache.CacheBlock(block); //var transactionsBuilder = ImmutableDictionary.CreateBuilder<UInt256, Transaction>(); //var inputTxHashList = block.Transactions.Skip(1).SelectMany(x => x.Inputs).Select(x => x.PreviousTxOutputKey.TxHash).Distinct(); //// pre-cache input transactions ////Parallel.ForEach(inputTxHashList, inputTxHash => //foreach (var inputTxHash in inputTxHashList) //{ // Transaction inputTx; // if (this.CacheContext.TransactionCache.TryGetValue(inputTxHash, out inputTx, saveInCache: false)) // { // transactionsBuilder.Add(inputTxHash, inputTx); // } //} //return Tuple.Create(block, transactionsBuilder.ToImmutable()); return(block); }), this.shutdownToken); var chainedBlockLookAhead = LookAheadMethods.LookAhead( () => blockHashes.Select(blockHash => this.CacheContext.GetChainedBlock(blockHash, saveInCache: false)), this.shutdownToken); return(blockLookAhead.Zip(chainedBlockLookAhead, (block, chainedBlock) => Tuple.Create(block, chainedBlock))); }
public IEnumerable<Tuple<Block, ChainedBlock /*, ImmutableDictionary<UInt256, Transaction>*/>> BlockAndTxLookAhead(IList<UInt256> blockHashes) { var blockLookAhead = LookAheadMethods.LookAhead( () => blockHashes.Select( blockHash => { var block = new MethodTimer(false).Time("GetBlock", () => this.CacheContext.GetBlock(blockHash, saveInCache: false)); this.CacheContext.TransactionCache.CacheBlock(block); //var transactionsBuilder = ImmutableDictionary.CreateBuilder<UInt256, Transaction>(); //var inputTxHashList = block.Transactions.Skip(1).SelectMany(x => x.Inputs).Select(x => x.PreviousTxOutputKey.TxHash).Distinct(); //// pre-cache input transactions ////Parallel.ForEach(inputTxHashList, inputTxHash => //foreach (var inputTxHash in inputTxHashList) //{ // Transaction inputTx; // if (this.CacheContext.TransactionCache.TryGetValue(inputTxHash, out inputTx, saveInCache: false)) // { // transactionsBuilder.Add(inputTxHash, inputTx); // } //} //return Tuple.Create(block, transactionsBuilder.ToImmutable()); return block; }), this.shutdownToken); var chainedBlockLookAhead = LookAheadMethods.LookAhead( () => blockHashes.Select(blockHash => this.CacheContext.GetChainedBlock(blockHash, saveInCache: false)), this.shutdownToken); return blockLookAhead.Zip(chainedBlockLookAhead, (block, chainedBlock) => Tuple.Create(block, chainedBlock)); }
public Data.Blockchain CalculateBlockchainFromExisting(Data.Blockchain currentBlockchain, ChainedBlock targetChainedBlock, out List<MissingDataException> missingData, CancellationToken cancelToken, Action<Data.Blockchain> onProgress = null) { Debug.WriteLine("Winning chained block {0} at height {1}, total work: {2}".Format2(targetChainedBlock.BlockHash.ToHexNumberString(), targetChainedBlock.Height, targetChainedBlock.TotalWork.ToString("X"))); // if the target block is at height 0 don't use currentBlockchain as-is, set it to be the genesis chain for the target block if (targetChainedBlock.Height == 0) { currentBlockchain = new Data.Blockchain ( blockList: ImmutableList.Create(targetChainedBlock), blockListHashes: ImmutableHashSet.Create(targetChainedBlock.BlockHash), utxo: ImmutableDictionary.Create<UInt256, UnspentTx>() ); } // if currentBlockchain is not present find the genesis block for the target block and use it as the current chain else if (currentBlockchain.IsDefault) { // find the genesis block for the target block var genesisBlock = targetChainedBlock; foreach (var prevBlock in PreviousChainedBlocks(targetChainedBlock)) { // cooperative loop this.shutdownToken.ThrowIfCancellationRequested(); cancelToken.ThrowIfCancellationRequested(); genesisBlock = prevBlock; } currentBlockchain = new Data.Blockchain ( blockList: ImmutableList.Create(genesisBlock), blockListHashes: ImmutableHashSet.Create(genesisBlock.BlockHash), utxo: ImmutableDictionary.Create<UInt256, UnspentTx>() ); } missingData = new List<MissingDataException>(); Debug.WriteLine("Searching for last common ancestor between current chainblock and winning chainblock"); List<UInt256> newChainBlockList; var lastCommonAncestorChain = RollbackToLastCommonAncestor(currentBlockchain, targetChainedBlock, cancelToken, out newChainBlockList); Debug.WriteLine("Last common ancestor found at block {0}, height {1:#,##0}, begin processing winning blockchain".Format2(currentBlockchain.RootBlockHash.ToHexNumberString(), currentBlockchain.Height)); // setup statistics var totalTxCount = 0L; var totalInputCount = 0L; var totalStopwatch = new Stopwatch(); var currentBlockCount = 0L; var currentTxCount = 0L; var currentInputCount = 0L; var currentRateStopwatch = new Stopwatch(); totalStopwatch.Start(); currentRateStopwatch.Start(); // with last common ancestor found and utxo rolled back to that point, calculate the new blockchain // use ImmutableList for BlockList during modification var newBlockchain = new Data.Blockchain ( blockList: lastCommonAncestorChain.BlockList, blockListHashes: lastCommonAncestorChain.BlockListHashes, utxo: lastCommonAncestorChain.Utxo ); // start calculating new utxo foreach (var tuple in BlockAndTxLookAhead(newChainBlockList)) { // cooperative loop this.shutdownToken.ThrowIfCancellationRequested(); cancelToken.ThrowIfCancellationRequested(); try { // get block and metadata for next link in blockchain var nextBlock = tuple.Item1; var nextChainedBlock = tuple.Item2; // calculate the new block utxo, double spends will be checked for ImmutableDictionary<UInt256, ImmutableHashSet<int>> newTransactions = ImmutableDictionary.Create<UInt256, ImmutableHashSet<int>>(); long txCount = 0, inputCount = 0; var newUtxo = new MethodTimer(false).Time("CalculateUtxo", () => CalculateUtxo(nextChainedBlock.Height, nextBlock, newBlockchain.Utxo, out newTransactions, out txCount, out inputCount)); var nextBlockchain = new MethodTimer(false).Time("nextBlockchain", () => new Data.Blockchain ( blockList: newBlockchain.BlockList.Add(nextChainedBlock), blockListHashes: newBlockchain.BlockListHashes.Add(nextChainedBlock.BlockHash), utxo: newUtxo )); // validate the block // validation utxo includes all transactions added in the same block, any double spends will have failed the block above validateStopwatch.Start(); new MethodTimer(false).Time("ValidateBlock", () => this.Rules.ValidateBlock(nextBlock, nextBlockchain, newBlockchain.Utxo, newTransactions)); validateStopwatch.Stop(); // create the next link in the new blockchain newBlockchain = nextBlockchain; if (onProgress != null) onProgress(newBlockchain); // blockchain processing statistics currentBlockCount++; currentTxCount += txCount; currentInputCount += inputCount; totalTxCount += txCount; totalInputCount += inputCount; var txInterval = 100.THOUSAND(); if ( newBlockchain.Height % 10.THOUSAND() == 0 || (totalTxCount % txInterval < (totalTxCount - txCount) % txInterval || txCount >= txInterval)) { LogBlockchainProgress(newBlockchain, totalStopwatch, totalTxCount, totalInputCount, currentRateStopwatch, currentBlockCount, currentTxCount, currentInputCount); currentBlockCount = 0; currentTxCount = 0; currentInputCount = 0; currentRateStopwatch.Reset(); currentRateStopwatch.Start(); } } catch (MissingDataException e) { // if there is missing data once blockchain processing has started, return the current progress missingData.Add(e); break; } catch (AggregateException e) { if (e.InnerExceptions.Any(x => !(x is MissingDataException))) { throw; } else { missingData.AddRange(e.InnerExceptions.OfType<MissingDataException>()); break; } } } if (onProgress != null) onProgress(newBlockchain); LogBlockchainProgress(newBlockchain, totalStopwatch, totalTxCount, totalInputCount, currentRateStopwatch, currentBlockCount, currentTxCount, currentInputCount); return newBlockchain; }
public Data.Blockchain CalculateBlockchainFromExisting(Data.Blockchain currentBlockchain, ChainedBlock targetChainedBlock, out List <MissingDataException> missingData, CancellationToken cancelToken, Action <Data.Blockchain> onProgress = null) { Debug.WriteLine("Winning chained block {0} at height {1}, total work: {2}".Format2(targetChainedBlock.BlockHash.ToHexNumberString(), targetChainedBlock.Height, targetChainedBlock.TotalWork.ToString("X"))); // if the target block is at height 0 don't use currentBlockchain as-is, set it to be the genesis chain for the target block if (targetChainedBlock.Height == 0) { currentBlockchain = new Data.Blockchain ( blockList: ImmutableList.Create(targetChainedBlock), blockListHashes: ImmutableHashSet.Create(targetChainedBlock.BlockHash), utxo: ImmutableDictionary.Create <UInt256, UnspentTx>() ); } // if currentBlockchain is not present find the genesis block for the target block and use it as the current chain else if (currentBlockchain == null) { // find the genesis block for the target block var genesisBlock = targetChainedBlock; foreach (var prevBlock in PreviousChainedBlocks(targetChainedBlock)) { // cooperative loop this.shutdownToken.ThrowIfCancellationRequested(); cancelToken.ThrowIfCancellationRequested(); genesisBlock = prevBlock; } currentBlockchain = new Data.Blockchain ( blockList: ImmutableList.Create(genesisBlock), blockListHashes: ImmutableHashSet.Create(genesisBlock.BlockHash), utxo: ImmutableDictionary.Create <UInt256, UnspentTx>() ); } missingData = new List <MissingDataException>(); Debug.WriteLine("Searching for last common ancestor between current chainblock and winning chainblock"); List <UInt256> newChainBlockList; var lastCommonAncestorChain = RollbackToLastCommonAncestor(currentBlockchain, targetChainedBlock, cancelToken, out newChainBlockList); Debug.WriteLine("Last common ancestor found at block {0}, height {1:#,##0}, begin processing winning blockchain".Format2(currentBlockchain.RootBlockHash.ToHexNumberString(), currentBlockchain.Height)); // setup statistics var totalTxCount = 0L; var totalInputCount = 0L; var totalStopwatch = new Stopwatch(); var currentBlockCount = 0L; var currentTxCount = 0L; var currentInputCount = 0L; var currentRateStopwatch = new Stopwatch(); totalStopwatch.Start(); currentRateStopwatch.Start(); // with last common ancestor found and utxo rolled back to that point, calculate the new blockchain // use ImmutableList for BlockList during modification var newBlockchain = new Data.Blockchain ( blockList: lastCommonAncestorChain.BlockList, blockListHashes: lastCommonAncestorChain.BlockListHashes, utxo: lastCommonAncestorChain.Utxo ); // start calculating new utxo foreach (var tuple in BlockAndTxLookAhead(newChainBlockList)) { // cooperative loop this.shutdownToken.ThrowIfCancellationRequested(); cancelToken.ThrowIfCancellationRequested(); try { // get block and metadata for next link in blockchain var nextBlock = tuple.Item1; var nextChainedBlock = tuple.Item2; // calculate the new block utxo, double spends will be checked for ImmutableDictionary <UInt256, ImmutableHashSet <int> > newTransactions = ImmutableDictionary.Create <UInt256, ImmutableHashSet <int> >(); long txCount = 0, inputCount = 0; var newUtxo = new MethodTimer(false).Time("CalculateUtxo", () => CalculateUtxo(nextChainedBlock.Height, nextBlock, newBlockchain.Utxo, out newTransactions, out txCount, out inputCount)); var nextBlockchain = new MethodTimer(false).Time("nextBlockchain", () => new Data.Blockchain ( blockList: newBlockchain.BlockList.Add(nextChainedBlock), blockListHashes: newBlockchain.BlockListHashes.Add(nextChainedBlock.BlockHash), utxo: newUtxo )); // validate the block // validation utxo includes all transactions added in the same block, any double spends will have failed the block above validateStopwatch.Start(); new MethodTimer(false).Time("ValidateBlock", () => this.Rules.ValidateBlock(nextBlock, nextBlockchain, newBlockchain.Utxo, newTransactions)); validateStopwatch.Stop(); // create the next link in the new blockchain newBlockchain = nextBlockchain; if (onProgress != null) { onProgress(newBlockchain); } // blockchain processing statistics currentBlockCount++; currentTxCount += txCount; currentInputCount += inputCount; totalTxCount += txCount; totalInputCount += inputCount; var txInterval = 100.THOUSAND(); if ( newBlockchain.Height % 10.THOUSAND() == 0 || (totalTxCount % txInterval < (totalTxCount - txCount) % txInterval || txCount >= txInterval)) { LogBlockchainProgress(newBlockchain, totalStopwatch, totalTxCount, totalInputCount, currentRateStopwatch, currentBlockCount, currentTxCount, currentInputCount); currentBlockCount = 0; currentTxCount = 0; currentInputCount = 0; currentRateStopwatch.Reset(); currentRateStopwatch.Start(); } } catch (MissingDataException e) { // if there is missing data once blockchain processing has started, return the current progress missingData.Add(e); break; } catch (AggregateException e) { if (e.InnerExceptions.Any(x => !(x is MissingDataException))) { throw; } else { missingData.AddRange(e.InnerExceptions.OfType <MissingDataException>()); break; } } } if (onProgress != null) { onProgress(newBlockchain); } LogBlockchainProgress(newBlockchain, totalStopwatch, totalTxCount, totalInputCount, currentRateStopwatch, currentBlockCount, currentTxCount, currentInputCount); return(newBlockchain); }
private bool WorkActionInner() { var targetBlockLocal = this.targetBlockWorker.TargetBlock; Chain targetChainLocal; if (this.rescanEvent.WaitOne(0)) { targetChainLocal = null; } else { targetChainLocal = this.targetChain; } if (targetBlockLocal != null && (targetChainLocal == null || targetBlockLocal.Hash != targetChainLocal.LastBlock.Hash)) { var newTargetChain = targetChainLocal != null ? targetChainLocal.ToBuilder() : new ChainBuilder(Chain.CreateForGenesisBlock(this.rules.GenesisChainedHeader)); var deltaBlockPath = new MethodTimer(false).Time("deltaBlockPath", () => new BlockchainWalker().GetBlockchainPath(newTargetChain.LastBlock, targetBlockLocal, blockHash => this.chainedHeaderCache[blockHash])); foreach (var rewindBlock in deltaBlockPath.RewindBlocks) { if (this.invalidBlockCache.ContainsKey(rewindBlock.Hash)) { this.rescanEvent.Set(); return(true); } newTargetChain.RemoveBlock(rewindBlock); } var invalid = false; foreach (var advanceBlock in deltaBlockPath.AdvanceBlocks) { if (this.invalidBlockCache.ContainsKey(advanceBlock.Hash)) { invalid = true; } if (!invalid) { newTargetChain.AddBlock(advanceBlock); } else { this.invalidBlockCache.TryAdd(advanceBlock.Hash, ""); } } this.logger.Debug("Winning chained block {0} at height {1}, total work: {2}".Format2(newTargetChain.LastBlock.Hash.ToHexNumberString(), newTargetChain.Height, newTargetChain.LastBlock.TotalWork.ToString("X"))); this.targetChain = newTargetChain.ToImmutable(); var handler = this.OnTargetChainChanged; if (handler != null) { handler(); } } return(false); }