public Task Sync() { return(Task.Run(async() => { Log += "syncing..." + Environment.NewLine; OnLogChanged(); while (true) { var(index, node) = Nodes.Aggregate((index: BlockChain.Last().Index, node: (Uri)null), (m, n) => Task.Run(async() => { HttpResponseMessage response; try { response = await httpClient_.PostAsync(n, new StringContent(JsonConvert.SerializeObject( new GetCurrentIndex { PortNumber = PortNumber }))); } catch (HttpRequestException) { return m; } if (!response.IsSuccessStatusCode) { return m; } var res = JsonConvert.DeserializeObject <GetCurrentIndexResponse>(await response.Content.ReadAsStringAsync()); if (res.CurrentIndex <= m.index) { return m; } return (index: res.CurrentIndex, node: n); }).Result); if (node == null) { break; } if (index > BlockChain.Last().Index) { IList <Block> branch; var currentIndex = BlockChain.Last().Index; { HttpResponseMessage response; try { response = await httpClient_.PostAsync(node, new StringContent(JsonConvert.SerializeObject( new GetBlocks { Index = currentIndex + 1, NumBlocks = index - currentIndex }))); } catch (HttpRequestException) { continue; } if (!response.IsSuccessStatusCode) { continue; } var res = JsonConvert.DeserializeObject <GetBlocksResponse>(await response.Content.ReadAsStringAsync()); branch = res.Blocks; } if (branch.First().PreviousHash == LastHash) { var removed = false; foreach (var block in branch) { foreach (var transaction in block.Transactions) { if (TransactionPool.Contains(transaction)) { TransactionPool.Remove(transaction); removed = true; } } } if (removed) { OnTransactionPoolChanged(); } BlockChain.AddRange(branch); break; } while (true) { HttpResponseMessage response; try { response = await httpClient_.PostAsync(node, new StringContent(JsonConvert.SerializeObject( new GetBlocks { Index = currentIndex, NumBlocks = 1 }))); } catch (HttpRequestException) { goto con; } if (!response.IsSuccessStatusCode) { goto con; } var res = JsonConvert.DeserializeObject <GetBlocksResponse>(await response.Content.ReadAsStringAsync()); branch.Insert(0, res.Blocks.First()); if (BlockChain[currentIndex].PreviousHash == branch.First().PreviousHash) { break; } --currentIndex; } BlockChain.RemoveRange(currentIndex, BlockChain.Count - currentIndex); var removed2 = false; foreach (var block in branch) { foreach (var transaction in block.Transactions) { if (TransactionPool.Contains(transaction)) { TransactionPool.Remove(transaction); removed2 = true; } } } if (removed2) { OnTransactionPoolChanged(); } BlockChain.AddRange(branch); break; } con:; } LastHash = SerializeHash(GetHash(BlockChain.Last())); OnBlockChainChanged(); Log += "sync completed." + Environment.NewLine; OnLogChanged(); })); }
public Node() { if (File.Exists(ConfigFileName)) { string s; using (var sr = new StreamReader(ConfigFileName, Encoding)) { s = sr.ReadToEnd(); } var config = JsonConvert.DeserializeObject <Config>(s); PortNumber = config.PortNumber; Nodes = config.Nodes ?? new HashSet <Uri>(); } BlockChain.Add(GetGenesisBlock()); LastHash = SerializeHash(GetHash(BlockChain.Last())); httpListener_.Prefixes.Add($"http://+:{PortNumber}/"); httpListener_.Start(); Task.Run(() => { while (true) { var context = httpListener_.GetContext(); void respond() { context.Response.StatusCode = (int)HttpStatusCode.BadRequest; context.Response.OutputStream.Close(); } string requestString; using (var sr = new StreamReader(context.Request.InputStream)) { requestString = sr.ReadToEnd(); } Log += $"request get: {requestString}{Environment.NewLine}"; OnLogChanged(); JObject requestJObject; try { requestJObject = JObject.Parse(requestString); } catch (JsonReaderException) { respond(); continue; } if (!requestJObject.ContainsKey("Matcha") || requestJObject["Matcha"].Type != JTokenType.String || requestJObject["Matcha"].Value <string>() != "Matcha") { respond(); continue; } var client = new Uri($"http://{context.Request.RemoteEndPoint.Address}" + $":{requestJObject["PortNumber"].Value<int>()}/"); Nodes.Add(client); var response = context.Response; response.StatusCode = 200; using (var sw = new StreamWriter(response.OutputStream, Encoding)) { switch (requestJObject["Type"].Value <string>()) { case nameof(Methods.GetNodes): { var nodes = new HashSet <Uri>(Nodes); nodes.Remove(client); sw.Write(JsonConvert.SerializeObject(new GetNodesResponse { Nodes = nodes })); break; } case nameof(SendTransaction): { var request = requestJObject.ToObject <SendTransaction>(); if (!TransactionPool.Contains(request.Transaction)) { TransactionPool.Add(request.Transaction); OnTransactionPoolChanged(); } break; } case nameof(GetCurrentIndex): { sw.Write(JsonConvert.SerializeObject(new GetCurrentIndexResponse { CurrentIndex = BlockChain.Last().Index })); break; } case nameof(GetBlocks): { var request = requestJObject.ToObject <GetBlocks>(); sw.Write(JsonConvert.SerializeObject(new GetBlocksResponse { Blocks = BlockChain.Skip(request.Index).Take(request.NumBlocks).ToList() })); break; } } } } }); }
public async Task <bool> Contains(Domain.Transaction tx) => await TransactionPool.Contains(tx);