Skip to content

Instantly share code, notes, and snippets.

@theahmadzai
Last active August 30, 2022 17:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save theahmadzai/fb9528212b723c13763aa87e9fe0cf78 to your computer and use it in GitHub Desktop.
Save theahmadzai/fb9528212b723c13763aa87e9fe0cf78 to your computer and use it in GitHub Desktop.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
namespace BlockChain
{
public interface IBlock
{
byte[] Data { get; }
byte[] Hash { get; set; }
int Nonce { get; set; }
byte[] PrevHash { get; set; }
DateTime TimeStamp { get; }
}
public class Block : IBlock
{
public byte[] Data { get; }
public byte[] Hash { get; set; }
public int Nonce { get; set; }
public byte[] PrevHash { get; set; }
public DateTime TimeStamp { get; }
public Block(byte[] data)
{
Data = data ?? throw new ArgumentNullException(nameof(data));
Nonce = 0;
PrevHash = new byte[] { 0x00 };
TimeStamp = DateTime.Now;
}
public override string ToString()
{
return $"{BitConverter.ToString(Hash).Replace("-", "")}:\n{BitConverter.ToString(PrevHash).Replace("-", "")}\n{Nonce} {TimeStamp}";
}
}
public class BlockChain : IEnumerable<IBlock>
{
public List<IBlock> Blocks { get; set; } = new List<IBlock>();
public int Count => Blocks.Count;
public IBlock this[int index] {
get => Blocks[index];
set => Blocks[index] = value;
}
public byte[] Difficulty { get; }
public BlockChain(byte[] difficulty, IBlock genesis)
{
Difficulty = difficulty;
genesis.Hash = genesis.MineHash(difficulty);
Blocks.Add(genesis);
}
public void Add(IBlock block)
{
if(Blocks.LastOrDefault() != null) {
block.PrevHash = Blocks.LastOrDefault()?.Hash;
}
block.Hash = block.MineHash(Difficulty);
}
public IEnumerator<IBlock> GetEnumerator()
{
return Blocks.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public static class BlockChainExtension
{
public static byte[] GenerateHash(this IBlock block)
{
using(SHA256 sha = new SHA256Managed())
using(MemoryStream ms = new MemoryStream())
using(BinaryWriter bw = new BinaryWriter(ms)) {
bw.Write(block.Data);
bw.Write(block.Nonce);
bw.Write(block.TimeStamp.ToBinary());
bw.Write(block.PrevHash);
return sha.ComputeHash(ms.ToArray());
}
}
public static byte[] MineHash(this IBlock block, byte[] difficulty) {
if(difficulty == null) throw new ArgumentNullException(nameof(difficulty));
byte[] hash = new byte[0];
int d = difficulty.Length;
while(!hash.Take(2).SequenceEqual(difficulty)) {
block.Nonce += 1;
hash = block.GenerateHash();
}
return hash;
}
public static bool IsValid(this IBlock block) {
var bk = block.GenerateHash();
return block.Hash.SequenceEqual(bk);
}
public static bool IsValid(this IEnumerable<IBlock> blocks) {
var blocksList = blocks.ToList();
return blocksList.Zip(blocksList.Skip(1), Tuple.Create).All(block => block.Item2.IsValid());
}
public static bool IsValidPrevBlock(this IBlock block, IBlock prevBlock) {
if(prevBlock == null) throw new ArgumentNullException(nameof(prevBlock));
var prev = prevBlock.GenerateHash();
return prevBlock.IsValid() && block.PrevHash.SequenceEqual(prev);
}
}
class Program
{
static void Main(string[] args)
{
Random rnd = new Random(DateTime.UtcNow.Millisecond);
IBlock genesis = new Block(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00 });
byte[] difficulty = new byte[] { 0x00, 0x00 };
BlockChain chain = new BlockChain(difficulty, genesis);
for (int i =0; i<200; i++) {
var data = Enumerable.Range(0, 2256).Select(p => (byte)rnd.Next());
chain.Add(new Block(data.ToArray()));
Console.WriteLine(chain.LastOrDefault()?.ToString());
Console.WriteLine($"chain is valid: {chain.IsValid()}");
}
Console.ReadKey();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment