private static void RunAlgoDemonstration() { var fileSource = new FileDataSource(_databasePath); var ruleSet = new RuleSet <string>(s => s.Split(','), new[] { (object)'?' }, new[] { _clusterColumnNumber }); var transactionStore = new TransactionStore <string>(fileSource, ruleSet); var clope = new clope.Clope(transactionStore, _repulsion); StartTimer(); transactionStore.InitStore(); StopTimerAndLogResult("Store initialization"); StartTimer(); var tableClusters = clope.Run(); StopTimerAndLogResult("Algorithm job"); ruleSet.Update(s => s.Split(','), new[] { (object)'?' }, new int[] { }); var display = new Display(0, transactionStore, tableClusters); display.Out(); if (_outputFileName == "") { return; } using (System.IO.StreamWriter file = new System.IO.StreamWriter(_outputFileName)) foreach (int num in tableClusters) { file.WriteLine(num.ToString()); } }
public AllTransactionStore(string workFolderPath, Network network) { WorkFolderPath = Guard.NotNullOrEmptyOrWhitespace(nameof(workFolderPath), workFolderPath, trim: true); IoHelpers.EnsureDirectoryExists(WorkFolderPath); Network = Guard.NotNull(nameof(network), network); MempoolStore = new TransactionStore(); ConfirmedStore = new TransactionStore(); }
static void Main(string[] args) { var transactionStore = new TransactionStore(new Clock()); var statementPrinter = new StatementPrinter(new DefaultConsole()); var account = new Account(transactionStore, statementPrinter); account.Deposit(1000); account.Withdraw(100); account.Deposit(500); account.PrintStatement(); System.Console.ReadLine(); }
public async Task InitializeAsync() { using (BenchmarkLogger.Measure()) { var initTasks = new[] { IndexStore.InitializeAsync(), TransactionStore.InitializeAsync() }; await Task.WhenAll(initTasks).ConfigureAwait(false); IsInitialized = true; } }
private static async Task <TransactionStore> CreateTransactionStoreAsync([CallerFilePath] string callerFilePath = "", [CallerMemberName] string callerMemberName = "") { // Make sure starts with clear state. var dir = Path.Combine(Common.GetWorkDir(callerFilePath, callerMemberName)); var filePath = Path.Combine(dir, "Transactions.dat"); if (File.Exists(filePath)) { File.Delete(filePath); } var txStore = new TransactionStore(); await txStore.InitializeAsync(dir, Network.Main, $"{nameof(TransactionStore)}.{nameof(TransactionStore.InitializeAsync)}", CancellationToken.None); return(txStore); }
public async Task InitializeAsync(CancellationToken cancel = default) { using (BenchmarkLogger.Measure()) { var initTasks = new[] { IndexStore.InitializeAsync(cancel), TransactionStore.InitializeAsync(cancel: cancel) }; await Task.WhenAll(initTasks).ConfigureAwait(false); IsInitialized = true; } }
public PieDatabase(TransactionStore store, SerializerSettings settings = null, Func<DataStore> createDataStore = null) { settings = settings ?? new SerializerSettings(); createDataStore = createDataStore ?? (() => new DataStore(settings)); var writeTransaction = new Func<GenericTransaction<DataStore>, string>( tran => JsonConvert.SerializeObject(tran, settings)) .Then(Funcs.AppendStringToStream); var readTransactions = Funcs.StreamToStreamReader.Then(Funcs.ReadStringsFromStreamReader) .ThenForEach( str => JsonConvert.DeserializeObject<GenericTransaction<DataStore>>(str, settings)); _transactionLog = new TransactionLog<DataStore>(createDataStore, writeTransaction, readTransactions, store); DataStore = new Lazy<DataStore>(() => _transactionLog.Value); }
public async Task InitializeAsync() { using (BenchmarkLogger.Measure()) { var networkWorkFolderPath = Path.Combine(WorkFolderPath, Network.ToString()); var indexStoreFolderPath = Path.Combine(networkWorkFolderPath, "IndexStore"); var initTasks = new[] { IndexStore.InitializeAsync(indexStoreFolderPath), TransactionStore.InitializeAsync(networkWorkFolderPath, Network) }; await Task.WhenAll(initTasks).ConfigureAwait(false); IsInitialized = true; } }
public PieDatabase(TransactionStore store, SerializerSettings settings = null, Func <DataStore> createDataStore = null) { settings = settings ?? new SerializerSettings(); createDataStore = createDataStore ?? (() => new DataStore(settings)); var writeTransaction = new Func <GenericTransaction <DataStore>, string>( tran => JsonConvert.SerializeObject(tran, settings)) .Then(Funcs.AppendStringToStream); var readTransactions = Funcs.StreamToStreamReader.Then(Funcs.ReadStringsFromStreamReader) .ThenForEach( str => JsonConvert.DeserializeObject <GenericTransaction <DataStore> >(str, settings)); _transactionLog = new TransactionLog <DataStore>(createDataStore, writeTransaction, readTransactions, store); DataStore = new Lazy <DataStore>(() => _transactionLog.Value); }
private static ISealEngine ConfigureSealEngine(TransactionStore transactionStore, EthereumSigner ethereumSigner, InitParams initParams) { var blockMiningTime = TimeSpan.FromMilliseconds(initParams.FakeMiningDelay ?? 12000); // var sealEngine = new EthashSealEngine(new Ethash()); var sealEngine = new FakeSealEngine(blockMiningTime, false); sealEngine.IsMining = initParams.IsMining ?? false; if (sealEngine.IsMining) { var transactionDelay = TimeSpan.FromMilliseconds((initParams.FakeMiningDelay ?? 12000) / 4); TestTransactionsGenerator testTransactionsGenerator = new TestTransactionsGenerator(transactionStore, ethereumSigner, transactionDelay, _logManager); // stateProvider.CreateAccount(testTransactionsGenerator.SenderAddress, 1000.Ether()); // stateProvider.Commit(specProvider.GenesisSpec); testTransactionsGenerator.Start(); } return(sealEngine); }
public void Setup() { _clock = Substitute.For <IClock>(); _transactionStore = new TransactionStore(_clock); }
private async Task StartProcessing(BlockTree blockTree, TransactionStore transactionStore, BlockValidator blockValidator, HeaderValidator headerValidator, TransactionValidator txValidator, InitParams initParams) { await blockTree.LoadBlocksFromDb(_runnerCancellation.Token).ContinueWith(async t => { if (t.IsFaulted) { if (_logger.IsErrorEnabled) { _logger.Error("Loading blocks from DB failed.", t.Exception); } } else if (t.IsCanceled) { if (_logger.IsWarnEnabled) { _logger.Warn("Loading blocks from DB cancelled."); } } else { if (_logger.IsInfoEnabled) { _logger.Info("Loaded all blocks from DB"); } if (!initParams.SynchronizationEnabled) { if (_logger.IsInfoEnabled) { _logger.Info("Synchronization disabled."); } } else { if (_logger.IsInfoEnabled) { _logger.Info($"Starting synchronization from block {blockTree.Head.ToString(BlockHeader.Format.Short)}."); } // TODO: only start sync manager after queued blocks are processed _syncManager = new SynchronizationManager( blockTree, blockValidator, headerValidator, transactionStore, txValidator, _logger, new BlockchainConfig()); _syncManager.Start(); await InitNet(initParams.P2PPort ?? 30303).ContinueWith(initNetTask => { if (initNetTask.IsFaulted) { _logger.Error("Unable to initialize network layer.", initNetTask.Exception); } }); if (initParams.DiscoveryEnabled) { await InitDiscovery(initParams).ContinueWith(initDiscoveryTask => { if (initDiscoveryTask.IsFaulted) { _logger.Error("Unable to initialize discovery protocol.", initDiscoveryTask.Exception); } }); } else if (_logger.IsInfoEnabled) { _logger.Info("Discovery protocol disabled"); } await InitPeerManager().ContinueWith(initPeerManagerTask => { if (initPeerManagerTask.IsFaulted) { _logger.Error("Unable to initialize peer manager.", initPeerManagerTask.Exception); } }); } } }); }
private async Task InitBlockchain(InitParams initParams) { ChainSpec chainSpec = LoadChainSpec(initParams.ChainSpecPath); /* spec */ // TODO: rebuild to use chainspec ISpecProvider specProvider; if (chainSpec.ChainId == RopstenSpecProvider.Instance.ChainId) { specProvider = RopstenSpecProvider.Instance; } else if (chainSpec.ChainId == MainNetSpecProvider.Instance.ChainId) { specProvider = MainNetSpecProvider.Instance; } else { throw new NotSupportedException($"Not yet tested, not yet supported ChainId {chainSpec.ChainId}"); } var ethereumSigner = new EthereumSigner(specProvider, _logManager); var transactionStore = new TransactionStore(); var sealEngine = ConfigureSealEngine(transactionStore, ethereumSigner, initParams); /* sync */ var blocksDb = new DbOnTheRocks(Path.Combine(_dbBasePath, DbOnTheRocks.BlocksDbPath)); var blockInfosDb = new DbOnTheRocks(Path.Combine(_dbBasePath, DbOnTheRocks.BlockInfosDbPath)); var receiptsDb = new DbOnTheRocks(Path.Combine(_dbBasePath, DbOnTheRocks.ReceiptsDbPath)); /* blockchain */ var blockTree = new BlockTree(blocksDb, blockInfosDb, receiptsDb, specProvider, _logManager); var difficultyCalculator = new DifficultyCalculator(specProvider); /* validation */ var headerValidator = new HeaderValidator(difficultyCalculator, blockTree, sealEngine, specProvider, _logManager); var ommersValidator = new OmmersValidator(blockTree, headerValidator, _logManager); var txValidator = new TransactionValidator(new SignatureValidator(specProvider.ChainId)); var blockValidator = new BlockValidator(txValidator, headerValidator, ommersValidator, specProvider, _logManager); /* state */ var dbProvider = new RocksDbProvider(_dbBasePath, _logManager); var codeDb = new DbOnTheRocks(Path.Combine(_dbBasePath, DbOnTheRocks.CodeDbPath)); var stateDb = new DbOnTheRocks(Path.Combine(_dbBasePath, DbOnTheRocks.StateDbPath)); var stateTree = new StateTree(stateDb); var stateProvider = new StateProvider(stateTree, codeDb, _logManager); var storageProvider = new StorageProvider(dbProvider, stateProvider, _logManager); /* blockchain processing */ var blockhashProvider = new BlockhashProvider(blockTree); var virtualMachine = new VirtualMachine(stateProvider, storageProvider, blockhashProvider, _logManager); var transactionProcessor = new TransactionProcessor(specProvider, stateProvider, storageProvider, virtualMachine, _tracer, _logManager); var rewardCalculator = new RewardCalculator(specProvider); var blockProcessor = new BlockProcessor(specProvider, blockValidator, rewardCalculator, transactionProcessor, dbProvider, stateProvider, storageProvider, transactionStore, _logManager); _blockchainProcessor = new BlockchainProcessor(blockTree, sealEngine, transactionStore, difficultyCalculator, blockProcessor, ethereumSigner, _logManager); // create shared objects between discovery and peer manager _nodeFactory = new NodeFactory(); _nodeStatsProvider = new NodeStatsProvider(_configProvider); var jsonSerializer = new JsonSerializer(_logManager); var encrypter = new AesEncrypter(_configProvider, _logManager); _keyStore = new FileKeyStore(_configProvider, jsonSerializer, encrypter, _cryptoRandom, _logManager); //creating blockchain bridge BlockchainBridge = new BlockchainBridge(ethereumSigner, stateProvider, _keyStore, blockTree, stateDb, transactionStore); EthereumSigner = ethereumSigner; _blockchainProcessor.Start(); LoadGenesisBlock(chainSpec, string.IsNullOrWhiteSpace(initParams.GenesisHash) ? null : new Keccak(initParams.GenesisHash), blockTree, stateProvider, specProvider); await StartProcessing(blockTree, transactionStore, blockValidator, headerValidator, txValidator, initParams); }
private static void InitBlockchain(ChainSpec chainSpec, bool isMining, int miningDelay) { /* spec */ var blockMiningTime = TimeSpan.FromMilliseconds(miningDelay); var transactionDelay = TimeSpan.FromMilliseconds(miningDelay / 4); var specProvider = RopstenSpecProvider.Instance; var difficultyCalculator = new DifficultyCalculator(specProvider); // var sealEngine = new EthashSealEngine(new Ethash()); var sealEngine = new FakeSealEngine(blockMiningTime, false); /* sync */ var transactionStore = new TransactionStore(); var blockTree = new BlockTree(RopstenSpecProvider.Instance, ChainLogger); /* validation */ var headerValidator = new HeaderValidator(difficultyCalculator, blockTree, sealEngine, specProvider, ChainLogger); var ommersValidator = new OmmersValidator(blockTree, headerValidator, ChainLogger); var txValidator = new TransactionValidator(new SignatureValidator(ChainId.Ropsten)); var blockValidator = new BlockValidator(txValidator, headerValidator, ommersValidator, specProvider, ChainLogger); /* state */ var dbProvider = new DbProvider(StateLogger); var codeDb = new InMemoryDb(); var stateDb = new InMemoryDb(); var stateTree = new StateTree(stateDb); var stateProvider = new StateProvider(stateTree, StateLogger, codeDb); var storageProvider = new StorageProvider(dbProvider, stateProvider, StateLogger); var storageDbProvider = new DbProvider(StateLogger); /* blockchain */ var ethereumSigner = new EthereumSigner(specProvider, ChainLogger); /* blockchain processing */ var blockhashProvider = new BlockhashProvider(blockTree); var virtualMachine = new VirtualMachine(specProvider, stateProvider, storageProvider, blockhashProvider, EvmLogger); var transactionProcessor = new TransactionProcessor(specProvider, stateProvider, storageProvider, virtualMachine, ethereumSigner, ChainLogger); var rewardCalculator = new RewardCalculator(specProvider); var blockProcessor = new BlockProcessor(specProvider, blockValidator, rewardCalculator, transactionProcessor, storageDbProvider, stateProvider, storageProvider, transactionStore, ChainLogger); _blockchainProcessor = new BlockchainProcessor(blockTree, sealEngine, transactionStore, difficultyCalculator, blockProcessor, ChainLogger); /* genesis */ foreach (KeyValuePair <Address, BigInteger> allocation in chainSpec.Allocations) { stateProvider.CreateAccount(allocation.Key, allocation.Value); } stateProvider.Commit(specProvider.GenesisSpec); var testTransactionsGenerator = new TestTransactionsGenerator(transactionStore, ethereumSigner, transactionDelay, ChainLogger); stateProvider.CreateAccount(testTransactionsGenerator.SenderAddress, 1000.Ether()); stateProvider.Commit(specProvider.GenesisSpec); if (isMining) { testTransactionsGenerator.Start(); } Block genesis = chainSpec.Genesis; genesis.Header.StateRoot = stateProvider.StateRoot; genesis.Header.RecomputeHash(); // we are adding test transactions account so the state root will change (not an actual ropsten at the moment) // var expectedGenesisHash = "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"; // if (chainSpec.Genesis.Hash != new Keccak(expectedGenesisHash)) // { // throw new Exception($"Unexpected genesis hash for Ropsten, expected {expectedGenesisHash}, but was {chainSpec.Genesis.Hash}"); // } /* start test processing */ sealEngine.IsMining = isMining; _blockchainProcessor.Start(); blockTree.AddBlock(genesis); _syncManager = new SynchronizationManager( blockTree, blockValidator, headerValidator, transactionStore, txValidator, NetworkLogger); _syncManager.Start(); }
public async ValueTask DisposeAsync() { await IndexStore.DisposeAsync().ConfigureAwait(false); await TransactionStore.DisposeAsync().ConfigureAwait(false); }
private async Task InitBlockchain() { ChainSpec chainSpec = LoadChainSpec(_initConfig.ChainSpecPath); /* spec */ // TODO: rebuild to use chainspec ISpecProvider specProvider; if (chainSpec.ChainId == RopstenSpecProvider.Instance.ChainId) { specProvider = RopstenSpecProvider.Instance; } else if (chainSpec.ChainId == MainNetSpecProvider.Instance.ChainId) { specProvider = MainNetSpecProvider.Instance; } else { throw new NotSupportedException($"Not yet tested, not yet supported ChainId {chainSpec.ChainId}"); } var ethereumSigner = new EthereumSigner( specProvider, _logManager); var transactionStore = new TransactionStore(); var sealEngine = ConfigureSealEngine( transactionStore, ethereumSigner); /* sync */ IDbConfig dbConfig = _configProvider.GetConfig <IDbConfig>(); foreach (PropertyInfo propertyInfo in typeof(IDbConfig).GetProperties()) { _logger.Info($"DB {propertyInfo.Name}: {propertyInfo.GetValue(dbConfig)}"); } var blocksDb = new DbOnTheRocks( Path.Combine(_dbBasePath, DbOnTheRocks.BlocksDbPath), dbConfig); var blockInfosDb = new DbOnTheRocks( Path.Combine(_dbBasePath, DbOnTheRocks.BlockInfosDbPath), dbConfig); var receiptsDb = new DbOnTheRocks( Path.Combine(_dbBasePath, DbOnTheRocks.ReceiptsDbPath), dbConfig); /* blockchain */ _blockTree = new BlockTree( blocksDb, blockInfosDb, receiptsDb, specProvider, _logManager); var difficultyCalculator = new DifficultyCalculator( specProvider); /* validation */ var headerValidator = new HeaderValidator( difficultyCalculator, _blockTree, sealEngine, specProvider, _logManager); var ommersValidator = new OmmersValidator( _blockTree, headerValidator, _logManager); var txValidator = new TransactionValidator( new SignatureValidator(specProvider.ChainId)); var blockValidator = new BlockValidator( txValidator, headerValidator, ommersValidator, specProvider, _logManager); /* state */ var dbProvider = new RocksDbProvider( _dbBasePath, _logManager, dbConfig); var stateDb = dbProvider.GetOrCreateStateDb(); var stateTree = new StateTree(stateDb); var stateProvider = new StateProvider( stateTree, dbProvider.GetOrCreateCodeDb(), _logManager); var storageProvider = new StorageProvider( dbProvider, stateProvider, _logManager); /* blockchain processing */ var blockhashProvider = new BlockhashProvider( _blockTree); var virtualMachine = new VirtualMachine( stateProvider, storageProvider, blockhashProvider, _logManager); var transactionProcessor = new TransactionProcessor( specProvider, stateProvider, storageProvider, virtualMachine, _tracer, _logManager); var rewardCalculator = new RewardCalculator( specProvider); var blockProcessor = new BlockProcessor( specProvider, blockValidator, rewardCalculator, transactionProcessor, dbProvider, stateProvider, storageProvider, transactionStore, _logManager); _blockchainProcessor = new BlockchainProcessor( _blockTree, sealEngine, transactionStore, difficultyCalculator, blockProcessor, ethereumSigner, _logManager, _perfService); // create shared objects between discovery and peer manager _nodeFactory = new NodeFactory(); _nodeStatsProvider = new NodeStatsProvider(_configProvider.GetConfig <IStatsConfig>(), _nodeFactory, _logManager); var jsonSerializer = new JsonSerializer( _logManager); var encrypter = new AesEncrypter( _configProvider, _logManager); _keyStore = new FileKeyStore( _configProvider, jsonSerializer, encrypter, _cryptoRandom, _logManager); //creating blockchain bridge BlockchainBridge = new BlockchainBridge( ethereumSigner, stateProvider, _keyStore, _blockTree, stateDb, transactionStore); EthereumSigner = ethereumSigner; _blockchainProcessor.Start(); LoadGenesisBlock(chainSpec, string.IsNullOrWhiteSpace(_initConfig.GenesisHash) ? null : new Keccak(_initConfig.GenesisHash), _blockTree, stateProvider, specProvider); #pragma warning disable 4014 LoadBlocksFromDb(); #pragma warning restore 4014 await InitializeNetwork( transactionStore, blockValidator, headerValidator, txValidator); }
private async Task InitializeNetwork( TransactionStore transactionStore, BlockValidator blockValidator, HeaderValidator headerValidator, TransactionValidator txValidator) { if (!_initConfig.NetworkEnabled) { if (_logger.IsInfo) { _logger.Info($"Skipping blockchain synchronization init ({nameof(IInitConfig.NetworkEnabled)} = false)"); } return; } _syncManager = new SynchronizationManager( _blockTree, blockValidator, headerValidator, transactionStore, txValidator, _logManager, _configProvider.GetConfig <IBlockchainConfig>(), _perfService); InitDiscovery(); await InitPeer(); await StartSync().ContinueWith(initNetTask => { if (initNetTask.IsFaulted) { _logger.Error("Unable to start sync.", initNetTask.Exception); } }); await StartDiscovery().ContinueWith(initDiscoveryTask => { if (initDiscoveryTask.IsFaulted) { _logger.Error("Unable to start discovery protocol.", initDiscoveryTask.Exception); } }); await StartPeer().ContinueWith(initPeerManagerTask => { if (initPeerManagerTask.IsFaulted) { _logger.Error("Unable to start peer manager.", initPeerManagerTask.Exception); } }); var localIp = _networkHelper.GetLocalIp(); if (_logger.IsInfo) { _logger.Info($"Node is up and listening on {localIp}:{_initConfig.P2PPort}"); } if (_logger.IsInfo) { _logger.Info($"enode://{_privateKey.PublicKey}@{localIp}:{_initConfig.P2PPort}"); } }
protected async Task RunTest(BlockchainTest test, Stopwatch stopwatch = null) { LoggingTraceListener traceListener = new LoggingTraceListener(); // TODO: not supported in .NET Core, need to replace? // Debug.Listeners.Clear(); // Debug.Listeners.Add(traceListener); IDbProvider dbProvider = new MemDbProvider(_logManager); StateTree stateTree = new StateTree(dbProvider.GetOrCreateStateDb()); ISpecProvider specProvider; if (test.NetworkAfterTransition != null) { specProvider = new CustomSpecProvider( (0, Frontier.Instance), (1, test.Network), (test.TransitionBlockNumber, test.NetworkAfterTransition)); } else { specProvider = new CustomSpecProvider( (0, Frontier.Instance), // TODO: this thing took a lot of time to find after it was removed!, genesis block is always initialized with Frontier (1, test.Network)); } if (specProvider.GenesisSpec != Frontier.Instance) { Assert.Fail("Expected genesis spec to be Frontier for blockchain tests"); } IDifficultyCalculator difficultyCalculator = new DifficultyCalculator(specProvider); IRewardCalculator rewardCalculator = new RewardCalculator(specProvider); IBlockTree blockTree = new BlockTree(new MemDb(), new MemDb(), new MemDb(), specProvider, _logManager); IBlockhashProvider blockhashProvider = new BlockhashProvider(blockTree); ISignatureValidator signatureValidator = new SignatureValidator(ChainId.MainNet); ITransactionValidator transactionValidator = new TransactionValidator(signatureValidator); IHeaderValidator headerValidator = new HeaderValidator(difficultyCalculator, blockTree, SealEngine, specProvider, _logManager); IOmmersValidator ommersValidator = new OmmersValidator(blockTree, headerValidator, _logManager); IBlockValidator blockValidator = new BlockValidator(transactionValidator, headerValidator, ommersValidator, specProvider, _logManager); IStateProvider stateProvider = new StateProvider(stateTree, dbProvider.GetOrCreateCodeDb(), _logManager); IStorageProvider storageProvider = new StorageProvider(dbProvider, stateProvider, _logManager); IVirtualMachine virtualMachine = new VirtualMachine( stateProvider, storageProvider, blockhashProvider, _logManager); ISealEngine sealEngine = new EthashSealEngine(new Ethash(_logManager), _logManager); ITransactionStore transactionStore = new TransactionStore(); IEthereumSigner signer = new EthereumSigner(specProvider, _logManager); IBlockProcessor blockProcessor = new BlockProcessor( specProvider, blockValidator, rewardCalculator, new TransactionProcessor( specProvider, stateProvider, storageProvider, virtualMachine, NullTracer.Instance, _logManager), dbProvider, stateProvider, storageProvider, transactionStore, _logManager); IBlockchainProcessor blockchainProcessor = new BlockchainProcessor(blockTree, sealEngine, transactionStore, difficultyCalculator, blockProcessor, signer, _logManager); InitializeTestState(test, stateProvider, storageProvider, specProvider); List <(Block Block, string ExpectedException)> correctRlpsBlocks = new List <(Block, string)>(); for (int i = 0; i < test.Blocks.Length; i++) { try { TestBlockJson testBlockJson = test.Blocks[i]; var rlpContext = Hex.ToBytes(testBlockJson.Rlp).AsRlpContext(); Block suggestedBlock = Rlp.Decode <Block>(rlpContext); Assert.AreEqual(new Keccak(testBlockJson.BlockHeader.Hash), suggestedBlock.Header.Hash, "hash of the block"); for (int ommerIndex = 0; ommerIndex < suggestedBlock.Ommers.Length; ommerIndex++) { Assert.AreEqual(new Keccak(testBlockJson.UncleHeaders[ommerIndex].Hash), suggestedBlock.Ommers[ommerIndex].Hash, "hash of the ommer"); } correctRlpsBlocks.Add((suggestedBlock, testBlockJson.ExpectedException)); } catch (Exception e) { _logger?.Info($"Invalid RLP ({i})"); } } if (correctRlpsBlocks.Count == 0) { Assert.AreEqual(new Keccak(test.GenesisBlockHeader.Hash), test.LastBlockHash); return; } if (test.GenesisRlp == null) { test.GenesisRlp = Rlp.Encode(new Block(Convert(test.GenesisBlockHeader))); } Block genesisBlock = Rlp.Decode <Block>(test.GenesisRlp.Bytes); Assert.AreEqual(new Keccak(test.GenesisBlockHeader.Hash), genesisBlock.Header.Hash, "genesis header hash"); blockTree.NewHeadBlock += (sender, args) => { if (args.Block.Number == 0) { Assert.AreEqual(genesisBlock.Header.StateRoot, stateTree.RootHash, "genesis state root"); } }; blockchainProcessor.Start(); blockTree.SuggestBlock(genesisBlock); for (int i = 0; i < correctRlpsBlocks.Count; i++) { stopwatch?.Start(); try { if (correctRlpsBlocks[i].ExpectedException != null) { _logger.Info($"Expecting block exception: {correctRlpsBlocks[i].ExpectedException}"); } if (correctRlpsBlocks[i].Block.Hash == null) { throw new Exception($"null hash in {test.Name} block {i}"); } // TODO: mimic the actual behaviour where block goes through validating sync manager? if (blockValidator.ValidateSuggestedBlock(correctRlpsBlocks[i].Block)) { blockTree.SuggestBlock(correctRlpsBlocks[i].Block); } else { Console.WriteLine("Invalid block"); } } catch (InvalidBlockException ex) { } catch (Exception ex) { _logger?.Info(ex.ToString()); } } await blockchainProcessor.StopAsync(true); stopwatch?.Stop(); RunAssertions(test, blockTree.RetrieveHeadBlock(), storageProvider, stateProvider); }
public async Task Build_some_chain() { /* logging & instrumentation */ var logger = new OneLoggerLogManager(new SimpleConsoleLogger()); /* spec */ var blockMiningTime = TimeSpan.FromMilliseconds(500); var sealEngine = new FakeSealEngine(blockMiningTime); var specProvider = RopstenSpecProvider.Instance; /* store & validation */ var blockTree = new BlockTree(new MemDb(), new MemDb(), new MemDb(), specProvider, logger); var difficultyCalculator = new DifficultyCalculator(specProvider); var headerValidator = new HeaderValidator(difficultyCalculator, blockTree, sealEngine, specProvider, logger); var ommersValidator = new OmmersValidator(blockTree, headerValidator, logger); var transactionValidator = new TransactionValidator(new SignatureValidator(ChainId.Ropsten)); var blockValidator = new BlockValidator(transactionValidator, headerValidator, ommersValidator, specProvider, logger); /* state & storage */ var dbProvider = new MemDbProvider(logger); var stateTree = new StateTree(dbProvider.GetOrCreateStateDb()); var stateProvider = new StateProvider(stateTree, dbProvider.GetOrCreateCodeDb(), logger); var storageProvider = new StorageProvider(dbProvider, stateProvider, logger); /* blockchain processing */ var ethereumSigner = new EthereumSigner(specProvider, logger); var transactionStore = new TransactionStore(); var blockhashProvider = new BlockhashProvider(blockTree); var virtualMachine = new VirtualMachine(stateProvider, storageProvider, blockhashProvider, logger); var processor = new TransactionProcessor(specProvider, stateProvider, storageProvider, virtualMachine, NullTracer.Instance, logger); var rewardCalculator = new RewardCalculator(specProvider); var blockProcessor = new BlockProcessor(specProvider, blockValidator, rewardCalculator, processor, dbProvider, stateProvider, storageProvider, transactionStore, logger); var blockchainProcessor = new BlockchainProcessor(blockTree, sealEngine, transactionStore, difficultyCalculator, blockProcessor, ethereumSigner, logger); /* load ChainSpec and init */ ChainSpecLoader loader = new ChainSpecLoader(new UnforgivingJsonSerializer()); string path = Path.Combine(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\Chains", "ropsten.json")); logger.GetClassLogger().Info($"Loading ChainSpec from {path}"); ChainSpec chainSpec = loader.Load(File.ReadAllBytes(path)); foreach (KeyValuePair <Address, BigInteger> allocation in chainSpec.Allocations) { stateProvider.CreateAccount(allocation.Key, allocation.Value); } stateProvider.Commit(specProvider.GenesisSpec); chainSpec.Genesis.Header.StateRoot = stateProvider.StateRoot; // TODO: shall it be HeaderSpec and not BlockHeader? chainSpec.Genesis.Header.Hash = BlockHeader.CalculateHash(chainSpec.Genesis.Header); if (chainSpec.Genesis.Hash != new Keccak("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d")) { throw new Exception("Unexpected genesis hash"); } /* start processing */ sealEngine.IsMining = true; var testTransactionsGenerator = new TestTransactionsGenerator(transactionStore, ethereumSigner, blockMiningTime, logger); testTransactionsGenerator.Start(); blockchainProcessor.Start(); blockTree.SuggestBlock(chainSpec.Genesis); BigInteger roughlyNumberOfBlocks = 6; Thread.Sleep(blockMiningTime * (int)roughlyNumberOfBlocks); await blockchainProcessor.StopAsync(false); Assert.GreaterOrEqual(blockTree.Head.Number, roughlyNumberOfBlocks - 2, "number of blocks"); Assert.GreaterOrEqual(blockTree.Head.TotalTransactions, roughlyNumberOfBlocks - 2, "number of transactions"); }
public bool Process(SmartTransaction tx) { if (!tx.Transaction.PossiblyP2WPKHInvolved()) { return(false); // We do not care about non-witness transactions for other than mempool cleanup. } uint256 txId = tx.GetHash(); var walletRelevant = false; if (tx.Confirmed) { foreach (var coin in Coins.Where(x => x.TransactionId == txId)) { coin.Height = tx.Height; walletRelevant = true; // relevant } } if (!tx.Transaction.IsCoinBase) // Transactions we already have and processed would be "double spends" but they shouldn't. { var doubleSpends = new List <SmartCoin>(); foreach (SmartCoin coin in Coins) { var spent = false; foreach (TxoRef spentOutput in coin.SpentOutputs) { foreach (TxIn txIn in tx.Transaction.Inputs) { if (spentOutput.TransactionId == txIn.PrevOut.Hash && spentOutput.Index == txIn.PrevOut.N) // Do not do (spentOutput == txIn.PrevOut), it's faster this way, because it won't check for null. { doubleSpends.Add(coin); spent = true; walletRelevant = true; break; } } if (spent) { break; } } } if (doubleSpends.Any()) { if (tx.Height == Height.Mempool) { // if the received transaction is spending at least one input already // spent by a previous unconfirmed transaction signaling RBF then it is not a double // spanding transaction but a replacement transaction. if (doubleSpends.Any(x => x.IsReplaceable)) { // remove double spent coins (if other coin spends it, remove that too and so on) // will add later if they came to our keys foreach (SmartCoin doubleSpentCoin in doubleSpends.Where(x => !x.Confirmed)) { Coins.TryRemove(doubleSpentCoin); } tx.SetReplacement(); walletRelevant = true; } else { return(false); } } else // new confirmation always enjoys priority { // remove double spent coins recursively (if other coin spends it, remove that too and so on), will add later if they came to our keys foreach (SmartCoin doubleSpentCoin in doubleSpends) { Coins.TryRemove(doubleSpentCoin); } walletRelevant = true; } } } var isLikelyCoinJoinOutput = false; bool hasEqualOutputs = tx.Transaction.GetIndistinguishableOutputs(includeSingle: false).FirstOrDefault() != default; if (hasEqualOutputs) { var receiveKeys = KeyManager.GetKeys(x => tx.Transaction.Outputs.Any(y => y.ScriptPubKey == x.P2wpkhScript)); bool allReceivedInternal = receiveKeys.All(x => x.IsInternal); if (allReceivedInternal) { // It is likely a coinjoin if the diff between receive and sent amount is small and have at least 2 equal outputs. Money spentAmount = Coins.Where(x => tx.Transaction.Inputs.Any(y => y.PrevOut.Hash == x.TransactionId && y.PrevOut.N == x.Index)).Sum(x => x.Amount); Money receivedAmount = tx.Transaction.Outputs.Where(x => receiveKeys.Any(y => y.P2wpkhScript == x.ScriptPubKey)).Sum(x => x.Value); bool receivedAlmostAsMuchAsSpent = spentAmount.Almost(receivedAmount, Money.Coins(0.005m)); if (receivedAlmostAsMuchAsSpent) { isLikelyCoinJoinOutput = true; } } } List <SmartCoin> spentOwnCoins = null; for (var i = 0U; i < tx.Transaction.Outputs.Count; i++) { // If transaction received to any of the wallet keys: var output = tx.Transaction.Outputs[i]; HdPubKey foundKey = KeyManager.GetKeyForScriptPubKey(output.ScriptPubKey); if (foundKey != default) { walletRelevant = true; if (output.Value <= DustThreshold) { continue; } foundKey.SetKeyState(KeyState.Used, KeyManager); spentOwnCoins ??= Coins.Where(x => tx.Transaction.Inputs.Any(y => y.PrevOut.Hash == x.TransactionId && y.PrevOut.N == x.Index)).ToList(); var anonset = tx.Transaction.GetAnonymitySet(i); if (spentOwnCoins.Count != 0) { anonset += spentOwnCoins.Min(x => x.AnonymitySet) - 1; // Minus 1, because do not count own. } SmartCoin newCoin = new SmartCoin(txId, i, output.ScriptPubKey, output.Value, tx.Transaction.Inputs.ToTxoRefs().ToArray(), tx.Height, tx.IsRBF, anonset, isLikelyCoinJoinOutput, foundKey.Label, spenderTransactionId: null, false, pubKey: foundKey); // Do not inherit locked status from key, that's different. // If we did not have it. if (Coins.TryAdd(newCoin)) { CoinReceived?.Invoke(this, newCoin); // Make sure there's always 21 clean keys generated and indexed. KeyManager.AssertCleanKeysIndexed(isInternal: foundKey.IsInternal); if (foundKey.IsInternal) { // Make sure there's always 14 internal locked keys generated and indexed. KeyManager.AssertLockedInternalKeysIndexed(14); } } else // If we had this coin already. { if (newCoin.Height != Height.Mempool) // Update the height of this old coin we already had. { SmartCoin oldCoin = Coins.FirstOrDefault(x => x.TransactionId == txId && x.Index == i); if (oldCoin != null) // Just to be sure, it is a concurrent collection. { oldCoin.Height = newCoin.Height; } } } } } // If spends any of our coin for (var i = 0; i < tx.Transaction.Inputs.Count; i++) { var input = tx.Transaction.Inputs[i]; var foundCoin = Coins.FirstOrDefault(x => x.TransactionId == input.PrevOut.Hash && x.Index == input.PrevOut.N); if (foundCoin != null) { walletRelevant = true; var alreadyKnown = foundCoin.SpenderTransactionId == txId; foundCoin.SpenderTransactionId = txId; if (!alreadyKnown) { CoinSpent?.Invoke(this, foundCoin); } if (tx.Confirmed) { SpenderConfirmed?.Invoke(this, foundCoin); } } } if (walletRelevant) { TransactionStore.AddOrUpdate(tx); } return(walletRelevant); }
public async Task Test() { TimeSpan miningDelay = TimeSpan.FromMilliseconds(50); /* logging & instrumentation */ var logger = new OneLoggerLogManager(new SimpleConsoleLogger(true)); /* spec */ var sealEngine = new FakeSealEngine(miningDelay); sealEngine.IsMining = true; var specProvider = RopstenSpecProvider.Instance; /* store & validation */ var blockTree = new BlockTree(new MemDb(), new MemDb(), new MemDb(), specProvider, logger); var difficultyCalculator = new DifficultyCalculator(specProvider); var headerValidator = new HeaderValidator(difficultyCalculator, blockTree, sealEngine, specProvider, logger); var ommersValidator = new OmmersValidator(blockTree, headerValidator, logger); var transactionValidator = new TransactionValidator(new SignatureValidator(ChainId.Ropsten)); var blockValidator = new BlockValidator(transactionValidator, headerValidator, ommersValidator, specProvider, logger); /* state & storage */ var codeDb = new MemDb(); var stateDb = new MemDb(); var stateTree = new StateTree(stateDb); var stateProvider = new StateProvider(stateTree, codeDb, logger); var storageDbProvider = new MemDbProvider(logger); var storageProvider = new StorageProvider(storageDbProvider, stateProvider, logger); /* blockchain processing */ var ethereumSigner = new EthereumSigner(specProvider, logger); var transactionStore = new TransactionStore(); var blockhashProvider = new BlockhashProvider(blockTree); var virtualMachine = new VirtualMachine(stateProvider, storageProvider, blockhashProvider, logger); var processor = new TransactionProcessor(specProvider, stateProvider, storageProvider, virtualMachine, NullTracer.Instance, logger); var rewardCalculator = new RewardCalculator(specProvider); var blockProcessor = new BlockProcessor(specProvider, blockValidator, rewardCalculator, processor, storageDbProvider, stateProvider, storageProvider, transactionStore, logger); var blockchainProcessor = new BlockchainProcessor(blockTree, sealEngine, transactionStore, difficultyCalculator, blockProcessor, ethereumSigner, logger, new PerfService(NullLogManager.Instance)); /* load ChainSpec and init */ ChainSpecLoader loader = new ChainSpecLoader(new UnforgivingJsonSerializer()); string path = Path.Combine(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\Chains", "ropsten.json")); logger.GetClassLogger().Info($"Loading ChainSpec from {path}"); ChainSpec chainSpec = loader.Load(File.ReadAllBytes(path)); foreach (KeyValuePair <Address, UInt256> allocation in chainSpec.Allocations) { stateProvider.CreateAccount(allocation.Key, allocation.Value); } stateProvider.Commit(specProvider.GenesisSpec); chainSpec.Genesis.Header.StateRoot = stateProvider.StateRoot; // TODO: shall it be HeaderSpec and not BlockHeader? chainSpec.Genesis.Header.Hash = BlockHeader.CalculateHash(chainSpec.Genesis.Header); if (chainSpec.Genesis.Hash != new Keccak("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d")) { throw new Exception("Unexpected genesis hash"); } /* start processing */ blockTree.SuggestBlock(chainSpec.Genesis); blockchainProcessor.Start(); ManualResetEvent manualResetEvent = new ManualResetEvent(false); blockTree.NewHeadBlock += (sender, args) => { if (args.Block.Number == 6) { manualResetEvent.Set(); } }; manualResetEvent.WaitOne(miningDelay * 12); await blockchainProcessor.StopAsync(true).ContinueWith( t => { if (t.IsFaulted) { throw t.Exception; } Assert.GreaterOrEqual((int)blockTree.Head.Number, 6); }); }