diff --git a/BasicBlockChain/BasicBlockChain.csproj b/BasicBlockChain/BasicBlockChain.csproj index 425c00d..ba0825e 100644 --- a/BasicBlockChain/BasicBlockChain.csproj +++ b/BasicBlockChain/BasicBlockChain.csproj @@ -50,6 +50,7 @@ + diff --git a/BasicBlockChain/Block.cs b/BasicBlockChain/Block.cs index d92b4f3..643403f 100644 --- a/BasicBlockChain/Block.cs +++ b/BasicBlockChain/Block.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Security.Cryptography; using System.Text; @@ -9,25 +10,38 @@ namespace BasicBlockChain public int Index { get; set; } public DateTime Date { get; set; } public string PreviousHash { get; set; } - public string Data { get; set; } + public List Transactions { get; } = new List(); public string Hash { get; set; } public int Nonce { get; set; } - public Block(DateTime date, Block previousBlock, string data) + public Block(DateTime date, Block previousBlock, IList transactions) { Index = (previousBlock?.Index ?? -1) + 1; Date = date; PreviousHash = previousBlock?.Hash; - Data = data; + if (transactions != null) { Transactions.AddRange(transactions); } Nonce = 0; Hash = CalculateHash(); } - public string CalculateHash() + private string GetData() { - SHA256 sha256 = SHA256.Create(); + VAR.Json.JsonWriter jsonWriter = new VAR.Json.JsonWriter(1); + return jsonWriter.Write(Transactions); + } - byte[] dataBytes = Encoding.UTF8.GetBytes(string.Format("{0}-{1}-{2}-{3}", Date, PreviousHash, Data, Nonce)); + public string CalculateHash(string data = null, SHA256 sha256 = null) + { + if (sha256 == null) { sha256 = SHA256.Create(); } + if (data == null) + { + data = GetData(); + } + byte[] dataBytes = Encoding.UTF8.GetBytes(string.Format("{0}-{1}-{2}-{3}", + Date, + PreviousHash, + data, + Nonce)); byte[] hashBytes = sha256.ComputeHash(dataBytes); string hash = Convert.ToBase64String(hashBytes); @@ -36,11 +50,13 @@ namespace BasicBlockChain public void Mine(int difficulty) { + SHA256 sha256 = SHA256.Create(); var leadingZeros = new string('0', difficulty); + string data = GetData(); while (Hash.Substring(0, difficulty) != leadingZeros) { Nonce++; - Hash = CalculateHash(); + Hash = CalculateHash(data, sha256); } } } diff --git a/BasicBlockChain/BlockChain.cs b/BasicBlockChain/BlockChain.cs index 69e1a34..3f34b3c 100644 --- a/BasicBlockChain/BlockChain.cs +++ b/BasicBlockChain/BlockChain.cs @@ -11,16 +11,16 @@ namespace BasicBlockChain public BlockChain(DateTime? genesisDate = null, int difficulty = 2) { - Block genesisBlock = new Block(genesisDate ?? DateTime.UtcNow, null, "{}"); + Block genesisBlock = new Block(genesisDate ?? DateTime.UtcNow, null, null); genesisBlock.Mine(difficulty); Difficulty = difficulty; Chain.Add(genesisBlock); } - public void AddData(DateTime date, string data) + public void AddBlock(DateTime date, IList transactions) { Block lastBlock = Chain.Last(); - Block newBlock = new Block(date, lastBlock, data); + Block newBlock = new Block(date, lastBlock, transactions); newBlock.Mine(Difficulty); Chain.Add(newBlock); } @@ -40,5 +40,30 @@ namespace BasicBlockChain } return true; } + + public long GetMicroCoinBalance(string receiver) + { + long microCoinBalance = 0; + + for (int i = 0; i < Chain.Count; i++) + { + for (int j = 0; j < Chain[i].Transactions.Count; j++) + { + var transaction = Chain[i].Transactions[j]; + + if (transaction.Sender == receiver) + { + microCoinBalance -= transaction.MicroCoinAmount; + } + + if (transaction.Receiver == receiver) + { + microCoinBalance += transaction.MicroCoinAmount; + } + } + } + + return microCoinBalance; + } } } diff --git a/BasicBlockChain/Program.cs b/BasicBlockChain/Program.cs index 42c4dd2..3d27a7e 100644 --- a/BasicBlockChain/Program.cs +++ b/BasicBlockChain/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace BasicBlockChain { @@ -13,9 +14,9 @@ namespace BasicBlockChain Console.WriteLine("#### Mining BlockChain with sample data"); var startTime = DateTime.UtcNow; BlockChain nullCoin = new BlockChain(genesisDate: new DateTime(2000, 1, 1), difficulty: 2); - nullCoin.AddData(new DateTime(2000, 1, 2), "{ sender: VAR, receiver: NAM, amount: 10.00}"); - nullCoin.AddData(new DateTime(2000, 1, 3), "{ sender: NAM, receiver: VAR, amount: 5.00}"); - nullCoin.AddData(new DateTime(2000, 1, 4), "{ sender: NAM, receiver: VAR, amount: 5.00}"); + nullCoin.AddBlock(new DateTime(2000, 1, 2), new List { new Transaction("VAR", "NAM", 10_000_000) }); + nullCoin.AddBlock(new DateTime(2000, 1, 3), new List { new Transaction("NAM", "VAR", 5_000_000) }); + nullCoin.AddBlock(new DateTime(2000, 1, 4), new List { new Transaction("NAM", "VAR", 5_000_000) }); Console.WriteLine(jsonWriter.Write(nullCoin)); var endTime = DateTime.UtcNow; Console.WriteLine($"Duration: {endTime - startTime}"); @@ -23,14 +24,21 @@ namespace BasicBlockChain // Verify Console.WriteLine("BlockChain is Valid? {0}", nullCoin.Verify() ? "True" : "False"); + // Show balance + Console.WriteLine("Balance of \"{0}\": {1}", "VAR", nullCoin.GetMicroCoinBalance("VAR")); + Console.WriteLine("Balance of \"{0}\": {1}", "NAM", nullCoin.GetMicroCoinBalance("NAM")); + // Tamper with the data Console.WriteLine(); Console.WriteLine("#### Tampering with the data"); - nullCoin.Chain[1].Data = "{ sender: VAR, receiver: NAM, amount: 1000.00}"; + nullCoin.Chain[1].Transactions.Clear(); + nullCoin.Chain[1].Transactions.Add(new Transaction("VAR", "NAM", 1000_000_000)); Console.WriteLine(jsonWriter.Write(nullCoin)); // Verify Console.WriteLine("BlockChain is Valid? {0}", nullCoin.Verify() ? "True" : "False"); + Console.WriteLine("Balance of \"{0}\": {1}", "VAR", nullCoin.GetMicroCoinBalance("VAR")); + Console.WriteLine("Balance of \"{0}\": {1}", "NAM", nullCoin.GetMicroCoinBalance("NAM")); Console.Read(); } diff --git a/BasicBlockChain/Transaction.cs b/BasicBlockChain/Transaction.cs new file mode 100644 index 0000000..39e4750 --- /dev/null +++ b/BasicBlockChain/Transaction.cs @@ -0,0 +1,16 @@ +namespace BasicBlockChain +{ + public class Transaction + { + public string Sender { get; set; } + public string Receiver { get; set; } + public long MicroCoinAmount { get; set; } + + public Transaction(string sender, string receiver, long microCoinAmount) + { + Sender = sender; + Receiver = receiver; + MicroCoinAmount = microCoinAmount; + } + } +}