当前位置:   article > 正文

用java写区块链_java中实现一个区块链的基本功能

java中实现一个区块链的基本功能

区块链就好比多个区块连接起来。其中每一块都将拥有自己的签名,签名由其前面的块签名、当前块的一些数据(例如交易信息)生成。

每个块不仅仅包含它之前的块信息,同时也包含自身。如果前面一块内容改变了,其 hash 值也会改变,将会导致其后面所有的块发生变化。通过计算和比较所得的 hash 值,我们可以判断区块链是否合法。换句话说,改变区块链中的任意内容,将会改变整个区块链的签名。区块链就是区块+链,首先创建区块,然后把区块串起来,就像串珠子一样。每个区块可以存储各种数据或数据的摘要。区块链是一个数据库,区块就是数据库的一条记录。

根据上面的分析,我们先创建一个 Block 类。

  1. import java.util.Date;
  2. public class Block {
  3. public String hash; //本区块的数字签名
  4. public String preHash; //前面区块的数字签名
  5. private String data;//本区块存放的数据
  6. private long timeStamp;//本区块产生的时间
  7. public Block(String data, String preHash) {
  8. this.data = data;
  9. this.preHash = preHash;
  10. this.timeStamp = new Date().getTime();
  11. }
  12. }

接下来,我们需要一个生成签名的方法。有很多加密算法可供选择,这里使用 SHA256。

  1. import java.security.MessageDigest;
  2. public class StringUtil {
  3. public static String applySha256(String input) {
  4. try {
  5. MessageDigest digest = MessageDigest.getInstance("SHA-256");
  6. byte[] hash = digest.digest(input.getBytes("UTF-8"));
  7. StringBuilder hexString = new StringBuilder();
  8. for (int i = 0; i < hash.length; i++) {
  9. String hex = Integer.toHexString(0xff & hash[i]);
  10. if (hex.length() == 1) hexString.append('0');
  11. hexString.append(hex);
  12. }
  13. return hexString.toString();
  14. } catch (Exception e) {
  15. throw new RuntimeException(e);
  16. }
  17. }
  18. }

现在,我们向 Block 类中添加计算数字签名的方法,并修改一下其构造方法。

  1. public Block(String data, String preHash) {
  2. this.data = data;
  3. this.preHash = preHash;
  4. this.timeStamp = new Date().getTime();
  5. this.hash = calculateHash();
  6. }
  7. public String calculateHash() {
  8. String calculatedhash = StringUtil.applySha256(preHash + Long.toString(timeStamp) + data);
  9. return calculatedhash;
  10. }

 到这里,可以写个 Main 方法看一下效果。

  1. public class Main {
  2. public static void main(String[] args) {
  3. Block first = new Block("Hi i am the first block", "0");
  4. System.out.println("Hash for block 1 : " + first.hash);
  5. Block second = new Block("Hi i am the second block", first.hash);
  6. System.out.println("Hash for block 2 : " + second.hash);
  7. Block third = new Block("Hi i am the third block", second.hash);
  8. System.out.println("Hash for block 3 : " + third.hash);
  9. }
  10. }

可以看见每个 Block 都有自己唯一的 数字签名,当然,现在还没有构成一个区块链,将这些块存放到一个 ArrayList 中吧。修改 Main 类后再次运行。

  1. import com.google.gson.GsonBuilder;
  2. import java.util.ArrayList;
  3. public class Main {
  4. public static ArrayList<Block> blockchain = new ArrayList<Block>();
  5. public static void main(String[] args) {
  6. blockchain.add(new Block("Hi i am the first block", "0"));
  7. blockchain.add(new Block("Hi i am the second block", blockchain.get(blockchain.size() - 1).hash));
  8. blockchain.add(new Block("Hi i am the third block", blockchain.get(blockchain.size() - 1).hash));
  9. String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
  10. System.out.println(blockchainJson);
  11. }
  12. }

现在,需要一种方法去验证创建的区块链。编写一段 isChainValid() 方法。任何块的改变将会导致这个方法失效。

  1. public static Boolean isChainValid() {
  2. Block currentBlock;
  3. Block previousBlock;
  4. for (int i = 1; i < blockchain.size(); i++) {
  5. currentBlock = blockchain.get(i);
  6. previousBlock = blockchain.get(i - 1);
  7. if (!currentBlock.hash.equals(currentBlock.calculateHash())) {
  8. //当前区块不能由上一区块计算出来,说明上一区块改变了
  9. System.out.println("Current Hashes not equal!");
  10. return false;
  11. }
  12. if (!previousBlock.hash.equals(currentBlock.preHash)) {
  13. //当前区块中保持的上一区块hash不等于上一区块hash,说明上一区块改变了
  14. System.out.println("Previous Hashes not equal!");
  15. return false
  16. }
  17. }
  18. return true;
  19. }

