用java开发区块链之一、实现单节点脚手架

1 篇文章 0 订阅
0 篇文章 0 订阅

参考文章:https://hackernoon.com/learn-blockchains-by-building-one-117428612f46

原文使用python实现,这里使用java

首先,使用springboot作为容器,打开https://start.spring.io/,输入各项参数,生成项目下载,如下图

因为需要通过web接口接收请求,所以这里需要选择spring web starter

导入项目后,在pom中添加json依赖,以便于后继调试

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.28</version>
</dependency>

以下是完整的包类路径

bo包是业务对象,里面有3个对象,分别是chain--链,block--块,transaction--交易,这三者也是区块链中最基础的业务模型

utils包是工具类包,实现hash算法,用于实现挖矿算法的原型,以及时间戳生成

web包是web接口包,提供了服务与外部之间的交互,按原文,实现了挖矿、新交易、展示区块链内容,

接下来展开各个类来详细介绍如何实现

Transaction.java

package com.zibra.chain.bo;

public class Transaction {
    /*
     * 交易发起人
     */
    private String sender;
    /*
     * 交易接收人
     */
    private String recipient;
    /*
     * 数额
     */
    private String amount;

    public Transaction(String sender, String recipient, String amount) {
        this.sender = sender;
        this.recipient = recipient;
        this.amount = amount;
    }

    public String getSender() {
        return sender;
    }

    public void setSender(String sender) {
        this.sender = sender;
    }

    public String getRecipient() {
        return recipient;
    }

    public void setRecipient(String recipient) {
        this.recipient = recipient;
    }

    public String getAmount() {
        return amount;
    }

    public void setAmount(String amount) {
        this.amount = amount;
    }

}

交易对象里面包含3个属性,发起人、接收人、金额(比特币个数),用以记录每次交易的细节

Block.java

package com.zibra.chain.bo;

import java.util.ArrayList;
import java.util.List;

/**
 * 块
 */
public class Block {
    /*
     * 索引
     */
    private Integer index;
    /*
     * 创建时间戳
     */
    private String timestamp;
    /*
     * 交易列表 
     */
    private List<Transaction> transactions = new ArrayList<Transaction>();
    /*
     * 证明
     */
    private int proof;
    /*
     * 来源hash
     */
    private int previous_hash;

    public Block() {
    }

    public Integer getIndex() {
        return index;
    }

    public void setIndex(Integer index) {
        this.index = index;
    }

    public String getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(String timestamp) {
        this.timestamp = timestamp;
    }

    public List<Transaction> getTransactions() {
        return transactions;
    }

    public void setTransactions(List<Transaction> transactions) {
        this.transactions = transactions;
    }

    public int getProof() {
        return proof;
    }

    public void setProof(int proof) {
        this.proof = proof;
    }

    public int getPrevious_hash() {
        return previous_hash;
    }

    public void setPrevious_hash(int previous_hash) {
        this.previous_hash = previous_hash;
    }

}

块对象也就是区块链中的基础数据单元,形式很像传统关系型数据库中的表,包含了head字段如索引、时间戳、证明、区块链中上一块的hash值,以及截至到下个新块诞生为止的所有交易记录。

块对象是区块链实现不可篡改的核心对象,通过登记上一块的hash值与当前块的proof形成了完整的证据链。

Chain.java

package com.zibra.chain.bo;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import com.zibra.chain.utils.CommonUtil;

/**
 * 区块链原型
 */
public class Chain {
    /*
     * 节点唯一标识
     */
    private static String NODE_ID;
    /*
     * 区块链
     */
    public static List<Block> chain = new ArrayList<Block>();
    /*
     * 当前交易
     */
    public static List<Transaction> current_transactions = new ArrayList<Transaction>();

    /**
     * 初始化
     */
    public Chain() {
        newBlock(100, 1);
    }
    
    /**
     * 获取节点ID 后继可以考虑持久化
     * @return
     */
    public static String getNodeId() {
        if (null == NODE_ID) {
            NODE_ID = UUID.randomUUID().toString();
        }
        return NODE_ID;
    }

    /**
     * 创建一个新的块,并添加到链中
     * 
     * @return
     */
    public static Block newBlock(int proof, int previous_hash) {
        Block block = new Block();
        block.setIndex(chain.size() + 1);
        block.setTimestamp(CommonUtil.getTimesteap());
        block.setPrevious_hash(previous_hash);
        block.setProof(proof);
        block.setTransactions(new ArrayList<Transaction>(current_transactions));
        chain.add(block);
        return block;
    }

