Exemplo n.º 1
0
        public bool AddTransactionToPool(AbstractTransaction tx, bool publishToNetwork)
        {
            //_logger.LogInformation("Miner received transaction: {0}", JsonConvert.SerializeObject(tx));
            try
            {
                if (_txPool.Contains(tx))
                {
                    throw new TransactionRejectedException("Transaction already submitted to txpool");
                }

                _transactionValidator.ValidateTransaction(tx);
                _txPool.AddTransaction(tx);
                _logger.LogInformation("Added transaction to txpool ({0})", tx.Hash);

                if (publishToNetwork) // todo move this to ConcurrentTransactionPool maybe?
                {
                    EventPublisher.GetInstance().PublishValidTransactionReceived(this, new TransactionReceivedEventArgs(tx));
                }
                return(true);
            }
            catch (TransactionRejectedException e)
            {
                var errorTx = e.Transaction ?? tx;
                _logger.LogInformation("Transaction with hash {0} was rejected: {1}", errorTx.Hash, e.Message);
                return(false);
            }
            catch (Exception e)
            {
                _logger.LogInformation("An {0} occurred: {1}", e.GetType().Name, e.Message);
                return(false);
            }
        }
Exemplo n.º 2
0
 public PowBlockCreator(ITimestamper timestamper, IBlockValidator validator, IBlockFinalizer blockFinalizer, ITransactionValidator transactionValidator)
 {
     _timestamper          = timestamper ?? throw new ArgumentNullException(nameof(timestamper));
     _validator            = validator ?? throw new ArgumentNullException(nameof(validator));
     _blockFinalizer       = blockFinalizer ?? throw new ArgumentNullException(nameof(blockFinalizer));
     _transactionValidator = transactionValidator ?? throw new ArgumentNullException(nameof(transactionValidator));
     EventPublisher.GetInstance().OnValidatedBlockCreated += OnValidatedBlockCreated;
 }
Exemplo n.º 3
0
        public NetworkManager(NetworkNodesPool nodePool, ILoggerFactory loggerFactory, IBlockValidator blockValidator, IDifficultyCalculator difficultyCalculator, IBlockchainRepository repo, string netId)
        {
            _logger   = loggerFactory.CreateLogger <NetworkManager>();
            _nodePool = nodePool;
            _repo     = repo;
            _netId    = netId;
            _relayedTransactionHashes = new List <string>();
            _relayedBlockHashes       = new List <string>();
            _messageHandler           = new MessageHandler(this, ConcurrentTransactionPool.GetInstance(), nodePool, difficultyCalculator, blockValidator, loggerFactory, repo, netId);
            _handshakeMessageHandler  = new HandshakeMessageHandler(this, nodePool, loggerFactory, repo, netId);
            _delays = new ConcurrentBag <int>();

            EventPublisher.GetInstance().OnValidatedBlockCreated    += OnValidatedBlockCreated;
            EventPublisher.GetInstance().OnValidTransactionReceived += OnValidTransactionReceived;
            // In the first phase, check every 10s if there is a node that has a longer chain than ours.
            // After the sync completed, exit the 'syncing' state and accept new blocks and transactions.
            StartSyncProcess(new CancellationTokenSource()); // todo cts
        }
Exemplo n.º 4
0
        public Miner(string netId, string minerWalletPubKey, string minerWalletPrivKey,
                     IBlockchainRepository blockchainRepo, ITransactionRepository transactionRepo,
                     ITransactionCreator transactionCreator, ITransactionValidator transactionValidator,
                     IDifficultyCalculator difficultyCalculator, IPowBlockCreator blockCreator,
                     IBlockValidator blockValidator, ConcurrentTransactionPool txPool, ILoggerFactory loggerFactory)
        {
            _logger               = loggerFactory.CreateLogger <Miner>();
            _walletPubKey         = minerWalletPubKey;
            _walletPrivKey        = minerWalletPrivKey;
            _blockchainRepo       = blockchainRepo;
            _networkIdentifier    = netId;
            _blockchain           = _blockchainRepo.GetChainByNetId(_networkIdentifier);
            _transactionRepo      = transactionRepo;
            _transactionCreator   = transactionCreator;
            _transactionValidator = transactionValidator;
            _difficultyCalculator = difficultyCalculator;
            _blockCreator         = blockCreator;
            _blockValidator       = blockValidator;
            _txPool               = txPool;

            EventPublisher.GetInstance().OnUnvalidatedTransactionReceived += OnUnvalidatedTransactionReceived;
            EventPublisher.GetInstance().OnUnvalidatedBlockCreated        += OnUnvalidatedBlockCreated;
            difficulty = _difficultyCalculator.CalculateCurrentDifficulty(_blockchain);
        }