接下来,尝试一下挖矿! 

在 Block 类中,新增一个变量 nonce(随机数),并且添加到 calculateHash() 这个方法中,同时需要 mineBlock() 这个方法。这个方法中的 difficulty 变量就是用来控制计算量的。当设置的值较低时,大部分计算机很快就能算出来。

  1. import java.util.Date;
  2. public class Block {
  3. public String hash; //本区块的数字签名
  4. public String preHash; //前面区块的数字签名
  5. private String data;//本区块存放的数据
  6. private long timeStamp;//本区块产生的时间
  7. private int nonce;//随机数
  8. public Block(String data, String preHash) {
  9. this.data = data;
  10. this.preHash = preHash;
  11. this.timeStamp = new Date().getTime();
  12. this.hash = calculateHash();
  13. }
  14. /**
  15. * 根据前面区块前面+本区块产生时间+本区块数据生成本区块签名
  16. * @return
  17. */
  18. public String calculateHash() {
  19. String calculatedhash = StringUtil.applySha256(preHash + Long.toString(timeStamp) + Integer.toString(nonce) +
  20. data);
  21. return calculatedhash;
  22. }
  23. //挖矿
  24. public void mineBlock(int difficulty) {
  25. String target = new String(new char[difficulty]).replace('\0', '0');
  26. while (!hash.substring(0, difficulty).equals(target)) {//找到符合难度的hash
  27. nonce++;
  28. hash = calculateHash();
  29. }
  30. System.out.println("Block Mined!!!" + hash);
  31. }
  32. }

我们可以在 Main 类中定义个静态变量。尝试在每次创建新块去调用 mineBlock() 方法。

  1. import com.google.gson.GsonBuilder;
  2. import java.util.ArrayList;
  3. import java.util.Date;
  4. public class Main {
  5. public static ArrayList<Block> blockchain = new ArrayList<Block>();
  6. public static int difficulty = 5;
  7. public static void main(String[] args) {
  8. long beginTime1 = new Date().getTime();
  9. blockchain.add(new Block("Hi i am the first block", "0"));
  10. System.out.println("Trying to mine block 1...");
  11. blockchain.get(0).mineBlock(difficulty);
  12. long endTime1 = new Date().getTime();
  13. System.out.println("Mining block 1 cost " + (endTime1 - beginTime1));
  14. long beginTime2 = new Date().getTime();
  15. blockchain.add(new Block("Hi i am the second block", blockchain.get(blockchain.size() - 1).hash));
  16. System.out.println("Trying to mine block 2...");
  17. blockchain.get(1).mineBlock(difficulty);
  18. long endTime2 = new Date().getTime();
  19. System.out.println("Mining block 1 cost " + (endTime2 - beginTime2));
  20. long beginTime3 = new Date().getTime();
  21. blockchain.add(new Block("Hi i am the third block", blockchain.get(blockchain.size() - 1).hash));
  22. System.out.println("Trying to mine block 3...");
  23. blockchain.get(2).mineBlock(difficulty);
  24. long endTime3 = new Date().getTime();
  25. System.out.println("Mining block 1 cost " + (endTime3 - beginTime3));
  26. System.out.println("\nBlockchain is Valid: " + isChainValid());
  27. String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
  28. System.out.println(blockchainJson);
  29. }
  30. public static Boolean isChainValid() {
  31. Block currentBlock;
  32. Block previousBlock;
  33. String hashTarget = new String(new char[difficulty]).replace('\0', '0');
  34. for (int i = 1; i < blockchain.size(); i++) {
  35. currentBlock = blockchain.get(i);
  36. previousBlock = blockchain.get(i - 1);
  37. if (!currentBlock.hash.equals(currentBlock.calculateHash())) {
  38. System.out.println("Current Hashes not equal!");
  39. return false;
  40. }
  41. if (!previousBlock.hash.equals(currentBlock.preHash)) {
  42. System.out.println("Previous Hashes not equal!");
  43. return false;
  44. }
  45. if (!currentBlock.hash.substring(0, difficulty).equals(hashTarget)) {
  46. System.out.println("This block hasn't been mined");
  47. return false;
  48. }
  49. }
  50. return true;
  51. }
  52. }

运行发现,挖矿过程还是很费时间的。把计算量改成7,差不多每挖一个需要一分钟。。。

如果在此过程中,有人篡改了数据,将会导致:

1)区块链将会无效

2)不能够创建一个更长的区块链

3)网络中的诚实链将会比较长的区块链有时间上的优势

不过如果篡改数据拥有更强的运算速度,可能成功篡改。

这样,基本上简单实现了一个区块链了。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号