Java语言实现一个简单的比特币系统,全部源码赏析

发布时间:2018-04-10作者:laosun阅读(759)

Java语言实现一个简单的比特币系统,全部源码赏析

区块链简单比喻为一本账本,把区块比喻为账本的一页记录,账本的每一页里都记录了很多比特币的转账交易

    最近区块链技术突然爆火,这其实跟比特币价格去年的突飞猛涨是分不开的,比特币价格从去年初不到一千美金到今年初最高接近两万美金,赚钱效应已经足够博取大家眼球了,吃瓜群众对比特币价格一年上涨20倍早已目瞪狗呆,个个备足钱袋,跃跃越试。可是,细问一下这些做技术的朋友比特币到底是个什么东西,它是如何构造出来的,能从技术角度解释下比特币吗,还真没几个能答得上来的,作为技术出身的我今天就来带大家用Java语言实现一个简单的比特币系统,学完之后相信上面那几个问题也就能对答如流了

    区块链

    比特币是构建在区块链技术之上的一个加密数字货币,区块链顾名思义即由很多区块组成的链条,可以把区块链简单比喻为一本账本,把区块比喻为账本的一页记录,账本的每一页里都记录了很多比特币的转账交易,那根据这个账本里的所有交易记录应该是能算出任何一个交易者的余额,我们先来构造一个区块的结构:.

    package com.sunjs.model;
    
    import java.util.List;
    
    import com.alibaba.fastjson.JSON;
    import com.sunjs.security.CryptoUtil;
    
    /**
     * 区块结构
     * @author sun
     * @date 2018年4月10日 上午11:35:58
     */
    public class Block {
    
    	/**
    	 * 区块索引号
    	 */
    	private int index;
    	/**
    	 * 当前区块的hash值,区块唯一标识
    	 */
    	private String hash;
    	/**
    	 * 生成区块的时间戳
    	 */
    	private long timestamp;
    	/**
    	 * 当前区块的交易集合
    	 */
    	private List<Transaction> transactions;
    	/**
    	 * 工作量证明,计算正确hash值的次数
    	 */
    	private int nonce;
    	/**
    	 * 前一个区块的hash值
    	 */
    	private String previousHash;
    
    	public Block() {
    		super();
    	}
    
    	public Block(int index, long timestamp, List<Transaction> transactions,
    			int nonce, String previousHash, String hash) {
    		super();
    		this.index = index;
    		this.timestamp = timestamp;
    		this.transactions = transactions;
    		this.nonce = nonce;
    		this.previousHash = previousHash;
    		this.hash = hash;
    	}
    
    	public int getIndex() {
    		return index;
    	}
    
    	public void setIndex(int index) {
    		this.index = index;
    	}
    
    	public long getTimestamp() {
    		return timestamp;
    	}
    
    	public void setTimestamp(long timestamp) {
    		this.timestamp = timestamp;
    	}
    
    	public List<Transaction> getTransactions() {
    		return transactions;
    	}
    
    	public void setTransactions(List<Transaction> transactions) {
    		this.transactions = transactions;
    	}
    
    	public int getNonce() {
    		return nonce;
    	}
    
    	public void setNonce(int nonce) {
    		this.nonce = nonce;
    	}
    
    	public String getPreviousHash() {
    		return previousHash;
    	}
    
    	public void setPreviousHash(String previousHash) {
    		this.previousHash = previousHash;
    	}
    
    	public String getHash() {
    		return hash;
    	}
    
    	public void setHash(String hash) {
    		this.hash = hash;
    	}
    
    	/**
    	 * 挖矿
    	 * 
    	 * @param blockchain
    	 *            整个区块链
    	 * @param txs
    	 *            需记账交易记录
    	 * @param address
    	 *            矿工钱包地址
    	 * @return
    	 */
    	public static void mineBlock(List<Block> blockchain, List<Transaction> txs,
    			String address) {
    		// 加入系统奖励的交易
    		Transaction sysTx = new Transaction(CryptoUtil.UUID(), "", address, 10);
    		txs.add(sysTx);
    		// 获取当前区块链里的最后一个区块
    		Block latestBlock = blockchain.get(blockchain.size() - 1);
    		// 随机数
    		int nonce = 1;
    		String hash = "";
    		while (true) {
    			hash = CryptoUtil.SHA256(latestBlock.getHash()
    					+ JSON.toJSONString(txs) + nonce);
    			if (hash.startsWith("0000")) {
    				System.out.println("=====计算结果正确,计算次数为:" + nonce + ",hash:"
    						+ hash);
    				break;
    			}
    			nonce++;
    //			System.out.println("计算错误,hash:" + hash);
    		}
    
    		// 解出难题,可以构造新区块并加入进区块链里
    		Block newBlock = new Block(latestBlock.getIndex() + 1,
    				System.currentTimeMillis(), txs, nonce, latestBlock.getHash(),
    				hash);
    		blockchain.add(newBlock);
    		System.out.println("挖矿后的区块链:" + JSON.toJSONString(blockchain));
    	}
    
    }
    package com.sunjs.model;
    
    /**
     * 交易
     * 
     * @author sun
     * @date 2018年4月10日 上午11:36:16
     */
    public class Transaction {
    	/**
    	 * 交易唯一标识
    	 */
    	private String id;
    	/**
    	 * 交易发送方
    	 */
    	private String sender;
    	/**
    	 * 交易接收方
    	 */
    	private String recipient;
    	/**
    	 * 交易金额
    	 */
    	private int amount;
    
    	public Transaction() {
    		super();
    	}
    
    	public Transaction(String id, String sender, String recipient, int amount) {
    		super();
    		this.id = id;
    		this.sender = sender;
    		this.recipient = recipient;
    		this.amount = amount;
    	}
    
    	public String getId() {
    		return id;
    	}
    
    	public void setId(String id) {
    		this.id = id;
    	}
    
    	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 int getAmount() {
    		return amount;
    	}
    
    	public void setAmount(int amount) {
    		this.amount = amount;
    	}
    
    	@Override
    	public int hashCode() {
    		final int prime = 31;
    		int result = 1;
    		result = prime * result + ((id == null) ? 0 : id.hashCode());
    		return result;
    	}
    
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (getClass() != obj.getClass())
    			return false;
    		Transaction other = (Transaction) obj;
    		if (id == null) {
    			if (other.id != null)
    				return false;
    		} else if (!id.equals(other.id))
    			return false;
    		return true;
    	}
    
    }

    交易

    转账交易即比特币的拥有方之间进行的相互转账行为,我们把这些比特币的拥有方暂时假设为比特币的钱包,钱包有对应的钱包地址,那这些转账交易实际上就是钱包地址之间的转账交易(类似于支付宝用户之间的转账,其实就是支付宝用户名之间的转账),这些转账交易需要被记录到账本里才算真正的生效。

    由于比特币的转账交易设计比较复杂,我们今天暂时不深入讨论,所以这里我设计了一个简单的交易模型如下:

    挖矿

    挖矿到底是怎么回事?为什么那么多人吵着要去挖矿,梦想着一夜暴富?

    我们可以简单的把挖矿比喻成矿工解一道数学难题的过程,只要解对了就能获取比特币系统奖励的一笔比特币,同时获取了区块链账本新区块的交易记账权,矿工会把比特币系统近期发生的转账交易记录到账本新的一页上,并获取交易的手续费,一旦交易被记录进了账本,交易就算完成了,接收方才能真正收到发送方转账的比特币。那这道数学难题到底长什么样了?

    我们看下这个公式:

    Hash = SHA-256(区块链的最后一个区块的Hash + 需记账交易记录信息 + 随机数)

    这个公式已经很明白了,SHA-256是一种哈希加密算法,被加密的前两部分是固定不变的,我们只有依赖于随机数的不断变化计算出不同的hash结果,系统要求hash结果必须要以10个0开头,这个几率实在是太小太小,我们做测试可以简单一点,比如只要hash结果满足以4个0开头,我们就认为解题成功,即挖矿成功了,这时矿工就可以生成一个新的区块把需记账的交易记录全部记录进区块里去,同时再构造一笔系统奖励给自己的比特币的交易(发起方为系统,接收方为矿工,比特币金额假设为10个),将其也记录进账本,这样通过账本里的交易记录就会发现矿工的余额多了10个比特币了

    余额

    计算某个钱包地址的余额其实就是从区块链账本里找出所有该地址作为接收方的交易记录,将这些交易记录的发生金额累加就得到该地址收到的所有比特币金额了,然后找出所有该地址作为发送方的交易记录再次累加则得到改地址发送出去的所有比特币金额了,用收到的比特币金额之和减去发送出去的比特币金额之和就得到该地址的真正的比特币余额了。

    系统入口

    最后,我们看下这个小比特币系统的运行效果,main函数代码如下:

    package com.sunjs;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import com.alibaba.fastjson.JSON;
    import com.sunjs.model.Block;
    import com.sunjs.model.Transaction;
    import com.sunjs.security.CryptoUtil;
    
    public class Main {
    
    	public static void main(String[] args) {
    		// 创建一个空的区块链
    		List<Block> blockchain = new ArrayList<>();
    		// 生成创世区块
    		Block block = new Block(1, System.currentTimeMillis(),
    				new ArrayList<Transaction>(), 1, "1", "1");
    		// 加入创世区块到区块链里
    		blockchain.add(block);
    		System.out.println(JSON.toJSONString(blockchain));
    
    		// 发送方钱包地址
    		String sender = "sender_wallet";
    		// 接收方钱包地址
    		String recipient = "recipient_wallet";
    
    		// 创建一个空的交易集合
    		List<Transaction> txs = new ArrayList<>();
    		// 挖矿
    		Block.mineBlock(blockchain, txs, sender);
    		System.out.println(sender + "钱包的余额为:"
    				+ getWalletBalance(blockchain, sender));
    
    		// 创建一个空的交易集合
    		List<Transaction> txs1 = new ArrayList<>();
    		// 已发生但未记账的交易记录,发送者给接收者转账3个比特币
    		Transaction tx1 = new Transaction(CryptoUtil.UUID(), sender, recipient,
    				3);
    		// 已发生但未记账的交易记录,发送者给接收者转账1个比特币
    		Transaction tx2 = new Transaction(CryptoUtil.UUID(), sender, recipient,
    				1);
    		txs1.add(tx1);
    		txs1.add(tx2);
    		// 挖矿
    		Block.mineBlock(blockchain, txs1, sender);
    		System.out.println(sender + "钱包的余额为:"
    				+ getWalletBalance(blockchain, sender));
    		System.out.println(recipient + "钱包的余额为:"
    				+ getWalletBalance(blockchain, recipient));
    	}
    
    	/**
    	 * 查询余额
    	 * 
    	 * @param blockchain
    	 * @param address
    	 * @return
    	 */
    	public static int getWalletBalance(List<Block> blockchain, String address) {
    		int balance = 0;
    		for (Block block : blockchain) {
    			List<Transaction> transactions = block.getTransactions();
    			for (Transaction transaction : transactions) {
    				if (address.equals(transaction.getRecipient())) {
    					balance += transaction.getAmount();
    				}
    				if (address.equals(transaction.getSender())) {
    					balance -= transaction.getAmount();
    				}
    			}
    		}
    		return balance;
    	}
    
    }

    运行结果如下图所示:

    至此,我们就用java语言基于区块链账本技术实现了一个简单的比特币系统,包含区块链功能,挖矿产生新比特币功能,转账交易功能,查询余额功能。

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.blockchain.block</groupId>
        <artifactId>blockchain</artifactId>
        <version>1.0-SNAPSHOT</version>
        <properties>
            <java-version>1.8</java-version>
        </properties>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3.2</version>
                    <configuration>
                        <source>${java-version}</source>
                        <target>${java-version}</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.0.2</version>
                    <configuration>
                        <archive>
                            <addMavenDescriptor>false</addMavenDescriptor>
                            <manifest>
                                <addClasspath>true</addClasspath>
                                <classpathPrefix>lib/</classpathPrefix>
                                <mainClass>com.blockchain.Main</mainClass>
                            </manifest>
                        </archive>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-dependency-plugin</artifactId>
                    <version>2.1</version>
                    <executions>
                        <execution>
                            <id>copy-dependencies</id>
                            <phase>package</phase>
                            <goals>
                                <goal>copy-dependencies</goal>
                            </goals>
                            <configuration>
                                <outputDirectory>${project.build.directory}/lib</outputDirectory>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
            <finalName>blockchain</finalName>
            <defaultGoal>compile</defaultGoal>
        </build>
        <dependencies>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.7</version>
            </dependency>
        </dependencies>
    </project>


0 +1

版权声明

 Java  源码  扩展

 请文明留言

0 条评论