Exemplo n.º 5
0
        internal void HandleCommand()
        {
            ulong             transferFee    = TransferSupplyFee; // From BlockchainConstants.cs
            IEnumerable <Sku> skuWithHistory = null;
            var blockHash = "";
            var txIndex   = 0;

            Console.WriteLine("Current transfer supply fee is " + TransferSupplyFee + " TK.");
            while (skuWithHistory == null)
            {
                WriteLineWithInputCursor("Enter the block hash where the SKU was created:");
                blockHash = Console.ReadLine().ToUpper();

                WriteLineWithInputCursor("Enter index of the transaction where the SKU resides:");
                var txIndexInput = Console.ReadLine().ToLower();
                Int32.TryParse(txIndexInput, out txIndex);

                try
                {
                    if (blockHash == "LAST")
                    {
                        skuWithHistory = _skuRepository.GetAllWithHistory(_netId).Last();
                        blockHash      = skuWithHistory.First().Block.Header.Hash;
                    }
                    else
                    {
                        skuWithHistory = _skuRepository.GetSkuWithHistory(blockHash, txIndex, _netId);
                    }
                }
                catch (Exception)
                {
                    Console.WriteLine("The block or transaction could not be found. Try again.");
                }
            }

            Console.WriteLine("Selected " + skuWithHistory.First().Data.SkuId);
            WriteLineWithInputCursor("Enter the sender's public key:");
            var fromPub = Console.ReadLine();

            var fromPriv = Program.GetPrivKey(fromPub);

            while (String.IsNullOrWhiteSpace(fromPriv))
            {
                Console.WriteLine("Private key not found.");
                WriteLineWithInputCursor("Enter the sender's public key:");
                fromPub = Console.ReadLine();
            }

            var senderBalance = _transactionRepo.GetTokenBalanceForPubKey(fromPub, _netId);
            var skuSupply     = _skuRepository.GetSupplyBalanceForPubKey(fromPub, skuWithHistory);

            Console.WriteLine("The sender's token balance: " + senderBalance);
            Console.WriteLine("The sender's supply: " + skuSupply);


            WriteLineWithInputCursor("Enter the receiver's public key:");
            var toPub = Console.ReadLine();


            // Todo support custom fees in transactionCreator

            /*
             * var askFeeFirstTime = true;
             * var forceHigherFee = false;
             * while (transferFee < TransferSupplyFee && !forceHigherFee || askFeeFirstTime)
             * {
             *  askFeeFirstTime = false;
             *  WriteLineWithInputCursor("Use a different fee ["+ TransferSupplyFee + "]:");
             *  var feeInput = Console.ReadLine().ToLower();
             *  while (!ulong.TryParse(feeInput, out transferFee))
             *  {
             *      transferFee = TransferSupplyFee;
             *      if (feeInput != "")
             *      {
             *          WriteLineWithInputCursor("Invalid value. Use a positive numeric value without decimals.");
             *          feeInput = Console.ReadLine().ToLower();
             *      }
             *      else
             *      {
             *          break;
             *      }
             *  }
             *
             *  if (transferFee > senderBalance && !forceHigherFee)
             *  {
             *      Console.WriteLine("The given fee is higher than the sender's token balance and can cause a rejection.");
             *      WriteLineWithInputCursor("Type 'force' to use the given amount. Press ENTER to specify another amount.");
             *      feeInput = Console.ReadLine().ToLower();
             *      if (feeInput == "force")
             *      {
             *          forceHigherFee = true;
             *      }
             *  }
             * }
             */

            uint amount      = 0;
            bool forceAmount = false;

            while (amount < 1 || amount > skuSupply && !forceAmount)
            {
                WriteLineWithInputCursor("Specify the amount to transfer:");

                var amountInput = Console.ReadLine().ToLower();
                while (!UInt32.TryParse(amountInput, out amount))
                {
                    WriteLineWithInputCursor("Invalid value. Use a positive numeric value without decimals.");
                    amountInput = Console.ReadLine().ToLower();
                }

                if (amount > skuSupply && !forceAmount)
                {
                    Console.WriteLine("The given amount is higher than the sender's current supply balance and can cause a rejection.");
                    WriteLineWithInputCursor("Type 'force' to use the given amount. Press ENTER to specify another amount.");
                    amountInput = Console.ReadLine().ToLower();
                    if (amountInput == "force")
                    {
                        forceAmount = true;
                    }
                }
            }

            WriteLineWithInputCursor("Enter optional data []:");
            var optionalData = Console.ReadLine();

            AbstractTransaction transactionToSend = _transactionCreator.CreateSupplyTransferTransaction(fromPub, fromPriv, toPub, amount, blockHash, txIndex, optionalData);

            EventPublisher.GetInstance().PublishUnvalidatedTransactionReceived(this, new TransactionReceivedEventArgs(transactionToSend));
            Console.Write("> ");
        }
Exemplo n.º 6
0
        private void MineForBlocks(CancellationToken cancellationToken)
        {
            _logger.LogInformation("We want to achieve a total of {0} seconds for each {1} blocks to be created.", (BlockchainConstants.SecondsPerBlockGoal * BlockchainConstants.DifficultyUpdateCycle), BlockchainConstants.DifficultyUpdateCycle);
            _logger.LogInformation("Mining for blocks..");

            while (!cancellationToken.IsCancellationRequested)
            {
                // Every x blocks, recalculate the difficulty and save the blockchain.
                CheckForDifficultyUpdate();
                _logger.LogDebug("Current height: {0}", _blockchain.CurrentHeight);

                // Calculate our current balance
                var   allReceivedTransactions = _transactionRepo.GetAllReceivedByPublicKey(_walletPubKey, _networkIdentifier);
                ulong balance = _transactionRepo.GetTokenBalanceForPubKey(_walletPubKey, _networkIdentifier);
                _logger.LogDebug("Our balance: {0}", balance);

                // Create & add the coinbase transaction and then mine the block
                var coinbaseTx   = _transactionCreator.CreateCoinBaseTransaction(_walletPubKey, _walletPrivKey, "Mined by Montapacking!");
                var transactions = new List <AbstractTransaction>()
                {
                    coinbaseTx
                };
                lock (_txPool)
                {
                    int transactionsIncludedInBlock = _txPool.Count();
                    transactions.AddRange(_txPool.GetTransactions(maxTransactionsPerBlock - 1));
                    _logger.LogDebug("Inserted {0} transactions from the txpool into this block", transactions.Count - 1);
                }

                try
                {
                    if (difficulty < 1)
                    {
                        difficulty = 1;
                    }
                    var newBlock = _blockCreator.CreateValidBlockAndAddToChain(_walletPrivKey, _blockchain, transactions, difficulty, cancellationToken);

                    lock (_txPool)
                    {
                        foreach (var transaction in newBlock.Transactions)
                        {
                            _txPool.RemoveTransaction(transaction);
                        }
                    }

                    _logger.LogInformation("Created a new block!");

                    EventPublisher.GetInstance().PublishValidatedBlockCreated(this, new BlockCreatedEventArgs(newBlock));
                }
                catch (OperationCanceledException)
                {
                    _logger.LogInformation("Mining operation canceled.");
                }
                catch (BlockRejectedException ex)
                {
                    _logger.LogDebug("Our own block does not pass validation: {0}", ex.Message);
                }
                catch (NonceLimitReachedException)
                {
                    _logger.LogWarning("Nonce limit reached.");
                }
            }
        }
