Beispiel #1
0
        private string CalculateMinedBlockHash(Block blockCandidate, MinedBlockPostModel minedBlock)
        {
            string blockData = blockCandidate.Index.ToString() +
                               blockCandidate.Transactions.Count.ToString() +
                               blockCandidate.BlockDataHash;
            var nonceStr = minedBlock.Nonce.ToString();

            var data      = blockData + minedBlock.DateCreated + nonceStr;
            var blockHash = this.cryptographyHelpers.CalcSHA256(data);

            string requiredLeadingZeroes = new String('0', blockCandidate.Difficulty);

            if (blockHash.StartsWith(requiredLeadingZeroes))
            {
                return(blockHash);
            }

            throw new Exception(
                      $"Can not calculate valid block {blockCandidate.Index} hash: hash {blockHash}, nonce {nonceStr}, difficulty {blockCandidate.Difficulty.ToString()}"
                      );
        }
        public IActionResult SubmitBlock([FromBody] MinedBlockPostModel minedBlock)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest());
            }

            if (!this.dataService.MiningJobs.ContainsKey(minedBlock.BlockDataHash))
            {
                return(NotFound());
            }

            this.nodeService.VerifyMinedJob(minedBlock);

            var response = new
            {
                Status  = "accepted",
                Message = string.Format("Block accepted, reward paid.")
            };

            return(Ok(response));
        }
Beispiel #3
0
        public void VerifyMinedJob(MinedBlockPostModel minedBlock)
        {
            var blockCandidate = this.dataService.MiningJobs[minedBlock.BlockDataHash];

            try
            {
                var blockHash = this.CalculateMinedBlockHash(blockCandidate, minedBlock);
                // if next block - add to blockchain and notify peers
                if (blockCandidate.Index == (ulong)this.dataService.Blocks.Count + 1)
                {
                    blockCandidate.Nonce       = minedBlock.Nonce;
                    blockCandidate.BlockHash   = blockHash;
                    blockCandidate.DateCreated = DateTime.Parse(minedBlock.DateCreated);

                    this.AddBlockToBlockchain(blockCandidate);

                    //remove pending transactions that are already included in the blockchain
                    blockCandidate.Transactions.ForEach(transaction =>
                    {
                        this.dataService.PendingTransactions.Remove(
                            this.dataService
                            .PendingTransactions
                            .Single(t => t.TransactionHash == transaction.TransactionHash)
                            );
                    });

                    this.logger.LogInformation($"Block {blockCandidate.Index} with hash {blockHash} added to blockchain");
                }
                else
                {
                    this.logger.LogInformation($"Block candidate {blockCandidate.Index} with hash {blockHash} already exists in blockckain");
                }
            }
            catch (Exception e)
            {
                this.logger.LogInformation(e.Message);
            }
        }
Beispiel #4
0
        public static async Task MineAsync(IHttpHelpers httpHelpers, IDateTimeHelpers dateTimeHelpers, Logger log)
        {
            HttpStatusCode statusCode = HttpStatusCode.RequestTimeout;

            Stopwatch sw            = new Stopwatch();
            TimeSpan  maxTaskLength = new TimeSpan(0, 0, 2); // 2 seconds

            while (true)
            {
                sw.Start();

                MiningJob miningJob = null;

                do
                {
                    try
                    {
                        string path = "mining/get-mining-job/{minerAddress}";

                        var parameter = new Parameter()
                        {
                            Name  = "minerAddress",
                            Value = minerAddress,
                            Type  = ParameterType.UrlSegment
                        };

                        log.Information($"Trying to get mining job from node: {nodeUrl}");

                        Response <MiningJob> response = await httpHelpers.DoApiGet <MiningJob>(nodeUrl, path, parameter);

                        miningJob = response.Data;

                        statusCode = response.StatusCode;
                    }
                    catch (WebException e)
                    {
                        Console.WriteLine("WebException raised!");
                        Console.WriteLine("{0}\n", e.Message);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("Exception raised!");
                        Console.WriteLine("Source : {0}", e.Source);
                        Console.WriteLine("Message : {0}\n", e.Message);
                    }
                } while (statusCode != HttpStatusCode.OK);

                log.Information($"Successfully received mining job (Block Data Hash: {miningJob.BlockDataHash}) from node!");

                Console.WriteLine("Start New Mining Job:");
                Console.WriteLine("Block Index: {0}", miningJob.BlockIndex);
                Console.WriteLine("Transactions Included: {0}", miningJob.TransactionsIncluded);
                Console.WriteLine("Expected Reward: {0}", miningJob.ExpectedReward);
                Console.WriteLine("Reward Address: {0}", miningJob.RewardAddress);
                Console.WriteLine("Block Data Hash: {0}", miningJob.BlockDataHash);
                Console.WriteLine("Difficulty: {0}", miningJob.Difficulty);

                bool   blockFound = false;
                ulong  nonce      = 0;
                string timestamp  = dateTimeHelpers.ConvertDateTimeToUniversalTimeISO8601String(DateTime.Now);

                string requiredLeadingZeroes = new String('0', miningJob.Difficulty);

                string blockData = miningJob.BlockIndex.ToString() +
                                   miningJob.TransactionsIncluded.ToString() +
                                   miningJob.BlockDataHash;
                string data;
                string blockHash;

                while (!blockFound && nonce < uint.MaxValue)
                {
                    data      = blockData + timestamp + nonce.ToString();
                    blockHash = ByteArrayToHexString(Sha256(Encoding.UTF8.GetBytes(data)));

                    if (blockHash.StartsWith(requiredLeadingZeroes))
                    {
                        Console.WriteLine("Block Mined!");
                        Console.WriteLine($"Block Hash: {blockHash}\n");

                        var minedBlock = new MinedBlockPostModel()
                        {
                            DateCreated   = timestamp,
                            Nonce         = nonce,
                            BlockDataHash = miningJob.BlockDataHash
                        };

                        int retries = 0;
                        do
                        {
                            try
                            {
                                statusCode = HttpStatusCode.RequestTimeout;

                                string path = "mining/submit-mined-block";

                                HttpResponseMessage response = await httpHelpers.DoApiPost(nodeUrl, path, minedBlock);

                                statusCode = response.StatusCode;

                                string statusDescription = response.ReasonPhrase;

                                log.Information($"Sent request to: {nodeUrl} with mined block (hash: {blockHash})!");

                                Console.WriteLine(statusDescription);
                                log.Information($"Received response from {nodeUrl} - status code: {statusCode}, description: {statusDescription}");
                            }
                            catch (WebException e)
                            {
                                Console.WriteLine("WebException raised!");
                                Console.WriteLine("{0}\n", e.Message);
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine("Exception raised!");
                                Console.WriteLine("Source : {0}", e.Source);
                                Console.WriteLine("Message : {0}\n", e.Message);
                            }

                            System.Threading.Thread.Sleep(1000);
                        } while (statusCode != HttpStatusCode.OK && retries++ < 3);

                        blockFound = true;
                        break;
                    }

                    // print intermediate data
                    if (nonce % 1000000 == 0)
                    {
                        Console.WriteLine(timestamp);
                        Console.WriteLine($"Nonce: {nonce}");
                        Console.WriteLine($"Block Hash: {blockHash}\n");
                    }

                    // get new timestamp on every 100000 iterations
                    if (nonce % 100000 == 0)
                    {
                        timestamp = dateTimeHelpers.ConvertDateTimeToUniversalTimeISO8601String(DateTime.Now);
                    }

                    nonce++;

                    if (maxTaskLength < sw.Elapsed)
                    {
                        sw.Reset();
                        break;
                    }
                }
            }
        }