예제 #1
0
파일: Program.cs 프로젝트: k911mipt/clope
        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();
    }
예제 #3
0
        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();
        }
예제 #4
0
        public async Task InitializeAsync()
        {
            using (BenchmarkLogger.Measure())
            {
                var initTasks = new[]
                {
                    IndexStore.InitializeAsync(),
                    TransactionStore.InitializeAsync()
                };

                await Task.WhenAll(initTasks).ConfigureAwait(false);

                IsInitialized = true;
            }
        }
예제 #5
0
        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);
        }
예제 #6
0
        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;
            }
        }
예제 #7
0
        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;
            }
        }
예제 #9
0
        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);
        }
예제 #10
0
        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);
 }
예제 #12
0
        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);
                            }
                        });
                    }
                }
            });
        }
예제 #13
0
        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);
        }
예제 #14
0
        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();
        }
예제 #15
0
        public async ValueTask DisposeAsync()
        {
            await IndexStore.DisposeAsync().ConfigureAwait(false);

            await TransactionStore.DisposeAsync().ConfigureAwait(false);
        }
예제 #16
0
        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);
        }
예제 #17
0
        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}");
            }
        }
예제 #18
0
        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);
        }
예제 #19
0
        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");
        }
예제 #20
0
        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);
        }
예제 #21
0
        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);
            });
        }