Exemplo n.º 7
0
        internal void HandleCommand(string netId)
        {
            uint tokenFee = 10; // From BlockchainConstants.cs

            Console.WriteLine("Current transfer token fee is " + tokenFee + " TK.");
            WriteLineWithInputCursor("Enter the sender's public key:");
            var fromPub = Console.ReadLine();

            var fromPriv = Program.GetPrivKey(fromPub);

            while (String.IsNullOrWhiteSpace(fromPriv))
            {
                Console.WriteLine("Private key not found.");
                WriteLineWithInputCursor("Enter the sender's public key:");
                fromPub = Console.ReadLine();
            }

            var balance = _transactionRepo.GetTokenBalanceForPubKey(fromPub, netId);

            Console.WriteLine("The sender's balance: " + balance);

            WriteLineWithInputCursor("Enter the receiver's public key:");
            var toPub = Console.ReadLine();

            // Todo support custom fees in transactionCreator

            /*
             * var askFeeFirstTime = true;
             * var forceLowerFee = false;
             * while (tokenFee < 10 && !forceLowerFee || askFeeFirstTime)
             * {
             *  askFeeFirstTime = false;
             *  WriteLineWithInputCursor("Use a different fee [10]:");
             *  var feeInput = Console.ReadLine().ToLower();
             *  while (!UInt32.TryParse(feeInput, out tokenFee))
             *  {
             *      tokenFee = 10;
             *      if (feeInput != "")
             *      {
             *          WriteLineWithInputCursor("Invalid value. Use a positive numeric value without decimals.");
             *          feeInput = Console.ReadLine().ToLower();
             *      }
             *      else
             *      {
             *          break;
             *      }
             *  }
             *
             *  if (tokenFee < 10 && !forceLowerFee)
             *  {
             *      Console.WriteLine("This low fee might result into a rejection. ");
             *      WriteLineWithInputCursor("Type 'force' to use the given fee. Press ENTER to specify another amount.");
             *      feeInput = Console.ReadLine().ToLower();
             *      if (feeInput == "force")
             *      {
             *          forceLowerFee = true;
             *      }
             *  }
             * }
             */

            uint amount      = 0;
            bool forceAmount = false;

            while (amount < 1 || amount > balance && !forceAmount)
            {
                Console.WriteLine("Enter the amount to send:");

                var amountInput = Console.ReadLine().ToLower();
                while (!UInt32.TryParse(amountInput, out amount))
                {
                    WriteLineWithInputCursor("Invalid value. Use a positive numeric value without decimals.");
                    amountInput = Console.ReadLine().ToLower();
                }

                if (amount + tokenFee > balance && !forceAmount)
                {
                    Console.WriteLine("The given amount + fee is higher than the sender's balance and can cause a rejection.");
                    WriteLineWithInputCursor("Type 'force' to use the given amount. Press ENTER to specify another amount.");
                    amountInput = Console.ReadLine().ToLower();
                    if (amountInput == "force")
                    {
                        forceAmount = true;
                    }
                }
            }

            WriteLineWithInputCursor("Enter optional data []:");
            var optionalData = Console.ReadLine();

            AbstractTransaction transactionToSend = _transactionCreator.CreateTokenTransferTransaction(fromPub, fromPriv, toPub, amount, optionalData);

            EventPublisher.GetInstance().PublishUnvalidatedTransactionReceived(this, new TransactionReceivedEventArgs(transactionToSend));
            Console.Write("> ");
        }
Exemplo n.º 8
0
        internal void HandleCommand(string netId)
        {
            ulong creationFee = CreateSkuFee; // From BlockchainConstants.cs

            Console.WriteLine("Current SKU creation fee is " + creationFee + " TK.");
            WriteLineWithInputCursor("Enter the sender's public key:");
            var fromPub = Console.ReadLine();

            var fromPriv = Program.GetPrivKey(fromPub);

            while (String.IsNullOrWhiteSpace(fromPriv))
            {
                Console.WriteLine("Private key not found.");
                WriteLineWithInputCursor("Enter the sender's public key:");
                fromPub = Console.ReadLine();
            }

            var balance = _transactionRepo.GetTokenBalanceForPubKey(fromPub, netId);

            Console.WriteLine("The sender's balance: " + balance);

            // Todo support custom fees in transactionCreator

            /*
             * var askFeeFirstTime = true;
             * var forceLowerFee = false;
             * while (creationFee < CreateSkuFee && !forceLowerFee || askFeeFirstTime)
             * {
             *  askFeeFirstTime = false;
             *  WriteLineWithInputCursor("Use a different fee ["+ CreateSkuFee + "]:");
             *  var feeInput = Console.ReadLine().ToLower();
             *  while (!ulong.TryParse(feeInput, out creationFee))
             *  {
             *      creationFee = CreateSkuFee;
             *      if (feeInput != "")
             *      {
             *          WriteLineWithInputCursor("Invalid value. Use a positive numeric value without decimals.");
             *          feeInput = Console.ReadLine().ToLower();
             *      }
             *      else
             *      {
             *          break;
             *      }
             *  }
             *
             *  if (creationFee < CreateSkuFee && !forceLowerFee)
             *  {
             *      Console.WriteLine("This low fee might result into a rejection. ");
             *      WriteLineWithInputCursor("Type 'force' to use the given fee. Press ENTER to specify another amount.");
             *      feeInput = Console.ReadLine().ToLower();
             *      if (feeInput == "force")
             *      {
             *          forceLowerFee = true;
             *      }
             *  }
             * }
             */

            var sku = HandleCreateSkuCommand();

            bool firstTimeSupplyAmountInput = true;
            uint supplyAmount = 0;

            while (supplyAmount < 0 || firstTimeSupplyAmountInput)
            {
                firstTimeSupplyAmountInput = false;
                WriteLineWithInputCursor("Specify the initial supply:");

                var amountInput = Console.ReadLine().ToLower();
                while (!UInt32.TryParse(amountInput, out supplyAmount))
                {
                    WriteLineWithInputCursor("Invalid value. Use a positive numeric value without decimals.");
                    amountInput = Console.ReadLine().ToLower();
                }
            }

            AbstractTransaction transactionToSend = _transactionCreator.CreateSkuCreationTransaction(fromPub, fromPriv, supplyAmount, sku);

            EventPublisher.GetInstance().PublishUnvalidatedTransactionReceived(this, new TransactionReceivedEventArgs(transactionToSend));
            Console.Write("> ");
        }