    /**
     * 添加一笔新的交易到transactions中
     * 
     * @param sender 发送者地址
     * @param recipient 接收者地址
     * @param amount amount 数量
     * @return 包含该交易记录的块的索引
     */
    public static int newTransaction(Transaction transaction) {
        current_transactions.add(transaction);
        return lastBlock().getIndex() + 1;
    }

    /**
     * 生成块的hash
     * 
     * @param block
     * @return
     */
    public static int hash(Block block) {
        return block.hashCode();
    }

    /**
     * 返回链中的最后一个块
     * 
     * @return
     */
    public static Block lastBlock() {
        return chain.get(chain.size() > 0 ? chain.size() - 1 : 0);
    }

    /**
     * 工作量证明
     * 
     * @param last_proof
     */
    public static Integer proofOfWork(int last_proof) {
        int proof = 0;
        if (validProof(last_proof, proof)) {
            proof++;
        }
        return proof;
    }

    /**
     * 验证算法
     * 
     * @param last_proof
     * @param proof
     * @return
     */
    public static boolean validProof(int last_proof, int proof) {
        return CommonUtil.getHash((String.valueOf(last_proof) + String.valueOf(proof))).startsWith("00");
    }

}

链对象中包含两个链表,一个记录了所有按先后顺序生成的块,另一个记录了所有交易的列表。

这里还实现了一些区块链核心功能,如创建新块、块的hash值计算、挖矿算法(proof of work)、验证hash值(传说中0越多难度越高的控制器)。

原文中为了阐述原理,略去了为了控制比特币奖励、按时间提高挖矿难度的导致程序可读性下降的逻辑,但如果了解原理,还是很容易在代码上实现的。

关于比特币,大家请自行查看资料。

CommonUtil.java

package com.zibra.chain.utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class CommonUtil {

    /**
     * 获取hash值
     * @param source
     * @return
     */
    public static String getHash(String source) {
        return getHash2(source, "MD5");
    }

    /**
     * 获取hash值
     * @param source
     * @param hashType
     * @return
     */
    public static String getHash2(String source, String hashType) {
        StringBuilder sb = new StringBuilder();
        MessageDigest md5;
        try {
            md5 = MessageDigest.getInstance(hashType);
            md5.update(source.getBytes());
            for (byte b : md5.digest()) {
                sb.append(String.format("%02X", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 获取时间戳
     * @return
     */
    public static String getTimesteap() {
        return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date());
    }
}

工具类中使用java的md5进行hash计算,与时间戳

 

BlockChainController.java

package com.zibra.chain.web;

import java.util.HashMap;
import java.util.Map;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.zibra.chain.bo.Block;
import com.zibra.chain.bo.Chain;
import com.zibra.chain.bo.Transaction;

/**
 * 入口
 */
@RestController
public class BlockChainController {
    /**
     * 挖矿
     * 
     * @return
     */
    @PostMapping(value = "/mine")
    public Map<String, Object> mine() {
        //运行工作量证明算法,获取下一个proof
        Block block = Chain.lastBlock();
        int last_proof = block.getProof();
        int proof = Chain.proofOfWork(last_proof);
        //获取奖励,发送者为"0", 表明是该节点挖出来的新币
        Chain.newTransaction(new Transaction("0", Chain.getNodeId(), "1"));
        //创建新的区块,并添加到链中
        int previous_hash = Chain.hash(block);
        block = Chain.newBlock(proof, previous_hash);
        //回复挖矿结果
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("message", "New Block Forged");
        result.put("index", block.getIndex());
        result.put("transactions", JSON.toJSONString(block.getTransactions(), SerializerFeature.PrettyFormat));
        result.put("proof", block.getProof());
        result.put("previous_hash", block.getPrevious_hash());
        return result;
    }

    /**
     * 添加交易
     * 
     * @param transaction
     * @return
     */
    @PostMapping(value = "/transactions/new")
    public String newTransaction(Transaction transaction) {
        if (null == transaction.getSender() || null == transaction.getSender() || null == transaction.getSender()) {
            return "error/404";
        }
        int index = Chain.newTransaction(transaction);
        return "添加新交易" + index;
    }

    /**
     * 显示内容
     * 
     * @return
     */
    @PostMapping(value = "/chain")
    public String chain() {
        return JSON.toJSONString(Chain.chain, SerializerFeature.PrettyFormat);
    }
}

web入口实现了挖矿,添加交易,查看区块链全体内容三个方法,可以通过postman调用

可以按如下步骤执行,先查看区块链内容,里面只有一个初始块

执行一个挖矿动作,会返回一个新块内容

执行一次新增交易,可以看到提交成功

查看区块链内容

可见交易已经成功添加到块中

以此类推,添加块,交易,就能看到交易信息被记录到各个块中了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值