consolidate all repos to one for archive
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<Application x:Class="WpfBlockChanApp.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:WpfBlockChanApp"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace WpfBlockChanApp
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
using System.Windows;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace WpfBlockChanApp
|
||||
{
|
||||
internal class Block
|
||||
{
|
||||
public int Index { get; set; }
|
||||
public string PreviousHash { get; set; }
|
||||
public string Hash { get; set; }
|
||||
public string Data { get; set; }
|
||||
public long Timestamp { get; set; }
|
||||
public int Nonce { get; set; }
|
||||
public int Difficulty { get; set; }
|
||||
public int LastAdjustBlock { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public string GetString
|
||||
{
|
||||
get { return $"{Index}\n{Data}\n{PreviousHash}\n{Hash}"; }
|
||||
}
|
||||
|
||||
public Block(int index, string previousHash, string data, int difficulty, int lastAdjustBlock)
|
||||
{
|
||||
Index = index;
|
||||
PreviousHash = previousHash;
|
||||
Data = data;
|
||||
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
Nonce = 0;
|
||||
Difficulty = difficulty;
|
||||
LastAdjustBlock = lastAdjustBlock;
|
||||
Hash = CalculateHash();
|
||||
}
|
||||
|
||||
public string CalculateHash()
|
||||
{
|
||||
using (SHA256 sha256 = SHA256.Create())
|
||||
{
|
||||
byte[] inputBytes = Encoding.UTF8.GetBytes($"{Index}{PreviousHash}{Timestamp}{Data}{Difficulty}{Nonce}");
|
||||
byte[] outputBytes = sha256.ComputeHash(inputBytes);
|
||||
return Convert.ToBase64String(outputBytes);
|
||||
}
|
||||
}
|
||||
|
||||
public bool MatchDifficulty()
|
||||
{
|
||||
return Hash[..Difficulty] != new string('0', Difficulty);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace WpfBlockChanApp
|
||||
{
|
||||
|
||||
internal struct ReturnOption
|
||||
{
|
||||
public bool isValid;
|
||||
public Block value;
|
||||
public ReturnOption(bool isValid, Block value)
|
||||
{
|
||||
this.isValid = isValid;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
static class Blockchain
|
||||
{
|
||||
public static List<Block> Chain { get; set; }
|
||||
public static Mutex chainMutax = new Mutex();
|
||||
|
||||
readonly static int diffAdjustInterval = 10;
|
||||
readonly static long timeExpected = 100_000;
|
||||
public static bool Compute { get; set; }
|
||||
|
||||
static Block GetLatestBlock()
|
||||
{
|
||||
return Chain[Chain.Count - 1];
|
||||
}
|
||||
|
||||
static ReturnOption GetSomeBlock(int lastAdjustBlock)
|
||||
{
|
||||
if(lastAdjustBlock + diffAdjustInterval > Chain.Count) {
|
||||
return new(false, Chain[0]);
|
||||
}
|
||||
ReturnOption ret = new(true, Chain[lastAdjustBlock]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static ReturnOption ComputeBlock(string data)
|
||||
{
|
||||
Block lastBlock = GetLatestBlock();
|
||||
int index = lastBlock.Index + 1;
|
||||
string previousHash = lastBlock.Hash;
|
||||
int difficulty = lastBlock.Difficulty;
|
||||
int lastAdjustBlock = lastBlock.LastAdjustBlock;
|
||||
|
||||
var previousAdjustmentBlock = GetSomeBlock(lastAdjustBlock);
|
||||
if (previousAdjustmentBlock.isValid) {
|
||||
long timeTaken = lastBlock.Timestamp - previousAdjustmentBlock.value.Timestamp;
|
||||
if (timeTaken < (timeExpected / 2))
|
||||
difficulty += 1; // povečanje težavnosti
|
||||
else if (timeTaken > (timeExpected * 2))
|
||||
difficulty -= 1; // pomanjšanje težavnosti
|
||||
|
||||
lastAdjustBlock = index;
|
||||
}
|
||||
|
||||
var newBlock = new Block(index, previousHash, data, difficulty, lastAdjustBlock);
|
||||
while (newBlock.MatchDifficulty())
|
||||
{
|
||||
if (!Compute) return new ( false, newBlock );
|
||||
newBlock.Nonce++;
|
||||
newBlock.Hash = newBlock.CalculateHash();
|
||||
}
|
||||
return new( true, newBlock );
|
||||
}
|
||||
|
||||
public static bool AddBlock(Block block)
|
||||
{
|
||||
Block previusBlock = GetLatestBlock();
|
||||
if (block.PreviousHash != previusBlock.Hash) return false;
|
||||
if (block.Hash != block.CalculateHash()) return false;
|
||||
if (block.Index != previusBlock.Index + 1) return false;
|
||||
|
||||
chainMutax.WaitOne();
|
||||
Chain.Add(block);
|
||||
chainMutax.ReleaseMutex();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static bool IsValid(List<Block> chain)
|
||||
{
|
||||
for (int i = 1; i < chain.Count; i++)
|
||||
{
|
||||
Block currentBlock = chain[i];
|
||||
Block previusBlock = chain[i - 1];
|
||||
|
||||
if (currentBlock.PreviousHash != previusBlock.Hash) return false;
|
||||
if (currentBlock.Hash != currentBlock.CalculateHash()) return false;
|
||||
if (currentBlock.Index != previusBlock.Index + 1) return false;
|
||||
if (currentBlock.Timestamp > previusBlock.Timestamp + 60_000) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool Evaluete(List<Block> chain1, List<Block> chain2)
|
||||
{
|
||||
List<Block> result = new List<Block>();
|
||||
double chain1Dif = 0;
|
||||
foreach (var item in chain1)
|
||||
{
|
||||
chain1Dif += Math.Pow(2, item.Difficulty);
|
||||
}
|
||||
|
||||
double chain2Dif = 0;
|
||||
foreach (var item in chain2)
|
||||
{
|
||||
chain2Dif += Math.Pow(2, item.Difficulty);
|
||||
}
|
||||
|
||||
return (chain1Dif > chain2Dif) ? false : true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
<Window x:Class="WpfBlockChanApp.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:WpfBlockChanApp"
|
||||
mc:Ignorable="d"
|
||||
Closing="Window_Closing"
|
||||
Title="MainWindow" MinHeight="450" MinWidth="800" Width="800" Height="450">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="100"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
|
||||
<Button Content="Start" HorizontalAlignment="Left" Margin="10,34,0,0" VerticalAlignment="Top" Click="Start_Click"/>
|
||||
<Button Content="Stop" HorizontalAlignment="Left" Margin="10,60,0,0" VerticalAlignment="Top" Click="Stop_Click"/>
|
||||
|
||||
<Label Grid.Row="0" Content="MyName" HorizontalAlignment="Left" Margin="82,14,0,0" VerticalAlignment="Top"/>
|
||||
<TextBox HorizontalAlignment="Left" Margin="154,18,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120"/>
|
||||
|
||||
<Label Content="Conect To" HorizontalAlignment="Left" Margin="82,49,0,0" VerticalAlignment="Top"/>
|
||||
<TextBox Name="ConnectBox" HorizontalAlignment="Left" Margin="154,57,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120"/>
|
||||
<Button Content="Connect" HorizontalAlignment="Left" Margin="292,57,0,0" VerticalAlignment="Top" Click="Connect_Click"/>
|
||||
|
||||
<Label Content="My Port" HorizontalAlignment="Left" Margin="392,14,0,0" VerticalAlignment="Top"/>
|
||||
<Label Name="MyPort" Content="" HorizontalAlignment="Left" Margin="458,14,0,0" VerticalAlignment="Top"/>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ListView Name="ChainView" Grid.Column="0" Margin="10">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Margin="2">
|
||||
<Label Content="{Binding Path=GetString}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
<ListView Name="LogView" Grid.Column="1" Margin="10">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel>
|
||||
<Label Name="Naslov" Content="{Binding}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
|
||||
</Grid>
|
||||
</Window>
|
@@ -0,0 +1,249 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using System.Threading;
|
||||
using System.Windows.Threading;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections;
|
||||
using System.Data;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.Windows.Media.Media3D;
|
||||
using System.Text.Json;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace WpfBlockChanApp
|
||||
{
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
|
||||
DispatcherTimer timer1s;
|
||||
DispatcherTimer timer1m;
|
||||
|
||||
ObservableCollection<Block> observableBlockChain = new ObservableCollection<Block>();
|
||||
ObservableCollection<int> observableString = new ObservableCollection<int>();
|
||||
//static List<string> strings = new List<string>();
|
||||
static List<int> clients = new List<int>();
|
||||
|
||||
const string STD_IP = "127.0.0.1";
|
||||
static string data;
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.DataContext = this;
|
||||
ChainView.ItemsSource = observableBlockChain;
|
||||
LogView.ItemsSource = observableString;
|
||||
|
||||
timer1s = new DispatcherTimer();
|
||||
timer1s.Interval = TimeSpan.FromSeconds(1);
|
||||
timer1s.Tick += UpdateData;
|
||||
timer1s.Start();
|
||||
|
||||
timer1m = new DispatcherTimer();
|
||||
timer1m.Interval = TimeSpan.FromSeconds(30);
|
||||
timer1m.Tick += Timer1m_Tick;
|
||||
timer1m.Start();
|
||||
|
||||
|
||||
|
||||
tcpListener = new TcpListener(IPAddress.Parse(STD_IP), 0);
|
||||
tcpListener.Start();
|
||||
data = ((IPEndPoint)tcpListener.LocalEndpoint).Port.ToString();
|
||||
MyPort.Content = data;
|
||||
|
||||
Blockchain.Chain = new List<Block>();
|
||||
Blockchain.Compute = true;
|
||||
Block tmpBlock = new Block(0, "", "", 0, 0);
|
||||
tmpBlock.Hash = "";
|
||||
Blockchain.Chain.Add(tmpBlock);
|
||||
|
||||
stopNetwork = false;
|
||||
listenThread = new Thread(() => listenerThredFunction());
|
||||
listenThread.Start();
|
||||
}
|
||||
|
||||
private void Timer1m_Tick(object? sender, EventArgs e)
|
||||
{
|
||||
UpdateClients();
|
||||
}
|
||||
void UpdateData(object? sender, EventArgs e)
|
||||
{
|
||||
for (int i = observableBlockChain.Count; i < Blockchain.Chain.Count; i++)
|
||||
observableBlockChain.Add(Blockchain.Chain[i]);
|
||||
|
||||
for (int i = observableString.Count; i < clients.Count; i++)
|
||||
observableString.Add(clients[i]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Thread calcualteBlockThread;
|
||||
static bool stopNetwork = false;
|
||||
static bool stopMiner = false;
|
||||
static void ComputeBlockThreadFunction()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (stopMiner) break;
|
||||
Blockchain.Compute = true;
|
||||
ReturnOption option = Blockchain.ComputeBlock(data);
|
||||
|
||||
if (!option.isValid) { continue; }
|
||||
|
||||
if (Blockchain.AddBlock(option.value))
|
||||
{
|
||||
UpdateClients(option.value);
|
||||
//UpdateClients();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static TcpListener tcpListener;
|
||||
Thread listenThread;
|
||||
|
||||
static void listenerThredFunction()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (stopNetwork) break;
|
||||
listen();
|
||||
}
|
||||
}
|
||||
static void listen()
|
||||
{
|
||||
try
|
||||
{
|
||||
using TcpClient tcpClient = tcpListener.AcceptTcpClient();
|
||||
using NetworkStream networkStream = tcpClient.GetStream();
|
||||
|
||||
byte[] buffer = new byte[4];
|
||||
int readByts = networkStream.Read(buffer, 0, buffer.Length);
|
||||
if (readByts <= 0) return;
|
||||
int sizeOfStruct = BitConverter.ToInt32(buffer);
|
||||
|
||||
byte[] isListBuffer = new byte[1];
|
||||
readByts = networkStream.Read(isListBuffer, 0, isListBuffer.Length);
|
||||
if(readByts <= 0) return;
|
||||
bool isList = BitConverter.ToBoolean(isListBuffer);
|
||||
|
||||
byte[] data = new byte[sizeOfStruct];
|
||||
int messageSize = networkStream.Read(data, 0, data.Length);
|
||||
if (messageSize <= 0) return;
|
||||
|
||||
string messageString = Encoding.UTF8.GetString(data, 0, messageSize);
|
||||
|
||||
if (isList)
|
||||
{
|
||||
List<Block> chain = JsonSerializer.Deserialize<List<Block>>(messageString);
|
||||
if (!Blockchain.IsValid(chain)) return;
|
||||
bool update = Blockchain.Evaluete(chain, Blockchain.Chain);
|
||||
if (update)
|
||||
{
|
||||
Blockchain.Chain = chain;
|
||||
Blockchain.Compute = false;
|
||||
UpdateClients();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Block block = JsonSerializer.Deserialize<Block>(messageString);
|
||||
if (Blockchain.AddBlock(block))
|
||||
{
|
||||
Blockchain.Compute = false;
|
||||
UpdateClients(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
static void UpdateClients()
|
||||
{
|
||||
string chainString = JsonSerializer.Serialize(Blockchain.Chain);
|
||||
|
||||
foreach (var clien in clients)
|
||||
{
|
||||
UpdateClient(clien, chainString, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateClients(Block block)
|
||||
{
|
||||
string blockString = JsonSerializer.Serialize(block);
|
||||
|
||||
foreach (var clien in clients)
|
||||
{
|
||||
UpdateClient(clien, blockString, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateClient(int port, string data, bool isListBool)
|
||||
{
|
||||
try
|
||||
{
|
||||
using TcpClient tcpClient = new TcpClient();
|
||||
tcpClient.Connect(IPAddress.Parse(STD_IP), port);
|
||||
using NetworkStream networkStream = tcpClient.GetStream();
|
||||
|
||||
|
||||
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
|
||||
byte[] isList = BitConverter.GetBytes(isListBool);
|
||||
byte[] size = BitConverter.GetBytes(dataBytes.Length);
|
||||
|
||||
networkStream.Write(size, 0, size.Length);
|
||||
networkStream.Write(isList, 0, isList.Length);
|
||||
networkStream.Write(dataBytes, 0, dataBytes.Length);
|
||||
|
||||
|
||||
}catch(Exception e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
private void Start_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Blockchain.Compute = true;
|
||||
stopMiner = false;
|
||||
calcualteBlockThread = new Thread(() => ComputeBlockThreadFunction());
|
||||
calcualteBlockThread.Start();
|
||||
}
|
||||
private void Stop_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
Blockchain.Compute = false;
|
||||
stopMiner = true;
|
||||
}
|
||||
private void Connect_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
int i = 0;
|
||||
if(int.TryParse(ConnectBox.Text, out i))
|
||||
{
|
||||
clients.Add(i);
|
||||
ConnectBox.Text = "";
|
||||
}
|
||||
}
|
||||
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
stopNetwork = true;
|
||||
stopMiner = true;
|
||||
tcpListener.Stop();
|
||||
Blockchain.Compute = false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
Reference in New Issue
Block a user