Exemplo n.º 9
0
        public static void Main(string[] args)
        {
            CryptographyCommandhandler cryptographyCmdHandler = new CryptographyCommandhandler(new KeyGenerator());

            cryptographyCmdHandler.HandleGenerateKeysCommand(out string walletPubKey, out string walletPrivKey);
            PushKeyPair(walletPubKey, walletPrivKey);

            Console.WriteLine("Your new public key: " + walletPubKey);
            Console.WriteLine("Your new private key: " + walletPrivKey);
            Console.WriteLine("Loading blockchain..");

            var       networkIdentifier = "testnet";
            var       services          = SetupDI(networkIdentifier, walletPubKey, walletPrivKey);
            ushort    listeningPort     = NetworkConstants.DefaultListeningPort;
            IPAddress publicIP          = IPAddress.Parse("127.0.0.1"); // Our public IP so other nodes can find us, todo

            if (args.Length > 1 && args[0] == "-port")
            {
                listeningPort = ushort.Parse(args[1]);
            }

            GetServices(
                services,
                out IBlockchainRepository blockchainRepo,
                out ITransactionRepository transactionRepo,
                out ITransactionCreator transactionCreator,
                out ITimestamper timestamper,
                out ISkuRepository skuRepository,
                out INetworkManager networkManager,
                out ILoggerFactory loggerFactory,
                out ISkuRepository skuRepo,
                out Miner miner
                );
            _logger = loggerFactory.CreateLogger <Program>();
            Blockchain blockchain = blockchainRepo.GetChainByNetId(networkIdentifier);

            // Command handlers, only large commands are handles by these separate handlers.
            AccountsCommandHandler             accountsCmdHandler       = new AccountsCommandHandler(transactionRepo, networkIdentifier);
            SkusCommandHandler                 skusCmdHandler           = new SkusCommandHandler(blockchainRepo, timestamper, skuRepository, networkIdentifier);
            TransactionsCommandHandler         transactionsCmdHandler   = new TransactionsCommandHandler(transactionRepo, networkIdentifier);
            TransactionPoolCommandHandler      txpoolCmdHandler         = new TransactionPoolCommandHandler();
            TransferTokensCommandHandler       transferTokensCmdHandler = new TransferTokensCommandHandler(transactionRepo, transactionCreator);
            CreateSkuCommandHandler            createSkuCmdHandler      = new CreateSkuCommandHandler(transactionRepo, transactionCreator);
            TransferSupplyCommandHandler       transferSupplyCmdHandler = new TransferSupplyCommandHandler(skuRepository, transactionRepo, transactionCreator, networkIdentifier);
            NetworkingCommandHandler           networkingCmdHandler     = new NetworkingCommandHandler();
            TransactionGeneratorCommandHandler txGeneratorCmdHandler    = new TransactionGeneratorCommandHandler(miner, transactionCreator, skuRepo, blockchainRepo);
            CreateSupplyCommandHandler         createSupplyCmdHandler   = new CreateSupplyCommandHandler(skuRepository, transactionRepo, transactionCreator, networkIdentifier);
            DestroySupplyCommandHandler        destroySupplyCmdHandler  = new DestroySupplyCommandHandler(skuRepository, transactionRepo, transactionCreator, networkIdentifier);

            _logger.LogInformation("Loaded blockchain. Current height: {Height}", blockchain.CurrentHeight == -1 ? "GENESIS" : blockchain.CurrentHeight.ToString());
            networkManager.AcceptConnections(publicIP, listeningPort, new CancellationTokenSource());

            networkManager.ConnectToPeer(new NetworkNode(ConnectionType.Outbound, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345)));

            PrintConsoleCommands();

            var skuTransactions = 0;
            var txpool          = ConcurrentTransactionPool.GetInstance();

            EventPublisher.GetInstance().OnValidTransactionReceived += (object sender, TransactionReceivedEventArgs txargs) =>
            {
                if (txargs.Transaction.Action == TransactionAction.CreateSku.ToString())
                {
                    skuTransactions++;
                }

                if (skuTransactions > 200000 && txpool.Count() < 1)
                {
                    miner.StopMining(true);
                    txGeneratorCmdHandler.HandleStopCommand();
                }
            };

            var input = "";

            while (input != "exit")
            {
                input = Console.ReadLine().ToLower();
                switch (input)
                {
                case "help":
                    PrintConsoleCommands();
                    break;

                case "transactiongenerator startandmine":
                    txGeneratorCmdHandler.HandleStartCommand(true);
                    break;

                case "transactiongenerator start":
                    txGeneratorCmdHandler.HandleStartCommand(false);
                    break;

                case "transactiongenerator stop":
                    txGeneratorCmdHandler.HandleStopCommand();
                    break;

                case "generatekeys":
                    cryptographyCmdHandler.HandleGenerateKeysCommand(out walletPubKey, out walletPrivKey);
                    PushKeyPair(walletPubKey, walletPrivKey);
                    Console.WriteLine("Your new public key: " + walletPubKey);
                    Console.WriteLine("Your new private key: " + walletPrivKey);
                    Console.Write("> ");
                    break;

                case "accounts":
                case "users":
                case "balances":
                    accountsCmdHandler.HandleCommand();
                    break;

                case "skus":
                    skusCmdHandler.HandleCommand();
                    break;

                case "txpool":
                case "transactionpool":
                case "pendingtransactions":
                    txpoolCmdHandler.HandleCommand(miner.TransactionPool);
                    break;

                case "transactions":
                    transactionsCmdHandler.HandleCommand();
                    break;

                case "startmining":
                    miner.StartMining();
                    Console.Write("> ");
                    break;

                case "stopmining":
                    miner.StopMining(true);
                    PrintConsoleCommands();
                    break;

                case "resetblockchain":
                    miner.StopMining(false);
                    blockchainRepo.Delete(networkIdentifier);
                    Console.WriteLine("Blockchain deleted.");
                    blockchain = blockchainRepo.GetChainByNetId(networkIdentifier);
                    networkManager.Dispose();
                    _logger.LogWarning("All network connections shut down.");
                    // Initialize all variables again because the heap references changed.
                    services = SetupDI(networkIdentifier, walletPubKey, walletPrivKey);
                    GetServices(
                        services,
                        out blockchainRepo,
                        out transactionRepo,
                        out transactionCreator,
                        out timestamper,
                        out skuRepository,
                        out networkManager,
                        out var ingored,
                        out skuRepo,
                        out miner
                        );
                    networkManager.AcceptConnections(publicIP, listeningPort, new CancellationTokenSource());
                    accountsCmdHandler       = new AccountsCommandHandler(transactionRepo, networkIdentifier);
                    skusCmdHandler           = new SkusCommandHandler(blockchainRepo, timestamper, skuRepository, networkIdentifier);
                    transactionsCmdHandler   = new TransactionsCommandHandler(transactionRepo, networkIdentifier);
                    txpoolCmdHandler         = new TransactionPoolCommandHandler();
                    transferTokensCmdHandler = new TransferTokensCommandHandler(transactionRepo, transactionCreator);
                    createSkuCmdHandler      = new CreateSkuCommandHandler(transactionRepo, transactionCreator);
                    txGeneratorCmdHandler    = new TransactionGeneratorCommandHandler(miner, transactionCreator, skuRepo, blockchainRepo);
                    _logger.LogInformation("Loaded blockchain. Current height: {Height}", blockchain.CurrentHeight == -1 ? "GENESIS" : blockchain.CurrentHeight.ToString());
                    Console.Write("> ");
                    break;

                case "transfertokens":
                    transferTokensCmdHandler.HandleCommand(networkIdentifier);
                    break;

                case "createsku":
                    createSkuCmdHandler.HandleCommand(networkIdentifier);
                    break;

                case "transfersupply":
                    transferSupplyCmdHandler.HandleCommand();
                    break;

                case "createsupply":
                    createSupplyCmdHandler.HandleCommand();
                    break;

                case "destroysupply":
                    destroySupplyCmdHandler.HandleCommand();
                    break;

                case "networking setport":
                    listeningPort = networkingCmdHandler.HandleSetPortCommand(listeningPort);
                    break;

                case "networking setaddress":
                    publicIP = networkingCmdHandler.HandleSetAddressCommand(publicIP);
                    break;

                case "networking connect":
                    networkingCmdHandler.HandleConnectCommand(networkManager);
                    break;

                case "networking disconnect":
                    networkingCmdHandler.HandleDisconnectCommand(networkManager);
                    break;

                case "networking pool":
                    networkingCmdHandler.HandleListPoolCommand(NetworkNodesPool.GetInstance(loggerFactory));
                    break;

                case "networking stop":
                    networkManager.Dispose();
                    break;

                case "networking start":
                    if (networkManager.IsDisposed)
                    {
                        networkManager = GetService <INetworkManager>(services);
                    }
                    networkManager.AcceptConnections(publicIP, listeningPort, new CancellationTokenSource());
                    break;

                case "networking restart":
                    networkManager.Dispose();
                    Thread.Sleep(1000);
                    networkManager = GetService <INetworkManager>(services);
                    networkManager.AcceptConnections(publicIP, listeningPort, new CancellationTokenSource());
                    break;

                default:
                    Console.WriteLine("I don't recognize that command.");
                    Console.Write("> ");
                    break;
                }
            }
        }
Exemplo n.º 10
0
        // todo Chain of Responsibility pattern, make XXMessageHandler class for each command type
        // and refactor abstractmessagehandler to a regular MessageHandlerHelper
        public override async Task HandleMessage(NetworkNode node, Message msg)
        {
            try
            {
                if (msg.Command == NetworkCommand.CloseConn.ToString())
                {
                    await node.Disconnect();
                }
                else if (msg.Command == NetworkCommand.GetAddr.ToString())
                {
                    // Send our known peers
                    var addresses = new AddrPayload(_nodePool.GetAllRemoteListenEndpoints());
                    await SendMessageToNode(node, NetworkCommand.Addr, addresses);
                }
                else if (msg.Command == NetworkCommand.Addr.ToString())
                {
                    // Connect to all neighbors that the other node knows
                    var payload = (AddrPayload)msg.Payload;
                    foreach (IPEndPoint endpoint in payload.Endpoints)
                    {
                        await _networkManager.ConnectToPeer(endpoint);
                    }
                }
                else if (msg.Command == NetworkCommand.GetHeaders.ToString())
                {
                    // Send our headers
                    var payload = (GetHeadersPayload)msg.Payload;
                    try
                    {
                        var headers        = GetBlocksFromHash(payload.HighestHeightHash, payload.StoppingHash, false).Select(b => b.Header);
                        var headersPayload = new HeadersPayload(headers);
                        await SendMessageToNode(node, NetworkCommand.Headers, headersPayload);
                    }
                    catch (KeyNotFoundException)
                    {
                        // Send empty payload
                        await SendMessageToNode(node, NetworkCommand.NotFound, null);
                    }
                }
                else if (msg.Command == NetworkCommand.GetBlocks.ToString())
                {
                    var payload       = (GetBlocksPayload)msg.Payload;
                    var blocksPayload = new StateBlocksPayload();
                    if (payload.Headers.Count() > 0)
                    {
                        blocksPayload = new StateBlocksPayload(GetBlocksFromHash(payload.Headers.First(), payload.Headers.Last(), true));
                    }

                    await SendMessageToNode(node, NetworkCommand.Blocks, blocksPayload);
                }
                else if (msg.Command == NetworkCommand.Headers.ToString() && node.IsSyncingWithNode)
                {
                    node.SetSyncStatus(SyncStatus.InProgress);
                    var headersPayload = (HeadersPayload)msg.Payload;

                    if (headersPayload.Headers.Count() == 0)
                    {
                        _logger.LogInformation("Successfully synced with remote node.");
                        node.SetSyncStatus(SyncStatus.Succeeded);
                        return;
                    }

                    // Request these blocks
                    var getBlocksPayload = new GetBlocksPayload(headersPayload.Headers.Select(h => h.Hash));
                    await SendMessageToNode(node, NetworkCommand.GetBlocks, getBlocksPayload);
                }
                else if (msg.Command == NetworkCommand.NotFound.ToString() && node.IsSyncingWithNode)
                {
                    node.SetSyncStatus(SyncStatus.Failed); // Restart the syncing process with another node.
                }
                else if (msg.Command == NetworkCommand.Blocks.ToString() && node.IsSyncingWithNode)
                {
                    var blocksPayload = (StateBlocksPayload)msg.Payload;

                    // Todo rewrite this code to support multithreaded 'Blocks' messages. Combine all gathered blocks
                    // until the process has completed and all blocks are downloaded. Then, grab a block that points to the
                    // end of our chain and add it to our chain. Repeat that process until all blocks have been added.

                    var blocksProcessed = 0;

                    lock (_blockchain)
                    {
                        while (blocksPayload.Blocks.Where(b => b.Header.PreviousHash == _blockchain.Blocks.Last().Header.Hash).Any())
                        {
                            var blockToProcess = blocksPayload.Blocks.Where(b => b.Header.PreviousHash == _blockchain.Blocks.Last().Header.Hash).First();

                            if (_blockchain.CurrentHeight % 5 == 0 && _blockchain.CurrentHeight > 0)
                            {
                                _difficulty = _difficultyCalculator.CalculateCurrentDifficulty(_blockchain); // todo use CalculateCurrentDifficulty when testing is done
                            }

                            if (_difficulty < 1)
                            {
                                _difficulty = 1;
                            }
                            var currentTarget = BlockchainConstants.MaximumTarget / _difficulty;                    // todo refactor these 3 lines. They are copy-pasted from the miner.
                            _blockValidator.ValidateBlock(blockToProcess, currentTarget, _blockchain, false, true); // Rethrow when we have a Block- / TransactionRejectedException. We don't want to keep a connection with bad nodes.
                            blocksProcessed++;
                        }
                    }

                    _logger.LogDebug("Downloaded and added {0} new blocks from remote node", blocksProcessed);
                    _logger.LogDebug("Current height: {0}", _blockchain.CurrentHeight);

                    if (blocksProcessed != blocksPayload.Blocks.Count())
                    {
                        _logger.LogError("Added {0} new blocks from remote node, but expected {1}. Sync failed.", blocksProcessed, blocksPayload.Blocks.Count());
                        node.SetSyncStatus(SyncStatus.Failed);
                        return;
                    }

                    _blockchainRepo.Update(_blockchain);

                    // Block batch processed. Keep on ask for more headers.
                    var getHeadersPayload = new GetHeadersPayload(_blockchain.Blocks.Last().Header.Hash);
                    await SendMessageToNode(node, NetworkCommand.GetHeaders, getHeadersPayload);
                }
                else if (msg.Command == NetworkCommand.GetTxPool.ToString())
                {
                    var txPoolPayload = new StateTransactionsPayload(_txPool.GetAllTransactions());
                    await SendMessageToNode(node, NetworkCommand.TxPool, txPoolPayload);
                }
                else if (msg.Command == NetworkCommand.TxPool.ToString())
                {
                    var txPoolPayload = (StateTransactionsPayload)msg.Payload;
                    foreach (var tx in txPoolPayload.Transactions)
                    {
                        _txPool.AddTransaction(tx);
                    }
                }
                else if (msg.Command == NetworkCommand.NewTransaction.ToString())
                {
                    var txPayload = (SingleStateTransactionPayload)msg.Payload;
                    if (_networkManager.IsSyncing)
                    {
                        return;
                    }

                    var validationResult = EventPublisher.GetInstance().PublishUnvalidatedTransactionReceived(node, new TransactionReceivedEventArgs(txPayload.Transaction));
                    if (validationResult == false)
                    {
                        //await node.Disconnect(); // Dishonest node, buuh!
                    }
                }
                else if (msg.Command == NetworkCommand.NewBlock.ToString())
                {
                    var blockPayload = (SingleStateBlockPayload)msg.Payload;
                    if (_networkManager.IsSyncing)
                    {
                        return;
                    }

                    var validationResult = EventPublisher.GetInstance().PublishUnvalidatedBlockCreated(node, new BlockCreatedEventArgs(blockPayload.Block));
                    if (validationResult == false)
                    {
                        //await node.Disconnect(); // Dishonest node, buuh!
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("An {0} occurred during the process of handling a {1} message: {2}. Node will be disconnected.", ex.GetType().Name, msg.Command.ToString(), ex.Message);
                node?.Disconnect();
            }
        }